diff --git a/TODO.md b/TODO.md index 17d8258..0a9463f 100644 --- a/TODO.md +++ b/TODO.md @@ -14,16 +14,29 @@ pre-1.0 # Next Step -Reconcile the uncommitted ARCHITECTURE.md edits on main: finish and -commit, or revert. +Triage the stale remote branches (issue #71): for each, merge the work +or delete the branch. # Completed Steps +- 2026-08-09: Finished the lint remediation under the canonical + `.golangci.yml` (issue #61, which also unblocks issue #59). Fixed the + last 80 findings behavior-preservingly — `wsl_v5` 60, `sqlclosecheck` + 10, `gosec` 4, `prealloc` 3, `revive` 3 — so `make check` now exits 0 + on `main`. The `sqlclosecheck` sites now close `sql.Rows` in a + deferred closure instead of via the `CloseRows` helper, which the + linter could not see through; the four `gosec` and three `revive` + findings carry per-site `//nolint` directives with justifications, and + the package-rename question behind the `revive` ones is tracked in + issue #76. - 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned (`Dockerfile` lint stage, `Makefile` deps target), replaced `.golangci.yml` with the canonical config (v2 schema, `default: all`), - and remediated all lint findings it surfaced (issue #61): - behavior-preserving fixes across every package, `make check` green. + and remediated the bulk of the lint findings it surfaced (issue #61): + behavior-preserving fixes across every package, 2,990 findings down to + 80. `make test` and `make fmt-check` were green at that point but + `make lint` was still red; the commit message claiming `make check` + was green was wrong. - 2026-08-07: Added the standard `.golangci.yml` and `.editorconfig` (issue #59); lint findings under the new config are tracked in issue #61. `script/bootstrap` now installs sqlite3 (needed by tests). @@ -49,6 +62,4 @@ commit, or revert. # Future Steps -- Review stale local branches (add-godoc-to-cli-package, - feature/pluggable-storage-backend) and merge or delete them. - Define remaining scope for a first tagged release and cut v0.1.0. diff --git a/internal/crypto/encryption.go b/internal/crypto/encryption.go index 36c2564..04f36dd 100644 --- a/internal/crypto/encryption.go +++ b/internal/crypto/encryption.go @@ -1,6 +1,6 @@ // Package crypto provides thread-safe age encryption and decryption // helpers used to protect blob and metadata content. -package crypto +package crypto //nolint:revive,nolintlint // stdlib crypto unused; see #76 import ( "bytes" diff --git a/internal/log/log.go b/internal/log/log.go index 17025ca..a1544a6 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -1,6 +1,6 @@ // Package log provides the application-wide structured logger: slog // with a colorized TTY handler on terminals and JSON output otherwise. -package log +package log //nolint:revive,nolintlint // stdlib log unused here; see #76 import ( "context" @@ -69,8 +69,10 @@ func Initialize(cfg Config) { Level: level, } - // Check if stdout is a TTY - if term.IsTerminal(int(os.Stdout.Fd())) { + // Check if stdout is a TTY. term.IsTerminal takes an int, and a file + // descriptor always fits in one on every platform Go supports; a + // 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 logger = slog.New(NewTTYHandler(os.Stdout, opts)) } else { diff --git a/internal/log/module.go b/internal/log/module.go index 525f969..f428604 100644 --- a/internal/log/module.go +++ b/internal/log/module.go @@ -1,4 +1,4 @@ -package log +package log //nolint:revive,nolintlint // stdlib log unused here; see #76 import ( "go.uber.org/fx" diff --git a/internal/log/tty_handler.go b/internal/log/tty_handler.go index e787de8..cfdf4f9 100644 --- a/internal/log/tty_handler.go +++ b/internal/log/tty_handler.go @@ -1,4 +1,4 @@ -package log +package log //nolint:revive,nolintlint // stdlib log unused here; see #76 import ( "context" diff --git a/internal/types/types.go b/internal/types/types.go index c076f41..5310179 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -2,7 +2,7 @@ // vaultik codebase. Using distinct types for IDs, hashes, paths, and // credentials prevents accidental mixing of semantically different values // that happen to share the same underlying type. -package types +package types //nolint:revive,nolintlint // rename decision tracked in #76 import ( "database/sql/driver" diff --git a/internal/ui/ui.go b/internal/ui/ui.go index 8216c83..afb1c7a 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -113,7 +113,10 @@ func shouldColor(w io.Writer) bool { return false } - return term.IsTerminal(int(f.Fd())) + // term.IsTerminal takes an int, and a file descriptor always fits in + // 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 ───────────────────────── diff --git a/internal/vaultik/verify.go b/internal/vaultik/verify.go index 07d1e01..8f06c48 100644 --- a/internal/vaultik/verify.go +++ b/internal/vaultik/verify.go @@ -306,6 +306,10 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error) 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() // Stream decompress directly to file @@ -314,7 +318,7 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error) written, err := io.Copy(tempFile, decompressor) if err != nil { _ = tempFile.Close() - _ = os.Remove(tempPath) + _ = os.Remove(tempPath) //nolint:gosec // G703: path from os.CreateTemp return nil, fmt.Errorf("failed to decompress database: %w", err) } @@ -326,7 +330,7 @@ func (v *Vaultik) decryptAndLoadDatabase(reader io.ReadCloser) (*tempDB, error) // Open the database db, err := sql.Open("sqlite", tempPath) if err != nil { - _ = os.Remove(tempPath) + _ = os.Remove(tempPath) //nolint:gosec // G703: path from os.CreateTemp return nil, fmt.Errorf("failed to open database: %w", err) }