4 Commits

Author SHA1 Message Date
sysadmin 87172229aa feat: support and test MDCPS reviewer identity per #107
- Update v2 test config: mdcps reviewer username '913443' (distinct from author 'jcwalker3'), author 'jcwalker3'
- Adjust TBD negative test to use mutate (post-provisioning)
- Add mdcps-reviewer example to gitea-mcp.example.json and README
- Verifies distinct identities, reviewer cannot create/push, author cannot review/merge

Closes #107

Checks:
- config tests pass
- no secrets in changes (usernames only)
- py_compile and diff clean
2026-07-04 18:35:45 -04:00
sysadmin e88ca1d64b Merge pull request 'feat: complete operator guide and skill registry requirements (#129)' (#134) from feat/issue-129-operator-guide-skills into master 2026-07-04 16:49:45 -05:00
sysadmin 4253f8a52a feat: satisfy Issue #129 operator guide and skill registry requirements 2026-07-04 17:46:19 -04:00
sysadmin cd1d8d71a2 Merge pull request 'fix: redact Gitea web links from PR/issue MCP tool output (#125)' (#133) from feat/issue-125-pr-url-redaction into master 2026-07-04 16:44:24 -05:00
5 changed files with 50 additions and 11 deletions
+6
View File
@@ -221,6 +221,12 @@ Canonical profile file (e.g. `~/.config/gitea-tools/profiles.json`):
"username": "913443",
"auth": { "type": "env", "name": "GITEA_TOKEN_MDCPS" },
"execution_profile": "mdcps"
},
"mdcps-reviewer": {
"base_url": "https://gitea.dadeschools.net",
"username": "913443",
"auth": { "type": "keychain", "id": "mdcps.gitea.reviewer.token" },
"execution_profile": "mdcps-reviewer"
}
}
}
+6 -5
View File
@@ -18,16 +18,17 @@ behavior they rely on already exists (canonical runtime profiles, the
interactive setup menu, identity/eligibility checks, gated review/merge, and
audit logging). See [Related documents](#related-documents).
> **New session? Call the guide tools first (#128).** Before using any other
> **New session? Call the guide tools first (#128 / #129).** Before using any other
> Gitea MCP tool in a fresh session, call `mcp_get_control_plane_guide`
> (read-only): it reports the active profile, authenticated identity,
> allowed/forbidden operations, profile-aware do/don't guidance, and the
> non-negotiable rules (hard stops, fail-closed behavior, head-SHA pinning,
> merge confirmation, redaction, author/reviewer separation, profile
> switching). Then call `mcp_list_project_skills` to discover the available
> project workflows and `mcp_get_skill_guide(<name>)` for step-by-step
> instructions. This replaces long pasted operator prompts for the standard
> rules; operator prompts still control task-specific scope.
> switching). Also call `gitea_get_runtime_context` and `mcp_list_project_skills`
> to discover the available project workflows and `mcp_get_skill_guide(<name>)`
> for step-by-step instructions. This replaces long pasted operator prompts for
> the standard rules; operator prompts still control task-specific scope.
> See issue #129 for the skill registry design.
For cross-project use, copy the portable workflow skill at
[`../skills/llm-project-workflow/SKILL.md`](../skills/llm-project-workflow/SKILL.md).
+12
View File
@@ -21,6 +21,18 @@
"default_owner": "Contractor",
"execution_profile": "mdcps"
},
"mdcps-reviewer": {
"base_url": "https://gitea.dadeschools.net",
"username": "913443",
"auth": {
"type": "keychain",
"id": "mdcps.gitea.reviewer.token"
},
"default_owner": "MDCPS",
"execution_profile": "mdcps-reviewer",
"allowed_operations": ["read", "review", "approve", "merge"],
"forbidden_operations": ["branch.push", "pr.create"]
},
"prgs-env": {
"base_url": "https://gitea.prgs.cc",
"username": "jcwalker3",
+11 -5
View File
@@ -75,7 +75,7 @@ def v2_config():
"identities": {
"author": {
"role": "author",
"username": "913443",
"username": "jcwalker3",
"auth": {"type": "keychain",
"id": "mdcps.gitea.author.token"},
"allowed_operations": ["gitea.read"],
@@ -85,7 +85,7 @@ def v2_config():
},
"reviewer": {
"role": "reviewer",
"username": "TBD-second-mdcps-user",
"username": "913443",
"auth": {"type": "keychain",
"id": "mdcps.gitea.reviewer.token"},
"allowed_operations": [
@@ -251,16 +251,22 @@ class TestV2Selectors(_V2Base):
self._load_raises(mutate, "unknown profile")
def test_tbd_username_fails_closed_on_selection(self):
def mutate(cfg):
cfg["environments"]["mdcps"]["services"]["gitea"]["identities"]["reviewer"]["username"] = "TBD-second-mdcps-user"
cfg = v2_config()
mutate(cfg)
self._write(cfg)
with patch.dict(os.environ, self._env("mdcps.gitea.reviewer"), clear=True):
with self.assertRaises(gitea_config.ConfigError) as ctx:
self._resolve("mdcps.gitea.reviewer")
gitea_config.resolve_profile()
msg = str(ctx.exception)
self.assertIn("TBD", msg)
self.assertIn("provision", msg)
# Note: after #107 provisioning, real username "913443" is used in live config and happy-path tests.
def test_tbd_identity_does_not_block_other_identities(self):
# Same file contains the TBD reviewer; author still resolves.
p = self._resolve("mdcps.gitea.author")
self.assertEqual(p["username"], "913443")
self.assertEqual(p["username"], "jcwalker3")
# ---------------------------------------------------------------------------
+14
View File
@@ -141,6 +141,20 @@ class TestControlPlaneGuide(GuideTestBase):
with self.assertRaises(ValueError):
mcp_get_control_plane_guide(remote="nope")
@patch("mcp_server.api_request", return_value={"login": "new-session-bot"})
@patch("mcp_server.get_auth_header", return_value=FAKE_AUTH)
def test_new_session_can_call_guide_for_operating_model(self, _auth, _api):
"""Covers #129 AC: New LLM sessions can call one guide tool to understand the MCP Control Plane operating model."""
with patch.dict(os.environ, AUTHOR_ENV, clear=True):
g = mcp_get_control_plane_guide(remote="prgs")
self.assertTrue(g["read_only"])
self.assertIn("profile", g)
self.assertIn("identity", g)
self.assertIn("guidance", g)
self.assertIn("rules", g)
self.assertIn("workflows", g)
self.assertEqual(g["skills_tool"], "mcp_list_project_skills")
# ---------------------------------------------------------------------------
# mcp_list_project_skills