ci: validate dogfood image tooling by running gen, fmt, lint, build (#25475)

Adds a `test_image` job that runs `make gen`, `make fmt`, `make lint`, and `make build` inside the
newly built image via `docker run`. This helps detect breaking changes before merge. 

> [!NOTE]
> Generated with [Coder Agents](https://coder.com/agents)
This commit is contained in:
Cian Johnston
2026-05-25 17:02:13 +01:00
committed by GitHub
parent 52e73b1343
commit 0a45f96d30
3 changed files with 175 additions and 6 deletions
+64 -5
View File
@@ -11,15 +11,19 @@ on:
# PRs: `build_image` builds the image variants but never pushes
# (each `depot/build-push-action` step's `push:` and the
# `Push Nix image` step are gated on `github.ref ==
# 'refs/heads/main'`). `deploy_template` runs `terraform init` +
# `validate` only; the apply step and SHA/title gathering are
# gated on main.
# 'refs/heads/main'`). `test_image` rebuilds the Ubuntu images
# from Depot cache with `load: true` and runs `make gen`, `fmt`,
# `lint`, and a Linux build inside each image to validate that
# the baked-in tooling works. `deploy_template` runs
# `terraform init` + `validate` only; the apply step and
# SHA/title gathering are gated on main.
#
# Pushes to main: `build_image` retags rolling tags on
# `codercom/oss-dogfood` (`:latest`, `:22.04`, `:26.04`),
# `codercom/oss-dogfood-vscode-coder` (`:latest`), and
# `codercom/oss-dogfood-nix` (`:latest`), plus a per-branch tag on
# each. `deploy_template` runs `terraform apply` and creates new
# each. `test_image` validates tooling as above.
# `deploy_template` runs `terraform apply` and creates new
# `coderd_template` versions on dev.coder.com whose `name` is the
# commit short SHA. Content is unchanged when neither `dogfood/**`
# nor the flake files changed, so the new versions are cosmetic.
@@ -31,12 +35,16 @@ on:
- ".github/workflows/dogfood.yaml"
- "flake.lock"
- "flake.nix"
- "mise.toml"
- "mise.lock"
pull_request:
paths:
- "dogfood/**"
- ".github/workflows/dogfood.yaml"
- "flake.lock"
- "flake.nix"
- "mise.toml"
- "mise.lock"
workflow_dispatch:
permissions:
@@ -193,8 +201,59 @@ jobs:
env:
DOCKER_TAG: ${{ steps.docker-tag-name.outputs.tag }}
deploy_template:
# Validate that the Ubuntu dogfood images contain working tooling.
# Failures here block template deployment (deploy_template).
test_image:
needs: build_image
strategy:
fail-fast: false
matrix:
image-version: ["22.04", "26.04"]
runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }}
steps:
- name: Harden Runner
uses: step-security/harden-runner@f808768d1510423e83855289c910610ca9b43176 # v2.17.0
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
persist-credentials: false
- name: Set up Depot CLI
uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.7.1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
# Near-instant cache hit from build_image; loads into local daemon
# without pushing to a registry.
- name: Load dogfood image from Depot cache
uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.17.0
with:
project: b4q6ltmpzh
token: ${{ secrets.DEPOT_TOKEN }}
buildx-fallback: true
context: "{{defaultContext}}"
file: dogfood/coder/ubuntu-${{ matrix.image-version }}/Dockerfile
secrets: |
github_token=${{ secrets.GITHUB_TOKEN }}
pull: true
load: true
push: false
tags: "dogfood-test:${{ matrix.image-version }}"
- name: Test image tooling
run: ./scripts/dogfood_test_image.sh "dogfood-test:${{ matrix.image-version }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
deploy_template:
needs:
- build_image
- test_image
runs-on: ubuntu-latest
permissions:
# Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage)
+4 -1
View File
@@ -992,7 +992,10 @@ GEN_FILES := \
$(AIBRIDGED_MOCKS)
# all gen targets should be added here and to gen/mark-fresh
gen: gen/db gen/golden-files $(GEN_FILES)
# Set GEN_SKIP_GOLDEN=1 to skip gen/golden-files (which needs Docker to
# start PostgreSQL via testcontainers).
GEN_SKIP_GOLDEN ?=
gen: gen/db $(if $(GEN_SKIP_GOLDEN),,gen/golden-files) $(GEN_FILES)
.PHONY: gen
gen/db: $(DB_GEN_FILES)
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# Validates dogfood image tooling by running gen, fmt, lint, and build inside
# the image. Can be run locally or in CI (mirrors the test_image workflow job).
#
# Usage: ./scripts/dogfood_test_image.sh <image>
#
# Arguments:
# image Docker image to test, e.g. dogfood-test:22.04 or
# ghcr.io/coder/dogfood:latest
#
# Environment:
# GITHUB_TOKEN Passed into the container for authenticated API calls
# (optional for local runs).
# GITHUB_BASE_REF Base branch for diff-only lint checks (e.g. emdash).
# Set automatically by GitHub Actions for PRs.
# CI When set, fmt targets run in check-mode and actionlint
# is excluded from make lint (it runs separately in CI).
# STEPS Space-separated list of steps to run. Defaults to all.
# Valid values: gen fmt lint build check-unstaged
#
# Example:
# ./scripts/dogfood_test_image.sh dogfood-test:22.04
# STEPS="gen fmt" ./scripts/dogfood_test_image.sh dogfood-test:26.04
set -euo pipefail
# shellcheck source=scripts/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
cdroot
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <image>" >&2
exit 1
fi
IMAGE="$1"
STEPS="${STEPS:-gen fmt lint build check-unstaged}"
log() {
echo "==> $*" >&2
}
# --- setup -------------------------------------------------------------------
if [[ -n "${CI:-}" ]]; then
log "Preparing checkout for container user (UID 1000)"
chmod -R a+rwX .
else
log "NOTE: if the container cannot write to the checkout, run: chmod -R a+rwX ."
fi
# Helper: run a make target inside the image.
# Caches are persisted in named Docker volumes so that subsequent steps (and
# repeated local runs) reuse downloaded modules and compiled artifacts.
run_make() {
docker run --rm \
--volume "$(pwd)":/home/coder/coder \
--env GIT_CONFIG_COUNT=1 \
--env GIT_CONFIG_KEY_0=safe.directory \
--env GIT_CONFIG_VALUE_0=/home/coder/coder \
--volume coder-dogfood-gomod:/home/coder/go/pkg/mod \
--volume coder-dogfood-gobuild:/home/coder/.cache/go-build \
--volume coder-dogfood-pnpm:/home/coder/.local/share/pnpm/store \
--workdir /home/coder/coder \
--network=host \
--env GITHUB_TOKEN \
--env GITHUB_BASE_REF \
--env CI \
"$IMAGE" \
make "$@"
}
# --- steps -------------------------------------------------------------------
for step in $STEPS; do
case "$step" in
gen)
log "make gen (GEN_SKIP_GOLDEN=1, skips tests that need Docker/testcontainers)"
run_make --output-sync=line -j gen GEN_SKIP_GOLDEN=1
;;
fmt)
log "make fmt"
run_make --output-sync=line -j fmt
;;
lint)
log "make lint"
run_make --output-sync=line -j lint
;;
build)
log "make build (fat binary)"
run_make -j build/coder_linux_amd64
;;
check-unstaged)
# Runs on the host: inspects git state after container steps wrote
# generated/formatted files back via the volume mount.
log "Checking for unstaged files"
./scripts/check_unstaged.sh
;;
*)
echo "Unknown step: $step" >&2
echo "Valid steps: gen fmt lint build check-unstaged" >&2
exit 1
;;
esac
done
log "All steps passed."