CI Pipeline / lint (push) Successful in 22s
CI Pipeline / unit-tests (push) Successful in 37s
CI Pipeline / canary (push) Successful in 5s
CI Pipeline / best-practices (push) Successful in 5s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / gitea-offline (push) Successful in 43s
CI Pipeline / required-checks (push) Skipped
CI Pipeline / lint (pull_request) Successful in 21s
CI Pipeline / unit-tests (pull_request) Successful in 39s
CI Pipeline / canary (pull_request) Successful in 6s
CI Pipeline / best-practices (pull_request) Successful in 4s
CI Pipeline / documentation (pull_request) Successful in 5s
CI Pipeline / gitea-offline (pull_request) Successful in 37s
CI Pipeline / required-checks (pull_request) Successful in 0s
Auto-version and Release / release (pull_request) Failing after 4s
70 lines
2.2 KiB
Python
70 lines
2.2 KiB
Python
"""Content-addressed immutable evidence storage."""
|
|
|
|
from pathlib import Path
|
|
|
|
from rune.orchestration.evidence_store import EvidenceStore
|
|
|
|
|
|
def test_put_returns_sha256_digest(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
digest = store.put(b"tool output")
|
|
assert digest.startswith("sha256:")
|
|
assert store.contains(digest)
|
|
assert store.get(digest) == b"tool output"
|
|
|
|
|
|
def test_identical_content_deduplicates(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
d1 = store.put(b"same bytes")
|
|
d2 = store.put(b"same bytes")
|
|
assert d1 == d2
|
|
assert store.size(d1) == len(b"same bytes")
|
|
|
|
|
|
def test_missing_digest_raises(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
assert not store.contains("sha256:deadbeef")
|
|
try:
|
|
store.get("sha256:deadbeef")
|
|
raise AssertionError("expected KeyError")
|
|
except KeyError:
|
|
pass
|
|
|
|
|
|
def test_content_hash_identifies_different_content(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
assert store.put(b"a") != store.put(b"b")
|
|
|
|
|
|
def test_rejects_malformed_digests(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
assert not store.contains("sha256:../secret")
|
|
assert not store.contains("sha256:zz")
|
|
assert not store.contains("sha256:")
|
|
assert not store.contains("md5:abc")
|
|
for bad in ("sha256:../secret", "sha256:zz", "sha256:", "md5:abc"):
|
|
try:
|
|
store.get(bad)
|
|
raise AssertionError(f"expected KeyError for {bad!r}")
|
|
except KeyError:
|
|
pass
|
|
|
|
|
|
def test_rejects_tampered_blob_on_put(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
digest = store.put(b"original")
|
|
blob = tmp_path / "evidence" / (digest[len("sha256:") :] + ".bin")
|
|
blob.write_bytes(b"TAMPERED")
|
|
try:
|
|
store.put(b"original")
|
|
raise AssertionError("expected CorruptBlobError")
|
|
except EvidenceStore.CorruptBlobError:
|
|
pass
|
|
|
|
|
|
def test_valid_digest_still_round_trips(tmp_path: Path):
|
|
store = EvidenceStore(tmp_path / "evidence")
|
|
digest = store.put(b"hello")
|
|
assert store.contains(digest)
|
|
assert store.get(digest) == b"hello"
|