# Lint phase. The linter is invoked directly rather than through `make
# lint` or `script/lint`, which are themselves a docker build and would
# recurse into a daemon that does not exist in a build step.
# golangci/golangci-lint:v2.14.0, 2026-10-05
FROM golangci/golangci-lint:v2.14.0@sha256:ad862ba6b3798cbe0fd9fd7408d498fd74fbd2623a92406b2fd3898faf0bf98f AS lint
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
# `golangci-lint run` silently ignores an unknown top-level key in
# .golangci.yml, such as a misspelt `linters:`; `config verify` fails on it.
RUN golangci-lint config verify --config .golangci.yml
RUN golangci-lint run --config .golangci.yml ./...

# Test phase. -race needs cgo and so a C compiler, which the Debian Go
# image ships and the alpine one does not.
# golang:1.26.1 (Debian trixie), 2026-10-05
FROM golang:1.26.1@sha256:cd78d88e00afadbedd272f977d375a6247455f3a4b1178f8ae8bbcb201743a8a AS test
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test -timeout 90s -race -cover ./... || \
    { echo "--- Rerunning with -v for details ---"; \
      go test -timeout 90s -race -v ./...; exit 1; }

# Build stage. Nothing is wanted from either phase above; the copies
# are what make BuildKit build them first, so this stage cannot run
# unless lint and test passed.
# golang:1.26.1-alpine, 2026-03-17
FROM golang:1.26.1-alpine@sha256:2389ebfa5b7f43eeafbd6be0c3700cc46690ef842ad962f6c5bd6be49ed82039 AS builder
COPY --from=lint /src/go.sum /dev/null
COPY --from=test /src/go.sum /dev/null
RUN apk add --no-cache git
# A tar-stream context keeps the sender's file owners, which git refuses.
RUN git config --system --add safe.directory /src
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# The VERSION build arg when one is given, otherwise
# `git describe --tags --always` on the .git in the build context. The
# commit and its date always come from that .git. With .git present, a
# version that is still empty, dev or unknown, or a commit or date that
# is unknown, fails the build: git is missing or could not read the
# checkout, as when .git is a file pointing outside the context. A
# context without .git, such as a source export, stamps "dev" and an
# "unknown" commit and date.
ARG VERSION
RUN VERSION="${VERSION:-$(git describe --tags --always || echo dev)}"; \
    commit="$(git rev-parse HEAD || echo unknown)"; \
    commit_date="$(git show -s --format=%cs HEAD || echo unknown)"; \
    if [ -e .git ]; then \
        case "$VERSION" in ""|dev|unknown) \
            echo "version is '$VERSION' although .git is present" >&2; \
            exit 1 ;; \
        esac; \
        if [ "$commit" = unknown ] || [ "$commit_date" = unknown ]; then \
            echo "commit is '$commit' and its date '$commit_date'" \
                "although .git is present" >&2; \
            exit 1; \
        fi; \
    fi; \
    globals=sneak.berlin/go/vaultik/internal/globals; \
    CGO_ENABLED=0 go build -trimpath \
        -ldflags="-s -w -X ${globals}.Version=${VERSION} \
            -X ${globals}.Commit=${commit} \
            -X ${globals}.CommitDate=${commit_date}" \
        -o /vaultik ./cmd/vaultik

# Runtime stage, and the last one: a plain `docker build .` builds this
# stage's chain and nothing else.
# alpine:3.21, 2026-02-25
FROM alpine:3.21@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709

RUN apk add --no-cache ca-certificates

# Copy binary from builder
COPY --from=builder /vaultik /usr/local/bin/vaultik

# Create non-root user
RUN adduser -D -H -s /sbin/nologin vaultik

USER vaultik

ENTRYPOINT ["/usr/local/bin/vaultik"]
