From d32b1a13fdef00d1260b423c6f3e3548d2e43c19 Mon Sep 17 00:00:00 2001 From: XxJSONDeruloxX Date: Fri, 23 Oct 2026 14:34:44 -0400 Subject: [PATCH] ci: verify x86 container build recipe --- tools/components/preloads.lock.json | 3 ++- tools/components/preloads.py | 20 +++++++++++++++++++- tools/tests/test_preload_snapshots.py | 12 +++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/tools/components/preloads.lock.json b/tools/components/preloads.lock.json index a92cd6dea..45beb4152 100644 --- a/tools/components/preloads.lock.json +++ b/tools/components/preloads.lock.json @@ -121,5 +121,6 @@ "arm64": "Ubuntu 24.04 GCC cross compiler; exact build commands pinned by arm64_recipe", "x86": "Debian bullseye compiler image and recipe pinned by source inputs" }, - "version": 1 + "version": 1, + "x86_recipe": "36d06d49f7a4bff5ef675c1e03ce5a5b61498df4c36b9d15a938b41564f755cc" } diff --git a/tools/components/preloads.py b/tools/components/preloads.py index 671474040..5f16610c3 100644 --- a/tools/components/preloads.py +++ b/tools/components/preloads.py @@ -91,6 +91,20 @@ def recipe(root=ROOT, commit=None): return sha(text.replace('\r\n', '\n').encode()) +def x86_recipe(root=ROOT, commit=None): + path = 'tools/components/recipes/x86-preloads.sh' + if commit and not run('git', 'ls-tree', commit, path, root=root): + workflow = run('git', 'show', f'{commit}:.github/workflows/build.yml', root=root).decode() + section = workflow[workflow.index(' - name: Build the x86 preloads'):] + text = section.split(' run: |\n', 1)[1].split('\n - name:', 1)[0] + text = textwrap.dedent(text).rstrip() + '\n' + else: + text = (run('git', 'show', f'{commit}:{path}', root=root).decode() if commit + else (root / path).read_text()) + text = text.removeprefix('#!/usr/bin/env bash\n') + return sha(text.replace('\r\n', '\n').encode()) + + def artifact_bytes(origin, cache): build = api(f"actions/runs/{origin['run']}") if (build['event'] != 'push' or build['head_branch'] != 'main' or build['conclusion'] != 'success' @@ -160,6 +174,8 @@ def prove_origin(data, cache, root=ROOT): raise ValueError('Snapshot omits or changes a producing build dependency') if recipe(root, commit) != data['arm64_recipe']: raise ValueError('Snapshot recipe differs from the producing source') + if x86_recipe(root, commit) != data['x86_recipe']: + raise ValueError('Snapshot x86 recipe differs from the producing source') def unpack(content, data): @@ -188,6 +204,7 @@ def restore(root=ROOT): validate_lock(data) matching = {group: source_files(group, root) == data['groups'][group] for group in INPUTS} matching['arm64'] &= recipe(root) == data['arm64_recipe'] + matching['x86'] &= x86_recipe(root) == data.get('x86_recipe') if os.environ.get('FORCE_PRELOAD_REBUILD') == 'true': matching = dict.fromkeys(INPUTS, False) if any(matching.values()): @@ -243,7 +260,8 @@ def snapshot(run_id, destination, root=ROOT): content = artifact_bytes(origin, root / 'app/build/component-downloads') run('git', 'fetch', '--no-tags', 'origin', origin['commit'], root=root) data = dict(version=1, origin=origin, groups={g: source_files(g, root, origin['commit']) for g in INPUTS}, - arm64_recipe=recipe(root, origin['commit']), outputs={name: sha(value) for name, value in content.items()}, + arm64_recipe=recipe(root, origin['commit']), x86_recipe=x86_recipe(root, origin['commit']), + outputs={name: sha(value) for name, value in content.items()}, toolchain=dict(arm64='Ubuntu 24.04 GCC cross compiler; exact build commands pinned by arm64_recipe', x86='Debian bullseye compiler image and recipe pinned by source inputs')) stream = io.BytesIO() diff --git a/tools/tests/test_preload_snapshots.py b/tools/tests/test_preload_snapshots.py index ee03da0f8..464b24e7b 100644 --- a/tools/tests/test_preload_snapshots.py +++ b/tools/tests/test_preload_snapshots.py @@ -41,6 +41,9 @@ class PreloadSnapshotTest(unittest.TestCase): recipe = 'tools/components/build-arm64-preloads.sh' (self.root / recipe).parent.mkdir(parents=True, exist_ok=True) (self.root / recipe).write_text((snapshots.ROOT / recipe).read_text()) + x86 = 'tools/components/recipes/x86-preloads.sh' + (self.root / x86).parent.mkdir(parents=True, exist_ok=True) + (self.root / x86).write_text((snapshots.ROOT / x86).read_text()) (self.root / '.github/workflows').mkdir(parents=True) (self.root / '.github/workflows/build.yml').write_text((snapshots.ROOT / '.github/workflows/build.yml').read_text()) self.git('init', '-q') @@ -52,7 +55,8 @@ class PreloadSnapshotTest(unittest.TestCase): self.content = archive(self.binaries) self.data = dict(version=1, origin=dict(run=123, commit='abc', artifact=456, artifact_sha256='0' * 64), groups={g: snapshots.source_files(g, self.root) for g in snapshots.INPUTS}, - arm64_recipe=snapshots.recipe(self.root), archive_sha256=snapshots.sha(self.content), + arm64_recipe=snapshots.recipe(self.root), x86_recipe=snapshots.x86_recipe(self.root), + archive_sha256=snapshots.sha(self.content), outputs={name: snapshots.sha(value) for name, value in self.binaries.items()}) (self.root / snapshots.LOCK).write_text(json.dumps(self.data)) self.git('add', '.') @@ -107,6 +111,12 @@ class PreloadSnapshotTest(unittest.TestCase): script.write_text(text.replace('-ldl\n', '-ldl ', 1)) self.assertNotEqual(original, snapshots.recipe(self.root)) + def test_x86_container_recipe_changes_rebuild_x86_only(self): + script = self.root / 'tools/components/recipes/x86-preloads.sh' + script.write_text(script.read_text().replace('debian:bullseye', 'debian:bookworm')) + result, _, _ = self.restore() + self.assertEqual(result, dict(arm64=True, x86=False)) + def test_new_manifest_requires_main_build_proof(self): result, _, prove = self.restore('HEAD~1') self.assertTrue(all(result.values()))