Update the CLAUDE.md snapshot and roadmap for the merged tray applet, note the shared-checkout commit hygiene rule, and save the agreed SID drill coverage design as a draft spec. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3 KiB
3 KiB
SID Drill Coverage Design
Status: Draft — design agreed in session Q&A, spec not yet user-reviewed. No implementation plan written yet.
Goal: Fixture or drill coverage for every built-in SID, enforced by a CI gate that cannot rot: adding a detection without a drill fails the suite.
Context
Enodia Sentinel has 53 built-in SIDs across six engines:
| Range | Engine |
|---|---|
| 100001–100004 | eBPF exec rules (events/rules.py) |
| 100010–100016 | poll detectors (inline sids) |
| 100017–100021, 100026–100027 | FIM / pkgdb / pkgverify |
| 100022–100025, 100028–100031, 100034–100035, 100037–100038 | rootcheck |
| 100032–100033, 100036, 100039, 100048 | poll detectors (constants) |
| 100040–100047, 100050–100051 | posture |
| 100060–100066 | eBPF syscall rules (events/syscall_rules.py) |
Existing engine test files cover most behavior but nothing proves per-SID completeness, and the bash red-team harness covers only ~9 core signatures.
Decisions (from brainstorming Q&A)
- Deliverable: coverage gate + fixtures (not fixtures-only, not bash harness extension).
- Registry: new product module
enodia_sentinel/sids.py— aggregates existing constants by importing them (no renumbering, no moving definitions) into aBUILTIN_SIDStable:sid,name,engine, defining module. - Gate proof: emission-based. The gate runs every drill for real and
asserts the union of emitted alert
sids equals the registry exactly, in both directions.
Components
enodia_sentinel/sids.py— canonical SID table plus a sanity test (uniqueness, matches imported constants).tests/fixtures/sids/<sid>-<slug>.json— one event JSON per exec-rule and syscall-rule SID, in the exact formatrules testaccepts, so each fixture doubles as an operator drill (enodia-sentinel rules test tests/fixtures/sids/100001-*.json).tests/sid_drills.py—DRILLS: dict[int, Callable[[], list[Alert]]]for non-event engines. Each drill builds minimal fake state (fakeSystemState, monkeypatched rootcheck views, temp FIM tree, posture file fakes — same styles the existing tests use) and invokes the real engine code.tests/test_sid_coverage.py— the gate: replays all fixtures through the real rule engines, runs all drills, and asserts emitted sids == registry. Failure messages name the uncovered or unregistered SID.
Docs
docs/RULES.md: short "drill fixtures" note documenting the fixture naming convention and replay command.docs/ROADMAP.md: tick the per-SID fixture/drill item when implemented.
Out of scope (YAGNI)
- Extending the bash red-team harness — live-host drills for rootkit-module, kernel-taint, and pkg-DB-tamper SIDs are not safely simulable on a real host.
- Correlation SIDs — none exist yet; the gate will catch them when they land.
Execution note
Implement in an isolated git worktree: a concurrent session holds uncommitted
edits in this checkout (triage/enrichment work touching cli.py,
respond.py, snapshot.py, event sources, and docs).