Record tray applet completion and SID coverage design draft

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>
This commit is contained in:
Luna 2026-07-04 06:37:07 -07:00
parent afbc63ffbd
commit 2d23e8b878
3 changed files with 88 additions and 1 deletions

View file

@ -0,0 +1,72 @@
# 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 |
|---|---|
| 100001100004 | eBPF exec rules (`events/rules.py`) |
| 100010100016 | poll detectors (inline sids) |
| 100017100021, 100026100027 | FIM / pkgdb / pkgverify |
| 100022100025, 100028100031, 100034100035, 100037100038 | rootcheck |
| 100032100033, 100036, 100039, 100048 | poll detectors (constants) |
| 100040100047, 100050100051 | posture |
| 100060100066 | 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)
1. **Deliverable:** coverage gate + fixtures (not fixtures-only, not bash
harness extension).
2. **Registry:** new product module `enodia_sentinel/sids.py` — aggregates
existing constants by importing them (no renumbering, no moving
definitions) into a `BUILTIN_SIDS` table: `sid`, `name`, `engine`,
defining module.
3. **Gate proof:** emission-based. The gate runs every drill for real and
asserts the union of emitted alert `sid`s 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 format `rules test` accepts, 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 (fake
`SystemState`, 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).