diff --git a/CLAUDE.md b/CLAUDE.md index a925cd8..1760599 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ Primary functions: ## Current State Snapshot -As of 2026-06-16, the project is a local-first Linux IDS/IPS/EDR agent at +As of 2026-07-04, the project is a local-first Linux IDS/IPS/EDR agent at package version `0.7.0`. The branch has a working stdlib-only daemon, CLI, HTTPS management console, incident model, response planner, rootcheck, posture checks, file/package integrity checks, push notification backends, and optional @@ -70,6 +70,11 @@ Implemented investigation/response state: further change, identity kinds (listener/suid) retire on TTL or revoke. The filter runs at the daemon chokepoint, `fim-check`, and the dashboard integrity API. +- An optional desktop tray applet (`enodia-sentinel-tray`, `[tray]` extra with + pystray/Pillow) opens the dashboard, controls the daemon via systemctl, and + runs `check --json` quick checks. Its logic modules (`tray/state.py`, + `actions.py`, `notify.py`) are GUI-free and tested; only `tray/app.py` + imports GUI libs, and the core agent stays stdlib-only. - IPS behavior is currently explicit workflow: posture hardening plus reviewed dry-run containment actions. There is no automatic inline blocking or silent host mutation yet. @@ -109,6 +114,10 @@ Start with: signatures. - If you add config keys, update `config/enodia-sentinel.toml`, README, and the relevant docs. +- Multiple agent sessions may share this checkout. Before committing, check + `git status` for uncommitted edits you did not make; never sweep foreign + hunks into your commit (stage only your own changes) and never stash or + revert them. ## Current Architecture @@ -131,6 +140,9 @@ Start with: - `posture.py` performs advisory host hygiene checks. - `reconcile.py` owns the acknowledged-drift store and the `filter_alerts` chokepoint that suppresses operator-accepted FIM/package/listener/SUID drift. +- `tray/` is the optional desktop tray frontend over the CLI and systemctl; + only `tray/app.py` may import `pystray`/`PIL` (enforced by an import-guard + test). ## Current Threat Mapping diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index d069081..98b13e2 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -105,6 +105,9 @@ Purpose: define a stable single-host product. Dracula, Solarized Dark/Light, and Twilight palettes. - ✅ Add dashboard theme contrast/visual smoke checks so readable text and meaningful status colors are preserved across every palette. +- ✅ Add an optional desktop tray applet (`enodia-sentinel-tray`, `[tray]` + extra): dashboard launcher, systemd daemon control, status at a glance, and + `check --json` quick checks, with GUI-free tested logic modules. - Keep the dashboard read-only unless a separate authenticated write path is designed and reviewed. diff --git a/docs/superpowers/specs/2026-07-04-sid-drill-coverage-design.md b/docs/superpowers/specs/2026-07-04-sid-drill-coverage-design.md new file mode 100644 index 0000000..df59094 --- /dev/null +++ b/docs/superpowers/specs/2026-07-04-sid-drill-coverage-design.md @@ -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 | +|---|---| +| 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) + +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/-.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).