"""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")