#!/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, tag and" \
            "digest, 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 "$@"
