lint: add config-versioning robustness cops + fix v6/v7 package names#2568
Merged
dgageot merged 4 commits intodocker:mainfrom Apr 28, 2026
Merged
Conversation
Files in pkg/config/v6/ and pkg/config/v7/ declared 'package latest' instead of 'package v6' / 'package v7'. This was a copy-paste artifact from when those directories were the work-in-progress 'latest' version and got frozen without renaming the package clause. The bug stayed compilable only because every importer used an explicit alias (v6, v7, previous), masking the fact that the actual package name was 'latest'. Assisted-By: docker-agent
Adds three new cops to ./lint and fixes a regex bug in the existing ConfigVersionImport cop. New cops: - Lint/ConfigPackageName: files under pkg/config/<dir>/ must declare 'package <dir>' (with the standard '<dir>_test' exception for black-box tests). This catches the package-clause copy-paste bug that historically slipped into v6 and v7. - Lint/ConfigVersionConstant: 'const Version' in pkg/config/vN/ must equal "N". Guards against version-constant / directory-name drift during freeze. - Lint/LatestImportsPredecessor: pkg/config/latest/ may only import the highest existing vN sibling, not arbitrary historical versions. Bug fix: ConfigVersionImport's path regexes required a leading '/', so they silently never matched when running 'go run ./lint .' (the form used by 'mise lint'). Anchored with '(?:^|/)' and added a black-box test package skip to keep latest_test files happy. Assisted-By: docker-agent
Each of the four cops re-implemented its own path parsing and offense
construction. This commit factors the common ground into a single
helper file and slims every cop down to its rule.
Changes:
- New lint/configpath.go centralises:
* configDir(filename) — name of the dir under pkg/config/
* versionFromDir("vN") — N or false
* versionFromImport(path) — N if path ends in pkg/config/vN
* importPath(*ast.ImportSpec) — unquoted import path
* offense(c, fset, node, msg) — Offense covering an AST node
* highestSiblingVersion(...) — cached scan for the highest vN
- ConfigVersionImport: extracted a pure importViolation() function so
the rule reads as a flat switch over the import path; folded the two
inline checkVersionedImport / checkLatestImport helpers away.
- LatestImportsPredecessor: dropped the bespoke mutex+map cache in
favour of the shared sync.Map-backed helper.
- main.go: cops are now declared in a single var slice, making it
obvious where to register new ones.
- 4 regexes → 2; ~130 lines of duplication removed; per-cop file size
down to 50–90 lines.
Behaviour is unchanged: all four cops still flag the same regressions
(verified by injecting and reverting four faults across the config
chain) and all pkg/config/... tests pass.
Assisted-By: docker-agent
- Add black-box test file exemption to LatestImportsPredecessor cop (consistent with ConfigVersionImport and ConfigPackageName) - Check strconv.Atoi error in versionFromImport for consistency - Use 'must' instead of 'should' in error message for consistency Assisted-By: docker-agent
gtardif
approved these changes
Apr 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds three new project-specific linter cops under
./lint/to harden thepkg/config/versioned-schema invariants, fixes a latent regex bug in theexisting
Lint/ConfigVersionImportcop that prevented it from firingunder
mise lint, and corrects 16 stalepackage latestdeclarations inpkg/config/v6/andpkg/config/v7/.Bugs caught and fixed
pkg/config/v6/*.goandpkg/config/v7/*.godeclaredpackage latestinstead of
package v6/package v7. Copy-paste artifact from when thosedirectories were the work-in-progress version. Stayed compilable only
because every importer used an explicit alias (
v6,v7,previous).Lint/ConfigVersionImport's path regexes required a leading/, sothey never matched when invoked as
go run ./lint .(the formmise lintuses). Anchored with
(?:^|/)and added a black-box test-package skip.New cops
Lint/ConfigPackageNamepkg/config/<dir>/must declarepackage <dir>(allowing<dir>_testfor black-box tests). Catches the v6/v7 class of bug.Lint/ConfigVersionConstantconst Version = "N"inpkg/config/vN/must literally be"N". Guards against version-constant / directory-name drift.Lint/LatestImportsPredecessorpkg/config/latest/may only import the highest existingvN/sibling, not arbitrary historical versions. Closes a gap inLint/ConfigVersionImportfor the latest case.Architecture
A small shared helper file
lint/configpath.gocentralises path/versionparsing so each cop is small (50–90 LOC) and focused on its rule:
configDir(filename)→ name of the dir underpkg/config/versionFromDir("vN")→NorfalseversionFromImport(path)→Nif path ends inpkg/config/vNimportPath(*ast.ImportSpec)→ unquoted import pathoffense(c, fset, node, msg)→Offensecovering an AST nodehighestSiblingVersion(...)→ cached scan for the highestvN(sync.Map-backed)Cops are registered in a single
var cops = []cop.Cop{...}slice inmain.go— adding a new cop is one line.Validation
mise lint→golangci-lint: 0 issues; custom cops: 880 files, 0 offenses;go mod tidy --diff: clean.mise test→ all packages pass.Lint/ConfigPackageName)Versionconstant (Lint/ConfigVersionConstant)Lint/LatestImportsPredecessor)Lint/ConfigVersionImport)Lint/ConfigVersionImport)Commits
fix(config): use proper package names for v6 and v7— 16 files, package clause only.lint: add config-versioning robustness cops— adds 3 new cops + fixes the path regex bug in the existing one.lint: extract shared config-path helpers to simplify cops— refactor; ~130 lines of duplication removed across cops.fix(lint): add test file exemption and improve error handling— review-fix pass: black-box test exemption inLatestImportsPredecessor, explicitstrconv.Atoierror handling, error-message wording consistency.