"""Checks for the Gitea Wiki sync helper (issue #224). The repo-tracked ``docs/wiki/`` stays the source of truth; the helper mirrors it into the Gitea native wiki only when explicitly invoked. """ import os import subprocess from pathlib import Path REPO_ROOT = Path(__file__).resolve().parent.parent SCRIPT = REPO_ROOT / "scripts" / "sync-gitea-wiki.sh" REQUIRED_PAGES = [ "Home.md", "Operator-Guide.md", "Repositories.md", "Identity-and-Profiles.md", "Workflow.md", "Safety-and-Gates.md", "MCP-Tools.md", "Runbooks.md", "Open-Decisions.md", "History.md", ] def _run(*args, env_extra=None): env = dict(os.environ) env.pop("GITEA_WIKI_SYNC_CONFIRM", None) if env_extra: env.update(env_extra) return subprocess.run( [str(SCRIPT), *args], capture_output=True, text=True, env=env, cwd=str(REPO_ROOT), timeout=30) def test_script_exists_and_is_executable(): assert SCRIPT.is_file(), "missing scripts/sync-gitea-wiki.sh" assert os.access(SCRIPT, os.X_OK), "sync script is not executable" def test_dry_run_is_default_and_lists_every_page(): result = _run() assert result.returncode == 0, result.stderr out = result.stdout assert "dry-run" in out.lower() for page in REQUIRED_PAGES: assert page in out, f"dry-run plan does not list {page}" def test_dry_run_does_not_push_or_clone(): result = _run() blob = (result.stdout + result.stderr).lower() assert "pushing" not in blob assert "cloning" not in blob def test_push_refused_without_exact_confirmation(): result = _run("--push") assert result.returncode != 0 blob = result.stdout + result.stderr assert "GITEA_WIKI_SYNC_CONFIRM" in blob assert "cloning" not in blob.lower() def test_push_refused_with_wrong_confirmation(): result = _run("--push", env_extra={"GITEA_WIKI_SYNC_CONFIRM": "yes please"}) assert result.returncode != 0 assert "cloning" not in (result.stdout + result.stderr).lower() def test_script_embeds_no_service_urls_or_secrets(): text = SCRIPT.read_text(encoding="utf-8") for marker in ("http://", "https://", "token ", "Authorization", "ghp_", "keychain"): assert marker not in text, f"script embeds {marker!r}" def test_runbook_documents_wiki_sync(): runbooks = (REPO_ROOT / "docs" / "wiki" / "Runbooks.md").read_text(encoding="utf-8") assert "sync-gitea-wiki" in runbooks home = (REPO_ROOT / "docs" / "wiki" / "Home.md").read_text(encoding="utf-8") assert "source of truth" in home template = (REPO_ROOT / ".gitea" / "pull_request_template.md").read_text(encoding="utf-8") assert "sync-gitea-wiki" in template def test_wiki_pages_have_no_local_file_links(): for path in (REPO_ROOT / "docs" / "wiki").glob("*.md"): text = path.read_text(encoding="utf-8") assert "file://" not in text, f"{path.name} contains a file:// link" def test_pr_template_carries_wiki_publication_gate(): template = (REPO_ROOT / ".gitea" / "pull_request_template.md").read_text(encoding="utf-8") assert "Wiki tab" in template assert "#224" in template assert "not sufficient to close a wiki issue" in template def test_runbooks_document_publication_gate_and_closure_rule(): runbooks = (REPO_ROOT / "docs" / "wiki" / "Runbooks.md").read_text(encoding="utf-8") assert "Wiki Publication Readiness Gate (#224)" in runbooks or "Wiki publication readiness gate (#224)" in runbooks.lower() assert "Closure prevention" in runbooks assert "GITEA_WIKI_SYNC_CONFIRM" in runbooks def test_repositories_map_tracks_wiki_publication_status(): repositories = (REPO_ROOT / "docs" / "wiki" / "Repositories.md").read_text(encoding="utf-8") assert "Wiki publication status" in repositories or "Wiki Publication Status" in repositories for repo in ("mcp-control-plane", "Gitea-Tools"): assert repo in repositories assert "Gitea Wiki published" in repositories