Compare commits

..

1 Commits

Author SHA1 Message Date
efb0cea1c2 Suppress the revive package-name findings with no fix (closes #61)
All checks were successful
check / check (pull_request) Successful in 3m11s
Three findings remain that cannot be fixed without making a repo-wide
naming decision, so each carries a per-site //nolint directive with its
justification.

revive var-naming (internal/log, internal/crypto, internal/types):
fixing these means renaming packages across the whole codebase, which
is the repo owner's call, not a lint fix. Neither stdlib log nor stdlib
crypto is imported anywhere in the repo, so nothing is actually
shadowed today. The rename decision is tracked in issue #76. revive
reports a package-name failure only once per package directory, on
whichever file it happens to lint first, so every file of the affected
packages carries the directive and lists nolintlint alongside revive so
the ones that lose the race are not reported as unused.

No gosec directives are needed: the pinned golangci-lint v2.12.2 that
CI and the Dockerfile use reports nothing at the term.IsTerminal
conversions in internal/log and internal/ui or at the os.Remove calls
in internal/vaultik/verify.go, so suppressing there would itself fail
nolintlint as an unused directive.

Verification is script/cibuild, which builds the hash-pinned lint
image: it exits 0, with make lint reporting "0 issues" under the
canonical .golangci.yml (sha256
021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb,
unmodified), plus make fmt-check, make test and the release build. That
also unblocks issue #59. make check is not a valid gate here: script/lint
runs whatever golangci-lint is on PATH rather than the pinned version,
which is tracked in issue #78.

Also corrects the capacity comment in collectBatchFlushData: an empty
file contributes no chunk mappings, so the pending-file count is a
rough starting capacity, not a lower bound.

TODO.md: record this work, note that the previous next step (reconciling
uncommitted ARCHITECTURE.md edits) needed no work because the tree is
clean, and move the next step on to the stale-branch triage.
2026-08-09 02:13:57 +00:00
5 changed files with 25 additions and 26 deletions

25
TODO.md
View File

@@ -20,15 +20,22 @@ or delete the branch.
# Completed Steps # Completed Steps
- 2026-08-09: Finished the lint remediation under the canonical - 2026-08-09: Finished the lint remediation under the canonical
`.golangci.yml` (issue #61, which also unblocks issue #59). Fixed the `.golangci.yml` (issue #61, which also unblocks issue #59). The
last 80 findings behavior-preservingly `wsl_v5` 60, `sqlclosecheck` remaining findings were fixed behavior-preservingly: `wsl_v5`
10, `gosec` 4, `prealloc` 3, `revive` 3 — so `make check` now exits 0 whitespace, `sqlclosecheck`, and `prealloc`. The `sqlclosecheck` sites
on `main`. The `sqlclosecheck` sites now close `sql.Rows` in a now close `sql.Rows` in a deferred closure instead of via the
deferred closure instead of via the `CloseRows` helper, which the `CloseRows` helper, which the linter could not see through. Only the
linter could not see through; the four `gosec` and three `revive` `revive` package-name findings remain suppressed, with per-site
findings carry per-site `//nolint` directives with justifications, and `//nolint` directives; the package-rename question behind them is
the package-rename question behind the `revive` ones is tracked in tracked in issue #76. Verified with `script/cibuild`, which exits 0 —
issue #76. that is the only trustworthy gate, because `script/lint` runs whatever
`golangci-lint` happens to be on `PATH` rather than the pinned
v2.12.2 that CI and the `Dockerfile` use, so `make check` can report
green on findings CI still fails. That tooling gap is tracked in issue
#78.
- 2026-08-09: The earlier next step "reconcile the uncommitted
`ARCHITECTURE.md` edits on `main`" needed no work: the working tree is
clean and `ARCHITECTURE.md` is committed on `main`.
- 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned - 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned
(`Dockerfile` lint stage, `Makefile` deps target), replaced (`Dockerfile` lint stage, `Makefile` deps target), replaced
`.golangci.yml` with the canonical config (v2 schema, `default: all`), `.golangci.yml` with the canonical config (v2 schema, `default: all`),

View File

@@ -69,10 +69,8 @@ func Initialize(cfg Config) {
Level: level, Level: level,
} }
// Check if stdout is a TTY. term.IsTerminal takes an int, and a file // Check if stdout is a TTY.
// descriptor always fits in one on every platform Go supports; a if term.IsTerminal(int(os.Stdout.Fd())) {
// closed file yields -1, which IsTerminal reports as not a terminal.
if term.IsTerminal(int(os.Stdout.Fd())) { //nolint:gosec // G115: fd fits in int
// Use colorized TTY handler // Use colorized TTY handler
logger = slog.New(NewTTYHandler(os.Stdout, opts)) logger = slog.New(NewTTYHandler(os.Stdout, opts))
} else { } else {

View File

@@ -624,9 +624,10 @@ func (s *Scanner) collectBatchFlushData(
collectStart := time.Now() collectStart := time.Now()
// Every pending file contributes at least one file-chunk and one // A pending file contributes one mapping of each kind per chunk, and
// chunk-file mapping, so the file count is a safe lower bound for the // an empty file contributes none, so the file count is only a rough
// initial capacity of both slices. // starting capacity for the mapping slices; append grows them as
// needed. It is exact for the file and file-ID slices.
allFileChunks := make([]database.FileChunk, 0, len(canFlush)) allFileChunks := make([]database.FileChunk, 0, len(canFlush))
allChunkFiles := make([]database.ChunkFile, 0, len(canFlush)) allChunkFiles := make([]database.ChunkFile, 0, len(canFlush))
allFileIDs := make([]types.FileID, 0, len(canFlush)) allFileIDs := make([]types.FileID, 0, len(canFlush))

View File

@@ -113,10 +113,7 @@ func shouldColor(w io.Writer) bool {
return false return false
} }
// term.IsTerminal takes an int, and a file descriptor always fits in return term.IsTerminal(int(f.Fd()))
// one on every platform Go supports; a closed file yields -1, which
// IsTerminal reports as not a terminal.
return term.IsTerminal(int(f.Fd())) //nolint:gosec // G115: fd fits in int
} }
// ───────────────────────── message methods ───────────────────────── // ───────────────────────── message methods ─────────────────────────

