From 902286dbc0daf63ddb21c96b81c63af1143447cc Mon Sep 17 00:00:00 2001 From: codex Date: Sun, 26 Jul 2026 20:52:31 +0000 Subject: [PATCH] fix(build): key nested images by base content --- .gitea/workflows/test.yml | 34 ++++++++++++- bot_bottle/backend/macos_container/launch.py | 6 +-- .../macos_container/nested_containers.py | 6 +-- scripts/check_image_inputs.py | 36 ++++++++++++- tests/unit/test_macos_nested_containers.py | 50 ++++++++++++------- 5 files changed, 104 insertions(+), 28 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index de2ff31c..09ee4e9c 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -156,9 +156,12 @@ jobs: 'import json; print(json.load(open("image-build-args.json"))["PYTHON_BASE_IMAGE"])') node_ref=$(python3 -c \ 'import json; print(json.load(open("image-build-args.json"))["NODE_BASE_IMAGE"])') + docker_cli_ref=$(python3 -c \ + 'import json; print(json.load(open("image-build-args.json"))["DOCKER_CLI_BASE_IMAGE"])') test -n "$python_ref" test -n "$node_ref" - for ref in "$python_ref" "$node_ref"; do + test -n "$docker_cli_ref" + for ref in "$python_ref" "$node_ref" "$docker_cli_ref"; do docker buildx imagetools inspect --raw "$ref" | python3 -c ' import json @@ -176,6 +179,35 @@ jobs: ' done + - name: Verify Codex archives for all supported architectures + run: | + set -euo pipefail + codex_version=$( + sed -n 's/^ARG CODEX_VERSION=//p' bot_bottle/contrib/codex/Dockerfile + ) + test -n "$codex_version" + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT + for target in \ + aarch64-unknown-linux-musl \ + x86_64-unknown-linux-musl + do + asset="codex-package-${target}.tar.gz" + expected=$( + awk -v asset="$asset" '$2 == asset { print $1 }' \ + bot_bottle/contrib/codex/codex-package_SHA256SUMS + ) + test -n "$expected" + curl -fsSL \ + "https://github.com/openai/codex/releases/download/rust-v${codex_version}/${asset}" \ + -o "$tmp/$asset" + echo "$expected $tmp/$asset" | sha256sum -c - + tar -tzf "$tmp/$asset" > "$tmp/$asset.contents" + grep -Fx 'bin/codex' "$tmp/$asset.contents" + grep -Fx 'bin/codex-code-mode-host' "$tmp/$asset.contents" + grep -Fx 'codex-package.json' "$tmp/$asset.contents" + done + - name: Build and smoke-test all supported images run: | set -euo pipefail diff --git a/bot_bottle/backend/macos_container/launch.py b/bot_bottle/backend/macos_container/launch.py index ae9faf85..702dcff3 100644 --- a/bot_bottle/backend/macos_container/launch.py +++ b/bot_bottle/backend/macos_container/launch.py @@ -107,7 +107,8 @@ def _layer_nested_containers( """ if not plan.nested_containers: return agent_image - derived = f"{agent_image}{nested_containers_mod.IMAGE_SUFFIX}" + pinned_base = container_mod.pinned_local_image_ref(agent_image) + derived = f"{pinned_base}{nested_containers_mod.IMAGE_SUFFIX}" if plan.spec.image_policy == "cached": if not container_mod.image_exists(derived): die( @@ -117,9 +118,8 @@ def _layer_nested_containers( info(f"using cached nested-container image {derived!r}") return derived return nested_containers_mod.build_image( - agent_image, + pinned_base, container_mod.build_image, - container_mod.pinned_local_image_ref, ) diff --git a/bot_bottle/backend/macos_container/nested_containers.py b/bot_bottle/backend/macos_container/nested_containers.py index 7b17c59b..781dc9b9 100644 --- a/bot_bottle/backend/macos_container/nested_containers.py +++ b/bot_bottle/backend/macos_container/nested_containers.py @@ -55,9 +55,8 @@ _GUEST_DEVICES = ("/dev/fuse", "/dev/net/tun") def build_image( - base_image: str, + pinned_base: str, build: Callable[..., None], - pin_local_base: Callable[[str], str], ) -> str: """Layer the nested-container tooling onto an already-built agent image. @@ -67,8 +66,7 @@ def build_image( # TODO(#394): replace this hand-rolled Dockerfile with a docker-layer # abstraction once that infrastructure exists. """ - image = f"{base_image}{IMAGE_SUFFIX}" - pinned_base = pin_local_base(base_image) + image = f"{pinned_base}{IMAGE_SUFFIX}" init_script = Path(__file__).with_name("nested-containers-init.sh") with tempfile.TemporaryDirectory(prefix="bot-bottle-nested-containers.") as tmp: context = Path(tmp) diff --git a/scripts/check_image_inputs.py b/scripts/check_image_inputs.py index 464bc4a4..fa9a106c 100644 --- a/scripts/check_image_inputs.py +++ b/scripts/check_image_inputs.py @@ -22,6 +22,11 @@ NPM_MANIFESTS = ( Path("bot_bottle/contrib/pi/package.json"), ) IMAGE_BUILD_ARGS = Path("image-build-args.json") +CODEX_CHECKSUMS = Path("bot_bottle/contrib/codex/codex-package_SHA256SUMS") +REQUIRED_CODEX_ASSETS = frozenset({ + "codex-package-aarch64-unknown-linux-musl.tar.gz", + "codex-package-x86_64-unknown-linux-musl.tar.gz", +}) REQUIRED_BASE_ARGS = frozenset({ "DOCKER_CLI_BASE_IMAGE", "NODE_BASE_IMAGE", @@ -248,6 +253,32 @@ def check_python_lock(root: Path) -> list[str]: return problems +def check_codex_checksums(root: Path) -> list[str]: + """Require one valid digest for every supported standalone archive.""" + try: + lines = (root / CODEX_CHECKSUMS).read_text(encoding="utf-8").splitlines() + except OSError as exc: + return [f"{CODEX_CHECKSUMS}: cannot read checksum manifest: {exc}"] + assets: dict[str, str] = {} + problems: list[str] = [] + for line in lines: + match = re.fullmatch(r"([0-9a-f]{64}) (\S+)", line) + if match is None: + problems.append(f"{CODEX_CHECKSUMS}: malformed checksum line: {line!r}") + continue + digest, asset = match.groups() + if asset in assets: + problems.append(f"{CODEX_CHECKSUMS}: duplicate checksum for {asset}") + assets[asset] = digest + missing = REQUIRED_CODEX_ASSETS - assets.keys() + if missing: + problems.append( + f"{CODEX_CHECKSUMS}: missing supported archives: " + f"{', '.join(sorted(missing))}", + ) + return problems + + def check_repo(root: Path = REPO_ROOT) -> list[str]: """Return every repository image-input policy violation.""" image_build_args, problems = load_image_build_args(root) @@ -260,6 +291,7 @@ def check_repo(root: Path = REPO_ROOT) -> list[str]: problems.extend(check_dockerfile(path, text, image_build_args)) for manifest in NPM_MANIFESTS: problems.extend(check_npm_manifest(root, manifest)) + problems.extend(check_codex_checksums(root)) nested_path = Path( "bot_bottle/backend/macos_container/nested_containers.py", ) @@ -276,9 +308,9 @@ def check_repo(root: Path = REPO_ROOT) -> list[str]: problems.append( "nested-containers image does not consume DOCKER_CLI_BASE_IMAGE", ) - if "pin_local_base(base_image)" not in nested_source: + if 'image = f"{pinned_base}{IMAGE_SUFFIX}"' not in nested_source: problems.append( - "nested-containers image does not pin its local agent base", + "nested-containers output is not keyed by its pinned agent base", ) problems.extend(check_python_lock(root)) return problems diff --git a/tests/unit/test_macos_nested_containers.py b/tests/unit/test_macos_nested_containers.py index 6cc5bff1..09355abf 100644 --- a/tests/unit/test_macos_nested_containers.py +++ b/tests/unit/test_macos_nested_containers.py @@ -115,10 +115,10 @@ class TestNestedContainersImage(unittest.TestCase): self.assertTrue((Path(context) / "nested-containers-init.sh").is_file()) image = nested_containers.build_image( - "agent:base", build, lambda _ref: "agent:sha256-deadbeef", + "agent:sha256-deadbeef", build, ) - self.assertEqual("agent:base-nested-containers", image) - self.assertEqual("agent:base-nested-containers", calls[0][0]) + self.assertEqual("agent:sha256-deadbeef-nested-containers", image) + self.assertEqual("agent:sha256-deadbeef-nested-containers", calls[0][0]) def test_installs_the_whole_podman_5_networking_stack(self) -> None: """Each missing piece fails at a different, misleading layer: no pasta @@ -132,7 +132,7 @@ class TestNestedContainersImage(unittest.TestCase): seen.append(Path(dockerfile).read_text(encoding="utf-8")) nested_containers.build_image( - "agent:base", build, lambda _ref: "agent:sha256-deadbeef", + "agent:sha256-deadbeef", build, ) for package in ("podman", "passt", "nftables", "aardvark-dns"): self.assertIn(package, seen[0]) @@ -150,7 +150,7 @@ class TestNestedContainersImage(unittest.TestCase): seen.append(Path(dockerfile).read_text(encoding="utf-8")) nested_containers.build_image( - "agent:base", build, lambda _ref: "agent:sha256-deadbeef", + "agent:sha256-deadbeef", build, ) text = seen[0] self.assertIn("sed -i '/^node:/d' /etc/subuid /etc/subgid", text) @@ -283,10 +283,15 @@ class TestBuildOrLoadImages(unittest.TestCase): ) with patch.object(launch_mod, "read_committed_image", return_value=None), \ patch.object(launch_mod.container_mod, "build_image") as build, \ + patch.object( + launch_mod.container_mod, + "pinned_local_image_ref", + return_value="agent:sha256-deadbeef", + ) as pin, \ patch.object( launch_mod.nested_containers_mod, "build_image", - return_value="agent:base-nested-containers", + return_value="agent:sha256-deadbeef-nested-containers", ) as derived: images = launch_mod.build_or_load_images(plan) @@ -294,10 +299,9 @@ class TestBuildOrLoadImages(unittest.TestCase): "agent:base", str(launch_mod.resources.build_root()), dockerfile="/repo/Dockerfile", ) - derived.assert_called_once_with( - "agent:base", build, launch_mod.container_mod.pinned_local_image_ref, - ) - self.assertEqual("agent:base-nested-containers", images.agent) + pin.assert_called_once_with("agent:base") + derived.assert_called_once_with("agent:sha256-deadbeef", build) + self.assertEqual("agent:sha256-deadbeef-nested-containers", images.agent) def test_derived_image_layers_onto_a_committed_image(self) -> None: plan = _plan( @@ -309,20 +313,22 @@ class TestBuildOrLoadImages(unittest.TestCase): ), \ patch.object(launch_mod.container_mod, "image_exists", return_value=True), \ patch.object(launch_mod.container_mod, "build_image") as build, \ + patch.object( + launch_mod.container_mod, + "pinned_local_image_ref", + return_value="agent:sha256-cafebabe", + ) as pin, \ patch.object( launch_mod.nested_containers_mod, "build_image", - return_value="agent:committed-nested-containers", + return_value="agent:sha256-cafebabe-nested-containers", ) as derived: images = launch_mod.build_or_load_images(plan) build.assert_not_called() - derived.assert_called_once_with( - "agent:committed", - build, - launch_mod.container_mod.pinned_local_image_ref, - ) - self.assertEqual("agent:committed-nested-containers", images.agent) + pin.assert_called_once_with("agent:committed") + derived.assert_called_once_with("agent:sha256-cafebabe", build) + self.assertEqual("agent:sha256-cafebabe-nested-containers", images.agent) def test_cached_policy_refuses_to_build_the_derived_image(self) -> None: plan = _plan( @@ -331,6 +337,11 @@ class TestBuildOrLoadImages(unittest.TestCase): spec=_Spec(image_policy="cached"), ) with patch.object(launch_mod, "read_committed_image", return_value=None), \ + patch.object( + launch_mod.container_mod, + "pinned_local_image_ref", + return_value="agent:sha256-deadbeef", + ), \ patch.object( launch_mod.container_mod, "image_exists", side_effect=_base_image_only, @@ -340,7 +351,10 @@ class TestBuildOrLoadImages(unittest.TestCase): with self.assertRaises(RuntimeError): launch_mod.build_or_load_images(plan) derived.assert_not_called() - self.assertIn("agent:base-nested-containers", die.call_args.args[0]) + self.assertIn( + "agent:sha256-deadbeef-nested-containers", + die.call_args.args[0], + ) if __name__ == "__main__":