Make pre commit fail, not ci #407

Closed
opened 2026-06-04 05:19:32 +00:00 by guettli · 2 comments
guettli commented 2026-06-04 05:19:32 +00:00 (Migrated from codeberg.org)

Make pre commit fail, not ci.

Look at:

failed to resolve image "ghcr.io/cirruslabs/flutter:3.44.1" (platform: "linux/amd64"): failed to resolve source metadata for ghcr.io/cirruslabs/flutter:3.44.1: ghcr.io/cirruslabs/flutter:3.44.1: not found

https://codeberg.org/guettli/sharedinbox/actions/runs/1521/jobs/0/attempt/1#jobstep-3-48

How could a pre commit config detect that?

This has the benefit, that this bug would have been detected before im the change was pushed.

Make pre commit fail, not ci. Look at: > failed to resolve image "ghcr.io/cirruslabs/flutter:3.44.1" (platform: "linux/amd64"): failed to resolve source metadata for ghcr.io/cirruslabs/flutter:3.44.1: ghcr.io/cirruslabs/flutter:3.44.1: not found https://codeberg.org/guettli/sharedinbox/actions/runs/1521/jobs/0/attempt/1#jobstep-3-48 How could a pre commit config detect that? This has the benefit, that this bug would have been detected before im the change was pushed.
guettlibot commented 2026-06-04 05:25:11 +00:00 (Migrated from codeberg.org)

I have everything I need. Here's the implementation plan I'll post as a comment:


Implementation Plan: Validate container image references in pre-commit

Root cause: ci/main.go holds hard-coded OCI image tags (e.g. From("ghcr.io/cirruslabs/flutter:3.44.1")). When the tag is bumped to one that does not yet exist on the registry, CI fails. No local check catches this before the push.

Approach: Add a pre-commit hook that uses skopeo inspect to verify every From("ghcr.io/...") reference in ci/main.go actually resolves in the registry. skopeo inspect --no-creds fetches only the image manifest (no layers), so it's fast and needs no running Docker daemon. It supports anonymous pulls for public GHCR images.


1. flake.nix — add skopeo to dev shell

Add skopeo to the buildInputs list in devShells.default. No other changes needed; the hook runs inside nix develop --command, so the tool will be on PATH.


2. scripts/check_ci_images.sh — new validation script

#!/usr/bin/env bash
set -euo pipefail

ROOT=$(git rev-parse --show-toplevel)
FILE="$ROOT/ci/main.go"

images=$(grep -oP 'From\("\K[^"]+' "$FILE" || true)

if [ -z "$images" ]; then
  echo "check-ci-images: no From() image references found in ci/main.go"
  exit 0
fi

fail=0
while IFS= read -r image; do
  printf "check-ci-images: checking %s ... " "$image"
  if skopeo inspect --no-creds "docker://$image" > /dev/null 2>&1; then
    echo "OK"
  else
    echo "NOT FOUND"
    fail=1
  fi
done <<< "$images"

if [ "$fail" -eq 1 ]; then
  echo "ERROR: one or more container images in ci/main.go could not be resolved."
  echo "Fix the image tag before committing."
  exit 1
fi

Make the script executable (chmod +x).


3. Taskfile.yml — add check-ci-images task

check-ci-images:
  desc: Verify that all container images referenced in ci/main.go are reachable
  cmds:
    - scripts/check_ci_images.sh

No deps: needed — no Dart/Flutter toolchain required.


4. .pre-commit-config.yaml — new hook

Add after the existing dagger-progress-plain hook:

      - id: ci-image-exists
        name: verify container images in ci/main.go are reachable
        language: system
        entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command task check-ci-images'
        pass_filenames: false
        files: ^ci/main\.go$

Key detail: files: ^ci/main\.go$ (not always_run: true) so the registry call only happens when ci/main.go is in the staged diff. This avoids a network round-trip on every unrelated commit.


No schema changes, no code generation needed.

