Files
MobilityOps/scripts/generate-release-provenance.py
NuklearRabbit 00191e9b54
MobilityOps acceptance / backend (push) Failing after 20s
MobilityOps acceptance / frontend (push) Successful in 28s
MobilityOps acceptance / e2e (push) Skipped
M48: harden demo operations and offsite recovery
2026-08-21 22:17:49 +02:00

62 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Generate inspectable release provenance for the images built by CI."""
from __future__ import annotations
import hashlib
import json
import os
import subprocess
from pathlib import Path
IMAGES = {
"api": "mobilityops-api-release",
"web": "mobilityops-web-release",
"backup_tools": "mobilityops-backup-tools-release",
}
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def main() -> None:
revision = os.environ.get("GITHUB_SHA", "")
if len(revision) != 40:
raise SystemExit("GITHUB_SHA must contain the full release revision")
images: dict[str, dict[str, str]] = {}
for name, image in IMAGES.items():
details = json.loads(
subprocess.check_output(["docker", "image", "inspect", image], text=True)
)[0]
labels = details.get("Config", {}).get("Labels", {}) or {}
if labels.get("org.opencontainers.image.revision") != revision:
raise SystemExit(f"revision label mismatch for {image}")
sbom = Path(f"mobilityops-{name.replace('_', '-')}-sbom.cdx.json")
images[name] = {
"reference": image,
"local_image_id": details["Id"],
"revision": labels["org.opencontainers.image.revision"],
"sbom": sbom.name,
"sbom_sha256": sha256(sbom),
}
provenance = {
"schema": "mobilityops.release-provenance.v1",
"revision": revision,
"repository": os.environ.get("GITHUB_REPOSITORY", "MobilityOps"),
"ref": os.environ.get("GITHUB_REF", ""),
"workflow_run": os.environ.get("GITHUB_RUN_ID", ""),
"images": images,
}
Path("release-provenance.json").write_text(
json.dumps(provenance, indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
if __name__ == "__main__":
main()