Skip to content

Commit ea0aeb2

Browse files
aledbfclaude
andcommitted
test(parity): enforce the containerd image store for the runtime lane
The runtime lane's update-UID and cache-export builds run `docker build --platform` against locally-built images, which the legacy graph-driver builder cannot resolve — only the containerd image store can. Without it the TS oracle fails those builds while the Go CLI (which omits --platform) succeeds, surfacing as confusing per-case TS-vs-Go divergences (e.g. up.dotfiles-local-*). Enforce the store up front: TestParityMatrix fails fast with an actionable message when the runtime lane runs docker cases without it (covers a direct `go test`, which skips the Taskfile preconditions), and parity:runtime / coverage:parity-runtime gain a matching ~1s precondition. The contract lane (PARITY_SKIP_DOCKER) and the default no-lane run are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 51d23aa commit ea0aeb2

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

Taskfile.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ tasks:
133133
preconditions:
134134
- sh: docker info >/dev/null 2>&1
135135
msg: Docker is required for runtime parity coverage
136+
- sh: docker info 2>/dev/null | grep -q io.containerd.snapshotter
137+
msg: The parity runtime lane requires the containerd image store (docker build --platform on local images); enable it with `task ci:prepare-runner`.
136138
- sh: bash scripts/docker-cache-export.sh
137139
msg: The Docker builder must support cache export (see scripts/ci-prepare-runner.sh)
138140
cmds:
@@ -221,6 +223,16 @@ tasks:
221223
preconditions:
222224
- sh: docker info >/dev/null 2>&1
223225
msg: Docker is required for runtime parity
226+
# Fail fast (~1s) if the containerd image store is off: the runtime lane's
227+
# update-UID / cache-export builds run `docker build --platform` against
228+
# locally-built images, which only the containerd store can resolve. Without
229+
# it the TS oracle fails those builds while Go succeeds → false divergences.
230+
# The test itself re-checks this (so a direct `go test` is covered too).
231+
- sh: docker info 2>/dev/null | grep -q io.containerd.snapshotter
232+
msg: |
233+
The parity runtime lane requires the containerd image store (docker build
234+
--platform against locally-built images). Enable it with `task ci:prepare-runner`,
235+
or add {"features":{"containerd-snapshotter":true}} to /etc/docker/daemon.json.
224236
# Fail fast (~1s) if the builder can't export build cache — otherwise the
225237
# runtime cases (build.cache-to-*, build.output-oci-*) fail ~4 min deep with
226238
# a cryptic buildkit error. The default `docker` driver lacks cache export.

internal/cli/parity_matrix_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,20 @@ func TestParityMatrix(t *testing.T) {
244244

245245
dockerAvailable := isDockerAvailable()
246246

247+
// The runtime lane's update-UID and cache-export builds run
248+
// `docker build --platform` against locally-built images, which the legacy
249+
// graph-driver builder cannot resolve — only the containerd image store can.
250+
// Without it the TS oracle fails those builds while the Go CLI (which omits
251+
// --platform) succeeds, producing false TS-vs-Go divergences. Enforce the
252+
// store up front — including on a direct `go test` that skips the Taskfile
253+
// precondition — so a misconfigured daemon fails loudly with a fix, not as a
254+
// confusing per-case divergence.
255+
runtimeLane := os.Getenv("PARITY_LANE") != "" && os.Getenv("PARITY_SKIP_DOCKER") != "true"
256+
if runtimeLane && dockerAvailable && !hasContainerdImageStore() {
257+
t.Fatal("parity runtime lane requires the containerd image store (docker build --platform against local images). " +
258+
"Enable it with `task ci:prepare-runner`, or add {\"features\":{\"containerd-snapshotter\":true}} to /etc/docker/daemon.json and restart Docker.")
259+
}
260+
247261
// Sharding: split the selected cases round-robin across parallel CI jobs, so
248262
// N runners (with independent docker daemons) share the wall-clock. Inert when
249263
// PARITY_SHARD_TOTAL is unset or <= 1. Cases in other shards stay not-selected,
@@ -1128,6 +1142,17 @@ func isDockerAvailable() bool {
11281142
return cmd.Run() == nil
11291143
}
11301144

1145+
// hasContainerdImageStore reports whether the Docker daemon has the containerd
1146+
// image store enabled (daemon.json {"features":{"containerd-snapshotter":true}}),
1147+
// which surfaces as an io.containerd.snapshotter driver in `docker info`.
1148+
func hasContainerdImageStore() bool {
1149+
out, err := exec.Command("docker", "info", "--format", "{{json .DriverStatus}}").Output()
1150+
if err != nil {
1151+
return false
1152+
}
1153+
return strings.Contains(string(out), "io.containerd.snapshotter")
1154+
}
1155+
11311156
func matchesFilter(tc parityCase) bool {
11321157
if os.Getenv("PARITY_NETWORK_ONLY") == "true" && !tc.NetworkRequired {
11331158
return false

0 commit comments

Comments
 (0)