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>
Add `enodia-sentinel posture check` — a config-hygiene audit that finds
the conditions making a host easy to attack, complementing the live
detectors. Checks: SSH root/password/empty-password login (Include-aware,
first-wins sshd resolution), passwordless and group/world-writable
sudoers, world-writable or non-root PATH directories, loose permissions
on sensitive files (/etc/shadow, /etc/passwd, ...), and downgraded
package-signature policy (reusing pkgdb.siglevel_alert).
Findings reuse the Alert type, so they serialize through the existing
JSON/triage pipeline (`posture check --json`). Each check is a pure
evaluator over injected content/stat facts plus a thin system reader, so
the 18 new tests need no root or live /etc. Posture is command-driven and
never runs in the daemon loop, per the v0.8 exit criterion.
SIDs 100040-100047 (classtype host-posture). Sample config and docs
(COMMAND_REFERENCE, OPERATIONS, ROADMAP, SPECIFICATION) updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>