Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .devcontainer/sandbox-bun/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-bun",
"build": {
"dockerfile": "../../bun/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=oven-sh/bun versioning=semver extractVersion=^bun-v(?<version>.+)
"BUN_VERSION": "1.3.14"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"BUN_VERSION": "${localEnv:BUN_VERSION}"
}
},
"runArgs": [
Expand Down
7 changes: 5 additions & 2 deletions .devcontainer/sandbox-debian/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-debian",
"build": {
"dockerfile": "../../debian/Dockerfile",
"args": {
// renovate: datasource=docker depName=debian versioning=debian
"DEBIAN_TAG": "trixie-20260713@sha256:fac46bff2e02f51425b6e33b0e1169f55dfb053d83511ca28aa50c09fd5ed7a4"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}"
}
},
"runArgs": [
Expand Down
10 changes: 6 additions & 4 deletions .devcontainer/sandbox-deno/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-deno",
"build": {
"dockerfile": "../../deno/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=denoland/deno versioning=semver extractVersion=^v(?<version>.+)
"DENO_VERSION": "2.9.4"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"DENO_VERSION": "${localEnv:DENO_VERSION}"
}
},
"runArgs": [
Expand Down
13 changes: 7 additions & 6 deletions .devcontainer/sandbox-golang/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-golang",
"build": {
"dockerfile": "../../golang/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=golang-version depName=golang
"GOLANG_VERSION": "1.26.5",
// renovate: datasource=go depName=golang.org/x/tools/gopls
"GOPLS_VERSION": "v0.23.0"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"GOLANG_VERSION": "${localEnv:GOLANG_VERSION}",
"GOPLS_VERSION": "${localEnv:GOPLS_VERSION}"
}
},
"runArgs": [
Expand Down
10 changes: 6 additions & 4 deletions .devcontainer/sandbox-mise/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-mise",
"build": {
"dockerfile": "../../mise/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=jdx/mise versioning=semver
"MISE_VERSION": "2026.7.13"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"MISE_VERSION": "${localEnv:MISE_VERSION}"
}
},
"runArgs": [
Expand Down
13 changes: 7 additions & 6 deletions .devcontainer/sandbox-node/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-node",
"build": {
"dockerfile": "../../node/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=node-version depName=node versioning=node
"NODE_VERSION": "26.5.0",
// renovate: datasource=npm depName=corepack versioning=semver
"COREPACK_VERSION": "0.35.0"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"NODE_VERSION": "${localEnv:NODE_VERSION}",
"COREPACK_VERSION": "${localEnv:COREPACK_VERSION}"
}
},
"runArgs": [
Expand Down
10 changes: 6 additions & 4 deletions .devcontainer/sandbox-rustup/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-rustup",
"build": {
"dockerfile": "../../rustup/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=rust-lang/rustup versioning=semver
"RUSTUP_VERSION": "1.29.0"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"RUSTUP_VERSION": "${localEnv:RUSTUP_VERSION}"
}
},
"runArgs": [
Expand Down
13 changes: 7 additions & 6 deletions .devcontainer/sandbox-terraform/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-terraform",
"build": {
"dockerfile": "../../terraform/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=hashicorp/terraform versioning=semver extractVersion=^v(?<version>.+)
"TERRAFORM_VERSION": "1.15.8",
// renovate: datasource=github-releases depName=hashicorp/terraform-ls versioning=semver extractVersion=^v(?<version>.+)
"TERRAFORM_LS_VERSION": "0.39.0"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"TERRAFORM_VERSION": "${localEnv:TERRAFORM_VERSION}",
"TERRAFORM_LS_VERSION": "${localEnv:TERRAFORM_LS_VERSION}"
}
},
"runArgs": [
Expand Down
10 changes: 6 additions & 4 deletions .devcontainer/sandbox-uv/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-uv",
"build": {
"dockerfile": "../../uv/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=github-releases depName=astral-sh/uv versioning=semver
"UV_VERSION": "0.11.32"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"UV_VERSION": "${localEnv:UV_VERSION}"
}
},
"runArgs": [
Expand Down
16 changes: 8 additions & 8 deletions .devcontainer/sandbox-zig/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
{
// Build args are read from the environment without defaults, so build-checks.yml
// supplies the values it just built the image with and the Dev Container CLI
// reuses those layers. A missing value fails the build instead of silently
// selecting a different version; AGENTS.md documents how to export them by hand.
"name": "sandbox-zig",
"build": {
"dockerfile": "../../zig/Dockerfile",
"args": {
// renovate: datasource=docker registryUrl=https://ghcr.io depName=bare-devcontainer/debian versioning=debian
"DEBIAN_TAG": "trixie-20260725@sha256:709adc59c1bd061e416d33119aad002fd361b4058a845543d9ddc4fac762dd48",
// renovate: datasource=gitea-tags registryUrl=https://codeberg.org depName=ziglang/zig versioning=semver
"ZIG_VERSION": "0.16.0",
// renovate: datasource=github-tags depName=zigtools/zls versioning=semver
"ZLS_VERSION": "0.16.0",
// renovate: datasource=gitea-commits registryUrl=https://codeberg.org depName=ziglang/shell-completions
"SHELL_COMPLETIONS_COMMIT": "c2983a75dcbcaf3a1df74ab563a9bd3c8e7f448e"
"DEBIAN_TAG": "${localEnv:DEBIAN_TAG}",
"ZIG_VERSION": "${localEnv:ZIG_VERSION}",
"ZLS_VERSION": "${localEnv:ZLS_VERSION}",
"SHELL_COMPLETIONS_COMMIT": "${localEnv:SHELL_COMPLETIONS_COMMIT}"
}
},
"runArgs": [
Expand Down
74 changes: 74 additions & 0 deletions .github/workflows/build-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- '*/rustup-init-*.sha256'
- '*/uv-*.sha256'
- .devcontainer/feature-**
- .devcontainer/sandbox-**
- scripts/build-config.sh
- scripts/changed-images.sh
- .trivyignore.yaml
Expand All @@ -25,6 +26,7 @@ on:
- '*/rustup-init-*.sha256'
- '*/uv-*.sha256'
- .devcontainer/feature-**
- .devcontainer/sandbox-**
- scripts/build-config.sh
- scripts/changed-images.sh

Expand Down Expand Up @@ -81,6 +83,43 @@ jobs:
echo "$REPORT" | jq -r '.[] |
"[" + (if .selected then "RUN " else "SKIP" end) + "] " + .image + ": " + .reason,
(.files[] | " " + .)'
- name: Verify sandbox configurations
# The build jobs export the build args of the variant they build so the
# sandbox configuration picks them up through ${localEnv:...}. That only
# holds while every image has a sandbox and every sandbox declares
# exactly the args of its image; otherwise an argument silently resolves
# to the empty string. Neither is tied to a changed image, so both are
# checked for the whole repository here.
run: |
IMAGES=$(bash scripts/build-config.sh images | jq -r '.[]')
SANDBOXES=$(find .devcontainer -maxdepth 1 -type d -name 'sandbox-*' -printf '%f\n' \
| sed 's/^sandbox-//' | sort)
if [ "$(echo "$IMAGES" | sort)" != "$SANDBOXES" ]; then
echo "ERROR: sandbox dev containers do not match the image list" >&2
diff <(echo "$IMAGES" | sort) <(echo "$SANDBOXES") >&2 || true
exit 1
fi

STATUS=0
for IMAGE in $IMAGES; do
CONFIG=".devcontainer/sandbox-${IMAGE}/devcontainer.json"
DECLARED=$(grep -o '\${localEnv:[A-Z_]\+}' "$CONFIG" \
| sed 's/^\${localEnv:\(.*\)}$/\1/' | sort -u)
for VARIANT in $(bash scripts/build-config.sh variants "$IMAGE" | jq -r '.[]'); do
# DEBIAN_TAG is a build arg of the debian image and the base
# selector of every other one, so only the latter add it here.
EXPECTED=$({
bash scripts/build-config.sh build-args "$IMAGE" "$VARIANT" | cut -d= -f1
[ "$IMAGE" = "debian" ] || echo "DEBIAN_TAG"
} | sort -u)
if [ "$DECLARED" != "$EXPECTED" ]; then
echo "ERROR: ${CONFIG} does not declare the build args of ${IMAGE}/${VARIANT}" >&2
diff <(echo "$EXPECTED") <(echo "$DECLARED") >&2 || true
STATUS=1
fi
done
done
exit "$STATUS"
- name: Build matrix
id: build
# Expand each entry across both architectures so images are
Expand Down Expand Up @@ -154,6 +193,21 @@ jobs:
--mount "type=bind,source=${{ github.workspace }}/debian/smoke-test.sh,target=/smoke-test.sh,readonly" \
"debian:${{ matrix.variant }}" \
bash /smoke-test.sh
- name: Verify sandbox dev container
# Built with the same args as the build step above, so the Dev Container
# CLI reuses those layers rather than rebuilding the image. The image
# contents are already covered by the smoke test, so this asserts only
# what the configuration adds: the CLI resolves it and applies remoteUser.
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450
env:
DEBIAN_TAG: ${{ steps.read.outputs.debian_tag }}
with:
configFile: .devcontainer/sandbox-debian/devcontainer.json
push: never
runCmd: |
set -e
[ "$(id -un)" = "dev" ] \
|| { echo "ERROR: expected user dev, got $(id -un)" >&2; exit 1; }
- name: Run Trivy vulnerability scanner
# Vulnerability findings are identical across architectures; scan once.
if: matrix.arch == 'amd64'
Expand Down Expand Up @@ -208,6 +262,13 @@ jobs:
echo "DEBIAN_TAG=${DEBIAN_VARIANT}"
echo "${DELIM}"
} >> "$GITHUB_OUTPUT"
# The sandbox configuration reads the same values through
# ${localEnv:...}. Exported rather than set per step because the keys
# differ per image.
{
bash scripts/build-config.sh build-args "${{ matrix.image }}" "${{ matrix.variant }}"
echo "DEBIAN_TAG=${DEBIAN_VARIANT}"
} >> "$GITHUB_ENV"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build language image
Expand Down Expand Up @@ -239,6 +300,19 @@ jobs:
--mount "type=bind,source=${{ github.workspace }}/${{ matrix.image }}/smoke-test.sh,target=/smoke-test.sh,readonly" \
"${{ matrix.image }}:${{ matrix.variant }}" \
bash -c "bash /smoke-test-debian.sh && bash /smoke-test.sh"
- name: Verify sandbox dev container
# Built with the same args as the build step above, so the Dev Container
# CLI reuses those layers rather than rebuilding the image. The image
# contents are already covered by the smoke test, so this asserts only
# what the configuration adds: the CLI resolves it and applies remoteUser.
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450
with:
configFile: .devcontainer/sandbox-${{ matrix.image }}/devcontainer.json
push: never
runCmd: |
set -e
[ "$(id -un)" = "dev" ] \
|| { echo "ERROR: expected user dev, got $(id -un)" >&2; exit 1; }
- name: Run Trivy vulnerability scanner
# Vulnerability findings are identical across architectures; scan once.
if: matrix.arch == 'amd64'
Expand Down
69 changes: 0 additions & 69 deletions .github/workflows/devcontainer-check.yml

This file was deleted.

Loading