#!/bin/sh # script/verify-lint-image-pin: fail unless the golangci-lint image # referenced by Dockerfile.lint and the one referenced by the main # Dockerfile's lint stage are the same image at the same digest. Our own # extension to scripts-to-rule-them-all, not one of its entrypoints. # # The linter version is pinned in two independent files. That is the # shape #42 turned into a build failure rather than tolerate: nothing # else keeps the two in sync, and a bump applied to one file alone would # leave `make lint` and the fail-fast lint stage of `make docker` # linting the same tree against different rulesets, both green. This is # the single guard that stops it, run as a gate in both files. # # It deliberately restates neither pin. A hardcoded expected digest here # would be a third copy — one more thing to bump, and the same drift one # file further out. It compares the two files to each other and knows # nothing about which version is correct. # # A reference that cannot be read is a hard failure, not a skip: a # comparison of two empty strings succeeds, which would turn this guard # into exactly the unearned green it exists to prevent. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" LINT_DOCKERFILE="Dockerfile.lint" MAIN_DOCKERFILE="Dockerfile" # Echo the single golangci-lint image reference in the named Dockerfile. # Scans every argument of every FROM instruction rather than assuming a # field position, so `FROM --platform=... img AS stage` reads correctly. # Exits non-zero, with a diagnosis, unless there is exactly one. lint_image_ref() { file="$1" if [ ! -f "$file" ]; then echo "verify-lint-image-pin: $file: not found" >&2 return 1 fi refs="$( awk ' toupper($1) == "FROM" { for (i = 2; i <= NF; i++) { if ($i ~ /^golangci\/golangci-lint[:@]/) { print $i } } } ' "$file" )" count="$(printf '%s' "$refs" | grep -c . || true)" if [ "$count" -ne 1 ]; then echo "verify-lint-image-pin: $file: expected exactly one" \ "golangci/golangci-lint FROM reference, found $count" >&2 return 1 fi printf '%s\n' "$refs" } main() { cd "$ROOT" lint_ref="$(lint_image_ref "$LINT_DOCKERFILE")" main_ref="$(lint_image_ref "$MAIN_DOCKERFILE")" if [ "$lint_ref" != "$main_ref" ]; then echo "verify-lint-image-pin: the linter image is pinned twice and" \ "the two pins disagree:" >&2 echo "verify-lint-image-pin: $LINT_DOCKERFILE: $lint_ref" >&2 echo "verify-lint-image-pin: $MAIN_DOCKERFILE: $main_ref" >&2 echo "verify-lint-image-pin: bump both FROM lines together so" \ "script/lint and the Dockerfile lint stage keep running the" \ "same linter" >&2 exit 1 fi echo "verify-lint-image-pin: $LINT_DOCKERFILE and $MAIN_DOCKERFILE" \ "agree on $lint_ref" } main "$@"