a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
140 lines
5.3 KiB
Go
140 lines
5.3 KiB
Go
package astquery
|
|
|
|
// Cross-language hygiene rules. Lower severity than SAST proper —
|
|
// these are debugging-print / dev-debugger leftovers / dead asserts.
|
|
// Category is CategoryHygiene so an agent can run `analyze sast` and
|
|
// keep them out of the security bundle when they don't want noise.
|
|
|
|
func init() {
|
|
registerHygieneJSConsoleLog()
|
|
registerHygieneJSDebugger()
|
|
registerHygienePyPrint()
|
|
registerHygienePyPdbSetTrace()
|
|
registerHygienePyBreakpoint()
|
|
registerHygieneRubyByebug()
|
|
registerHygieneFmtPrintln()
|
|
registerHygienePhpVarDump()
|
|
registerHygieneJavaStackTrace()
|
|
}
|
|
|
|
func registerHygieneJSConsoleLog() {
|
|
pat := `((call_expression
|
|
function: (member_expression object: (identifier) @obj property: (property_identifier) @fn)) @match
|
|
(#eq? @obj "console") (#match? @fn "^(log|debug|info)$"))`
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-js-console-log",
|
|
Description: "`console.log(...)` / `console.debug` / `console.info` in non-test source — leaks debug payloads to production. Use a structured logger.",
|
|
Severity: "info",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{"javascript": pat, "typescript": pat},
|
|
})
|
|
}
|
|
|
|
func registerHygieneJSDebugger() {
|
|
pat := `(debugger_statement) @match`
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-js-debugger",
|
|
Description: "`debugger;` statement in non-test source — pauses execution when devtools are open. Never ship.",
|
|
Severity: "warning",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{"javascript": pat, "typescript": pat},
|
|
})
|
|
}
|
|
|
|
func registerHygienePyPrint() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-py-print",
|
|
Description: "`print(...)` in non-test source — debug leftover. Use a logger.",
|
|
Severity: "info",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"python": `((call function: (identifier) @fn) @match (#eq? @fn "print"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygienePyPdbSetTrace() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-py-pdb-set-trace",
|
|
Description: "`pdb.set_trace()` / `ipdb.set_trace()` / `pudb.set_trace()` — debugger entrypoint left in source. Crashes production on hit.",
|
|
Severity: "error",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"python": `((call function: (attribute object: (identifier) @mod attribute: (identifier) @fn)) @match
|
|
(#match? @mod "^(pdb|ipdb|pudb|pdbpp)$") (#eq? @fn "set_trace"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygienePyBreakpoint() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-py-breakpoint",
|
|
Description: "`breakpoint()` — the 3.7+ shortcut for `pdb.set_trace()`. Crashes production on hit unless `PYTHONBREAKPOINT=0`.",
|
|
Severity: "warning",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"python": `((call function: (identifier) @fn) @match (#eq? @fn "breakpoint"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygieneRubyByebug() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-ruby-byebug",
|
|
Description: "`byebug` / `binding.pry` — debugger entrypoint. Crashes production on hit (or worse, leaks an interactive shell over stderr).",
|
|
Severity: "error",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"ruby": `((call method: (identifier) @fn) @match (#match? @fn "^(byebug|pry)$"))
|
|
((call receiver: (call method: (identifier) @b) method: (identifier) @fn) @match
|
|
(#eq? @b "binding") (#match? @fn "^(pry|irb)$"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygieneFmtPrintln() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-go-fmt-println",
|
|
Description: "`fmt.Println(...)` / `fmt.Printf(...)` in non-test Go source — debug leftover. Use a structured logger (`slog`, `zap`).",
|
|
Severity: "info",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"go": `((call_expression function: (selector_expression operand: (identifier) @pkg field: (field_identifier) @fn)) @match
|
|
(#eq? @pkg "fmt") (#match? @fn "^(Println|Printf|Print)$"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygienePhpVarDump() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-php-var-dump",
|
|
Description: "`var_dump($x)` / `print_r($x)` / `var_export($x)` — debug-dump functions. Leaks structure / credentials to the response in production.",
|
|
Severity: "warning",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"php": `((function_call_expression function: (name) @fn) @match (#match? @fn "^(var_dump|print_r|var_export|debug_print_backtrace)$"))`,
|
|
},
|
|
})
|
|
}
|
|
|
|
func registerHygieneJavaStackTrace() {
|
|
mustRegisterSAST(sastRule{
|
|
Name: "hygiene-java-printstacktrace",
|
|
Description: "`e.printStackTrace()` in non-test Java source — writes to stderr only; production loggers miss the entry. Use a logger.",
|
|
Severity: "info",
|
|
Category: CategoryHygiene,
|
|
Tags: []string{"hygiene", "debug-leftover"},
|
|
Pat: map[string]string{
|
|
"java": `((method_invocation name: (identifier) @fn) @match (#eq? @fn "printStackTrace"))`,
|
|
},
|
|
})
|
|
}
|