I have everything I need. Here's the implementation plan I'll post as a comment: --- **Implementation Plan: Validate container image references in pre-commit** **Root cause:** `ci/main.go` holds hard-coded OCI image tags (e.g. `From("ghcr.io/cirruslabs/flutter:3.44.1")`). When the tag is bumped to one that does not yet exist on the registry, CI fails. No local check catches this before the push. **Approach:** Add a pre-commit hook that uses `skopeo inspect` to verify every `From("ghcr.io/...")` reference in `ci/main.go` actually resolves in the registry. `skopeo inspect --no-creds` fetches only the image manifest (no layers), so it's fast and needs no running Docker daemon. It supports anonymous pulls for public GHCR images. --- ### 1. `flake.nix` — add `skopeo` to dev shell Add `skopeo` to the `buildInputs` list in `devShells.default`. No other changes needed; the hook runs inside `nix develop --command`, so the tool will be on `PATH`. --- ### 2. `scripts/check_ci_images.sh` — new validation script ``` #!/usr/bin/env bash set -euo pipefail ROOT=$(git rev-parse --show-toplevel) FILE="$ROOT/ci/main.go" images=$(grep -oP 'From\("\K[^"]+' "$FILE" || true) if [ -z "$images" ]; then echo "check-ci-images: no From() image references found in ci/main.go" exit 0 fi fail=0 while IFS= read -r image; do printf "check-ci-images: checking %s ... " "$image" if skopeo inspect --no-creds "docker://$image" > /dev/null 2>&1; then echo "OK" else echo "NOT FOUND" fail=1 fi done <<< "$images" if [ "$fail" -eq 1 ]; then echo "ERROR: one or more container images in ci/main.go could not be resolved." echo "Fix the image tag before committing." exit 1 fi ``` Make the script executable (`chmod +x`). --- ### 3. `Taskfile.yml` — add `check-ci-images` task ```yaml check-ci-images: desc: Verify that all container images referenced in ci/main.go are reachable cmds: - scripts/check_ci_images.sh ``` No `deps:` needed — no Dart/Flutter toolchain required. --- ### 4. `.pre-commit-config.yaml` — new hook Add after the existing `dagger-progress-plain` hook: ```yaml - id: ci-image-exists name: verify container images in ci/main.go are reachable language: system entry: bash -c 'cd "$(git rev-parse --show-toplevel)" && nix develop --command task check-ci-images' pass_filenames: false files: ^ci/main\.go$ ``` Key detail: `files: ^ci/main\.go$` (not `always_run: true`) so the registry call only happens when `ci/main.go` is in the staged diff. This avoids a network round-trip on every unrelated commit. --- ### No schema changes, no code generation needed.
guettlibot commented 2026-06-04 06:10:03 +00:00 (Migrated from codeberg.org)

The PR is open at https://codeberg.org/guettli/sharedinbox/pulls/413.

Here's what was implemented:

scripts/check_ci_images.sh — new script that uses grep -oP to extract every From("...") image reference from ci/main.go, then runs skopeo inspect --no-creds docker://<image> for each one. skopeo fetches only the manifest (no layer pull, no running Docker daemon required). Any tag that doesn't exist in the registry prints NOT FOUND and the script exits 1.

Taskfile.yml — new check-ci-images task wraps the script.

.pre-commit-config.yaml — new ci-image-exists hook calls nix develop --command task check-ci-images. Critically, it uses files: ^ci/main\.go$ instead of always_run: true, so the registry check only fires when ci/main.go is actually staged — no network round-trip on unrelated commits.

flake.nix — adds skopeo to the Nix devShell buildInputs so the tool is available when the hook runs via nix develop --command.

The PR is open at **https://codeberg.org/guettli/sharedinbox/pulls/413**. Here's what was implemented: **`scripts/check_ci_images.sh`** — new script that uses `grep -oP` to extract every `From("...")` image reference from `ci/main.go`, then runs `skopeo inspect --no-creds docker://<image>` for each one. `skopeo` fetches only the manifest (no layer pull, no running Docker daemon required). Any tag that doesn't exist in the registry prints `NOT FOUND` and the script exits 1. **`Taskfile.yml`** — new `check-ci-images` task wraps the script. **`.pre-commit-config.yaml`** — new `ci-image-exists` hook calls `nix develop --command task check-ci-images`. Critically, it uses `files: ^ci/main\.go$` instead of `always_run: true`, so the registry check only fires when `ci/main.go` is actually staged — no network round-trip on unrelated commits. **`flake.nix`** — adds `skopeo` to the Nix devShell `buildInputs` so the tool is available when the hook runs via `nix develop --command`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: guettli/sharedinbox#407