From 581dfa3b15da2b4727d15ed55bc33101f34bdca1 Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Sat, 3 Oct 2026 15:54:45 +0000 Subject: [PATCH] Fix git ownership and -race in the canonical Go Dockerfile (closes #73) The test phase ran go test -race on the alpine Go image, which has no C compiler, so cgo was off and the phase failed with "-race requires cgo" before running a test. It now uses the Debian Go image. A build context sent as a tar stream keeps the sender's file owners, so git in the stage that compiles refused the checkout and the version came out empty. That stage now runs git config --system --add safe.directory /src, and the policy text and both checklists say why. The apk add --no-cache git line is unchanged: its pinning waits on https://git.eeqj.de/sneak/prompts/issues/72. Model: opus-5-5 --- TODO.md | 7 +++++++ prompts/EXISTING_REPO_CHECKLIST.md | 14 +++++++++----- prompts/NEW_REPO_CHECKLIST.md | 14 +++++++++----- prompts/REPO_POLICIES.md | 24 +++++++++++++++--------- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/TODO.md b/TODO.md index f41f0b3..d55ba4e 100644 --- a/TODO.md +++ b/TODO.md @@ -21,6 +21,13 @@ fmt-check, and commit. # Completed Steps +- 2026-10-03: Fixed two defects in the canonical Go `Dockerfile` example (issue + 73). The test phase now uses the Debian Go image, since `-race` needs cgo and + the alpine image has no C compiler, so the phase failed before running a test. + The stage that compiles runs `git config --system --add safe.directory /src`, + because a context sent as a tar stream keeps the sender's file owners and git + refuses that checkout, leaving the version empty. Both checklists state that + step in the same words. - 2026-10-03: Brought the canonical `.gitignore` level with `.dockerignore` on secrets (issue 38): it now also ignores `prod.env`-style `*.env` files, `.envrc`, `*.p12`, `*.pfx` and the extensionless SSH private keys, written to diff --git a/prompts/EXISTING_REPO_CHECKLIST.md b/prompts/EXISTING_REPO_CHECKLIST.md index 369b534..f507a2d 100644 --- a/prompts/EXISTING_REPO_CHECKLIST.md +++ b/prompts/EXISTING_REPO_CHECKLIST.md @@ -1,6 +1,6 @@ --- title: Existing Repo Checklist -last_modified: 2026-10-02 +last_modified: 2026-10-03 --- Use this checklist when beginning work in a repo that may not yet conform to our @@ -67,10 +67,14 @@ with your task. argument when one is given, otherwise from `git describe --tags --always`. That gives the tag on a tagged commit; on a later commit, the tag, the number of commits since it and the short commit (`v1.2.3-4-gabc1234`); and - the short commit when no tag is reachable. `ARG VERSION` has no default, - and the build fails if the context carries `.git` and the version still - comes out empty, `dev` or `unknown`. A plain `docker build .` with no - build arguments must succeed; a Dockerfile that refuses an empty build + the short commit when no tag is reachable. The stage that compiles also + marks its working directory safe for git + (`git config --system --add safe.directory /src`): a context sent as a tar + stream keeps the sender's file owners, and git refuses a checkout owned by + another user, so the version would come out empty. `ARG VERSION` has no + default, and the build fails if the context carries `.git` and the version + still comes out empty, `dev` or `unknown`. A plain `docker build .` with + no build arguments must succeed; a Dockerfile that refuses an empty build argument drops that refusal and keeps the argument. `script/docker` and `script/cibuild` pass the version they compute on the host; it takes precedence. A tag-derived version additionally needs `fetch-depth: 0` on diff --git a/prompts/NEW_REPO_CHECKLIST.md b/prompts/NEW_REPO_CHECKLIST.md index b4d8e5f..fb78bbd 100644 --- a/prompts/NEW_REPO_CHECKLIST.md +++ b/prompts/NEW_REPO_CHECKLIST.md @@ -1,6 +1,6 @@ --- title: New Repo Checklist -last_modified: 2026-10-02 +last_modified: 2026-10-03 --- Use this checklist when creating a new repository from scratch. Follow the steps @@ -76,10 +76,14 @@ Template files can be fetched from: argument when one is given, otherwise from `git describe --tags --always`. That gives the tag on a tagged commit; on a later commit, the tag, the number of commits since it and the short commit (`v1.2.3-4-gabc1234`); and - the short commit when no tag is reachable. `ARG VERSION` has no default, - and the build fails if the context carries `.git` and the version still - comes out empty, `dev` or `unknown`. A plain `docker build .` with no - build arguments must succeed; a Dockerfile that refuses an empty build + the short commit when no tag is reachable. The stage that compiles also + marks its working directory safe for git + (`git config --system --add safe.directory /src`): a context sent as a tar + stream keeps the sender's file owners, and git refuses a checkout owned by + another user, so the version would come out empty. `ARG VERSION` has no + default, and the build fails if the context carries `.git` and the version + still comes out empty, `dev` or `unknown`. A plain `docker build .` with + no build arguments must succeed; a Dockerfile that refuses an empty build argument drops that refusal and keeps the argument. - The Dockerfile carries a `lint` phase and a `test` phase, each invoking its tool directly rather than through `make` or `script/`, and the final diff --git a/prompts/REPO_POLICIES.md b/prompts/REPO_POLICIES.md index ca05cb4..24d38f5 100644 --- a/prompts/REPO_POLICIES.md +++ b/prompts/REPO_POLICIES.md @@ -1,6 +1,6 @@ --- title: Repository Policies -last_modified: 2026-10-02 +last_modified: 2026-10-03 --- This document covers repository structure, tooling, and workflow standards. Code @@ -160,7 +160,7 @@ style conventions are in separate documents: - **The gate phases are separate stages, and the build stage depends on both.** The lint phase is based on the `golangci/golangci-lint` image (pinned by hash), so lint failures surface in seconds rather than after a full compile, - and the test phase is based on the Go image. The canonical Go repo + and the test phase is based on the Debian Go image. The canonical Go repo `Dockerfile`: ```dockerfile @@ -173,8 +173,9 @@ style conventions are in separate documents: COPY . . RUN golangci-lint run --config .golangci.yml ./... - # Test phase - # golang:1.x-alpine, YYYY-MM-DD + # Test phase. -race needs cgo and so a C compiler, which the Debian Go + # image ships and the alpine one does not. + # golang:1.x, YYYY-MM-DD FROM golang@sha256:... AS test WORKDIR /src COPY go.mod go.sum ./ @@ -192,6 +193,8 @@ style conventions are in separate documents: 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 @@ -244,11 +247,14 @@ style conventions are in separate documents: `git describe --tags --always`. That gives the tag on a tagged commit; on a later commit, the tag, the number of commits since it and the short commit (`v1.2.3-4-gabc1234`); and the short commit when no tag is - reachable. `ARG VERSION` has no default, and the build fails if the - context carries `.git` and the version still comes out empty, `dev` or - `unknown`. A plain `docker build .` with no build arguments must succeed; - a Dockerfile that refuses an empty build argument drops that refusal and - keeps the argument. + reachable. The stage that compiles also marks its working directory safe + for git (`git config --system --add safe.directory /src`): a context sent + as a tar stream keeps the sender's file owners, and git refuses a checkout + owned by another user, so the version would come out empty. `ARG VERSION` + has no default, and the build fails if the context carries `.git` and the + version still comes out empty, `dev` or `unknown`. A plain + `docker build .` with no build arguments must succeed; a Dockerfile that + refuses an empty build argument drops that refusal and keeps the argument. - Every repo should have a Gitea Actions workflow (`.gitea/workflows/`) that runs `script/cibuild` on push, and checks out the repo as its only other step.