audit-labs/evidence-seal
Tamper-evident seals and chain of custody for audit evidence.
clone: git clone https://gitbay.org/audit-labs/evidence-seal.git
v1.0.0: tests/test_cli.py · raw
1"""End-to-end tests for the CLI, covering exit codes."""
2
3import pytest
4
5from evidence_seal.cli import OK, USAGE, main
6
7
8@pytest.fixture
9def pkg(tmp_path):
10 d = tmp_path / "aws_audit_acme_2026-01-01"
11 d.mkdir()
12 (d / "iam.csv").write_text("user,mfa\nalice,true\n", encoding="utf-8")
13 return d
14
15
16def test_seal_then_verify_intact(pkg, tmp_path):
17 manifest = tmp_path / "m.json"
18 assert main(["seal", str(pkg), "--out", str(manifest), "--meta", "engagement=ACME"]) == OK
19 assert manifest.exists()
20 assert main(["verify", str(pkg), "--manifest", str(manifest)]) == OK
21
22
23def test_verify_fails_after_tamper(pkg, tmp_path):
24 manifest = tmp_path / "m.json"
25 main(["seal", str(pkg), "--out", str(manifest)])
26 (pkg / "iam.csv").write_text("user,mfa\nalice,false\n", encoding="utf-8")
27 assert main(["verify", str(pkg), "--manifest", str(manifest)]) == 1
28
29
30def test_default_manifest_path(pkg):
31 # No --out: manifest lands next to the dir and verify finds it by default.
32 assert main(["seal", str(pkg)]) == OK
33 assert (pkg.parent / f"{pkg.name}.manifest.json").exists()
34 assert main(["verify", str(pkg)]) == OK
35
36
37def test_manifest_inside_dir_is_not_self_sealed(pkg):
38 inside = pkg / "seal.json"
39 assert main(["seal", str(pkg), "--out", str(inside)]) == OK
40 # Verifying still passes even though the manifest now sits inside the dir.
41 assert main(["verify", str(pkg), "--manifest", str(inside)]) == OK
42
43
44def test_chain_command(pkg, tmp_path):
45 m1, m2 = tmp_path / "m1.json", tmp_path / "m2.json"
46 main(["seal", str(pkg), "--out", str(m1)])
47 (pkg / "iam.csv").write_text("user,mfa\nalice,true\nbob,true\n", encoding="utf-8")
48 main(["seal", str(pkg), "--out", str(m2), "--prev", str(m1)])
49 assert main(["chain", str(m1), str(m2)]) == OK
50 assert main(["chain", str(m2), str(m1)]) == 1
51
52
53def test_bad_metadata_is_usage_error(pkg, tmp_path):
54 assert main(["seal", str(pkg), "--out", str(tmp_path / "m.json"), "--meta", "novalue"]) == USAGE
55
56
57def test_sign_and_verify_via_cli(pkg, tmp_path):
58 pytest.importorskip("cryptography")
59 priv, pub = tmp_path / "k.key", tmp_path / "k.pub"
60 assert main(["keygen", "--private", str(priv), "--public", str(pub)]) == OK
61 manifest = tmp_path / "m.json"
62 assert main(["seal", str(pkg), "--out", str(manifest), "--sign", str(priv)]) == OK
63 assert main(["verify", str(pkg), "--manifest", str(manifest), "--pubkey", str(pub)]) == OK
64
65
66def test_verify_rejects_wrong_signer(pkg, tmp_path):
67 pytest.importorskip("cryptography")
68 priv, pub = tmp_path / "k.key", tmp_path / "k.pub"
69 other_pub = tmp_path / "o.pub"
70 main(["keygen", "--private", str(priv), "--public", str(pub)])
71 main(["keygen", "--private", str(tmp_path / "o.key"), "--public", str(other_pub)])
72 manifest = tmp_path / "m.json"
73 main(["seal", str(pkg), "--out", str(manifest), "--sign", str(priv)])
74 assert main(["verify", str(pkg), "--manifest", str(manifest), "--pubkey", str(other_pub)]) == 1
75
76
77def test_timestamp_request_apply_verify(pkg, tmp_path):
78 pytest.importorskip("asn1crypto")
79 import json
80
81 from tests.test_timestamp import issue_token
82
83 manifest = tmp_path / "m.json"
84 main(["seal", str(pkg), "--out", str(manifest)])
85
86 req = tmp_path / "m.tsq"
87 assert main(["timestamp", "request", str(manifest), "--out", str(req)]) == OK
88 assert req.exists() and req.stat().st_size > 0
89
90 manifest_id = json.loads(manifest.read_text())["id"]
91 tsr = tmp_path / "resp.tsr"
92 tsr.write_bytes(issue_token(manifest_id))
93
94 assert main(["timestamp", "apply", str(manifest), "--token", str(tsr)]) == OK
95 assert main(["timestamp", "verify", str(manifest)]) == OK
96 # A timestamp is checked as part of a normal verify too.
97 assert main(["verify", str(pkg), "--manifest", str(manifest)]) == OK
98
99
100def test_timestamp_verify_unstamped_is_failure(pkg, tmp_path):
101 pytest.importorskip("asn1crypto")
102 manifest = tmp_path / "m.json"
103 main(["seal", str(pkg), "--out", str(manifest)])
104 assert main(["timestamp", "verify", str(manifest)]) == 1