coulomb-social/scripts/verify-packaged-source.py

68 lines
3.2 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Compare retained OCI application bytes with exact Git commits, without startup.
No pull, mounts, network, application entrypoint, database or external writes.
Inventory follows the runtime COPY instructions in this repo's Dockerfile.
This proves packaged source equality, not dependency/build reproducibility.
"""
import argparse
import hashlib
import json
import re
import subprocess
PROBE = """import hashlib,json,pathlib
r=pathlib.Path('/app')
f={str(p.relative_to(r)):hashlib.sha256(p.read_bytes()).hexdigest()
for p in (r/'coulomb_social').rglob('*')
if p.is_file() and '__pycache__' not in p.parts and p.suffix != '.pyc'}
for n in ['manage.py','pyproject.toml','docker-entrypoint.sh']:
f[n]=hashlib.sha256((r/n).read_bytes()).hexdigest()
print(json.dumps(f,sort_keys=True))
"""
def canonical(value):
return json.dumps(value, sort_keys=True, separators=(",", ":")).encode()
def verify(image, sources):
if not re.fullmatch(r"forgejo\.coulomb\.social/coulomb/"
r"coulomb-social@sha256:[a-f0-9]{64}", image):
raise ValueError("Exact retained application image digest required")
if not sources or any(not re.fullmatch(r"[a-f0-9]{40}", source) for source in sources):
raise ValueError("Full source commit hashes required")
actual = json.loads(subprocess.check_output([
"docker", "run", "--rm", "--pull=never", "--network", "none", "--read-only",
"--cap-drop", "ALL", "--security-opt", "no-new-privileges", "--entrypoint", "python",
image, "-c", PROBE], timeout=60))
comparisons = []
for source in sources:
paths = subprocess.check_output([
"git", "ls-tree", "-r", "--name-only", source, "coulomb_social", "manage.py",
"pyproject.toml", "scripts/docker-entrypoint.sh"], text=True).splitlines()
expected = {}
for name in paths:
packaged = (name.removeprefix("scripts/")
if name == "scripts/docker-entrypoint.sh" else name)
expected[packaged] = hashlib.sha256(subprocess.check_output(
["git", "show", source + ":" + name])).hexdigest()
differences = sum(expected.get(n) != actual.get(n) for n in set(expected) | set(actual))
comparisons.append({"commit": source, "packaged_file_count": len(actual),
"source_file_count": len(expected), "different_files": differences,
"all_packaged_source_bytes_match": differences == 0})
return {"schema": "coulomb.packaged-source-provenance.v1", "image": image,
"network": "none", "read_only_root": True, "entrypoint_bypassed": True,
"database_contact": False, "production_changes": False, "comparisons": comparisons,
"actual_packaged_manifest_sha256": hashlib.sha256(canonical(actual)).hexdigest(),
"dependency_or_build_reproducibility_proved": False}
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--image", required=True)
parser.add_argument("--source", action="append", required=True)
arguments = parser.parse_args()
print(json.dumps(verify(arguments.image, arguments.source), indent=2))