Skip to content

Commit 20f76ba

Browse files
committed
feat: ruleguard to prevent pubsub.Publish in tx
Signed-off-by: Danny Kopping <dannykopping@gmail.com>
1 parent 83df557 commit 20f76ba

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

scripts/rules.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,38 @@ func databaseImport(m dsl.Matcher) {
134134
Where(m.File().PkgPath.Matches("github.com/coder/coder/v2/codersdk"))
135135
}
136136

137+
// publishInTransaction detects calls to Publish inside database transactions
138+
// which can lead to connection deadlocks or other unexpected behavior.
139+
//
140+
//nolint:unused,deadcode,varnamelen
141+
func publishInTransaction(m dsl.Matcher) {
142+
m.Import("github.com/coder/coder/v2/coderd/database/pubsub")
143+
144+
// Match direct calls to the Publish method of a pubsub instance inside InTx
145+
m.Match(`
146+
$db.InTx(func($tx $dbType) $retType {
147+
$*_
148+
$ps.Publish($*args)
149+
$*_
150+
}, $*txopts)
151+
`).
152+
Where(m["ps"].Type.Implements("pubsub.Pubsub") ||
153+
m["ps"].Text.Matches(`\w+\.pubsub`) ||
154+
m["ps"].Text.Matches(`pubsub\.\w+`)).
155+
Report("Avoid calling Publish inside database transactions as this may lead to connection deadlocks. Move the Publish call outside the transaction.")
156+
157+
// Also catch publish calls on nested fields like c.pubsub.Publish()
158+
m.Match(`
159+
$db.InTx(func($tx $dbType) $retType {
160+
$*_
161+
$ps.$field.Publish($*args)
162+
$*_
163+
}, $*txopts)
164+
`).
165+
Where(m["field"].Text == "pubsub").
166+
Report("Avoid calling Publish inside database transactions as this may lead to connection deadlocks. Move the Publish call outside the transaction.")
167+
}
168+
137169
// doNotCallTFailNowInsideGoroutine enforces not calling t.FailNow or
138170
// functions that may themselves call t.FailNow in goroutines outside
139171
// the main test goroutine. See testing.go:834 for why.

0 commit comments

Comments
 (0)