# Enodia Sentinel Command Reference This is the operator-facing command contract for the current local agent. Commands are intentionally plain: they either inspect state, manage baselines, run the daemon, or expose existing evidence. Global options: ```bash enodia-sentinel --version enodia-sentinel -c /path/to/config.toml ``` If no command is provided, `run` is used. ## Service Commands ### `run` ```bash enodia-sentinel run ``` Starts the daemon loop. This is the command used by the systemd service. It builds or loads baselines, starts optional event monitoring, writes heartbeats, runs detector sweeps, captures snapshots, and sends notifications. Expected use: systemd, not an interactive shell. ### `check` ```bash enodia-sentinel check ``` Runs the enabled detector set once and prints alerts. This forces the SUID scan and arms baseline-gated detectors immediately, so it is useful for health checks and debugging. Exit code: - `0`: no alerts. - `0`: alerts may still print today; this command is currently human-oriented, not a strict CI gate. ### `baseline` ```bash enodia-sentinel baseline ``` Rebuilds listener and SUID baselines under `log_dir`. Use after installing on a known-good host or after intentionally adding persistent services or privileged helpers. Do not run this to silence unexplained findings. ## Detection and Integrity Commands ### `list-detectors` ```bash enodia-sentinel list-detectors ``` Prints the poll detectors and whether each is enabled by config. ### `rootcheck` ```bash enodia-sentinel rootcheck ``` Runs anti-rootkit cross-view checks once: - PIDs alive via `kill(pid, 0)` but missing from `/proc`. - PIDs visible in `/proc` but missing from `ps`. - Live modules in `/sys/module` but missing from `/proc/modules`. - Listening TCP ports in `/proc/net/tcp*` but missing from `ss`. - UDP ports in `/proc/net/udp*` but missing from `ss -u`. - Raw and special-protocol sockets in `/proc/net` but missing from `ss`. - Network interfaces in promiscuous mode. - Known rootkit module names. - Tainted loaded modules (`/sys/module/*/taint`) and global kernel taint (`/proc/sys/kernel/tainted`). Exit code: - `0`: no rootcheck findings. - `1`: one or more rootcheck alerts. ### `fim-baseline` ```bash enodia-sentinel fim-baseline ``` Builds the SHA-256 file integrity baseline for configured critical paths plus Sentinel's own footprint. Use on a known-good host. The package hook also calls `fim-update` after normal package transactions. ### `fim-update` ```bash enodia-sentinel fim-update ``` Refreshes the FIM baseline. This exists primarily for the package manager hook. Manual use should be treated as an acknowledgement that the current file state is legitimate. ### `fim-check` ```bash enodia-sentinel fim-check enodia-sentinel fim-check --packages ``` Diffs current file state against the FIM baseline. With `--packages`, also runs package-owned file verification through the package manager (`pacman -Qkk` on Arch). Exit code: - `0`: no baseline changes. - `1`: one or more added, removed, or modified files. ### `pkgdb-check` ```bash enodia-sentinel pkgdb-check ``` Checks whether the local package database fingerprint changed outside a logged package transaction. This catches an attacker rewriting stored package checksums to hide a modified binary. Exit code: - `0`: package DB matches the anchor or was legitimately re-anchored. - `1`: out-of-band DB tampering suspected. ### `pkgdb-verify` ```bash enodia-sentinel pkgdb-verify enodia-sentinel pkgdb-verify --sample 200 ``` Compares on-disk package-owned files to SHA-256 hashes from `.MTREE` manifests inside cached signed packages. This is independent of the mutable local package database. The command also flags insecure global `SigLevel` settings and warns if the pacman keyring is missing. Exit code: - `0`: sampled files match and signature policy is not downgraded. - `1`: a signed-package mismatch or insecure signature setting was found. ### `incident` ```bash enodia-sentinel incident list [--json] enodia-sentinel incident show [--json] enodia-sentinel incident export ``` Groups related alerts into incidents so one intrusion reads as one story instead of several disconnected alerts. Grouping is **process-lineage first** (alerts sharing a PID or a common ancestor — the web server or SSH session they descend from), with a **time-window fallback** for alerts that carry no live PID (FIM drift, package tamper, hidden modules). Each captured snapshot records an `incident_id`; the index lives in `incidents.json` under `log_dir`. - `list` — incidents newest-first: id, last seen, severity, alert count, and the signatures involved. - `show ` — incident summary plus a time-ordered timeline of its member snapshots (time, severity, signatures, PIDs, and the snapshot file to open). - `export ` — a single JSON bundle of the incident record with every member snapshot report inlined, suitable for handoff or offline analysis. Tuning lives in config: `incident_window` (how long an incident stays open for new alerts) and `incident_lineage_depth` (ancestors walked when correlating). Exit code: `0` on success; `1` if the incident id is unknown; `2` if `show`/ `export` is called without an id. ### `posture check` ```bash enodia-sentinel posture check enodia-sentinel posture check --json ``` Audits host configuration hygiene — the conditions that make a host *easy* to attack, as opposed to an attack in progress: - SSH: root login, password authentication, and empty-password logins. - sudo: passwordless (`NOPASSWD`) rules, disabled authentication, and group/world-writable sudoers files. - World-writable or non-root-owned `PATH` directories (binary-hijack vectors). - Loose permissions on sensitive files (`/etc/shadow`, `/etc/passwd`, ...). - Downgraded package-signature policy (`SigLevel`). Findings are advisory and reuse the standard alert JSON shape (`--json`). This command does not run inside the daemon and never blocks startup. Exit code: - `0`: no posture findings. - `1`: one or more findings. ## Evidence and Operator Commands ### `respond` ```bash enodia-sentinel respond plan enodia-sentinel respond plan --json ``` Builds a dry-run response plan from an incident's retained JSON snapshots. The plan may include evidence preservation, process freeze/terminate candidates, outbound IP blocks, systemd unit disablement, suspicious-file quarantine, package-restore lookup, and follow-up verification checks. This command is intentionally read-only: it prints commands for operator review and never executes them. The JSON schema is `enodia.response.plan.v1` and marks `apply_supported: false` until an audited apply workflow exists. Exit code: - `0`: plan generated. - `1`: unknown incident id. - `2`: missing incident id. ### `status` ```bash enodia-sentinel status enodia-sentinel status --json ``` Prints a local health and alert summary: daemon running state, heartbeat age and staleness, total alerts with per-severity counts, last alert time, and eBPF monitor state. `--json` emits the same data as the dashboard `/api/status` endpoint, for cron/monitoring. Exit code: - `0`: daemon is running and the heartbeat is fresh. - `1`: daemon is down or the heartbeat is stale. ### `web` ```bash enodia-sentinel web ``` Starts the read-only dashboard. By default it binds to the Tailscale interface when available and uses bearer-token authentication for non-loopback binds. HTTPS is mandatory. If `web_tls_cert` / `web_tls_key` are not configured, Sentinel creates a self-signed pair under `log_dir`; add a browser exception for that certificate or replace it with a private/local CA certificate. The console exposes incidents, alert snapshots, posture findings, event tail, and dry-run response plans. It remains read-only; response commands are displayed for review but not executed from the browser. Expected use: `enodia-sentinel-web.service`. ### `triage` ```bash enodia-sentinel triage ``` Reads captured alert JSON snapshots and classifies distinct findings as likely false positive or review-needed. It suggests config snippets for known benign noise but never edits config automatically. ### `watchdog` ```bash enodia-sentinel watchdog --url https://100.x.y.z:8787 --token --max-age 120 enodia-sentinel watchdog --url https://100.x.y.z:8787 --token --insecure-tls ``` Polls a remote dashboard and alerts if the sensor is down, unreachable, or has a stale heartbeat. Run this from a separate host. Use `--insecure-tls` only for the built-in self-signed certificate while you have no local/private CA trust path. A watchdog on the same machine does not prove the protected host is alive. Exit code: - `0`: remote sensor is reachable and fresh. - `1`: remote sensor is stale, down, or unreachable. ## Development Shortcuts The Makefile wraps common local tasks: ```bash make test make check make baseline make web make drill ``` `make install` installs a plain package directory plus a launcher wrapper. It does not require pip or a virtualenv. ## Future Command Contracts The roadmap reserves these command shapes: ```bash enodia-sentinel respond apply ``` State-changing response commands should be introduced with stable JSON schemas, audit logs, and tests before they are documented as supported.