Migrate canonical .golangci.yml to gomodguard_v2, with a block list #55

Open
clawbot wants to merge 1 commits from gomodguard-v2-with-settings into main
Collaborator

Speculative, and closing it costs nothing. It is the option-2 answer to
sneak's ruling of 2026-08-19 on
sneak/homoicon#4 ("option 2. owner approves
policy exception in this one case only. update the config for the
updated linter"), where option 2 was migrate to the successor with
settings
. The minimal fix, #47,
which disabled the old linter and added no settings, was closed
unmerged; canonical therefore still emits the deprecation warning that
#25 tracks.

The change

golangci-lint v2.12.0 deprecated gomodguard, and this config sets
linters.default: all, so the deprecated linter is enabled everywhere
and warns on every run — in the same output where the evidence that a
check actually ran lives.

  • gomodguard stays in linters.disable, now grouped with wsl under
    a comment saying why a deprecated linter is retired by disabling the
    old name. The warning is attached to the old linter, so silencing it
    means removing that one, not adding the new one.
  • gomodguard_v2 is named in linters.enable. default: all already
    enables it; naming it is what gives the settings block below a visible
    owner.
  • linters.settings.gomodguard_v2.blocked gets four entries.

The v2 settings schema is a flat list of - module: entries, not v1's
list-of-single-key-maps, and local-replace-directives has moved to the
top level of the settings block. Checked against upstream's
.golangci.next.reference.yml at the pinned v2.12.2, not from memory,
and the file passes golangci-lint config verify under that version.
local-replace-directives is not set: that would be new policy.

What is blocked, and why only this

Every entry restates a decision already recorded in the Go package
defaults. Nothing here is a new rule.

Blocked module Use instead
github.com/rs/zerolog log/slog
github.com/go-redis/redis (pre-fork, unversioned) github.com/redis/go-redis/v9
github.com/sergi/go-diff github.com/aymanbagabas/go-udiff
github.com/hexops/gotextdiff github.com/aymanbagabas/go-udiff

