import hashlib import json from datetime import UTC, datetime import pytest from activity_core.custodian_inputs import admit @pytest.fixture def evidence(tmp_path): fleet = tmp_path / "fleet" file = fleet / "example/workplans/task.md" file.parent.mkdir(parents=True) file.write_text("task") manifest = {"schema": "repo-manager.fleet-input.v1", "freshness_verified": False, "repositories": [{"slug": "example", "commit": "a" * 40, "files": [ {"path": "workplans/task.md", "bytes": 4, "sha256": hashlib.sha256(b"task").hexdigest()}]}]} raw = json.dumps(manifest).encode() (fleet / "manifest.json").write_bytes(raw) (fleet / "COMPLETE").write_text(hashlib.sha256(raw).hexdigest()) policy = tmp_path / "policy.json" policy.write_text(json.dumps({"schema": "activity-core.custodian-input-policy.v1", "repositories": ["example"], "max_observation_age_seconds": 7200, "max_future_skew_seconds": 300, "max_snapshot_bytes": 1024, "expected_hub_instance": "railiance01"})) receipts = tmp_path / "receipts.json" receipt = {"schema": "repo-manager.freshness-receipt.v1", "repo_slug": "example", "forge_commit": "a" * 40, "outcome": "noop", "reason": "forge_head_matches_last_success", "finished_at": "2026-10-19T10:00:00Z", "hub": {"verified_primary": True, "instance_role": "primary", "instance_label": "railiance01"}} prior = {**receipt, "outcome": "applied", "reason": None, "finished_at": "2026-10-01T00:00:00Z", **{key: "a" * 40 for key in ("expected_commit", "derived_commit", "projected_commit")}} receipts.write_text(json.dumps([receipt, prior])) return fleet, policy, receipts def check(evidence): return admit(*evidence, ["example"], now=datetime(2026, 10, 19, 11, tzinfo=UTC)) def test_accepts_independent_recent_receipt(evidence): assert len(check(evidence)) == 64 @pytest.mark.parametrize("case", ["missing", "stale", "future", "wrong_commit", "wrong_hub", "failed"]) def test_rejects_invalid_freshness(evidence, case): path = evidence[2] rows = json.loads(path.read_text()) if case == "missing": rows = [] elif case == "stale": rows[0]["finished_at"] = "2026-10-18T10:00:00Z" elif case == "future": rows[0]["finished_at"] = "2026-10-20T10:00:00Z" elif case == "wrong_commit": rows[0]["forge_commit"] = "b" * 40 elif case == "wrong_hub": rows[0]["hub"]["instance_label"] = "workstation" else: rows[0]["outcome"] = "failed" path.write_text(json.dumps(rows)) with pytest.raises(ValueError, match="fresh Forge receipt"): check(evidence) @pytest.mark.parametrize("case", ["tamper", "extra", "marker", "extra_repo"]) def test_rejects_changed_snapshot(evidence, case): fleet = evidence[0] if case == "tamper": (fleet / "example/workplans/task.md").write_text("changed") elif case == "extra": (fleet / "example/workplans/extra.md").write_text("extra") elif case == "extra_repo": (fleet / "outside").mkdir() else: (fleet / "COMPLETE").write_text("incorrect") with pytest.raises(ValueError): check(evidence) def test_native_noop_uses_protected_issuer_contract(evidence): path = evidence[2] path.write_text(json.dumps(json.loads(path.read_text())[:1])) assert len(check(evidence)) == 64 def test_fifo_refused_without_open(evidence): import os path = evidence[2] path.unlink() os.mkfifo(path) with pytest.raises(ValueError, match="unsafe"): check(evidence) def test_descriptor_pins_snapshot_and_receipts(evidence, tmp_path): from activity_core.custodian_inputs import select_snapshot fleet, policy, receipts = evidence root = tmp_path / "snapshots" root.mkdir() fleet.rename(root / "capture-1") state = tmp_path / "state" (state / "inputs").mkdir(parents=True) retained = state / "inputs/capture-1.receipts.json" retained.write_bytes(receipts.read_bytes()) descriptor = state / "inputs/current.json" data = {"schema": "activity-core.custodian-snapshot-selection.v1", "snapshot_id": "capture-1", "manifest_sha256": hashlib.sha256((root / "capture-1/manifest.json").read_bytes()).hexdigest(), "receipts_sha256": hashlib.sha256(retained.read_bytes()).hexdigest()} descriptor.write_text(json.dumps(data)) assert select_snapshot(root, state, descriptor) == (root / "capture-1", retained) retained.write_text("[]") with pytest.raises(ValueError, match="digest mismatch"): select_snapshot(root, state, descriptor) data["snapshot_id"] = "../escape" descriptor.write_text(json.dumps(data)) with pytest.raises(ValueError, match="invalid snapshot"): select_snapshot(root, state, descriptor)