cra-ai-14 Data at rest — ECB/DES/3DES (python) + node createCipher
Delivery. Rules ship in the binary via include_str! and stage to a temp file at scan time, added as a second --config next to --config=auto — no Dockerfile/volume change, resilient (falls back to auto rules if staging fails).
Wiring.control-map gains controls_for_finding(tool, cwe?, rule_id?); custom controls bind by rule id with cwe: [] so a broad CWE can't over-attribute and let the grounded 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. LUT: cra-ai-1,7,10,14 needs_tooling→covered (covered 9→13).
Validated: all 9 rules fire on positive fixtures, 0 on a clean fixture. Green locally (clippy -D warnings, fmt, full test suite; control-map 4→7 tests, +1 triage test).
Next: B2 (grounded checker + retrieval for the absence-based controls), B3 (mark the 4 pure-architectural as not_code_checkable).
First slice of **B** (hybrid coverage for the 16 needs_tooling CRA controls): the pattern-expressible subset, done deterministically.
**Detectors** (`compliance-agent/rules/cra_semgrep.yaml`, 9 rules):
- `cra-ai-1` Secure-by-Default — flask/django `debug=True`, `verify=False`, CORS `*`
- `cra-ai-7` Strong auth — password/secret via md5/sha1 (metavariable-gated to password-ish args)
- `cra-ai-10` Session mgmt — `Secure`/`HttpOnly = false` cookies (python + express)
- `cra-ai-14` Data at rest — ECB/DES/3DES (python) + node `createCipher`
**Delivery.** Rules ship in the binary via `include_str!` and stage to a temp file at scan time, added as a second `--config` next to `--config=auto` — no Dockerfile/volume change, resilient (falls back to auto rules if staging fails).
**Wiring.** `control-map` gains `controls_for_finding(tool, cwe?, rule_id?)`; custom controls bind **by rule id** with `cwe: []` so a broad CWE can't over-attribute and let the grounded 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. LUT: cra-ai-1,7,10,14 needs_tooling→covered (covered **9→13**).
**Validated:** all 9 rules fire on positive fixtures, 0 on a clean fixture. Green locally (clippy -D warnings, fmt, full test suite; control-map 4→7 tests, +1 triage test).
Next: B2 (grounded checker + retrieval for the absence-based controls), B3 (mark the 4 pure-architectural as not_code_checkable).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
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>
sharang
merged commit 38fedc661b into main2026-07-21 12:31:20 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
First slice of B (hybrid coverage for the 16 needs_tooling CRA controls): the pattern-expressible subset, done deterministically.
Detectors (
compliance-agent/rules/cra_semgrep.yaml, 9 rules):cra-ai-1Secure-by-Default — flask/djangodebug=True,verify=False, CORS*cra-ai-7Strong auth — password/secret via md5/sha1 (metavariable-gated to password-ish args)cra-ai-10Session mgmt —Secure/HttpOnly = falsecookies (python + express)cra-ai-14Data at rest — ECB/DES/3DES (python) + nodecreateCipherDelivery. Rules ship in the binary via
include_str!and stage to a temp file at scan time, added as a second--confignext to--config=auto— no Dockerfile/volume change, resilient (falls back to auto rules if staging fails).Wiring.
control-mapgainscontrols_for_finding(tool, cwe?, rule_id?); custom controls bind by rule id withcwe: []so a broad CWE can't over-attribute and let the grounded judge FP-drop a genuine finding.rule_id_matchestolerates semgrep's path prefix on local check_ids. Triage now maps by rule id too. LUT: cra-ai-1,7,10,14 needs_tooling→covered (covered 9→13).Validated: all 9 rules fire on positive fixtures, 0 on a clean fixture. Green locally (clippy -D warnings, fmt, full test suite; control-map 4→7 tests, +1 triage test).
Next: B2 (grounded checker + retrieval for the absence-based controls), B3 (mark the 4 pure-architectural as not_code_checkable).
🤖 Generated with Claude Code