build: run all linting in Docker through script/lint (closes #104) #122

Merged
clawbot merged 1 commits from issue-104-docker-lint into next 2026-09-28 14:27:35 +02:00
Collaborator

What changed

make lint calls script/lint, the only way golangci-lint is run, everywhere; it is never installed on the host.

  • Inside a container, script/lint runs golangci-lint run --config .golangci.yml ./.... Anywhere else it builds the hash-pinned Dockerfile.lint, whose last step runs script/lint again.
  • The Dockerfile lint stage runs make lint, the same entrypoint.
  • script/bootstrap no longer installs golangci-lint, and the nix-shell package lists in the Makefile and script/test drop it.

What a reader would trip over

  • Both Dockerfiles set ENV container=docker (the systemd convention for marking a container), and script/lint checks it. /.dockerenv cannot be used: build steps lack it, and hosts that are themselves containers have it.
  • script/lint passes a new CACHEBUST build-arg on every run, so the lint step is never served from cache; the layers above it still cache.
  • That step mounts a tmpfs over /root/.cache, so Go's and golangci-lint's caches are discarded, not stored in a layer no later run reuses. One make lint run adds under 1 MB of build cache.
  • Two consecutive make lint runs on an unchanged tree both ran the linter.
  • A planted errcheck violation failed both make lint and the Dockerfile lint stage with that finding.
  • The two Dockerfiles pin the lint image separately; change both pins together.

Disclosures

  • golangci-lint config verify is not run: it fetches its schema over an unpinned live HTTPS call, which REPO_POLICIES.md forbids.
  • Judgement call: script/lint always supplies a fresh CACHEBUST, so Dockerfile.lint does not refuse to build without one.

Model: opus-4-8 (implementation); opus-5-5 (rework)

## What changed `make lint` calls `script/lint`, the only way golangci-lint is run, everywhere; it is never installed on the host. - Inside a container, `script/lint` runs `golangci-lint run --config .golangci.yml ./...`. Anywhere else it builds the hash-pinned `Dockerfile.lint`, whose last step runs `script/lint` again. - The `Dockerfile` lint stage runs `make lint`, the same entrypoint. - `script/bootstrap` no longer installs golangci-lint, and the nix-shell package lists in the `Makefile` and `script/test` drop it. ## What a reader would trip over - Both Dockerfiles set `ENV container=docker` (the systemd convention for marking a container), and `script/lint` checks it. `/.dockerenv` cannot be used: build steps lack it, and hosts that are themselves containers have it. - `script/lint` passes a new `CACHEBUST` build-arg on every run, so the lint step is never served from cache; the layers above it still cache. - That step mounts a tmpfs over `/root/.cache`, so Go's and golangci-lint's caches are discarded, not stored in a layer no later run reuses. One `make lint` run adds under 1 MB of build cache. - Two consecutive `make lint` runs on an unchanged tree both ran the linter. - A planted `errcheck` violation failed both `make lint` and the `Dockerfile` lint stage with that finding. - The two Dockerfiles pin the lint image separately; change both pins together. ## Disclosures - `golangci-lint config verify` is not run: it fetches its schema over an unpinned live HTTPS call, which `REPO_POLICIES.md` forbids. - Judgement call: `script/lint` always supplies a fresh `CACHEBUST`, so `Dockerfile.lint` does not refuse to build without one. Model: opus-4-8 (implementation); opus-5-5 (rework)
clawbot added the needs-review label 2026-09-21 20:26:02 +02:00
clawbot self-assigned this 2026-09-21 20:26:02 +02:00
Author
Collaborator

PASS: linting runs only inside Docker through script/lint; both cache-defeat and negative-control traps hold (two consecutive runs on an unchanged tree each re-executed the linter, and a planted violation failed the run with its exact finding); every image is pinned by digest; the Dockerfile lint stage and make check lint with the identical command, config, and image; the config verify exclusion is stated; the build leaves no image behind; and the full Docker builder gate is green on a clean rebase onto current next.

Model: opus-4-8

PASS: linting runs only inside Docker through `script/lint`; both cache-defeat and negative-control traps hold (two consecutive runs on an unchanged tree each re-executed the linter, and a planted violation failed the run with its exact finding); every image is pinned by digest; the `Dockerfile` lint stage and `make check` lint with the identical command, config, and image; the `config verify` exclusion is stated; the build leaves no image behind; and the full Docker builder gate is green on a clean rebase onto current `next`. Model: opus-4-8
clawbot added needs-rebase and removed needs-review labels 2026-09-21 21:26:13 +02:00
clawbot force-pushed issue-104-docker-lint from 66bf9a589d to 8dc46af6b7 2026-09-21 22:12:23 +02:00 Compare
clawbot added needs-review and removed needs-rebase labels 2026-09-21 22:12:41 +02:00
Author
Collaborator

Rebased onto the current next. The only conflict was in TODO.md Completed Steps: I kept the existing entry for #92 and placed this change's entry above it. Dockerfile merged cleanly — the lint-stage change here and the signing-key runtime change from #110 are in separate build stages and did not conflict. README.md needed no change: its script/lint description still reads correctly and the Getting Started signing-key text is untouched. The full build gate passed.

Model: opus-4-8

Rebased onto the current `next`. The only conflict was in `TODO.md` Completed Steps: I kept the existing entry for https://git.eeqj.de/sneak/pixa/issues/92 and placed this change's entry above it. `Dockerfile` merged cleanly — the lint-stage change here and the signing-key runtime change from https://git.eeqj.de/sneak/pixa/issues/110 are in separate build stages and did not conflict. `README.md` needed no change: its `script/lint` description still reads correctly and the Getting Started signing-key text is untouched. The full build gate passed. Model: opus-4-8
Owner

Fix the bootstrap issue where it's installing an unneeded binary. You need to not be so sloppy about this. Obviously if we're doing linting in a container, we don't need to be installing linting tools on the host. Clean up after yourself. Remember that.

Fix the bootstrap issue where it's installing an unneeded binary. You need to not be so sloppy about this. Obviously if we're doing linting in a container, we don't need to be installing linting tools on the host. Clean up after yourself. Remember that.
clawbot added needs-rework and removed needs-review labels 2026-09-22 00:43:53 +02:00
clawbot force-pushed issue-104-docker-lint from 8dc46af6b7 to f1c1bffb5a 2026-09-22 00:57:31 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-09-22 00:57:48 +02:00
Author
Collaborator

Reworked the host-install finding: golangci-lint is no longer installed on the host and now lives only in the pinned container image.

Removed:

  • script/bootstrap: the golangci-lint version and sha256 pins, the release-archive download, the ensure/verify helpers, and the sole-use curl dependency.
  • golangci-lint from the nix-shell package lists in the Makefile and script/test, which build and test but never lint.

Rebased onto next.

Model: opus-4-8

Reworked the host-install finding: golangci-lint is no longer installed on the host and now lives only in the pinned container image. Removed: - `script/bootstrap`: the golangci-lint version and sha256 pins, the release-archive download, the ensure/verify helpers, and the sole-use curl dependency. - `golangci-lint` from the nix-shell package lists in the `Makefile` and `script/test`, which build and test but never lint. Rebased onto `next`. Model: opus-4-8
Author
Collaborator

PASS: golangci-lint now installs and runs only inside the pinned Docker image and nowhere on the host — script/bootstrap no longer fetches or installs it (its version/sha256 pins, the release download, the ensure/verify helpers, and the curl dependency they alone used are all gone, with no orphaned references and the build/test toolchain still installed), and golangci-lint is dropped from the nix-shell lists in the Makefile and script/test; Dockerfile.lint and the Dockerfile lint stage are pinned to the same digest and run the identical command and config, the cache-defeat trap holds (two consecutive script/lint runs on an unchanged tree each re-executed the linter and a planted violation failed with its exact finding), the full builder gate is green on a clean rebase onto current next, and the PR targets next with the closes keyword and correct model lines throughout — see #104

Model: opus-4-8

PASS: golangci-lint now installs and runs only inside the pinned Docker image and nowhere on the host — `script/bootstrap` no longer fetches or installs it (its version/sha256 pins, the release download, the ensure/verify helpers, and the curl dependency they alone used are all gone, with no orphaned references and the build/test toolchain still installed), and `golangci-lint` is dropped from the nix-shell lists in the `Makefile` and `script/test`; `Dockerfile.lint` and the `Dockerfile` lint stage are pinned to the same digest and run the identical command and config, the cache-defeat trap holds (two consecutive `script/lint` runs on an unchanged tree each re-executed the linter and a planted violation failed with its exact finding), the full builder gate is green on a clean rebase onto current `next`, and the PR targets `next` with the closes keyword and correct model lines throughout — see https://git.eeqj.de/sneak/pixa/issues/104 Model: opus-4-8
Owner

“make lint” should invoke strta lint, which should detect if it’s in docker or not and either build the lint container or run the linter. one entrypoint in all cases.

“make lint” should invoke strta lint, which should detect if it’s in docker or not and either build the lint container or run the linter. one entrypoint in all cases.
clawbot added needs-rework and removed needs-review labels 2026-09-22 01:26:16 +02:00
Author
Collaborator

Rework plan for sneak's comment above (#122 (comment)), queued for the next free worker:

  • make lint calls script/lint, the only way the linter runs, everywhere.
  • script/lint detects whether it runs inside a container: inside, it runs golangci-lint directly; outside, it builds Dockerfile.lint, whose lint step calls script/lint again.
  • The Dockerfile lint stage goes back to RUN make lint.
  • Kept from before: no linter on the host, the lint step never served from cache, config verify excluded.

Model: opus-5-5

Rework plan for sneak's comment above (https://git.eeqj.de/sneak/pixa/pulls/122#issuecomment-98418), queued for the next free worker: - `make lint` calls `script/lint`, the only way the linter runs, everywhere. - `script/lint` detects whether it runs inside a container: inside, it runs `golangci-lint` directly; outside, it builds `Dockerfile.lint`, whose lint step calls `script/lint` again. - The `Dockerfile` lint stage goes back to `RUN make lint`. - Kept from before: no linter on the host, the lint step never served from cache, `config verify` excluded. Model: opus-5-5
clawbot force-pushed issue-104-docker-lint from f1c1bffb5a to d3f277d3f0 2026-09-28 13:10:16 +02:00 Compare
clawbot changed title from build: run all linting in Docker via Dockerfile.lint (closes #104) to build: run all linting in Docker through script/lint (closes #104) 2026-09-28 13:13:47 +02:00
Author
Collaborator

Reworked per #122 (comment): make lint calls script/lint, which runs golangci-lint when inside a container (both Dockerfiles set container=docker) and otherwise builds Dockerfile.lint, whose last step runs script/lint again; the Dockerfile lint stage is back to make lint. Rebased onto next and squashed to one commit.

Model: opus-5-5

Reworked per https://git.eeqj.de/sneak/pixa/pulls/122#issuecomment-98418: `make lint` calls `script/lint`, which runs golangci-lint when inside a container (both Dockerfiles set `container=docker`) and otherwise builds `Dockerfile.lint`, whose last step runs `script/lint` again; the `Dockerfile` lint stage is back to `make lint`. Rebased onto `next` and squashed to one commit. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 13:13:48 +02:00
Author
Collaborator

FAIL

  • Dockerfile.lint, the final RUN script/lint: the step writes Go's build cache and golangci-lint's cache (about 700 MB for this tree) into its layer, and because CACHEBUST changes on every run, each make lint (every pre-commit run included) leaves a new build-cache entry of that size that no later run can ever reuse. Acceptable: keep those caches (/root/.cache) out of the layer, for example with a tmpfs or cache mount on that RUN, so a lint run leaves nothing behind.
  • Dockerfile.lint header comment: "Pinned to the same image as the Dockerfile lint stage, so the two cannot drift to different linter versions" promises something nothing enforces; the two digests are separate pins and drift as soon as one is bumped alone. Acceptable: say that both pins must be changed together.

Model: opus-5-5

FAIL - `Dockerfile.lint`, the final `RUN script/lint`: the step writes Go's build cache and golangci-lint's cache (about 700 MB for this tree) into its layer, and because `CACHEBUST` changes on every run, each `make lint` (every pre-commit run included) leaves a new build-cache entry of that size that no later run can ever reuse. Acceptable: keep those caches (`/root/.cache`) out of the layer, for example with a tmpfs or cache mount on that `RUN`, so a lint run leaves nothing behind. - `Dockerfile.lint` header comment: "Pinned to the same image as the Dockerfile lint stage, so the two cannot drift to different linter versions" promises something nothing enforces; the two digests are separate pins and drift as soon as one is bumped alone. Acceptable: say that both pins must be changed together. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-09-28 13:27:41 +02:00
clawbot force-pushed issue-104-docker-lint from d3f277d3f0 to 38fae4295b 2026-09-28 13:39:06 +02:00 Compare
Author
Collaborator

Reworked against #122 (comment), rebased onto next:

  • Build cache: the lint step in Dockerfile.lint now mounts a tmpfs over /root/.cache; one make lint run adds under 1 MB.
  • Pin comment: now says to change both pins together.

Model: opus-5-5

Reworked against https://git.eeqj.de/sneak/pixa/pulls/122#issuecomment-103526, rebased onto `next`: - Build cache: the lint step in `Dockerfile.lint` now mounts a tmpfs over `/root/.cache`; one `make lint` run adds under 1 MB. - Pin comment: now says to change both pins together. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 13:39:17 +02:00
clawbot added needs-rebase and removed needs-review labels 2026-09-28 13:47:37 +02:00
clawbot force-pushed issue-104-docker-lint from 38fae4295b to d548cb7a17 2026-09-28 13:51:44 +02:00 Compare
clawbot added needs-review and removed needs-rebase labels 2026-09-28 13:51:48 +02:00
Author
Collaborator

FAIL

  • script/bootstrap, header comment: "golangci-lint runs only inside Dockerfile.lint" is not true; the Dockerfile lint stage runs it too (RUN make lint). Acceptable: say it runs only inside a container (Dockerfile.lint or the Dockerfile lint stage), never on the host.
  • Dockerfile, lint-stage pin comment (line 2): only Dockerfile.lint says the two pins must change together. Whoever bumps the Dockerfile pin is not pointed to Dockerfile.lint, so make lint and the image build end up on different linter versions. Acceptable: the same one-line note beside the Dockerfile pin, naming Dockerfile.lint.

Model: opus-5-5

FAIL - `script/bootstrap`, header comment: "golangci-lint runs only inside Dockerfile.lint" is not true; the `Dockerfile` lint stage runs it too (`RUN make lint`). Acceptable: say it runs only inside a container (`Dockerfile.lint` or the `Dockerfile` lint stage), never on the host. - `Dockerfile`, lint-stage pin comment (line 2): only `Dockerfile.lint` says the two pins must change together. Whoever bumps the `Dockerfile` pin is not pointed to `Dockerfile.lint`, so `make lint` and the image build end up on different linter versions. Acceptable: the same one-line note beside the `Dockerfile` pin, naming `Dockerfile.lint`. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-09-28 14:09:03 +02:00
clawbot added 1 commit 2026-09-28 14:11:01 +02:00
make lint calls script/lint, the only way golangci-lint is run. Inside a
container it runs the linter; anywhere else it builds Dockerfile.lint,
whose last step runs script/lint again. Both Dockerfiles set
container=docker to mark the container, since /.dockerenv is missing in
build steps and present on hosts that are themselves containers. The
Dockerfile lint stage runs make lint.

A new CACHEBUST build-arg on every run keeps the lint step from being
served from cache; a tmpfs mount keeps Go's and golangci-lint's caches
out of that step's layer, so runs do not pile up build cache.
script/bootstrap and the nix-shell package lists no longer carry
golangci-lint. golangci-lint config verify is not run: it fetches its
schema over an unpinned live HTTPS call.

Model: opus-4-8 (implementation); opus-5-5 (rework)
clawbot force-pushed issue-104-docker-lint from d548cb7a17 to 643a5ffd74 2026-09-28 14:11:01 +02:00 Compare
Author
Collaborator

Reworked against #122 (comment), rebased onto next:

  • script/bootstrap header: golangci-lint runs only inside a container, Dockerfile.lint or the Dockerfile lint stage.
  • Dockerfile lint-stage pin: now names Dockerfile.lint and says to change both pins together.

Model: opus-5-5

Reworked against https://git.eeqj.de/sneak/pixa/pulls/122#issuecomment-103585, rebased onto `next`: - `script/bootstrap` header: golangci-lint runs only inside a container, `Dockerfile.lint` or the `Dockerfile` lint stage. - `Dockerfile` lint-stage pin: now names `Dockerfile.lint` and says to change both pins together. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-09-28 14:15:51 +02:00
Author
Collaborator

PASS: both comment findings are fixed, and make lint now goes through script/lint everywhere, including both Dockerfiles.

Model: opus-5-5

PASS: both comment findings are fixed, and `make lint` now goes through `script/lint` everywhere, including both Dockerfiles. Model: opus-5-5
clawbot merged commit 2f7365cc9b into next 2026-09-28 14:27:35 +02:00
clawbot deleted branch issue-104-docker-lint 2026-09-28 14:27:36 +02:00
clawbot removed the needs-review label 2026-09-28 14:27:36 +02:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#122