From e880a210ec1c17ff7cbbc58a876e0cd099e030b7 Mon Sep 17 00:00:00 2001 From: Jason Walker <913443@dadeschools.net> Date: Fri, 3 Jul 2026 18:08:41 -0400 Subject: [PATCH] feat: extend whoami and profile metadata for environments (#104) Closes #104 --- gitea_auth.py | 18 +++++++- mcp_server.py | 16 +++++++ tests/test_mcp_server.py | 92 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/gitea_auth.py b/gitea_auth.py index ac754e4..89c6426 100644 --- a/gitea_auth.py +++ b/gitea_auth.py @@ -473,13 +473,29 @@ def get_profile(): token_source = (os.environ.get("GITEA_TOKEN_SOURCE") or "").strip() \ or gitea_config.auth_source_name(jp) base_url = os.environ.get("GITEA_BASE_URL") or jp.get("base_url") or None + auth_type = None + if isinstance(jp.get("auth"), dict): + auth_type = jp["auth"].get("type") + elif token_source: + if token_source.startswith("keychain:"): + auth_type = "keychain" + else: + auth_type = "env" + return { "profile_name": name, "allowed_operations": ops, "forbidden_operations": forbidden, "audit_label": audit_label, "token_source_name": token_source, + "auth_source_type": auth_type, "base_url": base_url, "username": jp.get("username") or None, "default_owner": jp.get("default_owner") or None, - } + "profile_path": jp.get("profile_path") or None, + "environment": jp.get("environment") or None, + "service": jp.get("service") or None, + "identity": jp.get("identity") or None, + "role": jp.get("role") or None, + "execution_profile": jp.get("execution_profile") or None, + } \ No newline at end of file diff --git a/mcp_server.py b/mcp_server.py index 076abd8..4972ac5 100644 --- a/mcp_server.py +++ b/mcp_server.py @@ -1417,6 +1417,15 @@ def gitea_whoami( "profile": { "profile_name": profile["profile_name"], "allowed_operations": profile["allowed_operations"], + "forbidden_operations": profile["forbidden_operations"], + "environment": profile.get("environment"), + "service": profile.get("service"), + "identity": profile.get("identity"), + "role": profile.get("role"), + "profile_address": profile.get("profile_path"), + "execution_profile": profile.get("execution_profile"), + "audit_label": profile.get("audit_label"), + "auth_source_type": profile.get("auth_source_type"), }, } if _reveal_endpoints(): @@ -1480,6 +1489,13 @@ def gitea_get_profile( "allowed_operations": profile["allowed_operations"], "forbidden_operations": profile["forbidden_operations"], "audit_label": profile["audit_label"], + "environment": profile.get("environment"), + "service": profile.get("service"), + "identity": profile.get("identity"), + "role": profile.get("role"), + "profile_address": profile.get("profile_path"), + "execution_profile": profile.get("execution_profile"), + "auth_source_type": profile.get("auth_source_type"), # Auth is reported as a status only (#120): the token source *name* # (env var name / keychain id) joins endpoint URLs behind the # GITEA_MCP_REVEAL_ENDPOINTS admin opt-in. Token values never appear. diff --git a/tests/test_mcp_server.py b/tests/test_mcp_server.py index 5ac086a..50d0c3d 100644 --- a/tests/test_mcp_server.py +++ b/tests/test_mcp_server.py @@ -995,6 +995,65 @@ class TestRuntimeProfile(unittest.TestCase): for secret in ("super-secret-token", "token", "authorization", "basic "): self.assertNotIn(secret, blob) + @patch("mcp_server.api_request") + @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) + def test_whoami_v2_metadata(self, _auth, mock_api): + mock_api.return_value = {"id": 7, "login": "rev"} + env = { + "GITEA_PROFILE_NAME": "gitea-reviewer", + "GITEA_ALLOWED_OPERATIONS": "read,review,approve", + "GITEA_FORBIDDEN_OPERATIONS": "merge", + "GITEA_AUDIT_LABEL": "reviewer-runtime", + "GITEA_TOKEN_SOURCE": "keychain:prgs-reviewer-token", + } + with patch.dict(os.environ, env, clear=True): + result = gitea_whoami(remote="prgs") + profile = result["profile"] + self.assertEqual(profile["environment"], None) + self.assertEqual(profile["service"], None) + self.assertEqual(profile["identity"], None) + self.assertEqual(profile["role"], None) + self.assertEqual(profile["profile_address"], None) + self.assertEqual(profile["execution_profile"], None) + self.assertEqual(profile["audit_label"], "reviewer-runtime") + self.assertEqual(profile["auth_source_type"], "keychain") + self.assertEqual(profile["forbidden_operations"], ["merge"]) + + @patch("mcp_server.api_request") + @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) + @patch("mcp_server.get_profile") + def test_whoami_v2_resolved_metadata(self, mock_get_profile, _auth, mock_api): + mock_api.return_value = {"id": 7, "login": "rev"} + mock_get_profile.return_value = { + "profile_name": "prgs.gitea.reviewer", + "allowed_operations": ["read", "review"], + "forbidden_operations": ["merge"], + "audit_label": "rev-audit", + "token_source_name": "keychain:prgs-reviewer-token", + "auth_source_type": "keychain", + "base_url": "https://gitea.prgs.cc", + "username": "sysadmin", + "default_owner": "Scaled-Tech-Consulting", + "profile_path": "prgs.gitea.reviewer", + "environment": "prgs", + "service": "gitea", + "identity": "reviewer", + "role": "reviewer", + "execution_profile": "reviewer-profile", + } + result = gitea_whoami(remote="prgs") + profile = result["profile"] + self.assertEqual(profile["environment"], "prgs") + self.assertEqual(profile["service"], "gitea") + self.assertEqual(profile["identity"], "reviewer") + self.assertEqual(profile["role"], "reviewer") + self.assertEqual(profile["profile_address"], "prgs.gitea.reviewer") + self.assertEqual(profile["execution_profile"], "reviewer-profile") + self.assertEqual(profile["audit_label"], "rev-audit") + self.assertEqual(profile["auth_source_type"], "keychain") + self.assertEqual(profile["forbidden_operations"], ["merge"]) + + # --------------------------------------------------------------------------- # Profile discovery (read-only) — issue #13 @@ -1082,6 +1141,39 @@ class TestProfileDiscovery(unittest.TestCase): self.assertIsNone(result["remote"]) self.assertIn("remote_error", result) + @patch("mcp_server.api_request") + @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) + @patch("mcp_server.get_profile") + def test_get_profile_v2_resolved_metadata(self, mock_get_profile, _auth, mock_api): + mock_api.return_value = {"id": 7, "login": "rev"} + mock_get_profile.return_value = { + "profile_name": "prgs.gitea.reviewer", + "allowed_operations": ["read", "review"], + "forbidden_operations": ["merge"], + "audit_label": "rev-audit", + "token_source_name": "keychain:prgs-reviewer-token", + "auth_source_type": "keychain", + "base_url": "https://gitea.prgs.cc", + "username": "sysadmin", + "default_owner": "Scaled-Tech-Consulting", + "profile_path": "prgs.gitea.reviewer", + "environment": "prgs", + "service": "gitea", + "identity": "reviewer", + "role": "reviewer", + "execution_profile": "reviewer-profile", + } + result = gitea_get_profile(remote="prgs") + self.assertEqual(result["environment"], "prgs") + self.assertEqual(result["service"], "gitea") + self.assertEqual(result["identity"], "reviewer") + self.assertEqual(result["role"], "reviewer") + self.assertEqual(result["profile_address"], "prgs.gitea.reviewer") + self.assertEqual(result["execution_profile"], "reviewer-profile") + self.assertEqual(result["auth_source_type"], "keychain") + self.assertEqual(result["forbidden_operations"], ["merge"]) + + # --------------------------------------------------------------------------- # PR eligibility checks (read-only) — issue #14 -- 2.43.7