Start a per-subsystem behavioral specification under docs/behavior/ that
documents the current Python agent's observable behavior at reimplementation
fidelity. It is the parity contract for the Go 2.0 rewrite (Active Migration
Track), complementing the product-oriented docs/SPECIFICATION.md.
Section 1 covers system-state capture, the daemon sweep loop, alert dedup, the
detector registry gating, and the baseline lifecycle — including three
behaviors the port must match exactly: baselines are rebuilt (not loaded) at
daemon start, arming is time-based via baseline_grace, and first_seen's
initialized flag persists across restarts while listener/SUID baselines
re-learn every start.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D36ffwoga57opftxzJVHPW
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>
Optional desktop system-tray applet as a thin launcher over the existing
CLI and systemd. Core agent stays stdlib-only; tray ships as an optional
[tray] extra (pystray + Pillow). Covers menu actions, icon state, error
handling, packaging, and testing seams.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements the v0.9 roadmap item from the approved design spec. Operators
accept a specific FIM/package/listener/SUID drift item with a mandatory
reason; the ack suppresses that one alert only while the live state still
matches the recorded fingerprint. Content kinds (fim/pkgfile) re-alert on
further change; identity kinds (listener/suid) retire on TTL or revoke.
- reconcile.py: ReconcileStore (mtime-cached, fails closed on missing/corrupt
store), fingerprint builders, and the filter_alerts chokepoint.
- CLI: baseline accept/revoke/list with --reason/--expires/--force/--stale/--json.
- Wired at the daemon sweep + eBPF chokepoint, fim-check, and /api/integrity.
- RECONCILE_V1 schema, config knob, COMMAND_REFERENCE/SCHEMAS/OPERATIONS/ROADMAP
docs, and reconcile unit/CLI/integration tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers the v0.9 roadmap item: accept legitimate FIM/package/listener/SUID
drift with a mandatory reason and audited fingerprint-bound ack store.
Approach A selected: ReconcileStore with re-alert-on-fingerprint-change,
optional TTL, and stale tracking. Filter applied at daemon chokepoint,
CLI fim check, and dashboard API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Close the remaining v0.8 posture bullet: flag enabled systemd units with
group/world-writable unit files (systemd_unit_writable, sid 100050) and
units whose ExecStart binary runs from a writable/unsafe path such as
/tmp, /dev/shm, /var/tmp, /home, or /run/user (systemd_exec_unsafe_path,
sid 100051).
- posture.systemd_findings/parse_systemctl_show/read_systemd_units, wired
into posture.run() behind the new posture_systemd config knob.
- read_systemd_units shells out to systemctl with timeouts and fails closed
on non-systemd hosts; the dashboard /api/posture surfaces findings for free.
- Unit tests for the parser and evaluator; TestRunIntegration patches the
new reader so run() never touches live systemctl.
- Docs: COMMAND_REFERENCE posture list, ROADMAP v0.8 bullet, RUNBOOKS
Runbook 2 triggers, config TOML knob.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface integrity and watchdog state in the read-only dashboard via a new
/api/integrity endpoint and integrity_report(): watchdog/heartbeat
verdict, FIM baseline and package-DB anchor freshness, pacman keyring and
SigLevel posture, and Sentinel's own self-integrity footprint. The
endpoint summarizes existing anchors and heartbeats only — it runs no live
FIM or package verification from the request path, keeping the dashboard
read-only.
Add the enodia.integrity.v1 schema (schemas.py + docs/SCHEMAS.md) with a
contract test, a new "Integrity" dashboard tab and summary metric, and
web tests for the report shape, schema contract, endpoint, and console
wiring. Docs updated; completes the v1.0 "dashboard to local console"
roadmap item.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collapse related alerts into one incident, process-lineage first with a
time-window fallback. Each alert batch's flagged PIDs are walked up the
/proc PPid chain into a lineage set (excluding pid 0/1 so everything
doesn't correlate through init); batches whose lineage sets intersect —
sharing a process or a common ancestor like the web server or SSH
session — join the same incident. PID-less batches (FIM drift, package
tamper, hidden modules) fall back to the most recently active open
incident within incident_window.
snapshot.capture now computes lineage and records each snapshot into a
JSON incident index (incidents.json), writing incident_id into both the
report JSON (report level, so the per-alert schema is untouched) and the
text header. New commands:
incident list incidents newest-first, with signatures
incident show <id> summary + time-ordered snapshot timeline
incident export <id> JSON bundle: record + inlined snapshots
The lineage/assign cores are pure functions; record() serializes the
index under a lock (capture runs from sweep + eBPF threads) and is
best-effort so an index problem never loses a snapshot. 17 new tests
(lineage, assign, record, and an end-to-end capture→group→CLI path).
Config: incident_tracking / incident_window / incident_lineage_depth.
Docs + sample config updated; closes the last v0.8 roadmap item.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Red-team harness: every detector now has a named drill with an expected
signature/sid, shown by `sentinel-redteam --list`. Add the missing
`egress` drill (the one detector without one) — explicit-only, since it
is the sole drill that emits real outbound traffic. After firing, the
harness runs `enodia-sentinel check` and reports PASS/MISS per poll
detection, turning it into a shared regression check.
Add docs/RUNBOOKS.md: confirm/preserve/contain/recover playbooks for
reverse shells & egress, persistence, trojaned binaries / package
tampering, hidden listeners & rootkits, and sensor tampering — each tied
to the real signatures, sids, and commands. Linked from README and the
OPERATIONS alert workflow.
Both close the remaining smaller v0.8 roadmap items.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `enodia-sentinel status [--json]` — a local health and alert
summary: daemon running state, heartbeat freshness, per-severity alert
counts, last alert time, and eBPF state. Reuses web.daemon_status (the
same data behind /api/status), so the CLI and dashboard never diverge.
Exit code reflects health (0 = running and fresh, 1 = down or stale), so
it doubles as a cron/monitoring probe. Three CLI tests drive it against a
temp log_dir; no daemon or root needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>