62 lines
2.0 KiB
Python
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()
|