from __future__ import annotations import importlib.util import json import datetime as dt import os from pathlib import Path import sys import tempfile import unittest from unittest import mock ROOT = Path(__file__).parents[1] sys.path.insert(0, str(ROOT / "tools")) SPEC = importlib.util.spec_from_file_location("build_site", ROOT / "tools/build_site.py") build_site = importlib.util.module_from_spec(SPEC) assert SPEC.loader is not None SPEC.loader.exec_module(build_site) def _fixture(tmp_path: Path) -> Path: repo = tmp_path / "canon-repo" source = repo / "canon/standards/example.md" source.parent.mkdir(parents=True) source.write_text( """--- id: example title: "Example Standard" status: proposed revision: "draft-1" owner: example-owner last_reviewed: "2026-08-18" review_interval: 6m --- # Example ## 1. Rule | Level | Meaning | | --- | --- | | **V0** | No position. | | **V1** | Restart recovery. | """, encoding="utf-8", ) manifest = tmp_path / "publication.json" manifest.write_text( json.dumps( { "schema_version": 1, "site": {"title": "Test", "base_url": "https://example.invalid"}, "repositories": {"canon": {"path": "canon-repo"}}, "documents": [ { "id": "example", "source_repo": "canon", "source_path": "canon/standards/example.md", "canonical_path": "standards/example/v1/index.html", "revision_path": "standards/example/v1/revisions/{revision}/index.html", "legacy_paths": ["example.html"], "review_interval": "6m", } ], } ), encoding="utf-8", ) return manifest class PublicationTest(unittest.TestCase): def test_archive_build_accepts_only_exact_source_revision_override(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) repo = root / "net-kingdom" source = repo / "canon/example.md" source.parent.mkdir(parents=True) source.write_text("example", encoding="utf-8") key = "POLICY_NEXUS_SOURCE_REVISION_NET_KINGDOM" with mock.patch.dict(os.environ, {key: "a" * 40}): self.assertEqual("a" * 40, build_site._source_revision(repo, source)) with mock.patch.dict(os.environ, {key: "main"}): with self.assertRaisesRegex(ValueError, "clean 40-hex Git commit"): build_site._source_revision(repo, source) def test_manifest_builds_index_current_revision_and_legacy_alias(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) output = root / "site" records = build_site.build(manifest, output, as_of=dt.date(2026, 8, 18)) self.assertEqual("2027-02-18", records[0]["review_due"]) self.assertTrue((output / "index.html").is_file()) current = (output / "standards/example/v1/index.html").read_text( encoding="utf-8" ) revision = output / "standards/example/v1/revisions/draft-1/index.html" self.assertIn("Availability", current) self.assertIn("policy-source-revision", current) self.assertIn("policy-source-digest", current) self.assertIn("Review due: 2027-02-18", current) self.assertEqual(revision.read_text(encoding="utf-8"), current) self.assertIn( "/standards/example/v1/index.html", (output / "example.html").read_text(encoding="utf-8"), ) def test_revision_address_refuses_changed_source_under_same_revision(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) output = root / "site" build_site.build(manifest, output, as_of=dt.date(2026, 8, 18)) source = root / "canon-repo/canon/standards/example.md" source.write_text( source.read_text(encoding="utf-8") + "\nChanged.\n", encoding="utf-8" ) with self.assertRaisesRegex(RuntimeError, "immutable revision"): build_site.build(manifest, output, as_of=dt.date(2026, 8, 18)) def test_same_content_can_move_from_worktree_to_commit_provenance(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) output = root / "site" build_site.build(manifest, output, as_of=dt.date(2026, 8, 18)) revision = output / "standards/example/v1/revisions/draft-1/index.html" original = revision.read_text(encoding="utf-8") original_source_revision = build_site._source_revision try: build_site._source_revision = lambda _repo, _source: "new-commit" build_site.build(manifest, output, as_of=dt.date(2026, 8, 18)) finally: build_site._source_revision = original_source_revision self.assertEqual(original, revision.read_text(encoding="utf-8")) current = (output / "standards/example/v1/index.html").read_text( encoding="utf-8" ) self.assertIn('policy-source-revision" content="new-commit', current) def test_stale_and_superseded_notices_do_not_mutate_revision_page(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) document = json.loads(manifest.read_text(encoding="utf-8")) document["documents"][0]["lifecycle"] = "superseded" document["documents"][0]["successor"] = "/standards/example/v2/" manifest.write_text(json.dumps(document), encoding="utf-8") output = root / "site" build_site.build(manifest, output, as_of=dt.date(2027, 2, 19)) current = (output / "standards/example/v1/index.html").read_text( encoding="utf-8" ) revision = ( output / "standards/example/v1/revisions/draft-1/index.html" ).read_text(encoding="utf-8") self.assertIn("Superseded.", current) self.assertIn("Review overdue.", current) self.assertNotIn("Superseded.", revision) self.assertNotIn("Review overdue.", revision) def test_manifest_rejects_unsafe_publication_path(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) document = json.loads(manifest.read_text(encoding="utf-8")) document["documents"][0]["canonical_path"] = "../escape.html" manifest.write_text(json.dumps(document), encoding="utf-8") with self.assertRaisesRegex(ValueError, "unsafe publication path"): build_site.load_manifest(manifest) def test_build_rejects_missing_publication_owner(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) manifest = _fixture(root) source = root / "canon-repo/canon/standards/example.md" source.write_text( source.read_text(encoding="utf-8").replace( "owner: example-owner\n", "" ), encoding="utf-8", ) with self.assertRaisesRegex(ValueError, "owner is required"): build_site.build(manifest, root / "site") if __name__ == "__main__": unittest.main()