diff --git a/config/golden-image-container-integration.yaml b/config/golden-image-container-integration.yaml index bc03c9c..ed3f7d4 100644 --- a/config/golden-image-container-integration.yaml +++ b/config/golden-image-container-integration.yaml @@ -2,7 +2,7 @@ schema_version: 1 image: type: container - alias: nddev-u24-amd64-ctr-docker-runner-2.336.0-r20260801-b13 + alias: nddev-u24-amd64-ctr-docker-runner-2.336.0-r20260801-b14 current_alias: nddev-ubuntu-24.04-amd64-container-docker-current previous_alias: nddev-ubuntu-24.04-amd64-container-docker-previous source_alias: nddev-source-ubuntu-24.04-amd64-container-r20260801 @@ -53,6 +53,11 @@ toolchains: archive: bun-linux-x64.zip download_url: https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip archive_sha256: 951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f + - name: codeql + version: 2.26.4 + archive: codeql-bundle-linux64.tar.gz + download_url: https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.26.4/codeql-bundle-linux64.tar.gz + archive_sha256: 48e1ab8b874d57bd6fd7c90fefee75addc5a45e9bd063982df9beb45a62dd5d3 - name: go version: 1.26.6 archive: go1.26.6.linux-amd64.tar.gz diff --git a/config/golden-image-container.yaml b/config/golden-image-container.yaml index 7018e09..d565f2f 100644 --- a/config/golden-image-container.yaml +++ b/config/golden-image-container.yaml @@ -2,7 +2,7 @@ schema_version: 1 image: type: container - alias: nddev-ubuntu-24.04-amd64-container-runner-2.336.0-r20260801-b20 + alias: nddev-ubuntu-24.04-amd64-container-runner-2.336.0-r20260801-b21 current_alias: nddev-ubuntu-24.04-amd64-container-current previous_alias: nddev-ubuntu-24.04-amd64-container-previous source_alias: nddev-source-ubuntu-24.04-amd64-container-r20260801 @@ -53,6 +53,11 @@ toolchains: archive: bun-linux-x64.zip download_url: https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip archive_sha256: 951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f + - name: codeql + version: 2.26.4 + archive: codeql-bundle-linux64.tar.gz + download_url: https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.26.4/codeql-bundle-linux64.tar.gz + archive_sha256: 48e1ab8b874d57bd6fd7c90fefee75addc5a45e9bd063982df9beb45a62dd5d3 - name: go version: 1.26.6 archive: go1.26.6.linux-amd64.tar.gz diff --git a/config/golden-image-integration.yaml b/config/golden-image-integration.yaml index 0c12a31..40b7ae0 100644 --- a/config/golden-image-integration.yaml +++ b/config/golden-image-integration.yaml @@ -1,7 +1,7 @@ schema_version: 1 image: - alias: nddev-ubuntu-24.04-amd64-docker-runner-2.336.0-r20260801-b16 + alias: nddev-ubuntu-24.04-amd64-docker-runner-2.336.0-r20260801-b17 current_alias: nddev-ubuntu-24.04-amd64-docker-current previous_alias: nddev-ubuntu-24.04-amd64-docker-previous source_alias: nddev-source-ubuntu-24.04-amd64-r20260801 @@ -52,6 +52,11 @@ toolchains: archive: bun-linux-x64.zip download_url: https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip archive_sha256: 951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f + - name: codeql + version: 2.26.4 + archive: codeql-bundle-linux64.tar.gz + download_url: https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.26.4/codeql-bundle-linux64.tar.gz + archive_sha256: 48e1ab8b874d57bd6fd7c90fefee75addc5a45e9bd063982df9beb45a62dd5d3 - name: go version: 1.26.6 archive: go1.26.6.linux-amd64.tar.gz diff --git a/config/golden-image.yaml b/config/golden-image.yaml index 160e6c0..4f53a3a 100644 --- a/config/golden-image.yaml +++ b/config/golden-image.yaml @@ -1,7 +1,7 @@ schema_version: 1 image: - alias: nddev-ubuntu-24.04-amd64-runner-2.336.0-r20260801-b17 + alias: nddev-ubuntu-24.04-amd64-runner-2.336.0-r20260801-b18 current_alias: nddev-ubuntu-24.04-amd64-current previous_alias: nddev-ubuntu-24.04-amd64-previous source_alias: nddev-source-ubuntu-24.04-amd64-r20260801 @@ -52,6 +52,11 @@ toolchains: archive: bun-linux-x64.zip download_url: https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip archive_sha256: 951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f + - name: codeql + version: 2.26.4 + archive: codeql-bundle-linux64.tar.gz + download_url: https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.26.4/codeql-bundle-linux64.tar.gz + archive_sha256: 48e1ab8b874d57bd6fd7c90fefee75addc5a45e9bd063982df9beb45a62dd5d3 - name: go version: 1.26.6 archive: go1.26.6.linux-amd64.tar.gz diff --git a/internal/imagebuild/assets/docker-provision.sh b/internal/imagebuild/assets/docker-provision.sh index 40ef912..32dbc28 100644 --- a/internal/imagebuild/assets/docker-provision.sh +++ b/internal/imagebuild/assets/docker-provision.sh @@ -40,6 +40,7 @@ jq -n --arg storage_driver "${GHA_DOCKER_STORAGE_DRIVER}" '({ "default-address-pools":[{"base":"172.30.0.0/16","size":24}], "exec-opts":["native.cgroupdriver=systemd"], "features":{"buildkit":true}, + "registry-mirrors":["https://192.0.2.1:5001"], "live-restore":false, "log-driver":"local", "log-opts":{"max-file":"3","max-size":"10m"}, diff --git a/internal/imagebuild/assets/provision.sh b/internal/imagebuild/assets/provision.sh index c5e5078..e63ff8b 100644 --- a/internal/imagebuild/assets/provision.sh +++ b/internal/imagebuild/assets/provision.sh @@ -237,9 +237,9 @@ toolchain_manifest="$(printf '%s' "${GHA_TOOLCHAINS_B64}" | base64 --decode)" jq -e 'type == "array"' <<<"${toolchain_manifest}" >/dev/null mapfile -t toolchain_names < <(jq -r '.[].name' <<<"${toolchain_manifest}") toolchain_set="$(printf '%s\n' "${toolchain_names[@]}" | LC_ALL=C sort | paste -sd, -)" -if [[ "${toolchain_set}" != bun,gh,go,rustup,uv \ - && "${toolchain_set}" != bun,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn \ - && "${toolchain_set}" != bun,flutter,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]]; then +if [[ "${toolchain_set}" != bun,codeql,gh,go,rustup,uv \ + && "${toolchain_set}" != bun,codeql,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn \ + && "${toolchain_set}" != bun,codeql,flutter,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]]; then echo "toolchain manifest does not pin the exact baked set" >&2 exit 1 fi @@ -254,6 +254,20 @@ for toolchain_name in "${toolchain_names[@]}"; do echo "${toolchain_sha256} ${toolchain_archive}" | sha256sum --check --strict toolchain_scratch="$(mktemp -d /var/tmp/gha-toolchain.XXXXXXXXXX)" case "${toolchain_name}" in + codeql) + # The action resolves ${runner_tool_cache}/CodeQL/0.0.0-codeql-bundle-v + # with an x64.complete marker beside x64/, and prefers it over the 800 MB + # network download an ephemeral runner would otherwise repeat every + # analyze job. + codeql_root="${runner_tool_cache}/CodeQL/0.0.0-codeql-bundle-v${toolchain_version}" + install -d -o runner -g runner -m 0755 "${runner_tool_cache}/CodeQL" \ + "${codeql_root}" "${codeql_root}/x64" + tar --extract --gzip --file "${toolchain_archive}" \ + --directory "${codeql_root}/x64" --no-same-owner --no-same-permissions + chown -R runner:runner "${codeql_root}" + install -o runner -g runner -m 0644 /dev/null "${codeql_root}/x64.complete" + [[ "$(runuser -u runner -- "${codeql_root}/x64/codeql/codeql" version --format=terse)" == "${toolchain_version}" ]] + ;; bun) unzip -q "${toolchain_archive}" -d "${toolchain_scratch}" install -o root -g root -m 0755 \ diff --git a/internal/imagebuild/assets/smoke-integration.sh b/internal/imagebuild/assets/smoke-integration.sh index d139f64..b8f4e26 100644 --- a/internal/imagebuild/assets/smoke-integration.sh +++ b/internal/imagebuild/assets/smoke-integration.sh @@ -88,7 +88,7 @@ runner_tool_cache="$(jq -er .runner_tool_cache /etc/nddev/image-build.json)" [[ "${runner_tool_cache}" == /home/runner/actions-runner/_work/_tool ]] smoke_toolchains="$(printf '%s' "${GHA_TOOLCHAINS_B64}" | base64 --decode)" mapfile -t smoke_toolchain_names < <(jq -r '.[].name' <<<"${smoke_toolchains}") -[[ "$(printf '%s\n' "${smoke_toolchain_names[@]}" | LC_ALL=C sort | paste -sd, -)" == bun,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]] +[[ "$(printf '%s\n' "${smoke_toolchain_names[@]}" | LC_ALL=C sort | paste -sd, -)" == bun,codeql,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]] for smoke_toolchain in "${smoke_toolchain_names[@]}"; do entry="$(jq -ce --arg name "${smoke_toolchain}" '.[] | select(.name == $name)' <<<"${smoke_toolchains}")" expected_version="$(jq -er .version <<<"${entry}")" @@ -96,6 +96,12 @@ for smoke_toolchain in "${smoke_toolchain_names[@]}"; do [[ "$(jq -er --arg name "${smoke_toolchain}" '.toolchains[$name].version' /etc/nddev/image-build.json)" == "${expected_version}" ]] [[ "$(jq -er --arg name "${smoke_toolchain}" '.toolchains[$name].archive_sha256' /etc/nddev/image-build.json)" == "${expected_sha256}" ]] case "${smoke_toolchain}" in + codeql) + codeql_root="${runner_tool_cache}/CodeQL/0.0.0-codeql-bundle-v${expected_version}" + test -f "${codeql_root}/x64.complete" + [[ "$(stat --format='%U' -- "${codeql_root}/x64/codeql/codeql")" == runner ]] + [[ "$(runuser -u runner -- "${codeql_root}/x64/codeql/codeql" version --format=terse)" == "${expected_version}" ]] + ;; bun) [[ "$(bun --version)" == "${expected_version}" ]] # The path oven-sh/setup-bun probes before deciding to download. diff --git a/internal/imagebuild/assets/smoke.sh b/internal/imagebuild/assets/smoke.sh index 26a573b..6b61ab5 100644 --- a/internal/imagebuild/assets/smoke.sh +++ b/internal/imagebuild/assets/smoke.sh @@ -64,9 +64,9 @@ runner_tool_cache="$(jq -er .runner_tool_cache /etc/nddev/image-build.json)" smoke_toolchains="$(printf '%s' "${GHA_TOOLCHAINS_B64}" | base64 --decode)" mapfile -t smoke_toolchain_names < <(jq -r '.[].name' <<<"${smoke_toolchains}") smoke_toolchain_set="$(printf '%s\n' "${smoke_toolchain_names[@]}" | LC_ALL=C sort | paste -sd, -)" -[[ "${smoke_toolchain_set}" == bun,gh,go,rustup,uv \ - || "${smoke_toolchain_set}" == bun,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn \ - || "${smoke_toolchain_set}" == bun,flutter,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]] +[[ "${smoke_toolchain_set}" == bun,codeql,gh,go,rustup,uv \ + || "${smoke_toolchain_set}" == bun,codeql,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn \ + || "${smoke_toolchain_set}" == bun,codeql,flutter,gh,go,node22,node24,node25,pnpm,rustup,uv,yarn ]] for smoke_toolchain in "${smoke_toolchain_names[@]}"; do entry="$(jq -ce --arg name "${smoke_toolchain}" '.[] | select(.name == $name)' <<<"${smoke_toolchains}")" expected_version="$(jq -er .version <<<"${entry}")" @@ -74,6 +74,12 @@ for smoke_toolchain in "${smoke_toolchain_names[@]}"; do [[ "$(jq -er --arg name "${smoke_toolchain}" '.toolchains[$name].version' /etc/nddev/image-build.json)" == "${expected_version}" ]] [[ "$(jq -er --arg name "${smoke_toolchain}" '.toolchains[$name].archive_sha256' /etc/nddev/image-build.json)" == "${expected_sha256}" ]] case "${smoke_toolchain}" in + codeql) + codeql_root="${runner_tool_cache}/CodeQL/0.0.0-codeql-bundle-v${expected_version}" + test -f "${codeql_root}/x64.complete" + [[ "$(stat --format='%U' -- "${codeql_root}/x64/codeql/codeql")" == runner ]] + [[ "$(runuser -u runner -- "${codeql_root}/x64/codeql/codeql" version --format=terse)" == "${expected_version}" ]] + ;; bun) [[ "$(bun --version)" == "${expected_version}" ]] # The path oven-sh/setup-bun probes before deciding to download. diff --git a/internal/imagebuild/orchestrator_test.go b/internal/imagebuild/orchestrator_test.go index 37b6d23..b121f60 100644 --- a/internal/imagebuild/orchestrator_test.go +++ b/internal/imagebuild/orchestrator_test.go @@ -164,7 +164,7 @@ func TestRecipeFingerprintIsDeterministic(t *testing.T) { // alias is part of the recipe, so a manifest whose contents changed under an // unchanged alias would otherwise ask the builder to produce different bytes // for a name that is already promoted. - if first != "sha256:4cc00e2ee72d7ed4646f84229f3b6a2d5c6d4aeeb05aae29f15f4e1bd381eeb1" { + if first != "sha256:ba41e9cfcebc856bfa3ee0b75f12d4e3f7a9b85598308491ea70f72b2fe2baff" { t.Fatalf("deployed standard recipe fingerprint drifted: %q", first) } smoke, err := SmokeFingerprint(plan) diff --git a/internal/imagemanifest/manifest_test.go b/internal/imagemanifest/manifest_test.go index fbfefee..1e6e273 100644 --- a/internal/imagemanifest/manifest_test.go +++ b/internal/imagemanifest/manifest_test.go @@ -42,7 +42,7 @@ func TestRepositoryManifestIsValidAndPinned(t *testing.T) { if !strings.HasPrefix(fingerprint, "sha256:") || len(fingerprint) != len("sha256:")+64 { t.Fatalf("unexpected fingerprint %q", fingerprint) } - if fingerprint != "sha256:4c76a6c764a529923aa4dcd0327863aa43a4700b3a5e5d99aa30426a7db96217" { + if fingerprint != "sha256:47a1569f94fa824b69de51d5ee917a5e8b72cc4a4c9b727c214019f891615a56" { t.Fatalf("standard manifest fingerprint drifted: %q", fingerprint) } } @@ -71,6 +71,7 @@ func assertBakedToolchains(t *testing.T, manifest Manifest) { t.Helper() wanted := map[string]struct{ version, archiveSHA256 string }{ "bun": {"1.3.14", "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f"}, + "codeql": {"2.26.4", "48e1ab8b874d57bd6fd7c90fefee75addc5a45e9bd063982df9beb45a62dd5d3"}, "gh": {"2.97.0", "a2c9b8497e1f85b1ad0dfcb78b5a622e098801b8e461e459e88e1ee12f018112"}, "go": {"1.26.6", "708effb774be8237570d0add163225abbdfaf4fca28b2611df167beba4feef89"}, "node22": {"22.23.2", "d60acfe00a2932254bb0ad20e01b0d74397a0875595de719654b214f4b03f307"}, diff --git a/internal/imagemanifest/types.go b/internal/imagemanifest/types.go index c1ae04a..4b800ae 100644 --- a/internal/imagemanifest/types.go +++ b/internal/imagemanifest/types.go @@ -122,7 +122,7 @@ func BakedToolchains() []string { // was unreachable in the shipped image. The default channel serves jobs // that call cargo directly, and actions-rust-lang/setup-rust-toolchain // resolves rust-toolchain.toml channels through rustup either way. - return []string{"bun", "gh", "go", "node22", "node24", "node25", "pnpm", "rustup", "uv", "yarn"} + return []string{"bun", "codeql", "gh", "go", "node22", "node24", "node25", "pnpm", "rustup", "uv", "yarn"} } // OptionalToolchains may be pinned by an image that needs them and omitted by diff --git a/internal/imagemanifest/validate.go b/internal/imagemanifest/validate.go index 6887dbd..5e27351 100644 --- a/internal/imagemanifest/validate.go +++ b/internal/imagemanifest/validate.go @@ -112,6 +112,16 @@ var toolchainAssets = map[string]struct { return "/rustup/archive/" + version + "/x86_64-unknown-linux-gnu/rustup-init" }, }, + // The CodeQL bundle the action would otherwise download on every analyze + // job of an ephemeral runner: 800 MB per run, resolved from the runner + // tool cache when present. + "codeql": { + Host: "github.com", + Archive: func(string) string { return "codeql-bundle-linux64.tar.gz" }, + Path: func(version string) string { + return "/github/codeql-action/releases/download/codeql-bundle-v" + version + "/codeql-bundle-linux64.tar.gz" + }, + }, "uv": { Host: "github.com", Archive: func(string) string { return "uv-x86_64-unknown-linux-gnu.tar.gz" }, diff --git a/internal/imageplan/plan_test.go b/internal/imageplan/plan_test.go index 7bfa000..fa75f8f 100644 --- a/internal/imageplan/plan_test.go +++ b/internal/imageplan/plan_test.go @@ -82,7 +82,7 @@ func TestBuildProducesDeterministicBoundedPlan(t *testing.T) { } // The baked set plus the optional Flutter SDK this manifest pins, still // sorted: the plan's ordering is what makes the recipe fingerprint stable. - if !slices.Equal(names, []string{"bun", "flutter", "gh", "go", "node22", "node24", "node25", "pnpm", "rustup", "uv", "yarn"}) { + if !slices.Equal(names, []string{"bun", "codeql", "flutter", "gh", "go", "node22", "node24", "node25", "pnpm", "rustup", "uv", "yarn"}) { t.Fatalf("plan toolchains are not the canonical sorted set: %v", names) } if first.CompilerCache.Name != "sccache" || first.CompilerCache.Version != "v0.17.0" || diff --git a/internal/repositorycontract/external_downloads_test.go b/internal/repositorycontract/external_downloads_test.go index 852e3b4..3c81ada 100644 --- a/internal/repositorycontract/external_downloads_test.go +++ b/internal/repositorycontract/external_downloads_test.go @@ -20,6 +20,7 @@ func TestEveryNetworkBootstrapSurfaceIsClassified(t *testing.T) { "internal/garmproviderincus/provider/incus.go", "internal/garmproviderincus/provider/specs.go", "internal/imagebuild/assets/container-provision.sh", + "internal/imagebuild/assets/docker-provision.sh", "internal/imagebuild/assets/provision.sh", "internal/imagebuild/assets/smoke-integration.sh", "internal/imagebuild/assets/smoke.sh",