Files
govoplan/tests/test_devkit_audit_scope.py
zemion 2ffdb23f69
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s
feat(devkit): add resumable workspace automation and UI review tooling
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:17 +02:00

439 lines
16 KiB
Python
Executable File

"""Audit the selected fixture workspace, never a fuller neighboring checkout."""
from argparse import Namespace
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
from types import ModuleType, SimpleNamespace
import pytest
META_ROOT = Path(__file__).resolve().parents[1]
SCRIPT = META_ROOT / "tools/inventory/platform-interface-inventory.py"
WEBUI_SCRIPT = META_ROOT / "tools/inventory/extract-webui-structure.mjs"
SPEC = importlib.util.spec_from_file_location("audit_scope_inventory", SCRIPT)
assert SPEC is not None and SPEC.loader is not None
inventory = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(inventory)
sys.path.insert(0, str(META_ROOT / "tools/devkit"))
from govoplan_devkit import docs, issues, runner # noqa: E402
from govoplan_devkit.workspace import Project, Repository # noqa: E402
def write(path, content):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
@pytest.fixture
def workspaces(tmp_path):
selected = tmp_path / "selected"
default = tmp_path / "fuller-default"
meta = tmp_path / "legacy-siblings/govoplan"
selected.mkdir()
meta.mkdir(parents=True)
catalog = {
"default_parent": str(default),
"repositories": [
{"name": "govoplan-core", "path": "govoplan-core"},
{"name": "govoplan-example", "path": "nested/example"},
{"name": "govoplan-optional", "path": "govoplan-optional"},
],
}
write(meta / "repositories.json", json.dumps(catalog))
write(
selected / "nested/example/webui/src/Page.tsx",
"export const page = <h1>SELECTED_ONLY</h1>;\n",
)
write(
default / "nested/example/webui/src/Page.tsx",
"export const page = <h1>DEFAULT_ONLY</h1>;\n",
)
write(
default / "govoplan-optional/webui/src/Page.tsx",
"export const page = <h1>DEFAULT_OPTIONAL</h1>;\n",
)
for item in catalog["repositories"]:
(default / item["path"] / "src").mkdir(parents=True)
return selected, default, meta, catalog
def test_explicit_partial_root_beats_fuller_legacy_discovery(workspaces, monkeypatch):
selected, default, meta, catalog = workspaces
monkeypatch.setattr(inventory, "META_ROOT", meta)
assert inventory._resolve_workspace_root(catalog) == default
assert inventory._resolve_workspace_root(catalog, selected) == selected
with pytest.raises(ValueError, match="existing directory"):
inventory._resolve_workspace_root(catalog, selected / "missing")
@pytest.mark.parametrize("relative", ["../fuller-default", "/absolute/path"])
def test_repository_paths_cannot_escape_explicit_root(workspaces, relative):
selected, _, _, _ = workspaces
with pytest.raises(ValueError, match="inside the selected workspace"):
inventory._validate_repository_roots(
{"repositories": [{"path": relative}]}, selected
)
def test_linked_repository_cannot_borrow_default_sources(workspaces):
selected, default, _, catalog = workspaces
(selected / "govoplan-core").symlink_to(
default / "govoplan-core", target_is_directory=True
)
with pytest.raises(ValueError, match="escapes the selected workspace"):
inventory._validate_repository_roots(catalog, selected)
def test_python_forwards_selected_root_and_configured_node(workspaces, monkeypatch):
selected, _, meta, _ = workspaces
monkeypatch.setattr(inventory, "META_ROOT", meta)
monkeypatch.setenv("NODE", "/selected/toolchain/node")
calls = []
def run(argv, **kwargs):
calls.append((argv, kwargs))
return SimpleNamespace(stdout=json.dumps({"workspaceRoot": str(selected)}))
monkeypatch.setattr(inventory.subprocess, "run", run)
assert inventory._extract_webui(selected)["workspaceRoot"] == str(selected)
argv, options = calls[0]
assert argv == [
"/selected/toolchain/node",
str(meta / "tools/inventory/extract-webui-structure.mjs"),
str(meta),
"--workspace-root",
str(selected),
]
assert options == {"check": True, "capture_output": True, "text": True}
def test_python_rejects_webui_result_from_another_root(workspaces, monkeypatch):
selected, default, _, _ = workspaces
monkeypatch.setattr(
inventory.subprocess,
"run",
lambda *a, **k: SimpleNamespace(
stdout=json.dumps({"workspaceRoot": str(default)})
),
)
with pytest.raises(ValueError, match="did not confirm"):
inventory._extract_webui(selected)
def test_main_forwards_same_root_to_every_collector(workspaces, monkeypatch):
selected, _, meta, catalog = workspaces
monkeypatch.setattr(inventory, "META_ROOT", meta)
roots = []
monkeypatch.setattr(
inventory, "_extract_webui", lambda root: roots.append(root) or {}
)
monkeypatch.setattr(
inventory,
"_extract_backend_endpoints",
lambda data, root: roots.append(root) or [],
)
monkeypatch.setattr(
inventory, "_extract_manifests", lambda data, root: roots.append(root) or []
)
monkeypatch.setattr(inventory, "_load_endpoint_declarations", lambda _: {})
monkeypatch.setattr(inventory, "_load_high_risk_help_baseline", lambda _: {})
monkeypatch.setattr(inventory, "_assemble_inventory", lambda **kwargs: {})
monkeypatch.setattr(inventory, "_render_markdown", lambda data: "fixture\n")
output = selected / "output"
monkeypatch.setattr(
sys,
"argv",
[str(SCRIPT), "--workspace-root", str(selected), "--output-dir", str(output)],
)
assert inventory.main() == 0
assert roots == [selected, selected, selected]
report = json.loads((output / "platform-interface-inventory.json").read_text())
assert report["workspace_root"] == str(selected)
assert report["workspace_selection"] == "explicit"
def install_fixture_compiler(root):
compiler = META_ROOT.parent / "govoplan-core/webui/node_modules/typescript"
if not compiler.is_dir() or not shutil.which("node"):
pytest.skip("Node and the installed Core TypeScript parser are required")
target = root / "govoplan-core/webui/node_modules/typescript"
target.parent.mkdir(parents=True, exist_ok=True)
# Parser dependencies may be shared; audited source checkouts may not.
target.symlink_to(compiler, target_is_directory=True)
def collect_webui(meta, selected=None):
argv = [shutil.which("node") or "node", str(WEBUI_SCRIPT), str(meta)]
if selected is not None:
argv += ["--workspace-root", str(selected)]
return subprocess.run(argv, capture_output=True, text=True, timeout=30)
def test_javascript_explicit_root_is_authoritative_and_legacy_cli_still_works(
workspaces,
):
selected, default, meta, _ = workspaces
install_fixture_compiler(selected)
install_fixture_compiler(default)
explicit = collect_webui(meta, selected)
assert explicit.returncode == 0, explicit.stderr
report = json.loads(explicit.stdout)
assert report["workspaceRoot"] == str(selected)
assert [item["value"] for item in report["visibleText"]] == ["SELECTED_ONLY"]
assert report["visibleText"][0]["file"] == "webui/src/Page.tsx"
legacy = collect_webui(meta)
assert legacy.returncode == 0, legacy.stderr
assert json.loads(legacy.stdout)["workspaceRoot"] == str(default)
assert {item["value"] for item in json.loads(legacy.stdout)["visibleText"]} == {
"DEFAULT_ONLY",
"DEFAULT_OPTIONAL",
}
def test_javascript_does_not_borrow_missing_core_dependencies(workspaces):
selected, default, meta, _ = workspaces
install_fixture_compiler(default)
result = collect_webui(meta, selected)
assert result.returncode != 0
assert (
str(selected / "govoplan-core/webui/node_modules/typescript") in result.stderr
)
assert not result.stdout
def test_javascript_rejects_source_root_linked_outside_workspace(workspaces):
selected, default, meta, _ = workspaces
install_fixture_compiler(selected)
linked = selected / "govoplan-optional/webui/src"
linked.parent.mkdir(parents=True)
linked.symlink_to(default / "govoplan-optional/webui/src", target_is_directory=True)
result = collect_webui(meta, selected)
assert result.returncode != 0
assert "source root escapes the selected workspace" in result.stderr
def test_backend_does_not_borrow_optional_endpoints(workspaces):
selected, default, _, catalog = workspaces
source = "from fastapi import APIRouter\nrouter = APIRouter()\n@router.get('/selected')\ndef endpoint(): pass\n"
write(selected / "nested/example/src/routes.py", source)
write(
default / "govoplan-optional/src/routes.py", source.replace("selected", "other")
)
endpoints = inventory._extract_backend_endpoints(catalog, selected)
assert [item["path"] for item in endpoints] == ["/selected"]
(selected / "nested/example/src/foreign.py").symlink_to(
default / "govoplan-optional/src/routes.py"
)
with pytest.raises(ValueError, match="Backend source path escapes"):
inventory._extract_backend_endpoints(catalog, selected)
def test_manifests_require_selected_core_sources(workspaces, monkeypatch):
selected, default, _, catalog = workspaces
write(
default / "govoplan-core/src/govoplan_core/core/platform_interfaces.py",
"raise AssertionError('foreign source imported')",
)
monkeypatch.syspath_prepend(str(default / "govoplan-core/src"))
with pytest.raises(ValueError, match="requires Core interface sources"):
inventory._extract_manifests(catalog, selected)
def test_cached_application_import_cannot_replace_missing_checkout(
workspaces, monkeypatch
):
selected, default, _, _ = workspaces
# Meta's own devkit/release packages may audit another workspace.
tooling = ModuleType("govoplan_release")
tooling.__file__ = str(default / "tools/release/govoplan_release/__init__.py")
modules = {"govoplan_release": tooling, "govoplan_devkit.docs": docs}
# Isolate the fixture from application packages collected by unrelated
# suites, without removing or replacing those real cached imports.
monkeypatch.setattr(inventory, "sys", SimpleNamespace(modules=modules))
inventory._assert_workspace_imports(selected)
application = ModuleType("govoplan_audit_fixture")
application.__file__ = str(
default / "govoplan-optional/src/govoplan_audit_fixture/__init__.py"
)
modules["govoplan_audit_fixture"] = application
with pytest.raises(ValueError, match="outside the selected inventory workspace"):
inventory._assert_workspace_imports(selected)
def test_partial_manifest_collection_uses_selected_sources_in_fresh_process(workspaces):
selected, default, _, catalog = workspaces
core = selected / "govoplan-core/src/govoplan_core"
write(core / "__init__.py", "")
write(core / "core/__init__.py", "")
write(
core / "core/platform_interfaces.py",
"def manifest_interface_catalog(manifest): return {'selected': True}\n",
)
write(
default / "govoplan-core/src/govoplan_core/__init__.py",
"raise AssertionError('foreign Core loaded')\n",
)
module = selected / "nested/example/src/govoplan_example"
write(module / "__init__.py", "")
write(module / "backend/__init__.py", "")
manifest = (
"from types import SimpleNamespace as S\n"
"def get_manifest():\n"
" return S(id='selected', name='Selected', version='1', dependencies=(), "
"optional_dependencies=(), required_capabilities=(), provides_interfaces=(), "
"capability_factories={}, permissions=(), documentation=(), architecture=None, "
"information_governance=S(to_dict=lambda: {}), frontend=None)\n"
)
write(module / "backend/manifest.py", manifest)
write(
default / "govoplan-optional/src/govoplan_optional/backend/manifest.py",
manifest.replace("selected", "foreign"),
)
code = (
"import importlib.util, json; from pathlib import Path; "
f"spec=importlib.util.spec_from_file_location('fixture', {str(SCRIPT)!r}); "
"module=importlib.util.module_from_spec(spec); spec.loader.exec_module(module); "
f"print(json.dumps(module._extract_manifests({catalog!r}, Path({str(selected)!r}))))"
)
env = {
**os.environ,
"PYTHONPATH": os.pathsep.join(
str(default / item["path"] / "src") for item in catalog["repositories"]
),
}
result = subprocess.run(
[sys.executable, "-c", code],
env=env,
capture_output=True,
text=True,
timeout=30,
)
assert result.returncode == 0, result.stderr
manifests = json.loads(result.stdout)
assert [manifest["id"] for manifest in manifests] == ["selected"]
assert manifests[0]["interface_catalog"] == {"selected": True}
def doc_plan(workspace, monkeypatch):
repos = tuple(
Repository(name, workspace / name)
for name in ("govoplan", "govoplan-core", "govoplan-example")
)
project = Project("fixture", repos, {})
monkeypatch.setattr(docs, "load_project", lambda *a: project)
args = Namespace(
workspace_root=workspace,
project=None,
state_dir=workspace.parent / "state",
repo=["govoplan-example"],
changed=False,
)
return docs.build_doc_stages(args)
def test_docs_plan_forwards_root_and_persists_all_limitations(workspaces, monkeypatch):
selected, _, _, _ = workspaces
stages = doc_plan(selected, monkeypatch)
by_id = {stage["id"]: stage for stage in stages}
for stage_id in (
"docs.manifests",
"docs.interface-inventory",
"docs.plain-display-labels",
):
argv = by_id[stage_id]["argv"]
assert argv[argv.index("--workspace-root") + 1] == str(selected)
assert by_id["docs.translation-structure"]["argv"][1] == str(
selected / "govoplan-core/webui/scripts/audit-i18n-structural.mjs"
)
assert issues.coverage_notes(stages) == docs.LIMITATIONS
assert by_id["docs.plain-display-labels"]["argv"][-2:] == [
"--repo",
"govoplan-example",
]
def test_docs_limitations_survive_real_receipt_and_issue_evidence(
workspaces, monkeypatch, tmp_path
):
selected, _, _, _ = workspaces
stages = doc_plan(selected, monkeypatch)
repo = selected / "example"
repo.mkdir()
subprocess.run(["git", "init", "-q", str(repo)], check=True, timeout=10)
write(repo / "source.txt", "fixture\n")
subprocess.run(
["git", "-C", str(repo), "add", "source.txt"], check=True, timeout=10
)
subprocess.run(
[
"git",
"-C",
str(repo),
"-c",
"user.name=Fixture",
"-c",
"user.email=fixture@example.invalid",
"commit",
"-qm",
"fixture",
],
check=True,
timeout=10,
)
project = tmp_path / "project.json"
write(
project,
json.dumps(
{
"schema_version": 1,
"name": "fixture",
"repositories": [{"name": "example", "path": "example"}],
"checks": [],
"profiles": {},
}
),
)
args = Namespace(
workspace_root=selected,
project=project,
state_dir=tmp_path / "state",
dry_run=False,
jobs=2,
profile="docs",
resume=None,
)
for stage in stages:
stage.update(
argv=[sys.executable, "-c", "print('fixture audit')"],
cwd=str(repo),
deps=[],
resources=[],
timeout_seconds=10,
)
monkeypatch.setattr(docs, "build_doc_stages", lambda _: stages)
monkeypatch.setattr(
runner, "environment_fingerprint", lambda *a, **k: "fixture-env"
)
result = docs.audit(args)
assert result["status"] == "passed", result
assert all(result["summary"].count(note) == 1 for note in docs.LIMITATIONS)
receipt = runner.read_receipt(selected, args.state_dir, result["run_id"])
assert issues.coverage_notes(receipt["stages"]) == docs.LIMITATIONS
evidence = issues.evidence_record(result["run_id"], args)
assert evidence["coverage_notes"] == docs.LIMITATIONS
assert evidence["source_state"] == "matches-current"
target = issues.NoteTarget(
repo, "https://gitea.example.invalid", "fixture", "example", 1
)
_, body = issues.render_note(
{"summary": [], "next": [], "body": ""}, evidence, target, "fixture"
)
assert all(note in body for note in docs.LIMITATIONS)