test_provenance_unit.py python
130 lines 4.4 KB
Raw
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 54 days ago
1 """Unit tests for Track P / P1 provenance envelope (§P0.8)."""
2
3 from __future__ import annotations
4
5 import pytest
6
7 from adapters.config import load_config
8 from adapters.errors import ConfigError
9 from tests.support import (
10 FIXTURES,
11 generate_ed25519_keypair,
12 seed_honesty_repo,
13 sign_entry_hash,
14 write_config,
15 )
16 from tools.honesty.canonical import compute_entry_hash
17 from tools.honesty.ed25519_util import verify_ed25519_signature
18 from tools.honesty.genesis import GENESIS_PREV
19 from tools.honesty.provenance import validate_provenance
20 from tools.honesty.validate import EntryValidationError, validate_append_body
21
22
23 def test_provenance_required_fields() -> None:
24 with pytest.raises(EntryValidationError) as exc:
25 validate_provenance({"agent_id": "a"})
26 assert exc.value.exit_code == 2
27
28
29 def test_provenance_strict_keys() -> None:
30 with pytest.raises(EntryValidationError) as exc:
31 validate_provenance({"agent_id": "a", "model_id": "m", "extra": True})
32 assert exc.value.exit_code == 2
33
34
35 def test_provenance_sig_pubkey_pairing() -> None:
36 with pytest.raises(EntryValidationError) as exc:
37 validate_provenance({"agent_id": "a", "model_id": "m", "sig": "ed25519:AA=="})
38 assert exc.value.exit_code == 2
39
40
41 def test_compute_entry_hash_excludes_provenance_sig() -> None:
42 private_key, pubkey = generate_ed25519_keypair()
43 body = {
44 "v": 1,
45 "kind": "verdict",
46 "ts": "2026-01-01T00:00:00Z",
47 "prev_hash": GENESIS_PREV,
48 "provenance": {
49 "agent_id": "cursor-agent",
50 "model_id": "gpt-5.6",
51 "pubkey": pubkey,
52 },
53 }
54 unsigned_hash = compute_entry_hash(body)
55 body["provenance"]["sig"] = sign_entry_hash(private_key, unsigned_hash)
56 assert compute_entry_hash(body) == unsigned_hash
57
58
59 def test_legacy_unsigned_entry_hash_unchanged() -> None:
60 body = {
61 "v": 1,
62 "kind": "hook_check",
63 "ts": "2026-01-01T00:00:00Z",
64 "prev_hash": GENESIS_PREV,
65 "actor_role": "overseer",
66 "actor_session_id": "legacy",
67 "hook": "handoff",
68 "ok": True,
69 }
70 expected = "0044b277fdbebdf824a0dd6005dc5630a9fe4d65f5b01d029cdd7028f6122d4e"
71 # Pin the legacy hash so regressions are caught if canonical rules drift.
72 assert compute_entry_hash(body) == expected
73
74
75 def test_ed25519_sign_verify_round_trip() -> None:
76 private_key, pubkey = generate_ed25519_keypair()
77 entry_hash = "abc123" * 10 + "abcd"
78 sig = sign_entry_hash(private_key, entry_hash)
79 assert verify_ed25519_signature(pubkey_token=pubkey, entry_hash_hex=entry_hash, sig_token=sig)
80
81
82 def test_genesis_rejects_provenance() -> None:
83 with pytest.raises(EntryValidationError) as exc:
84 validate_append_body(
85 kind="genesis",
86 body={"provenance": {"agent_id": "a", "model_id": "m"}},
87 )
88 assert exc.value.exit_code == 2
89
90
91 def test_soft_provenance_allowed_on_verdict() -> None:
92 merged = validate_append_body(
93 kind="verdict",
94 body={
95 "actor_role": "verifier",
96 "actor_session_id": "v1",
97 "artifact_sha256": "aa" * 32,
98 "passed": True,
99 "evidence": {"reexecuted": ["verify-step:x"]},
100 "provenance": {"agent_id": "cursor-agent", "model_id": "gpt-5.6"},
101 },
102 )
103 assert merged["provenance"]["agent_id"] == "cursor-agent"
104
105
106 def test_git_only_require_agent_signature_config_error_26(repo_root) -> None:
107 seed_honesty_repo(repo_root)
108 cfg = repo_root / ".overseer" / "config.yaml"
109 import yaml
110
111 data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
112 data["honesty"]["require_agent_signature"] = True
113 cfg.write_text(yaml.safe_dump(data), encoding="utf-8")
114 with pytest.raises(ConfigError) as exc:
115 load_config(cfg)
116 assert exc.value.exit_code == 26
117
118
119 def test_muse_regime_allows_require_agent_signature(tmp_path) -> None:
120 write_config(tmp_path, "config-muse-git-mirror.yaml")
121 cfg = tmp_path / ".overseer" / "config.yaml"
122 import yaml
123
124 data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
125 data.setdefault("honesty", {})["enabled"] = True
126 data["honesty"]["ledger"] = ".overseer/honesty/VERDICT-LEDGER.jsonl"
127 data["honesty"]["require_agent_signature"] = True
128 cfg.write_text(yaml.safe_dump(data), encoding="utf-8")
129 config = load_config(cfg)
130 assert config.honesty.require_agent_signature is True
File History 1 commit
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439 feat: K1-P1 complete — agent provenance, build-verification… Sonnet 4.6 patch 54 days ago