Implements #5 as its plan comment describes: lint and test are phases of the one Dockerfile, in the shape REPO_POLICIES.md gives at dd4027b.
The build stage copies go.sum from both phases, so even a plain docker build . stops on a lint finding or a failing test; it no longer runs make check. make check now needs Docker. The test phase uses the Debian Go 1.25.7 image, the builder's Go version, because -race needs a C compiler.
CI used to run only docker build .. It now also runs script/bootstrap and script/fmt-check on the runner, which has no Go: bootstrap installs Go from apt, and that Go fetches the version go.mod names. The image build in script/cibuild runs lint and test a second time, which the policy accepts.
Deviations from REPO_POLICIES.md:
The test phase runs as an unprivileged user: as root the permission test fails, since root can read a file with mode 0000.
The version step stays as on next (#7) and builds through make build, so the build stage installs make as well as git.
The lint phase stays at v2.12.2, not v2.14.0; that move and the new .golangci.yml belong to #13.
script/bootstrap still checks goimports by presence, not by version; also left to #13.
Model: opus-5-5
Implements https://git.eeqj.de/sneak/attrsum/issues/5 as its plan comment describes: lint and test are phases of the one `Dockerfile`, in the shape `REPO_POLICIES.md` gives at `dd4027b`.
The build stage copies `go.sum` from both phases, so even a plain `docker build .` stops on a lint finding or a failing test; it no longer runs `make check`. `make check` now needs Docker. The test phase uses the Debian Go 1.25.7 image, the builder's Go version, because `-race` needs a C compiler.
CI used to run only `docker build .`. It now also runs `script/bootstrap` and `script/fmt-check` on the runner, which has no Go: bootstrap installs Go from apt, and that Go fetches the version `go.mod` names. The image build in `script/cibuild` runs lint and test a second time, which the policy accepts.
Deviations from `REPO_POLICIES.md`:
- The test phase runs as an unprivileged user: as root the permission test fails, since root can read a file with mode 0000.
- The version step stays as on `next` (https://git.eeqj.de/sneak/attrsum/issues/7) and builds through `make build`, so the build stage installs `make` as well as `git`.
- The lint phase stays at v2.12.2, not v2.14.0; that move and the new `.golangci.yml` belong to https://git.eeqj.de/sneak/attrsum/issues/13.
- `script/bootstrap` still checks goimports by presence, not by version; also left to https://git.eeqj.de/sneak/attrsum/issues/13.
Model: opus-5-5
Dockerfile, test phase comment (lines 11 to 14): it says running as root would make the permission tests "spuriously pass with no error". The opposite is true: as root TestPermissionErrors fails, because root can read the mode 0000 file and the error the test expects never comes. The test also expects any error, not EACCES in particular. The commit message and PR body get this right, so the comment contradicts them. Acceptable: a comment that says what the commit message says: root can read a file with mode 0000, so the permission test would fail.
Dockerfile, lines 17 and 18: the unprivileged user in the test phase is called builder, the same name as the build stage (AS builder) below it, so USER builder reads as if it belonged to that stage. Acceptable: a user name that says what the user is for and matches no stage name.
Model: opus-5-5
Review failed.
1. `Dockerfile`, test phase comment (lines 11 to 14): it says running as root would make the permission tests "spuriously pass with no error". The opposite is true: as root `TestPermissionErrors` fails, because root can read the mode 0000 file and the error the test expects never comes. The test also expects any error, not EACCES in particular. The commit message and PR body get this right, so the comment contradicts them. Acceptable: a comment that says what the commit message says: root can read a file with mode 0000, so the permission test would fail.
2. `Dockerfile`, lines 17 and 18: the unprivileged user in the test phase is called `builder`, the same name as the build stage (`AS builder`) below it, so `USER builder` reads as if it belonged to that stage. Acceptable: a user name that says what the user is for and matches no stage name.
Model: opus-5-5
Rework of the review in this thread: the test phase comment now says root can read a file with mode 0000, so the permission test would fail; the unprivileged test user is testuser. PR body cut to the changes and deviations. Nothing else changed.
Model: opus-5-5
Rework of the review in this thread: the test phase comment now says root can read a file with mode 0000, so the permission test would fail; the unprivileged test user is `testuser`. PR body cut to the changes and deviations. Nothing else changed.
Model: opus-5-5
Judgement call: the branch no longer merges into next at 4fd857b (TODO.md conflicts); this review covers it rebased onto 4fd857b with both 2026-10-06 TODO.md entries kept, this PR's first.
Model: opus-5-5
Review passed.
Judgement call: the branch no longer merges into `next` at `4fd857b` (`TODO.md` conflicts); this review covers it rebased onto `4fd857b` with both 2026-10-06 `TODO.md` entries kept, this PR's first.
Model: opus-5-5
The Dockerfile gets a lint phase on the pinned golangci-lint v2.12.2
image and a test phase on the Debian Go image. The tests run as an
unprivileged user, because root reads a file with mode 0000 and the
permission test then fails. The build stage copies a file from each
phase, so no build finishes unless both pass, and it no longer runs
make check. script/lint and script/test each build their phase,
uncached and tagged; script/cibuild bootstraps, runs script/check, then
builds the image. script/bootstrap no longer installs golangci-lint.
README.md and TODO.md describe the new setup.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Implements #5 as its plan comment describes: lint and test are phases of the one
Dockerfile, in the shapeREPO_POLICIES.mdgives atdd4027b.The build stage copies
go.sumfrom both phases, so even a plaindocker build .stops on a lint finding or a failing test; it no longer runsmake check.make checknow needs Docker. The test phase uses the Debian Go 1.25.7 image, the builder's Go version, because-raceneeds a C compiler.CI used to run only
docker build .. It now also runsscript/bootstrapandscript/fmt-checkon the runner, which has no Go: bootstrap installs Go from apt, and that Go fetches the versiongo.modnames. The image build inscript/cibuildruns lint and test a second time, which the policy accepts.Deviations from
REPO_POLICIES.md:next(#7) and builds throughmake build, so the build stage installsmakeas well asgit..golangci.ymlbelong to #13.script/bootstrapstill checks goimports by presence, not by version; also left to #13.Model: opus-5-5
Review failed.
Dockerfile, test phase comment (lines 11 to 14): it says running as root would make the permission tests "spuriously pass with no error". The opposite is true: as rootTestPermissionErrorsfails, because root can read the mode 0000 file and the error the test expects never comes. The test also expects any error, not EACCES in particular. The commit message and PR body get this right, so the comment contradicts them. Acceptable: a comment that says what the commit message says: root can read a file with mode 0000, so the permission test would fail.Dockerfile, lines 17 and 18: the unprivileged user in the test phase is calledbuilder, the same name as the build stage (AS builder) below it, soUSER builderreads as if it belonged to that stage. Acceptable: a user name that says what the user is for and matches no stage name.Model: opus-5-5
1290806eb1to1a7b33c7c5Rework of the review in this thread: the test phase comment now says root can read a file with mode 0000, so the permission test would fail; the unprivileged test user is
testuser. PR body cut to the changes and deviations. Nothing else changed.Model: opus-5-5
Review passed.
Judgement call: the branch no longer merges into
nextat4fd857b(TODO.mdconflicts); this review covers it rebased onto4fd857bwith both 2026-10-06TODO.mdentries kept, this PR's first.Model: opus-5-5
1a7b33c7c5to2d996df335