From 9508d51b3952137c953dbdc735b76f82728b3593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Br=C3=A4mer?= <22003767+robinbraemer@users.noreply.github.com> Date: Mon, 10 Aug 2026 11:11:31 +0200 Subject: [PATCH 1/2] ci: migrate Linux x64 jobs to AgentOS ARC --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release-please.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/update-openapi.yml | 2 +- scripts/release.ts | 2 +- test/release.test.ts | 4 ++-- test/workflows.test.ts | 13 +++++++++++++ 7 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f124205..7fc2330 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ permissions: jobs: check: - runs-on: ubuntu-latest + runs-on: akua-x64-ci-v2 steps: - uses: actions/checkout@v7 - uses: jdx/mise-action@v2 @@ -19,7 +19,7 @@ jobs: - run: mise run check package-release: - runs-on: ubuntu-24.04 + runs-on: akua-heavy-ci-v2 outputs: matrix: ${{ steps.release-matrix.outputs.matrix }} steps: diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index c9a80c9..f40af6c 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -16,7 +16,7 @@ concurrency: jobs: release-please: - runs-on: ubuntu-latest + runs-on: akua-x64-ci-v2 outputs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a2df9a..73ef82a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ concurrency: jobs: package: - runs-on: ubuntu-24.04 + runs-on: akua-heavy-ci-v2 outputs: matrix: ${{ steps.release-matrix.outputs.matrix }} commit: ${{ steps.release-ref.outputs.commit }} @@ -103,7 +103,7 @@ jobs: publish: needs: [package, install-smoke] - runs-on: ubuntu-24.04 + runs-on: akua-x64-ci-v2 env: EXPECTED_COMMIT: ${{ needs.package.outputs.commit }} permissions: @@ -153,7 +153,7 @@ jobs: tap-update: needs: publish - runs-on: ubuntu-24.04 + runs-on: akua-x64-ci-v2 permissions: contents: read steps: diff --git a/.github/workflows/update-openapi.yml b/.github/workflows/update-openapi.yml index 286be86..b0537f5 100644 --- a/.github/workflows/update-openapi.yml +++ b/.github/workflows/update-openapi.yml @@ -11,7 +11,7 @@ permissions: jobs: update: - runs-on: ubuntu-latest + runs-on: akua-x64-ci-v2 steps: - uses: actions/checkout@v7 - uses: jdx/mise-action@v2 diff --git a/scripts/release.ts b/scripts/release.ts index c11edec..35b9b5e 100644 --- a/scripts/release.ts +++ b/scripts/release.ts @@ -57,7 +57,7 @@ export const RELEASE_TARGETS: readonly ReleaseTarget[] = [ arch: "x64", archive: "tar.gz", executable: "akua", - runner: "ubuntu-24.04", + runner: "akua-x64-ci-v2", homebrew: { os: "linux", arch: "intel" }, }, { diff --git a/test/release.test.ts b/test/release.test.ts index e9b2d82..59a92bb 100644 --- a/test/release.test.ts +++ b/test/release.test.ts @@ -67,7 +67,7 @@ describe("release target contract", () => { arch: "x64", archive: "tar.gz", executable: "akua", - runner: "ubuntu-24.04", + runner: "akua-x64-ci-v2", homebrew: { os: "linux", arch: "intel" }, }, { @@ -91,7 +91,7 @@ describe("release target contract", () => { { target: "darwin-arm64", runner: "macos-15" }, { target: "darwin-x64", runner: "macos-15-intel" }, { target: "linux-arm64", runner: "ubuntu-24.04-arm" }, - { target: "linux-x64", runner: "ubuntu-24.04" }, + { target: "linux-x64", runner: "akua-x64-ci-v2" }, { target: "windows-x64", runner: "windows-2025" }, ], }); diff --git a/test/workflows.test.ts b/test/workflows.test.ts index bbd9c67..98056a7 100644 --- a/test/workflows.test.ts +++ b/test/workflows.test.ts @@ -2,6 +2,19 @@ import { describe, expect, test } from "bun:test"; import { readFile } from "node:fs/promises"; describe("distribution workflows", () => { + test("Linux x64 jobs use the audited AgentOS ARC pools", async () => { + const workflows = await Promise.all([ + readFile(".github/workflows/ci.yml", "utf8"), + readFile(".github/workflows/release-please.yml", "utf8"), + readFile(".github/workflows/release.yml", "utf8"), + readFile(".github/workflows/update-openapi.yml", "utf8"), + ]); + + for (const workflow of workflows) { + expect(workflow).not.toMatch(/^\s+runs-on: (?:ubuntu-latest|ubuntu-24\.04|ubuntu-22\.04)$/m); + } + }); + test("the release workflow consumes the complete release target matrix", async () => { const workflow = await readFile(".github/workflows/release.yml", "utf8"); From 0af4a29b2adc5b0b441986b8a98fe5df3210035a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Br=C3=A4mer?= <22003767+robinbraemer@users.noreply.github.com> Date: Mon, 10 Aug 2026 14:29:43 +0200 Subject: [PATCH 2/2] fix: build release binaries on Kata shared storage --- scripts/release.ts | 20 +++++++++++++++++++- test/release.test.ts | 17 +++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/scripts/release.ts b/scripts/release.ts index eb588af..a659898 100644 --- a/scripts/release.ts +++ b/scripts/release.ts @@ -321,7 +321,13 @@ export async function packageExistingExecutables(input: PackageExistingExecutabl export async function packageRelease(input: PackageReleaseInput): Promise { validateVersion(input.version); - const binaryRoot = await mkdtemp(join(tmpdir(), "akua-release-build-")); + // Bun's compiled output is memory-mapped. Under Kata, output created on the + // guest-local /tmp filesystem was observed as correctly sized but entirely + // sparse/zero-filled. Keep compilation on the Actions workspace's virtiofs + // volume, then validate the native executable header before packaging it. + const binaryBuildParent = join(process.cwd(), "dist"); + await mkdir(binaryBuildParent, { recursive: true }); + const binaryRoot = await mkdtemp(join(binaryBuildParent, ".tmp-akua-release-build-")); const binaries: Record = {}; try { for (const target of RELEASE_TARGETS) { @@ -337,6 +343,7 @@ export async function packageRelease(input: PackageReleaseInput): Promise "--no-compile-autoload-bunfig", `--outfile=${binaryPath}`, ]); + assertCompiledExecutable(target, await readFile(binaryPath)); binaries[target.id] = binaryPath; } await packageExistingExecutables({ version: input.version, outputDir: input.outputDir, binaries }); @@ -345,6 +352,17 @@ export async function packageRelease(input: PackageReleaseInput): Promise } } +export function assertCompiledExecutable(target: Pick, bytes: Uint8Array): void { + const expectedMagic = target.os === "darwin" + ? [0xcf, 0xfa, 0xed, 0xfe] + : target.os === "linux" + ? [0x7f, 0x45, 0x4c, 0x46] + : [0x4d, 0x5a]; + if (bytes.length < expectedMagic.length || expectedMagic.some((byte, index) => bytes[index] !== byte)) { + throw new Error(`Compiled executable has an invalid ${target.os} header for ${target.id}`); + } +} + export function hostTargetId(platform = process.platform, arch = process.arch): ReleaseTargetId { const normalizedPlatform = platform === "win32" ? "windows" : platform; const id = `${normalizedPlatform}-${arch}`; diff --git a/test/release.test.ts b/test/release.test.ts index f9a7259..61981d3 100644 --- a/test/release.test.ts +++ b/test/release.test.ts @@ -124,6 +124,23 @@ describe("release target contract", () => { ); }); + test("rejects zero-filled compiled outputs before release packaging", async () => { + const release = await import("../scripts/release") as Record; + const assertCompiledExecutable = release.assertCompiledExecutable as ( + target: { id: string; os: "darwin" | "linux" | "windows" }, + bytes: Uint8Array, + ) => void; + + expect(() => assertCompiledExecutable( + { id: "linux-x64", os: "linux" }, + new Uint8Array(64), + )).toThrow("invalid linux header"); + expect(() => assertCompiledExecutable( + { id: "linux-x64", os: "linux" }, + new Uint8Array([0x7f, 0x45, 0x4c, 0x46]), + )).not.toThrow(); + }); + test("plans uploads for only release assets missing from an identical existing subset", async () => { const release = await import("../scripts/release") as Record; expect(typeof release.planReleaseUploads).toBe("function");