mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
ci: add InTx linter replacing ruleguard rule (#24422)
Replace the old `InTx` ruleguard rule in `scripts/rules.go` with a custom in-tree `go/analysis` analyzer under `scripts/intxcheck/`. The new analyzer catches the same direct and pass-through misuse classes as before, plus two new classes the pattern-matcher couldn't reach: - **Indirect same-package helper misuse** — flags `p.someHelper(ctx)` inside `InTx` when the helper body uses the outer store (the PR #24369 bug class). - **Nested dangerous closures** — descends into `go func() { ... }()`, `defer func() { ... }()`, and immediately-invoked function literals. The analyzer uses semantic `types.Object` identity instead of raw expression string comparison, which avoids false positives from closure-local shadowing and catches simple aliases like `outer := s.db` and `alias := s`. This PR also fixes three real outer-store-inside-transaction bugs the new analyzer surfaced: - `coderd/wsbuilder/wsbuilder.go`: `FindMatchingPresetID` and `getWorkspaceTask` now use the inner transaction store instead of `b.store`. - `enterprise/dbcrypt/dbcrypt.go`: `ensureEncrypted` now calls `s.InsertDBCryptKey` (the tx-wrapped store) instead of `db.InsertDBCryptKey`. The `dbCrypt.InTx` method wraps the raw tx in a new `*dbCrypt`, so `s.InsertDBCryptKey` still dispatches through the encryption layer. Two call sites need `// intxcheck:ignore` suppressions. Both are one-off patterns that only look like misuse because the analyzer doesn't track assignments — proving them safe would require full dataflow analysis, which is well beyond what a targeted lint like this should attempt: - `coderd/database/dbfake/dbfake.go` — `b.db` is reassigned to `tx` on the preceding line, so `b.doInTX()` actually uses the transaction. The analyzer sees the original `b.db` identity and flags it. - `coderd/database/db_test.go` — test intentionally passes the outer store to `require.Equal` to assert that nested `InTx` returns the same handle. Suppressions use `// intxcheck:ignore` instead of `//nolint:intxcheck` because `intxcheck` runs as a standalone `go/analysis` tool outside golangci-lint. golangci-lint's `nolintlint` checker flags `//nolint` directives for linters it doesn't control, so we use a custom comment prefix to avoid that conflict.
This commit is contained in:
@@ -248,52 +248,6 @@ func useStandardTimeoutsAndDelaysInTests(m dsl.Matcher) {
|
||||
Report("Do not use magic numbers in test timeouts and delays. Use the standard testutil.Wait* or testutil.Interval* constants instead.")
|
||||
}
|
||||
|
||||
// InTx checks to ensure the database used inside the transaction closure is the transaction
|
||||
// database, and not the original database that creates the tx.
|
||||
func InTx(m dsl.Matcher) {
|
||||
// ':=' and '=' are 2 different matches :(
|
||||
m.Match(`
|
||||
$x.InTx(func($y) error {
|
||||
$*_
|
||||
$*_ = $x.$f($*_)
|
||||
$*_
|
||||
})
|
||||
`, `
|
||||
$x.InTx(func($y) error {
|
||||
$*_
|
||||
$*_ := $x.$f($*_)
|
||||
$*_
|
||||
})
|
||||
`).Where(m["x"].Text != m["y"].Text).
|
||||
At(m["f"]).
|
||||
Report("Do not use the database directly within the InTx closure. Use '$y' instead of '$x'.")
|
||||
|
||||
// When using a tx closure, ensure that if you pass the db to another
|
||||
// function inside the closure, it is the tx.
|
||||
// This will miss more complex cases such as passing the db as apart
|
||||
// of another struct.
|
||||
m.Match(`
|
||||
$x.InTx(func($y database.Store) error {
|
||||
$*_
|
||||
$*_ = $f($*_, $x, $*_)
|
||||
$*_
|
||||
})
|
||||
`, `
|
||||
$x.InTx(func($y database.Store) error {
|
||||
$*_
|
||||
$*_ := $f($*_, $x, $*_)
|
||||
$*_
|
||||
})
|
||||
`, `
|
||||
$x.InTx(func($y database.Store) error {
|
||||
$*_
|
||||
$f($*_, $x, $*_)
|
||||
$*_
|
||||
})
|
||||
`).Where(m["x"].Text != m["y"].Text).
|
||||
At(m["f"]).Report("Pass the tx database into the '$f' function inside the closure. Use '$y' over $x'")
|
||||
}
|
||||
|
||||
// HttpAPIErrorMessage intends to enforce constructing proper sentences as
|
||||
// error messages for the api. A proper sentence includes proper capitalization
|
||||
// and ends with punctuation.
|
||||
|
||||
Reference in New Issue
Block a user