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

v0.1.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