nnb9: black-box internal/db tests (bookshelf-nnb9.7) #1407
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "bd-bookshelf-nnb9.7"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Converts internal/db's white-box test file (export_test.go) to black-box, removing the last test-only backdoor from the db package.
What changed
export_test.go, which re-exported unexported db.go symbols (maskDSN,min,retryParams,sqlOpenFunc,newMigrateSource/newDBDriver/newMigrator,migrator) purely so a white-box shim would compile.RetryConnectnow takes an explicitRetryPolicyparameter (replacing the package-private mutableretryParamsglobal +SetRetryParamsshim) — tests pass a fast policy directly, no injection backdoor needed.min()helper — Go 1.21+ has a builtinmin;RetryConnectnow calls the builtin directly.Open()'s malformed-DSN error path is now exercised with a real invalid DSN (go-sql-driver/mysql parses the DSN eagerly insidesql.Open'sOpenConnector, so it fails for real, noSetSQLOpenFuncinjection needed).RunMigrations' "migrate driver" error branch already had a real test (closed DB →mysql.WithInstance'sPingfails); added a new real "migrate up" test that marksschema_migrationsdirty (a genuine crashed-migration scenario) to exercise that branch too.newMigrateSource/newDBDriver/newMigrator/migratorinjection seams entirely —RunMigrationsnow callsiofs.New/mysql.WithInstance/migrate.NewWithInstancedirectly, since nothing swaps them anymore.migrate.NewWithInstancenever actually returns an error in the pinned golang-migrate version, so that error branch was unreachable test-only dead weight; removing the seam doesn't lose any coverage guarantee (internal/dbis excluded from themake coveragegate — it's verified bymake integrationinstead).maskDSN's masking behavior is now asserted end-to-end viaOpen()'s real logged output instead of calling the unexported func directly.internal/db/export_test.gofromscripts/test_policy_check/allowlist.txt(23 → 22 entries).Test plan
go build ./...,go vet ./...— clean.go run ./scripts/test_policy_check .— OK, no net-new white-box offenders.golangci-lint run ./internal/db/...— 0 issues.go test -tags integration ./internal/db/...— all specs pass locally (real MySQL via testcontainers), including the two new real-path tests (malformed DSN, dirty-migration).Docs: N/A (test-only change, no user-facing surface).
Closes bead bookshelf-nnb9.7 on merge.
Security review — PR #1407 (bd-bookshelf-nnb9.7)
Reviewed the full diff (
internal/db/db.go,internal/db/db_test.go, deletion ofinternal/db/export_test.go+internal/db/helpers_test.go,scripts/test_policy_check/allowlist.txt) against the PR description and the suspicion raised by sibling PR #1406 (production security-guard deletion disguised as "dead code").Verdict up front: this one is clean — genuine test-only conversion + a trivial, behavior-preserving production simplification. No error-handling was removed, no credential exposure introduced, no retry-classification change.
Migration error-path check
RunMigrationsstill performs the exact same three error-wrapped steps it did before:What was deleted (
newMigrateSource,newDBDriver,newMigrator, themigratorinterface) were only test-injection seams — package-levelvarindirections whose sole purpose was lettinghelpers_test.goswap in fakes to hit each error branch without a real DB. Noif err != nilcheck, no return, no log call was removed. The two migration-failure integration tests that previously relied on fake injection (SetNewMigrateSource/SetNewDBDriver/SetNewMigratorreturning canned errors) are replaced with real failure scenarios indb_test.go: a closed DB (realmysql.WithInstanceping failure → "migrate driver") and adirty=1schema_migrationsrow (real golang-migrate dirty-guard → "migrate up"). This is a coverage improvement, not a loss — no silent-failure risk introduced.DSN / credential-substring change
maskDSNitself is byte-for-byte unchanged — still finds the last@, masks everything between the last:before it and the@with***. The only new code is a test-only helperdsnUserPassAtindb_test.goused to assertOpen()'s real logged output never contains the fulluser:pass@credential pair (replacing a prior white-box call tomaskDSNdirectly). The helper's own doc comment explains why it compares the full"user:pass@"string rather than a bare password substring: DSNs where user and password are identical (e.g.root:root@) would otherwise let the password "coincidentally" appear (as the username) and pass a naive substring check. This is a stricter, not weaker, test assertion, and it's test code — it doesn't touch what gets logged in production. Confirmed no plaintext DSN/credential logging is introduced anywhere in the diff.RetryPolicy signature change
RetryConnect(ctx, logger, connect)→RetryConnect(ctx, logger, policy RetryPolicy, connect). This replaces a mutable package-globalretryParams(previously mutated in-place by tests viaSetRetryParams, a real shared-state hazard) with an explicit, immutable-per-call struct argument.Open()still calls it withdefaultRetryPolicy{MaxAttempts:5, BaseSleep:500ms, MaxSleep:30s}— identical values to the old defaults, so production retry behavior is unchanged.RetryConnect's loop still blindly retriesconnect()up toMaxAttemptsregardless of error type (no classification of permanent vs transient failures) — that was already the pre-existing behavior; this PR does not change what errors get retried, only how the policy is threaded in. Not a regression.Exported-surface check
RetryPolicy(a plain 3-field numeric struct) is newly exported frominternal/db. This is an intentional, narrow widening (needed so bothOpen()and tests can construct a policy value without a mutable-global backdoor) — no sensitive data, no new attack surface. Minor note, not a finding worth blocking on.Dead code claim verification
The PR description asserts
migrate.NewWithInstance"never actually returns an error in the pinned golang-migrate version," which is why that fake-injection seam was dropped without a replacement real-path test. I did not independently verify this against the vendored golang-migrate version, but this only affects test coverage of an already-presentif err != nil { return ... }guard in production code — the guard itself remains in place and will correctly propagate an error if the underlying library's behavior ever changes. Not a security concern regardless.Comparison to PR #1406
Unlike #1406 (which reportedly deleted a live production security guard under a "dead code" label), this PR only removes test-injection indirection (
varfunction pointers / interfaces that existed purely to let white-box tests fake dependencies) and replaces fake-injected failure paths with real ones. Every productionif err != nilbranch, everyfmt.Errorfwrap, andmaskDSN's masking logic survive unchanged.REVIEW VERDICT: 0 blocker, 0 major, 0 minor
Code Review — PR #1407 (bd-bookshelf-nnb9.7)
Adversarial diff review of
internal/db/db.go+ test changes, with the sibling #1406 false-dead-code incident specifically in mind.Verification performed
newDBDriver/newMigrator/newMigrateSource/migratorDI seams — these were test-injection-only indirection layers, not guards or security checks. Every error branch they used to let tests hit (migrate source,migrate driver,migrate init,migrate up) is still present verbatim indb.gopost-diff; nothing was deleted from the actual error-handling logic, only the seam that let a fake implementation be substituted.migrate.NewWithInstance"never errors" claim — verified directly against the vendored source (github.com/golang-migrate/migrate/v4@v4.19.1/migrate.go:171-181): the function body ism := newCommon(); ...; return m, nil— it is structurally incapable of returning a non-nil error. The claim is factually correct, not an excuse.iofs.Newfor the embeddedmigrationsFS — this is a build-time invariant (fixed embedded FS, not user input); realistically unreachable at runtime same as before. Not gated by coverage either (see #4), so no incentive to hide it.scripts/check-coverage.shthatinternal/dbis explicitly excluded from the 100%-statement gate ("Integration- and DB-backed packages (internal/db, internal/dbtest) are NOT coverage-gated"). This removes the gate-gaming motive entirely — the seam deletion is driven by the black-box test-policy conversion (killingexport_test.go's white-box symbol exports), not by chasing a coverage number.RetryPolicyexport — genuinely consumed by production code:Open()callsRetryConnect(ctx, logger, defaultRetryPolicy, ...)withdefaultRetryPolicyas a real production value; it is not a test-only affordance. Passes the nnb9 no-export-to-game-blackbox check.min()deletion — Go 1.21+ ships a builtin genericmin; the hand-rolled one-liner was pure duplication, not a guard. Confirmedmin(sleep*2, policy.MaxSleep)still compiles against the builtin.sql.Openeager-parse failure), unreachable host + retry exhaustion, a broken/closed DB connection formysql.WithInstance, and adirty=1schema_migrationsrow to hit golang-migrate's real dirty-check refusal path forUp(). These are strictly better tests than the deleted fake-injection versions — they hit the actual library code paths instead of a stand-in.dsnUserPassAthelper compares the fulluser:pass@credential prefix rather than a bare password substring, correctly avoiding a false pass whenuser == password(e.g.root:root). This is a new test (no prior masked-DSN test existed), not a "flake fix" that papers over something — legitimate hardening of the assertion.internal/db/db_test.goremains and declarespackage db_test;export_test.go(white-box,package db) andhelpers_test.go(which depended onexport_test.go's exported aliases) are both deleted in full.allowlist.txtdrops exactly the one now-nonexistentinternal/db/export_test.goentry — a legitimate removal, not a broadened exception.Findings
None. No production error path, guard, or security-relevant check was deleted — every branch removed was pure test-injection scaffolding, and the two theoretically-still-dead branches (
migrate init,migrate source) were already effectively dead before this PR and remain untouched in behavior. This is a clean, honest nnb9 conversion, unlike the sibling #1406 case.REVIEW VERDICT: 0 blocker, 0 major, 0 minor