amber
Seal a set of files into a content-addressed snapshot you can prove unaltered. amber pins each named file's git-style blob SHA into one small JSON capsule whose fixity IS the content — a fixity manifest, not an archive (it stores hashes, not bytes). A seal_sha256 covers the whole manifest, so any later change to any sealed file, or to the capsule itself, breaks the seal loudly: verify FAILs and names the broken member. Prove a moment's exact bytes unchanged, cheaply and portably.
The honest edge
it proves IDENTITY, not BYTES: a green verify means every sealed file still hashes to what it did at seal time, never that the files are backed up — keep them in git or a zip if you need the bytes themselves. Content-addressed via git-style blob SHAs computed in-process (no git shell-out).
Run it
python3 amber.py seal src/ README.md --out capsule.json && python3 amber.py verify capsule.json
test_amber.py (13 golden + 10 mutations, all green)
Python 3, standard library only
The code — every file that ships
amber.py376 lineson GitHub →
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""
amber — seal a set of files into a content-addressed snapshot you can prove unaltered.
Amber is tree resin that hardened around an insect and held it, unchanged, for
forty million years — you can still read the wing. `amber` is that for a set of
files: it seals a *moment* — the exact bytes of the paths you name — into a small
JSON capsule whose fixity IS the content. Any later change to any sealed file, or
to the capsule itself, breaks the seal loudly. Nothing is silently altered.
WHAT IT IS (and is not)
It is a **fixity manifest**, not an archive. It does NOT copy your files or
store their bytes — it pins each file's content hash (a git-style blob SHA:
`sha1("blob <len>\\0" + bytes)`, the same address git itself would give the
file). The capsule is tiny — a list of {path, sha, bytes} plus one seal hash
over the whole manifest — no matter how large the sealed files are. To prove a
file unchanged later, `amber verify` re-hashes it and compares. (If you also
want the bytes preserved, keep the files in git, or zip them separately —
amber proves *identity*, git/zip preserve *bytes*. Amber is the cheap,
portable proof-of-no-change that rides alongside.)
THE SEAL (why a change anywhere is caught)
The manifest carries a `seal_sha256`: sha256 over the CANONICAL manifest with
the seal field blanked. It covers every pinned file's SHA transitively, so:
- change a sealed file's bytes -> its blob SHA changes -> verify FAILs
- edit the manifest (add/drop/reorder a file, fudge a size) -> seal FAILs
- blank/forge the seal itself -> recomputed seal ≠ stored -> FAILs
There is no edit that leaves a valid seal. `verify` names the broken member
and exits non-zero — never a silent pass over a tampered capsule.
DOCTRINE (binding, inherited from the Amber format)
1. Append-only. A sealed capsule is never edited. Re-sealing a moment makes a
NEW capsule with its own seal-date. The series of capsules is the record.
`seal` refuses to overwrite an existing capsule.
2. Fixity is the content. Amber pins content hashes, not copies — a specimen's
address IS its content, so the capsule can never drift from what it claims.
3. Byte, never token. Sizes in bytes; hashes over bytes.
4. The seal is loud. `verify` exits non-zero and names the broken member.
USAGE
amber seal --id my-snapshot --out capsule.json a.txt b/c.txt docs/
Pin every named file (a directory is walked, all files under it pinned)
into capsule.json, relative to --root (default: current directory).
Refuses to overwrite an existing capsule (append-only).
amber verify --capsule capsule.json
Re-hash every pinned file against --root and recompute the seal. PASS
(exit 0) iff nothing changed; FAIL (exit 1) naming each broken member.
amber show --capsule capsule.json
Print a human summary: id, seal date, member count, total bytes, seal.
amber --port # print amber's own port-verb (fold) and exit
amber --selftest # run built-in checks and exit
WHAT THIS IS A STRIP OF
An internal total-snapshot engine (CC-BY-NC) sealed a moment of a byte-truth
store — a payload, a faceted context Inclusion selected by YAML front-matter,
a panel of frozen reports, and an embedded fidelity reading — pinning git blob
SHAs under a canonical seal hash. This gift keeps the load-bearing atom — pin
content hashes (never duplicate) + one canonical seal hash + loud verify — and
drops the host-specific machinery (the front-matter facet query, the report
panel, the fidelity reading, the hardcoded repo root). What remains is a
plain, portable content-fixity sealer over any set of files. Net-new
stdlib-only Python; nothing lifted; re-licensed MIT.
amber's port-verb is `fold`: many files in, one sealed aggregate (the capsule)
out.
"""
import argparse
import hashlib
import json
import os
import sys
import datetime
PORT_VERB = "fold" # many files -> one sealed aggregate snapshot
AMBER_VERSION = 1
# ─── the content hash (git-style blob SHA — the same address git gives a file) ─
def blob_sha(path):
"""git blob SHA-1 of a file's bytes: sha1(b"blob <len>\\0" + bytes)."""
with open(path, "rb") as f:
data = f.read()
h = hashlib.sha1()
h.update(b"blob %d\0" % len(data))
h.update(data)
return h.hexdigest()
# ─── the canonical seal hash (covers the whole manifest, seal field blanked) ──
def seal_hash(manifest):
"""sha256 over the canonical manifest with the seal field blanked.
Deep-copy, blank fixity.seal_sha256, serialize with sorted keys and no
whitespace, hash. This transitively covers every pinned member's SHA and byte
count, so no manifest edit leaves a valid seal.
"""
m = json.loads(json.dumps(manifest)) # deep copy
m["fixity"]["seal_sha256"] = ""
canon = json.dumps(m, sort_keys=True, separators=(",", ":"))
return hashlib.sha256(canon.encode("utf-8")).hexdigest()
# ─── path collection (a file pins itself; a directory pins every file under it) ─
SKIP_DIRS = {".git", "node_modules", "__pycache__"}
def collect(root, targets):
"""Resolve targets (files or dirs) to a sorted list of file paths rel to root.
A directory is walked recursively; SKIP_DIRS are pruned. A named file is
pinned directly. Raises FileNotFoundError on a missing target.
"""
paths = []
for t in targets:
ap = t if os.path.isabs(t) else os.path.join(root, t)
if not os.path.exists(ap):
raise FileNotFoundError(t)
if os.path.isdir(ap):
for dirpath, dirnames, filenames in os.walk(ap):
dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
for fn in filenames:
paths.append(os.path.join(dirpath, fn))
else:
paths.append(ap)
# relative, de-duplicated, sorted (deterministic manifest)
rels = sorted(set(os.path.relpath(p, root) for p in paths))
return rels
def pin(root, rel):
"""Pin one file: {path, blob_sha, bytes}."""
ap = os.path.join(root, rel)
return {"path": rel, "blob_sha": blob_sha(ap), "bytes": os.path.getsize(ap)}
# ─── build a manifest (pure — no I/O of the capsule; testable) ────────────────
def build_manifest(root, capsule_id, targets, session=""):
"""Build the capsule manifest dict for the given targets. Sealed."""
rels = collect(root, targets)
members = [pin(root, r) for r in rels]
manifest = {
"amber_version": AMBER_VERSION,
"id": capsule_id,
"seal_date": datetime.date.today().isoformat(),
"seal_session": session,
"members": members,
"fixity": {
"seal_sha256": "",
"file_count": len(members),
"total_bytes": sum(m["bytes"] for m in members),
},
}
manifest["fixity"]["seal_sha256"] = seal_hash(manifest)
return manifest
# ─── verify a manifest against a live root (pure — returns broken members) ────
def verify_manifest(manifest, root):
"""Return a list of broken-member descriptions ([] iff the seal holds).
Checks: (1) the manifest seal hash recomputes; (2) every pinned member's file
exists and still hashes to its stored SHA.
"""
broken = []
if seal_hash(manifest) != manifest["fixity"]["seal_sha256"]:
broken.append("manifest seal hash")
for m in manifest["members"]:
ap = os.path.join(root, m["path"])
if not os.path.exists(ap):
broken.append(f"pinned missing: {m['path']}")
elif blob_sha(ap) != m["blob_sha"]:
broken.append(f"pinned drifted: {m['path']}")
return broken
# ─── CLI ──────────────────────────────────────────────────────────────────────
def cmd_seal(a):
root = os.path.abspath(a.root)
if os.path.exists(a.out):
sys.stderr.write(
f"amber: refusing to overwrite existing capsule {a.out} "
f"(append-only — re-seal a moment as a NEW capsule with a new id/out).\n")
return 2
if not a.targets:
sys.stderr.write("amber: seal needs at least one file or directory to pin.\n")
return 2
try:
manifest = build_manifest(root, a.id, a.targets, session=a.session)
except FileNotFoundError as e:
sys.stderr.write(f"amber: cannot seal — no such path: {e}\n")
return 2
with open(a.out, "w", encoding="utf-8") as f:
json.dump(manifest, f, indent=2)
fx = manifest["fixity"]
print(f"AMBER SEAL OK | {a.id} | pinned {fx['file_count']} member(s) | "
f"{fx['total_bytes']} B | seal {fx['seal_sha256'][:16]}…")
return 0
def cmd_verify(a):
with open(a.capsule, "r", encoding="utf-8") as f:
manifest = json.load(f)
root = os.path.abspath(a.root)
broken = verify_manifest(manifest, root)
if broken:
print("AMBER VERIFY: FAIL")
for b in broken:
print(f" ✗ {b}")
return 1
fx = manifest["fixity"]
print(f"AMBER VERIFY: PASS | {manifest['id']} | {fx['file_count']} member(s) | "
f"{fx['total_bytes']} B | seal {fx['seal_sha256'][:16]}…")
return 0
def cmd_show(a):
with open(a.capsule, "r", encoding="utf-8") as f:
m = json.load(f)
fx = m["fixity"]
print(f"AMBER {m['id']} (sealed {m['seal_date']}"
+ (f" · {m['seal_session']}" if m.get("seal_session") else "") + ")")
print(f" members : {fx['file_count']}")
print(f" bytes : {fx['total_bytes']}")
print(f" seal : {fx['seal_sha256']}")
# list up to 10 members for a quick glance
for mem in m["members"][:10]:
print(f" {mem['blob_sha'][:12]} {mem['bytes']:>8} {mem['path']}")
if len(m["members"]) > 10:
print(f" … and {len(m['members']) - 10} more")
return 0
def _selftest():
import tempfile
import shutil
n = 0
def check(cond, msg):
nonlocal n
assert cond, msg
n += 1
tmp = tempfile.mkdtemp()
try:
# a small tree
os.makedirs(os.path.join(tmp, "sub"))
with open(os.path.join(tmp, "a.txt"), "w") as f:
f.write("alpha\n")
with open(os.path.join(tmp, "sub", "b.txt"), "w") as f:
f.write("beta\n")
# build + seal
man = build_manifest(tmp, "s1", ["a.txt", "sub"])
check(man["fixity"]["file_count"] == 2, "seals both files")
check(man["members"][0]["path"] < man["members"][1]["path"], "members sorted")
check(len(man["fixity"]["seal_sha256"]) == 64, "seal is a sha256 hex")
# verify clean
check(verify_manifest(man, tmp) == [], "a fresh seal verifies clean")
# determinism: same tree seals to the same member SHAs + seal hash
man2 = build_manifest(tmp, "s1", ["a.txt", "sub"])
check(man2["fixity"]["seal_sha256"] == man["fixity"]["seal_sha256"],
"same bytes -> same seal (deterministic)")
# tamper a sealed file -> verify FAILs, names the drifted member
with open(os.path.join(tmp, "a.txt"), "w") as f:
f.write("ALPHA-CHANGED\n")
broken = verify_manifest(man, tmp)
check(any("a.txt" in b and "drifted" in b for b in broken),
"a changed file is caught as drifted")
# restore, verify clean again
with open(os.path.join(tmp, "a.txt"), "w") as f:
f.write("alpha\n")
check(verify_manifest(man, tmp) == [], "restoring the bytes restores the seal")
# delete a sealed file -> caught as missing
os.unlink(os.path.join(tmp, "sub", "b.txt"))
broken = verify_manifest(man, tmp)
check(any("b.txt" in b and "missing" in b for b in broken),
"a deleted file is caught as missing")
with open(os.path.join(tmp, "sub", "b.txt"), "w") as f:
f.write("beta\n")
# tamper the MANIFEST (fudge a byte count) -> seal hash FAILs
tampered = json.loads(json.dumps(man))
tampered["members"][0]["bytes"] += 1
broken = verify_manifest(tampered, tmp)
check("manifest seal hash" in broken, "editing the manifest breaks the seal")
# forge the seal to match a tampered manifest: build fresh, lie about a
# member's SHA, recompute the seal so the seal-hash check passes — the live
# member no longer matches, so verify still FAILs (the two checks are independent)
fresh = build_manifest(tmp, "s2", ["a.txt", "sub"])
forged = json.loads(json.dumps(fresh))
for mem in forged["members"]:
if mem["path"] == "a.txt":
mem["blob_sha"] = "0" * 40
forged["fixity"]["seal_sha256"] = seal_hash(forged) # attacker recomputes
broken = verify_manifest(forged, tmp)
check("manifest seal hash" not in broken, "the recomputed seal passes the hash check")
check(any("a.txt" in b and "drifted" in b for b in broken),
"a forged seal cannot hide that a member no longer matches the bytes")
# append-only: seal refuses to overwrite (CLI-level, tested via os path)
cap = os.path.join(tmp, "cap.json")
with open(cap, "w") as f:
f.write("{}")
class A: pass
a = A(); a.root = tmp; a.out = cap; a.id = "x"; a.targets = ["a.txt"]; a.session = ""
rc = cmd_seal(a)
check(rc == 2, "seal refuses to overwrite an existing capsule (append-only)")
# port-verb
check(PORT_VERB == "fold", "port-verb is fold")
finally:
shutil.rmtree(tmp, ignore_errors=True)
print(f"amber selftest: {n} checks passed")
return 0
def main(argv=None):
ap = argparse.ArgumentParser(
prog="amber",
description="Seal a set of files into a content-addressed snapshot you can prove unaltered.")
ap.add_argument("--port", action="store_true",
help="print amber's own port-verb (fold) and exit")
ap.add_argument("--selftest", action="store_true",
help="run built-in checks and exit")
sub = ap.add_subparsers(dest="cmd")
s = sub.add_parser("seal", help="pin a set of files into a sealed capsule")
s.add_argument("--id", required=True, help="capsule id")
s.add_argument("--out", required=True, help="capsule JSON path (refuses to overwrite)")
s.add_argument("--root", default=".", help="root the pinned paths are relative to (default: cwd)")
s.add_argument("--session", default="", help="optional seal-session label")
s.add_argument("targets", nargs="*", help="files and/or directories to pin")
s.set_defaults(fn=cmd_seal)
v = sub.add_parser("verify", help="re-hash every member and recompute the seal")
v.add_argument("--capsule", required=True, help="capsule JSON to verify")
v.add_argument("--root", default=".", help="root to verify against (default: cwd)")
v.set_defaults(fn=cmd_verify)
h = sub.add_parser("show", help="print a capsule summary")
h.add_argument("--capsule", required=True)
h.set_defaults(fn=cmd_show)
args = ap.parse_args(argv)
if args.port:
print(json.dumps({"slug": "amber", "port_verb": PORT_VERB}))
return 0
if args.selftest:
return _selftest()
if not getattr(args, "cmd", None):
ap.print_help()
return 0
return args.fn(args)
if __name__ == "__main__":
sys.exit(main())
test_amber.py405 lineson GitHub →
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
"""
test_amber.py — golden + mutation battery for the amber gift.
Run: python3 test_amber.py
Exit 0 iff every golden check passes AND every planted mutation is caught.
Discipline (the count-fill lessons, applied upfront):
1. ISOLATE each load-bearing predicate — a "bad" case must fail on EXACTLY the
predicate under test, never by another path.
2. A .replace(...,1) anchor targets a CODE line, not a docstring example; the
harness asserts each anchor is present outside the docstring AND bites.
Every ESCAPE is a real test gap (missing/weak golden check), never noise.
"""
import json
import os
import shutil
import subprocess
import sys
import tempfile
HERE = os.path.dirname(os.path.abspath(__file__))
SRC = os.path.join(HERE, "amber.py")
# _CLI_TARGET lets a mutation test point the CLI checks at a mutated copy on disk.
_CLI_TARGET = [SRC]
def _load_module_from_source(text, name):
import importlib.util
tmp = tempfile.NamedTemporaryFile("w", suffix=".py", delete=False, encoding="utf-8")
tmp.write(text)
tmp.close()
spec = importlib.util.spec_from_file_location(name, tmp.name)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
os.unlink(tmp.name)
return mod
def _run_cli(args, cwd=None):
proc = subprocess.run([sys.executable, _CLI_TARGET[0]] + args, capture_output=True, cwd=cwd)
return proc.returncode, proc.stdout.decode(), proc.stderr.decode()
def _mktree():
"""A small tree: a.txt, sub/b.txt. Returns the root path."""
root = tempfile.mkdtemp()
os.makedirs(os.path.join(root, "sub"))
with open(os.path.join(root, "a.txt"), "w") as f:
f.write("alpha\n")
with open(os.path.join(root, "sub", "b.txt"), "w") as f:
f.write("beta\n")
return root
GOLDEN = []
def golden(fn):
GOLDEN.append(fn)
return fn
@golden
def g_port_verb_is_fold(mod):
assert mod.PORT_VERB == "fold"
rc, out, _ = _run_cli(["--port"])
assert rc == 0
assert json.loads(out) == {"slug": "amber", "port_verb": "fold"}, out
@golden
def g_seals_all_files_sorted(mod):
"""A dir target pins every file under it; members are sorted (deterministic).
Uses several files whose creation/walk order is NOT their sorted order, so a
dropped sort() is actually detectable (not coincidentally sorted).
"""
root = tempfile.mkdtemp()
try:
# create in deliberately non-alphabetical order
for nm in ["zebra.txt", "apple.txt", "mango.txt", "banana.txt"]:
with open(os.path.join(root, nm), "w") as f:
f.write(nm + "\n")
man = mod.build_manifest(root, "s1", ["."])
assert man["fixity"]["file_count"] == 4, man["fixity"]
paths = [m["path"] for m in man["members"]]
assert paths == sorted(paths), f"members must be sorted, got: {paths}"
# and specifically the first must be the alphabetical first, last the last
assert paths[0] == "apple.txt" and paths[-1] == "zebra.txt", paths
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_fresh_seal_verifies_clean(mod):
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
assert mod.verify_manifest(man, root) == [], "a fresh seal must verify clean"
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_deterministic_seal(mod):
"""ISOLATES determinism: same bytes -> byte-identical seal hash."""
root = _mktree()
try:
m1 = mod.build_manifest(root, "s1", ["a.txt", "sub"])
m2 = mod.build_manifest(root, "s1", ["a.txt", "sub"])
assert m1["fixity"]["seal_sha256"] == m2["fixity"]["seal_sha256"], "seal must be deterministic"
assert m1["members"] == m2["members"], "member SHAs must be deterministic"
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_changed_file_is_drifted(mod):
"""ISOLATES the pinned-SHA check: a changed byte -> 'drifted', naming the file."""
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
with open(os.path.join(root, "a.txt"), "w") as f:
f.write("ALPHA-CHANGED\n")
broken = mod.verify_manifest(man, root)
assert any("a.txt" in b and "drifted" in b for b in broken), broken
# and the OTHER file (unchanged) is NOT flagged — isolation
assert not any("b.txt" in b for b in broken), "only the changed file drifts"
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_deleted_file_is_missing(mod):
"""ISOLATES the existence check: a deleted member -> 'missing'."""
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
os.unlink(os.path.join(root, "sub", "b.txt"))
broken = mod.verify_manifest(man, root)
assert any("b.txt" in b and "missing" in b for b in broken), broken
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_manifest_edit_breaks_seal(mod):
"""ISOLATES the seal-hash check: fudging a byte count -> seal hash breaks."""
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
tampered = json.loads(json.dumps(man))
tampered["members"][0]["bytes"] += 1
broken = mod.verify_manifest(tampered, root)
assert "manifest seal hash" in broken, broken
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_forged_seal_cannot_hide_drift(mod):
"""A recomputed seal over a tampered manifest still FAILs on the member check.
The attacker edits a member SHA and recomputes the seal so the seal-hash check
passes — but the member no longer matches the live bytes, so verify still FAILs.
This proves the two checks are independent (seal AND per-member), not one.
"""
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
tampered = json.loads(json.dumps(man))
# point a.txt at a wrong SHA, then recompute the seal to match the lie
for m in tampered["members"]:
if m["path"] == "a.txt":
m["blob_sha"] = "0" * 40
tampered["fixity"]["seal_sha256"] = mod.seal_hash(tampered)
broken = mod.verify_manifest(tampered, root)
# seal-hash now passes, but the member drift is still caught
assert "manifest seal hash" not in broken, "attacker's recomputed seal passes the hash check"
assert any("a.txt" in b and "drifted" in b for b in broken), (
"a forged seal cannot hide that a member no longer matches the bytes")
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_blob_sha_matches_git(mod):
"""ISOLATES the blob-SHA formula: it must equal git's own blob hash of the bytes."""
root = _mktree()
try:
got = mod.blob_sha(os.path.join(root, "a.txt"))
# git blob sha of "alpha\n" (6 bytes) — computed independently here
import hashlib
data = b"alpha\n"
want = hashlib.sha1(b"blob %d\0" % len(data) + data).hexdigest()
assert got == want, f"blob_sha must match git's formula: {got} != {want}"
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_cli_seal_verify_roundtrip(mod):
"""CLI end-to-end: seal then verify PASS; then tamper -> verify FAIL (exit 1)."""
root = _mktree()
try:
cap = os.path.join(root, "cap.json")
rc, out, err = _run_cli(["seal", "--id", "t", "--out", cap, "--root", root, "a.txt", "sub"])
assert rc == 0, (rc, err)
rc, out, err = _run_cli(["verify", "--capsule", cap, "--root", root])
assert rc == 0 and "PASS" in out, (rc, out, err)
with open(os.path.join(root, "a.txt"), "w") as f:
f.write("changed\n")
rc, out, err = _run_cli(["verify", "--capsule", cap, "--root", root])
assert rc == 1 and "FAIL" in out, (rc, out)
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_cli_seal_refuses_overwrite(mod):
"""ISOLATES append-only: seal onto an existing path is refused (exit 2)."""
root = _mktree()
try:
cap = os.path.join(root, "cap.json")
with open(cap, "w") as f:
f.write("{}")
rc, out, err = _run_cli(["seal", "--id", "t", "--out", cap, "--root", root, "a.txt"])
assert rc == 2 and "append-only" in err.lower(), (rc, err)
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_file_count_matches_members(mod):
"""ISOLATES the count: fixity.file_count must equal the actual member count.
(A wrong count is self-consistent under the seal — build and verify both use
it — so verify can't catch it; only an independent count check can.)
"""
root = _mktree()
try:
man = mod.build_manifest(root, "s1", ["a.txt", "sub"])
assert man["fixity"]["file_count"] == len(man["members"]), (
f"file_count {man['fixity']['file_count']} != {len(man['members'])} members")
finally:
shutil.rmtree(root, ignore_errors=True)
@golden
def g_missing_target_is_refused(mod):
"""A named path that does not exist -> refuse, don't seal a phantom."""
root = _mktree()
try:
try:
mod.build_manifest(root, "s1", ["nope.txt"])
assert False, "a missing target must raise"
except FileNotFoundError:
pass
finally:
shutil.rmtree(root, ignore_errors=True)
# ─── mutations: (name, code_anchor, replacement, target golden check) ─────────
MUTATIONS = [
("port_verb_wrong",
'PORT_VERB = "fold"',
'PORT_VERB = "sink"',
"g_port_verb_is_fold"),
# blob_sha drops the git header -> no longer matches git's formula
("blob_sha_no_header",
'h.update(b"blob %d\\0" % len(data))',
'h.update(b"")',
"g_blob_sha_matches_git"),
# members not sorted -> non-deterministic order (isolated by the sorted check)
("members_not_sorted",
" rels = sorted(set(os.path.relpath(p, root) for p in paths))",
" rels = list(set(os.path.relpath(p, root) for p in paths))",
"g_seals_all_files_sorted"),
# seal_hash must DEEP-COPY before blanking, else it mutates the caller's
# manifest as a side effect — corrupting the stored seal on verify. Aliasing
# instead of copying makes a fresh seal verify as broken.
("seal_hash_no_deepcopy",
'm = json.loads(json.dumps(manifest)) # deep copy',
'm = manifest # deep copy',
"g_fresh_seal_verifies_clean"),
# per-member drift check disabled -> a changed file no longer caught
("drift_check_disabled",
'elif blob_sha(ap) != m["blob_sha"]:',
'elif False:',
"g_changed_file_is_drifted"),
# existence check disabled -> a deleted member no longer caught as missing
("missing_check_disabled",
'if not os.path.exists(ap):\n broken.append(f"pinned missing: {m[\'path\']}")',
'if False:\n broken.append(f"pinned missing: {m[\'path\']}")',
"g_deleted_file_is_missing"),
# seal-hash check disabled -> a manifest edit no longer caught
("seal_check_disabled",
'if seal_hash(manifest) != manifest["fixity"]["seal_sha256"]:',
'if False:',
"g_manifest_edit_breaks_seal"),
# append-only guard disabled -> seal overwrites an existing capsule
("append_only_disabled",
" if os.path.exists(a.out):",
" if False:",
"g_cli_seal_refuses_overwrite"),
# missing-target guard disabled: collect() no longer raises on a bad path.
# Isolated by g_missing_target_is_refused.
("missing_target_ignored",
" if not os.path.exists(ap):\n raise FileNotFoundError(t)",
" if not os.path.exists(ap):\n continue",
"g_missing_target_is_refused"),
# total_bytes computed wrong (e.g. count members not bytes) -> seal changes but
# more importantly the deterministic-vs-live parity check would break. Isolate
# via the seal determinism: a bytes miscount still hashes deterministically, so
# target the file_count instead — a dropped member breaks the count check.
("file_count_wrong",
'"file_count": len(members),',
'"file_count": len(members) + 1,',
"g_file_count_matches_members"),
]
def _run_golden(mod, name):
fn = next(f for f in GOLDEN if f.__name__ == name)
try:
fn(mod)
return True
except Exception:
return False
def _run_cli_golden(name, script_path):
"""Run a CLI golden check against an arbitrary amber.py path (a mutated copy).
Points _CLI_TARGET at the mutated script, runs the check, restores. Returns
True iff the check passed (i.e. the mutation escaped detection).
"""
fn = next(f for f in GOLDEN if f.__name__ == name)
saved = _CLI_TARGET[0]
_CLI_TARGET[0] = script_path
try:
fn(None) # CLI golden checks don't use the module arg
return True
except Exception:
return False
finally:
_CLI_TARGET[0] = saved
def main():
src = open(SRC, encoding="utf-8").read()
base = _load_module_from_source(src, "amber_base")
gpass = 0
for fn in GOLDEN:
fn(base)
gpass += 1
print(f"golden: {gpass}/{len(GOLDEN)} passed")
caught = 0
body = src.split('"""', 2)[-1] if src.count('"""') >= 2 else src
for name, anchor, repl, target in MUTATIONS:
assert anchor in src, f"MUTATION {name}: anchor not found (stale test)"
assert anchor in body, f"MUTATION {name}: anchor only in docstring (non-biting)"
mutated = src.replace(anchor, repl, 1)
assert mutated != src, f"MUTATION {name}: replace was a no-op"
target_fn = next(f for f in GOLDEN if f.__name__ == target)
uses_cli = target in ("g_cli_seal_refuses_overwrite", "g_cli_seal_verify_roundtrip",
"g_port_verb_is_fold")
if uses_cli:
# Write mutated source to a temp file; run the CLI golden check against
# it by pointing a fresh _run_cli at that path (no global mutation).
mtmp = tempfile.NamedTemporaryFile("w", suffix=".py", delete=False)
mtmp.write(mutated); mtmp.close()
try:
still = _run_cli_golden(target, mtmp.name)
finally:
os.unlink(mtmp.name)
else:
mmod = _load_module_from_source(mutated, f"amber_mut_{name}")
still = _run_golden(mmod, target)
assert not still, (
f"MUTATION {name}: ESCAPED — {target} still passed. Real test gap: "
f"add/repair a golden check that isolates this predicate.")
caught += 1
print(f" mutation {name}: caught by {target}")
print(f"mutations: {caught}/{len(MUTATIONS)} caught")
print(f"\nAMBER TEST: {gpass} golden + {caught} mutations — ALL GREEN")
return 0
if __name__ == "__main__":
sys.exit(main())