11 KiB
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:
enodia-sentinel --version
enodia-sentinel -c /path/to/config.toml <command>
If no command is provided, run is used.
Service Commands
run
enodia-sentinel run
Starts the daemon loop. This is the command used by the systemd service. It builds or loads baselines, starts optional exec/syscall event monitoring, writes heartbeats, runs detector sweeps, captures snapshots, and sends notifications.
Expected use: systemd, not an interactive shell.
check
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
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
enodia-sentinel list-detectors
Prints the poll detectors and whether each is enabled by config.
rules
enodia-sentinel rules list
enodia-sentinel rules list --json
enodia-sentinel rules show <sid>
enodia-sentinel rules show <sid> --json
enodia-sentinel rules test <event-json>
enodia-sentinel rules test <event-json> --json
Inspects and tests event-driven detection rules without reading source code.
rules list includes built-in exec/syscall rules plus configured exec rules
from exec_rules_file. rules show <sid> prints the rule metadata and match
conditions. rules test <event-json> loads an exec or syscall event JSON file,
runs the matching rule engine, and prints any alerts that would fire. Use -
instead of a path to read the event JSON from stdin.
Exec event JSON shape:
{
"pid": 42,
"ppid": 1,
"uid": 1000,
"parent_comm": "nginx",
"filename": "/bin/sh",
"argv": ["-c", "id"]
}
Syscall event JSON shape:
{
"pid": 42,
"ppid": 1,
"uid": 1000,
"comm": "payload",
"syscall": "mprotect",
"args": [0, 4096, 6, 0, 0, 0]
}
Exit code:
0: list/show succeeded, orrules testmatched at least one rule.1: unknown sid forshow, or no rule matched fortest.2: malformed sid, missing target, unreadable JSON, or unsupported event shape.
rootcheck
enodia-sentinel rootcheck
Runs anti-rootkit cross-view checks once:
- PIDs alive via
kill(pid, 0)but missing from/proc. - PIDs visible in
/procbut missing fromps. - Live modules in
/sys/modulebut missing from/proc/modules. - Listening TCP ports in
/proc/net/tcp*but missing fromss. - UDP ports in
/proc/net/udp*but missing fromss -u. - Raw and special-protocol sockets in
/proc/netbut missing fromss. - 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
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
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
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
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
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
enodia-sentinel incident list [--json]
enodia-sentinel incident show <incident-id> [--json]
enodia-sentinel incident export <incident-id>
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 <id>— incident summary plus a time-ordered timeline of its member snapshots (time, severity, signatures, PIDs, and the snapshot file to open).export <id>— 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
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
PATHdirectories (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
enodia-sentinel respond plan <incident-id>
enodia-sentinel respond plan <incident-id> --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. Each CLI-generated plan is also saved under
<log_dir>/response-plans/, and a compact JSONL audit record is appended to
<log_dir>/response-audit.log with the plan id, incident id, action count, and
saved path. The JSON schema is enodia.response.plan.v1 and marks
apply_supported: false until an audited apply workflow exists. Dashboard/API
plan previews remain read-only and do not create new artifacts.
Exit code:
0: plan generated.1: unknown incident id.2: missing incident id.
status
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
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-rule metadata, 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
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
enodia-sentinel watchdog --url https://100.x.y.z:8787 --token <token> --max-age 120
enodia-sentinel watchdog --url https://100.x.y.z:8787 --token <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:
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:
enodia-sentinel respond apply <plan-id>
State-changing response commands should be introduced with stable JSON schemas, audit logs, and tests before they are documented as supported.