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
19 changes: 15 additions & 4 deletions .github/workflows/coverage-floor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ on:
type: boolean
default: false
postgres_image:
description: "Docker image for the postgres service. Default 'postgres:16'. Use e.g. 'pgvector/pgvector:pg16' when tests need the vector extension."
description: "Docker image for the postgres service. Default 'postgres:16'. A bare Docker Official Image name like that one (no '/') is pulled from Google's Docker Hub mirror as mirror.gcr.io/library/<name>, because Docker Hub rate-limits the anonymous pulls GitHub-hosted runners make. A reference with a '/' is pulled exactly as given, so pass a Docker Hub image outside library/ in its mirror form, e.g. 'mirror.gcr.io/pgvector/pgvector:pg16' when tests need the vector extension."
required: false
type: string
default: "postgres:16"
Expand All @@ -122,7 +122,7 @@ on:
type: boolean
default: false
redis_image:
description: "Docker image for the redis service. Default 'redis:7'."
description: "Docker image for the redis service. Default 'redis:7'. Pulled like postgres_image: a bare name from mirror.gcr.io/library/, a reference with a '/' exactly as given."
required: false
type: string
default: "redis:7"
Expand Down Expand Up @@ -216,9 +216,20 @@ jobs:
measure:
name: Measure coverage and enforce floor
runs-on: ubuntu-latest
# Docker Hub rate-limits anonymous pulls per IP, and GitHub-hosted runners
# share egress IPs: on 2026-10-09 dotclaude#479 (run 37991904725) and #485
# failed before their first step on `docker pull postgres:16` ->
# toomanyrequests. So a bare service image name (no `/`, so a Docker
# Official Image), the default or one a caller passes, is pulled from
# Google's Docker Hub mirror as mirror.gcr.io/library/<name>, which needs
# no credential. A reference with a `/` is pulled exactly as given: the
# expression language cannot split it to tell a registry from a Docker Hub
# namespace, so a caller using a Docker Hub `<namespace>/<name>` image
# passes its mirror form (mirror.gcr.io/<namespace>/<name>) itself.
# Pinned by selftest/test_job_images_off_docker_hub.py.
services:
postgres:
image: ${{ inputs.postgres_image || 'postgres:16' }}
image: ${{ contains(inputs.postgres_image || 'postgres:16', '/') && inputs.postgres_image || format('mirror.gcr.io/library/{0}', inputs.postgres_image || 'postgres:16') }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand All @@ -231,7 +242,7 @@ jobs:
--health-timeout 5s
--health-retries 5
redis:
image: ${{ inputs.redis_image || 'redis:7' }}
image: ${{ contains(inputs.redis_image || 'redis:7', '/') && inputs.redis_image || format('mirror.gcr.io/library/{0}', inputs.redis_image || 'redis:7') }}
ports:
- 6379:6379
options: >-
Expand Down
26 changes: 26 additions & 0 deletions selftest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,32 @@ arbitrary helper scripts; that's a different kind of repo.
`claude-review.yml`'s context step. GitHub's own diff (`gh pr diff`, the
files API) ignores `.gitattributes`, so a lane reading only that diff
needs nothing.
- `test_job_images_off_docker_hub.py` — no job in `.github/workflows/`
sends a default or bare image name to Docker Hub. Every image a job pulls
(each service's image, the job container, each `docker://` step) is
resolved by evaluating its expression with `inputs` empty (this repo's own
runs), with the declared defaults, and with bare names a caller might
pass; any result Docker would fetch from Docker Hub fails. Literals alone
prove nothing: `inputs.postgres_image || 'mirror.gcr.io/library/postgres:16'`
holds only mirrored literals and still sends a caller's `postgres:16` to
Docker Hub. The evaluator models only the expression subset image fields
use and raises on anything else, so an expression it cannot read fails
rather than passing unread. Hardcoded expectations pin
`coverage-floor.yml`'s two services: a bare name, the default or a
caller's, goes to `mirror.gcr.io/library/`; a reference with a `/` is
pulled as given, so a caller passing a Docker Hub `<namespace>/<name>`
image is still exposed until it passes the mirror form. Negative controls,
each asserting the failure it should cause: the pre-fix bare default; a
mirrored default (declared and fallback) that still lets a caller's bare
name through; every reference prefixed (a pgvector ref mangled); a typo in
the mirror path; the postgres service renamed out of the scan. Fixtures
cover every slot kind (literal, string-form service, pass-through,
container string and mapping, `docker://` step), a re-cased input name,
and a clean set.
Background: on 2026-10-09 dotclaude#479 (run 37991904725) and #485 failed
before their first step on `docker pull postgres:16` -> `toomanyrequests`:
Docker Hub rate-limits anonymous pulls per IP, and GitHub-hosted runners
share egress IPs.
- `test_workflow_guards.py` — pytest wrapper that runs the `.sh`
selftests above, so `tests-runner.yml`'s self-test path enforces them
in CI.
Expand Down
Loading
Loading