feat(ops): verify release provenance evidence pairs
This commit is contained in:
@@ -26,7 +26,7 @@ def test_documented_python_invocation_loads_project_without_pythonpath():
|
||||
)
|
||||
|
||||
assert completed.returncode == 0, completed.stderr
|
||||
assert "--expected-oci-revision" in completed.stdout
|
||||
assert "--observed-evidence-file" in completed.stdout
|
||||
assert script.stat().st_mode & 0o111 != 0
|
||||
|
||||
|
||||
@@ -62,6 +62,21 @@ def _argv(tmp_path: Path, repo: Path, head: str) -> list[str]:
|
||||
trex, rabbit = _fake_read_only_commands(tmp_path)
|
||||
broker_log = tmp_path / "broker.log"
|
||||
broker_log.write_text("event=order_submit account=must-not-leak\n", encoding="utf-8")
|
||||
evidence = tmp_path / "observed-evidence.json"
|
||||
evidence.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": 1,
|
||||
"target_id": "service-a",
|
||||
"target_kind": "compose-service",
|
||||
"image_id": "sha256:" + ("b" * 64),
|
||||
"image_digest": "sha256:" + ("a" * 64),
|
||||
"oci_revision": head,
|
||||
"observed_at": "2026-09-20T02:00:00Z",
|
||||
}
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
return [
|
||||
"--actor", "operator-a",
|
||||
"--reason", "deploy release",
|
||||
@@ -70,8 +85,7 @@ def _argv(tmp_path: Path, repo: Path, head: str) -> list[str]:
|
||||
"--phase", "pre",
|
||||
"--command-class", "deploy",
|
||||
"--checkout-dir", str(repo),
|
||||
"--expected-oci-revision", head,
|
||||
"--image-digest", "sha256:" + ("a" * 64),
|
||||
"--observed-evidence-file", str(evidence),
|
||||
"--runtime-file", "runtime.py",
|
||||
"--broker-log-path", str(broker_log),
|
||||
"--capture-command", f"pending_slots={trex} slots --status pending --instance inst-a --json",
|
||||
@@ -85,15 +99,20 @@ def test_cli_writes_unique_record_outside_checkout_and_keeps_checkout_clean(tmp_
|
||||
argv = _argv(tmp_path, repo, head)
|
||||
|
||||
assert release_provenance_gate.main(argv) == 0
|
||||
first = Path(capsys.readouterr().out.strip())
|
||||
first_receipt = json.loads(capsys.readouterr().out)
|
||||
first = Path(first_receipt["record_path"])
|
||||
assert release_provenance_gate.main(argv) == 0
|
||||
second = Path(capsys.readouterr().out.strip())
|
||||
second_receipt = json.loads(capsys.readouterr().out)
|
||||
second = Path(second_receipt["record_path"])
|
||||
|
||||
assert first != second
|
||||
assert first.parent == tmp_path / "repo-release-provenance"
|
||||
assert first.stat().st_mode & 0o222 == 0
|
||||
assert second.stat().st_mode & 0o222 == 0
|
||||
payload = json.loads(first.read_text(encoding="utf-8"))
|
||||
assert payload["schema_version"] == 1
|
||||
assert payload["observed_evidence"]["source"] == "operator_observed"
|
||||
assert first_receipt["record_sha256"] == __import__("hashlib").sha256(first.read_bytes()).hexdigest()
|
||||
assert payload["gate"]["passed"] is True
|
||||
assert "must-not-leak" not in first.read_text(encoding="utf-8")
|
||||
status = subprocess.run(
|
||||
@@ -108,7 +127,8 @@ def test_cli_dirty_checkout_is_fail_closed_and_isolated(tmp_path, capsys):
|
||||
(repo / "runtime.py").write_text("dirty\n", encoding="utf-8")
|
||||
|
||||
assert release_provenance_gate.main(argv) == 2
|
||||
output = Path(capsys.readouterr().out.strip())
|
||||
receipt = json.loads(capsys.readouterr().out)
|
||||
output = Path(receipt["record_path"])
|
||||
payload = json.loads(output.read_text(encoding="utf-8"))
|
||||
assert output.stat().st_mode & 0o222 == 0
|
||||
assert payload["gate"]["passed"] is False
|
||||
@@ -131,3 +151,20 @@ def test_cli_rejects_unsafe_command_and_checkout_local_output(tmp_path):
|
||||
argv.extend(["--output-dir", str(repo / "artifacts")])
|
||||
with pytest.raises(SystemExit):
|
||||
release_provenance_gate.main(argv)
|
||||
|
||||
|
||||
def test_invalid_observed_evidence_creates_no_record_or_receipt(tmp_path, capsys):
|
||||
repo, head = _init_repo(tmp_path)
|
||||
argv = _argv(tmp_path, repo, head)
|
||||
evidence_index = argv.index("--observed-evidence-file") + 1
|
||||
evidence = Path(argv[evidence_index])
|
||||
evidence.write_text(
|
||||
'{"schema_version":1,"schema_version":1,"target_id":"service-a"}',
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
release_provenance_gate.main(argv)
|
||||
|
||||
assert capsys.readouterr().out == ""
|
||||
assert not (tmp_path / "repo-release-provenance").exists()
|
||||
|
||||
Reference in New Issue
Block a user