"""Unit contracts for the transportable, exact RC candidate image set.""" from __future__ import annotations import hashlib import importlib.util import io import json import subprocess import sys import tarfile from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] RELEASE_BUILD = ROOT / "scripts" / "release_build.py" def _release_build_module(): spec = importlib.util.spec_from_file_location("rc_candidate_release_build", RELEASE_BUILD) assert spec and spec.loader module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module def _write_public_source_manifest(root: Path, module, source_revision: str) -> dict[str, object]: files = [] for relative_path in module.SOURCE_DOCKERFILES: path = root / relative_path path.parent.mkdir(parents=True, exist_ok=True) payload = ( f'LABEL {module.OCI_SOURCE_LABEL}="{module.PUBLIC_SOURCE_REPOSITORY}"\n' ).encode() path.write_bytes(payload) files.append( { "path": relative_path, "bytes": len(payload), "sha256": hashlib.sha256(payload).hexdigest(), } ) manifest: dict[str, object] = { "schemaVersion": 1, "sourceRevision": source_revision, "sourceRepository": module.PUBLIC_SOURCE_REPOSITORY, "files": files, } (root / "PUBLIC_SOURCE_MANIFEST.json").write_text(json.dumps(manifest), encoding="utf-8") return manifest def test_release_command_failure_keeps_the_docker_error_tail( monkeypatch: pytest.MonkeyPatch, ) -> None: module = _release_build_module() failure = subprocess.CompletedProcess( ["docker", "build"], 73, stdout="", stderr="progress\n" * 300 + "final Docker error" ) monkeypatch.setattr(module.subprocess, "run", lambda *_args, **_kwargs: failure) with pytest.raises(RuntimeError) as error: module.run("docker", "build") assert "final Docker error" in str(error.value) assert "failed (73)" in str(error.value) assert "progress\n" * 300 not in str(error.value) def _add_file(archive: tarfile.TarFile, name: str, payload: bytes) -> None: info = tarfile.TarInfo(name) info.size = len(payload) archive.addfile(info, io.BytesIO(payload)) def _image_records(module) -> dict[str, dict[str, object]]: records: dict[str, dict[str, object]] = {} for index, name in enumerate(module.IMAGES): records[name] = { "tag": f"{name}:1.3.0-rc.1", "architecture": "amd64", "labels": { "org.opencontainers.image.version": "1.3.0-rc.1", "org.opencontainers.image.revision": "a" * 40, }, "rootfs_layers": [f"sha256:{index + 1:064x}"], } return records def _write_bundle(path: Path, records: dict[str, dict[str, object]]) -> None: manifest: list[dict[str, object]] = [] with tarfile.open(path, "w") as archive: for index, (_name, record) in enumerate(records.items()): config = f"{index:064x}.json" layer = f"{index:064x}/layer.tar" payload = { "architecture": record["architecture"], "config": {"Labels": record["labels"]}, "rootfs": {"diff_ids": record["rootfs_layers"]}, } _add_file(archive, config, json.dumps(payload).encode()) _add_file(archive, layer, b"layer") manifest.append({"Config": config, "RepoTags": [record["tag"]], "Layers": [layer]}) _add_file(archive, "manifest.json", json.dumps(manifest).encode()) def test_image_bundle_binds_exact_tags_labels_and_layer_sets(tmp_path: Path) -> None: module = _release_build_module() records = _image_records(module) bundle = tmp_path / "candidate-images.tar" _write_bundle(bundle, records) verified = module.verify_image_bundle(bundle, records) assert set(verified) == set(module.IMAGES) assert verified["modelforge-api"]["tag"] == "modelforge-api:1.3.0-rc.1" def test_image_bundle_rejects_a_changed_filesystem_layer_set(tmp_path: Path) -> None: module = _release_build_module() records = _image_records(module) bundle = tmp_path / "candidate-images.tar" _write_bundle(bundle, records) records["modelforge-api"]["rootfs_layers"] = ["sha256:" + "f" * 64] with pytest.raises(ValueError, match="layer set"): module.verify_image_bundle(bundle, records) def test_parentless_export_requires_an_exact_canonical_source_manifest( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: module = _release_build_module() build_commit = "b" * 40 canonical_commit = "a" * 40 monkeypatch.setattr(module, "ROOT", tmp_path) monkeypatch.setattr( module, "run", lambda *args, **kwargs: { ("git", "rev-parse", "HEAD"): build_commit, ("git", "status", "--porcelain"): "", ("git", "describe", "--tags", "--always"): "candidate", ("git", "remote", "get-url", "origin"): "", ("git", "rev-parse", "--abbrev-ref", "HEAD"): "main", }.get(args, ""), ) with pytest.raises(SystemExit, match="unbound source-label override"): module.source_identity(False, canonical_commit) manifest = _write_public_source_manifest(tmp_path, module, canonical_commit) with pytest.raises(SystemExit, match="requires --canonical-source-commit"): module.source_identity(False) identity = module.source_identity(False, canonical_commit) assert identity["commit"] == canonical_commit assert identity["build_commit"] == build_commit assert identity["public_source_manifest_sha256"] assert identity["source_repository"] == module.PUBLIC_SOURCE_REPOSITORY manifest_path = tmp_path / "PUBLIC_SOURCE_MANIFEST.json" manifest["sourceRepository"] = "https://attacker.invalid/forged" manifest_path.write_text(json.dumps(manifest), encoding="utf-8") with pytest.raises(SystemExit, match="approved sanitized identity"): module.source_identity(False, canonical_commit) manifest["sourceRepository"] = module.PUBLIC_SOURCE_REPOSITORY manifest_path.write_text(json.dumps(manifest), encoding="utf-8") dockerfile = tmp_path / module.SOURCE_DOCKERFILES[0] dockerfile.write_text("LABEL org.opencontainers.image.source=\"https://attacker.invalid\"\n") with pytest.raises(SystemExit, match="does not bind the current"): module.source_identity(False, canonical_commit) def test_private_release_identity_uses_the_canonical_https_source( monkeypatch: pytest.MonkeyPatch, ) -> None: module = _release_build_module() commit = "b" * 40 monkeypatch.setattr(module, "ROOT", ROOT) monkeypatch.setattr( module, "run", lambda *args, **kwargs: { ("git", "rev-parse", "HEAD"): commit, ("git", "status", "--porcelain"): "", ("git", "describe", "--tags", "--always"): "candidate", ("git", "remote", "get-url", "origin"): "ssh://private.example/repo.git", ("git", "rev-parse", "--abbrev-ref", "HEAD"): "main", }.get(args, ""), ) identity = module.source_identity(False) assert identity["source_repository"] == module.CANONICAL_SOURCE_REPOSITORY def test_release_builder_checks_built_image_source_labels() -> None: module = _release_build_module() source = module.PUBLIC_SOURCE_REPOSITORY records = { "modelforge-api": {"labels": {module.OCI_SOURCE_LABEL: source}}, "modelforge-web": {"labels": {module.OCI_SOURCE_LABEL: source}}, } module._assert_image_source_identity(records, source) records["modelforge-web"]["labels"][module.OCI_SOURCE_LABEL] = "https://attacker.invalid" with pytest.raises(SystemExit, match="source label does not match source identity"): module._assert_image_source_identity(records, source)