Record the #139 accepted decision as a deployment doc: two static per-role MCP namespaces (gitea-author, gitea-reviewer), one credential per process, with dynamic profile switching and dispatcher routing explicitly rejected for now. Covers rationale (audit clarity, credential concentration, two-party review boundary, fail-closed behavior), reference-only client setup via GITEA_MCP_CONFIG/GITEA_MCP_PROFILE, the 'Auth unsupported' client-badge caveat, and reconnect/reload requirements after profile/config/code changes. Cross-linked from the execution-profiles model doc and the workflow runbooks; guarded by docs-content tests. Closes #143 Co-Authored-By: Claude Fable 5 <[email protected]>
71 lines
2.7 KiB
Python
71 lines
2.7 KiB
Python
"""Docs checks for the static dual-namespace deployment model (#143).
|
|
|
|
Issue #139's accepted decision: run two static, per-role Gitea MCP
|
|
namespaces (`gitea-author`, `gitea-reviewer`) instead of dynamic profile
|
|
switching or a dispatcher. These tests keep the deployment doc present,
|
|
accurate to that decision, cross-linked from the operator docs, and free
|
|
of secret material or raw service URLs.
|
|
"""
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
DOC = REPO_ROOT / "docs" / "gitea-dual-namespace-deployment.md"
|
|
|
|
|
|
def _doc_text():
|
|
assert DOC.is_file(), "missing docs/gitea-dual-namespace-deployment.md"
|
|
return DOC.read_text(encoding="utf-8")
|
|
|
|
|
|
def test_doc_exists_with_title_and_content():
|
|
text = _doc_text()
|
|
assert text.lstrip().startswith("#"), "doc lacks a title"
|
|
assert len(text.strip()) > 1000, "doc is a stub"
|
|
assert "#139" in text, "doc does not reference the #139 decision"
|
|
|
|
|
|
def test_doc_names_both_role_namespaces():
|
|
text = _doc_text()
|
|
assert "gitea-author" in text
|
|
assert "gitea-reviewer" in text
|
|
|
|
|
|
def test_doc_rejects_dynamic_switching_and_dispatcher():
|
|
text = _doc_text().lower()
|
|
assert "dynamic" in text and "switching" in text
|
|
assert "dispatcher" in text
|
|
for marker in ("rejected", "not enabled"):
|
|
assert marker in text, f"doc does not state {marker!r}"
|
|
|
|
|
|
def test_doc_explains_why():
|
|
text = _doc_text().lower()
|
|
for reason in ("audit", "credential", "two-party", "fail-closed"):
|
|
assert reason in text, f"doc does not explain the {reason!r} rationale"
|
|
|
|
|
|
def test_doc_gives_client_setup_examples_without_secret_values():
|
|
text = _doc_text()
|
|
assert "GITEA_MCP_PROFILE" in text, "no profile env var in setup examples"
|
|
assert "GITEA_MCP_CONFIG" in text, "no config env var in setup examples"
|
|
# References/names only — never values, hosts, or key material.
|
|
for marker in ("https://", "http://", "ghp_", "Authorization:",
|
|
"BEGIN PRIVATE KEY"):
|
|
assert marker not in text, f"doc contains {marker!r}"
|
|
|
|
|
|
def test_doc_covers_auth_unsupported_and_reload():
|
|
text = _doc_text()
|
|
assert "Auth unsupported" in text, (
|
|
"doc does not explain the 'Auth unsupported' client message")
|
|
lower = text.lower()
|
|
assert "reconnect" in lower and "reload" in lower, (
|
|
"doc does not cover reconnect/reload after profile/config changes")
|
|
|
|
|
|
def test_operator_docs_link_deployment_doc():
|
|
for name in ("llm-workflow-runbooks.md", "gitea-execution-profiles.md"):
|
|
text = (REPO_ROOT / "docs" / name).read_text(encoding="utf-8")
|
|
assert "gitea-dual-namespace-deployment.md" in text, (
|
|
f"docs/{name} does not link the deployment doc")
|