CI / Check (push) Skipped
CI / Check (pull_request) Successful in 5m50s
CI / Detect Changes (pull_request) Skipped
CI / Deploy Agent (pull_request) Skipped
CI / Deploy Dashboard (pull_request) Skipped
CI / Deploy Docs (pull_request) Skipped
CI / Deploy MCP (pull_request) Skipped
Covers the pattern-expressible slice of the needs_tooling bucket that no off-the-shelf ruleset digs out, keeping detection deterministic (LLM only FP-filters downstream, never detects): - cra-ai-1 Secure-by-Default: flask/django debug, TLS verify=False, CORS '*' - cra-ai-7 Strong auth: password/secret hashed with md5/sha1 (metavar-gated) - cra-ai-10 Session mgmt: Secure/HttpOnly = false cookies (py + express) - cra-ai-14 Data at rest: ECB/DES/3DES + node createCipher Rules ship in the binary (include_str!) and stage to a temp file at scan time, added as a second --config alongside --config=auto (no deploy/volume change). Wiring: control-map gains controls_for_finding (match by CWE and/or rule id); custom controls bind by rule id with cwe:[] so a broad CWE can't over-attribute and let the judge FP-drop a genuine finding. rule_id_matches tolerates semgrep's path prefix on local check_ids. Triage now maps by rule id too (a custom finding carries no LUT CWE). LUT: cra-ai-1,7,10,14 needs_tooling->covered (covered 9->13). Validated: all 9 rules fire on positive fixtures, 0 on clean. ControlCheckSpec gains Serialize/Deserialize (unrelated-safe; already used by the index cache). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>