Entries match the module path exactly (v2's default match-type), so
the versioned successor paths are untouched: blocking
github.com/go-redis/redis does not touch github.com/redis/go-redis/v9.

Deliberately not blocked, though the defaults name a winner for each:

  • github.com/google/uuid — it is the current default, not a rejected
    one. It gets replaced only when a stdlib uuid lands.
  • github.com/urfave/cli (cobra is the default) and the old unversioned
    github.com/go-chi/chi (chi/v5 is the default) — older repos are
    still on them and migrate opportunistically. Blocking them canonically
    would turn a re-vendor into a red gate in repos that have done nothing
    wrong. Follow-up: add both once those migrations have landed. A
    canonical config that reddens the fleet on re-vendor is worse than the
    warning it removes.

Dropped after checking the fleet (see below): github.com/mattn/go-sqlite3,
gorm.io/gorm, github.com/pmezard/go-difflib. All three are recorded
rejections, and all three are required by repos that vendor this file
today, so shipping them would break those repos on their next re-vendor.

Fleet verification

Each vendoring repo's go.mod read through the Gitea API, checked
against the candidate block list. d = direct require, i = indirect.

  • attrsum — clean
  • bsfirehose — mattn/go-sqlite3 (d), gorm.io/gorm (i) — both dropped
  • cattbox — clean
  • dnswatcher — pmezard/go-difflib (i) — dropped
  • mfer — pmezard/go-difflib (i) — dropped
  • pixa — clean
  • rgoue — clean
  • secret — pmezard/go-difflib (i) — dropped
  • sfdupes — clean
  • simplelog — clean
  • upaas — mattn/go-sqlite3 (d), pmezard/go-difflib (i) — dropped
  • vaultik — pmezard/go-difflib (i) — dropped
  • webhooker — gorm.io/gorm (d), mattn/go-sqlite3 (i), pmezard/go-difflib (i) — dropped

No repo requires any of the four modules that shipped.

The settings are actually applied

A mistyped settings key is silently ignored, and a config that applies
nothing is indistinguishable from a clean run. Against a Go corpus
through its own dockerized lint entrypoint at the pinned v2.12.2, the
committed config plus three temporary probe entries produced 12 findings
attributed to gomodguard_v2 and a non-zero exit; the probe entries were
then removed. Two further results fell out of the same run:

  • An exact-match entry catches a subpackage import, so blocking
    github.com/sergi/go-diff will catch .../go-diff/diffmatchpatch.
  • A module that is only an indirect requirement, never imported,
    produces no finding.

With the committed config alone, that corpus lints clean with no
deprecation warning.

Hashes, and what has to happen after a merge

  • old .golangci.yml: 021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb
  • new .golangci.yml: 769af9e07ca2f1420da869640c7bc781ce40dac83772d493575bebe686a96ed9

Every repo vendoring this file must re-vendor after merge. They
verify by sha256 and will mismatch the moment this lands: dnswatcher,
webhooker, vaultik, rgoue, cattbox, sfdupes, attrsum, upaas, simplelog,
mfer, secret, bsfirehose, pixa.

homoicon is a special case. Its copy carries an authorized divergence —
a header comment recording the owner-approved agent edit of 2026-08-07 —
under the one-case exception granted in
sneak/homoicon#4. A re-vendor there must
carry that comment forward, not drop it, and
sneak/homoicon#632 is the open item that will
do the re-vendor.

Disclosures

  • Judgement call: wsl moved two lines down so it sits with gomodguard
    under a shared "deprecated" comment. No behaviour change; it does widen
    the diff on a file you own.
  • Judgement call: pmezard/go-difflib is an indirect requirement only —
    testify pulls it — in all six repos that have it, and the probe above
    shows an indirect-only requirement produces no finding, so it would
    probably have been safe. It was dropped anyway, because the rule this
    PR followed is "required by any repo, direct or indirect, means drop".
    It is the cheapest entry to add back if you would rather have it.
  • #25 also asks for the new
    sha256 to be recorded in REPO_POLICIES.md. Not done here: no hash is
    published there today, so there is nothing to update, and adding a hash
    register is a separate decision. That issue is therefore not fully
    satisfied by this PR and is left open.
  • Partially verified: the corpus run proves the settings block is parsed
    and enforced, and that no shipped entry fires on that corpus. It does
    not execute the linter against each of the 13 vendoring repos; the
    per-repo claim above rests on reading their go.mod files.
  • golangci-lint config verify resolves its JSON schema over a live
    network fetch, so treat its pass as corroboration of the schema, not as
    the proof. The proof is the probe findings.
  • TODO.md gains a Completed Steps entry in the same commit, per its
    Workflow section. The repo's Next Step is unrelated and untouched.
Speculative, and closing it costs nothing. It is the option-2 answer to sneak's ruling of 2026-08-19 on https://git.eeqj.de/sneak/homoicon/issues/4 ("option 2. owner approves policy exception in this one case only. update the config for the updated linter"), where option 2 was *migrate to the successor with settings*. The minimal fix, https://git.eeqj.de/sneak/prompts/pulls/47, which disabled the old linter and added no settings, was closed unmerged; canonical therefore still emits the deprecation warning that https://git.eeqj.de/sneak/prompts/issues/25 tracks. ## The change `golangci-lint` v2.12.0 deprecated `gomodguard`, and this config sets `linters.default: all`, so the deprecated linter is enabled everywhere and warns on every run — in the same output where the evidence that a check actually ran lives. - `gomodguard` stays in `linters.disable`, now grouped with `wsl` under a comment saying why a deprecated linter is retired by disabling the old name. The warning is attached to the old linter, so silencing it means removing that one, not adding the new one. - `gomodguard_v2` is named in `linters.enable`. `default: all` already enables it; naming it is what gives the settings block below a visible owner. - `linters.settings.gomodguard_v2.blocked` gets four entries. The v2 settings schema is a flat list of `- module:` entries, not v1's list-of-single-key-maps, and `local-replace-directives` has moved to the top level of the settings block. Checked against upstream's `.golangci.next.reference.yml` at the pinned v2.12.2, not from memory, and the file passes `golangci-lint config verify` under that version. `local-replace-directives` is not set: that would be new policy. ## What is blocked, and why only this Every entry restates a decision already recorded in the Go package defaults. Nothing here is a new rule. | Blocked module | Use instead | | --- | --- | | `github.com/rs/zerolog` | `log/slog` | | `github.com/go-redis/redis` (pre-fork, unversioned) | `github.com/redis/go-redis/v9` | | `github.com/sergi/go-diff` | `github.com/aymanbagabas/go-udiff` | | `github.com/hexops/gotextdiff` | `github.com/aymanbagabas/go-udiff` | Entries match the module path exactly (v2's default `match-type`), so the versioned successor paths are untouched: blocking `github.com/go-redis/redis` does not touch `github.com/redis/go-redis/v9`. **Deliberately not blocked**, though the defaults name a winner for each: - `github.com/google/uuid` — it is the current default, not a rejected one. It gets replaced only when a stdlib uuid lands. - `github.com/urfave/cli` (cobra is the default) and the old unversioned `github.com/go-chi/chi` (chi/v5 is the default) — older repos are still on them and migrate opportunistically. Blocking them canonically would turn a re-vendor into a red gate in repos that have done nothing wrong. **Follow-up**: add both once those migrations have landed. A canonical config that reddens the fleet on re-vendor is worse than the warning it removes. **Dropped after checking the fleet** (see below): `github.com/mattn/go-sqlite3`, `gorm.io/gorm`, `github.com/pmezard/go-difflib`. All three are recorded rejections, and all three are required by repos that vendor this file today, so shipping them would break those repos on their next re-vendor. ## Fleet verification Each vendoring repo's `go.mod` read through the Gitea API, checked against the candidate block list. `d` = direct require, `i` = indirect. - attrsum — clean - bsfirehose — `mattn/go-sqlite3` (d), `gorm.io/gorm` (i) — both dropped - cattbox — clean - dnswatcher — `pmezard/go-difflib` (i) — dropped - mfer — `pmezard/go-difflib` (i) — dropped - pixa — clean - rgoue — clean - secret — `pmezard/go-difflib` (i) — dropped - sfdupes — clean - simplelog — clean - upaas — `mattn/go-sqlite3` (d), `pmezard/go-difflib` (i) — dropped - vaultik — `pmezard/go-difflib` (i) — dropped - webhooker — `gorm.io/gorm` (d), `mattn/go-sqlite3` (i), `pmezard/go-difflib` (i) — dropped No repo requires any of the four modules that shipped. ## The settings are actually applied A mistyped settings key is silently ignored, and a config that applies nothing is indistinguishable from a clean run. Against a Go corpus through its own dockerized lint entrypoint at the pinned v2.12.2, the committed config plus three temporary probe entries produced 12 findings attributed to `gomodguard_v2` and a non-zero exit; the probe entries were then removed. Two further results fell out of the same run: - An exact-match entry catches a **subpackage** import, so blocking `github.com/sergi/go-diff` will catch `.../go-diff/diffmatchpatch`. - A module that is only an **indirect** requirement, never imported, produces no finding. With the committed config alone, that corpus lints clean with no deprecation warning. ## Hashes, and what has to happen after a merge - old `.golangci.yml`: `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb` - new `.golangci.yml`: `769af9e07ca2f1420da869640c7bc781ce40dac83772d493575bebe686a96ed9` **Every repo vendoring this file must re-vendor after merge.** They verify by sha256 and will mismatch the moment this lands: dnswatcher, webhooker, vaultik, rgoue, cattbox, sfdupes, attrsum, upaas, simplelog, mfer, secret, bsfirehose, pixa. `homoicon` is a special case. Its copy carries an authorized divergence — a header comment recording the owner-approved agent edit of 2026-08-07 — under the one-case exception granted in https://git.eeqj.de/sneak/homoicon/issues/4. A re-vendor there must **carry that comment forward, not drop it**, and https://git.eeqj.de/sneak/homoicon/issues/632 is the open item that will do the re-vendor. ## Disclosures - Judgement call: `wsl` moved two lines down so it sits with `gomodguard` under a shared "deprecated" comment. No behaviour change; it does widen the diff on a file you own. - Judgement call: `pmezard/go-difflib` is an indirect requirement only — testify pulls it — in all six repos that have it, and the probe above shows an indirect-only requirement produces no finding, so it would probably have been safe. It was dropped anyway, because the rule this PR followed is "required by any repo, direct or indirect, means drop". It is the cheapest entry to add back if you would rather have it. - https://git.eeqj.de/sneak/prompts/issues/25 also asks for the new sha256 to be recorded in `REPO_POLICIES.md`. Not done here: no hash is published there today, so there is nothing to update, and adding a hash register is a separate decision. That issue is therefore not fully satisfied by this PR and is left open. - Partially verified: the corpus run proves the settings block is parsed and enforced, and that no shipped entry fires on that corpus. It does not execute the linter against each of the 13 vendoring repos; the per-repo claim above rests on reading their `go.mod` files. - `golangci-lint config verify` resolves its JSON schema over a live network fetch, so treat its pass as corroboration of the schema, not as the proof. The proof is the probe findings. - `TODO.md` gains a Completed Steps entry in the same commit, per its Workflow section. The repo's Next Step is unrelated and untouched.
clawbot added the needs-review label 2026-08-31 03:54:50 +02:00
sneak was assigned by clawbot 2026-08-31 03:54:50 +02:00
clawbot added 1 commit 2026-08-31 03:54:51 +02:00
Migrate canonical .golangci.yml to gomodguard_v2 with a block list
All checks were successful
check / check (push) Successful in 9s
bb19029f53
golangci-lint v2.12.0 deprecated gomodguard, and `linters.default: all`
enables it, so every lint run in every consuming Go repo prints a
deprecation warning. Disable the old name, which is what silences the
warning; name gomodguard_v2 in linters.enable so the settings block has
a visible owner; give it a blocked module list.

The block list restates only decisions already recorded in the Go
package defaults: zerolog, the pre-fork go-redis/redis, sergi/go-diff
and hexops/gotextdiff. Recorded rejections that repos vendoring this
file still require are deliberately absent, so a re-vendor cannot
redden a repo that has done nothing wrong.
All checks were successful
check / check (push) Successful in 9s
Required
Details
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin gomodguard-v2-with-settings:gomodguard-v2-with-settings
git checkout gomodguard-v2-with-settings
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/prompts#55