View File

@@ -306,10 +306,6 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error)
return nil, fmt.Errorf("failed to create temp file: %w", err) return nil, fmt.Errorf("failed to create temp file: %w", err)
} }
// tempPath is generated by os.CreateTemp above and never derives from
// user input, but gosec's G703 taint analysis treats every path that
// originates from an *os.File as tainted, so the os.Remove calls
// below carry per-site nolint directives.
tempPath := tempFile.Name() tempPath := tempFile.Name()
// Stream decompress directly to file // Stream decompress directly to file
@@ -318,7 +314,7 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error)
written, err := io.Copy(tempFile, decompressor) written, err := io.Copy(tempFile, decompressor)
if err != nil { if err != nil {
_ = tempFile.Close() _ = tempFile.Close()
_ = os.Remove(tempPath) //nolint:gosec // G703: path from os.CreateTemp _ = os.Remove(tempPath)
return nil, fmt.Errorf("failed to decompress database: %w", err) return nil, fmt.Errorf("failed to decompress database: %w", err)
} }
@@ -330,7 +326,7 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error)
// Open the database // Open the database
db, err := sql.Open("sqlite", tempPath) db, err := sql.Open("sqlite", tempPath)
if err != nil { if err != nil {
_ = os.Remove(tempPath) //nolint:gosec // G703: path from os.CreateTemp _ = os.Remove(tempPath)
return nil, fmt.Errorf("failed to open database: %w", err) return nil, fmt.Errorf("failed to open database: %w", err)
} }