8.9 KiB
Enodia Sentinel Packaging
Applies to package version: 0.7.0
Docs version: 0.7
Schema generation: v1
Sentinel is a stdlib-only Python package installed as a plain source directory plus launcher wrapper. The service and package are designed around Linux hosts with systemd.
Arch Linux
Arch is the primary packaged target.
Build from the repository root:
packaging/build-package.sh
Install the generated package:
sudo pacman -U enodia-sentinel-*.pkg.tar.zst
sudo systemctl daemon-reload
sudo systemctl enable --now enodia-sentinel.service
The Arch package installs:
| Path | Purpose |
|---|---|
/usr/bin/enodia-sentinel |
Launcher wrapper for the Python package. |
/usr/bin/sentinel-redteam |
Safe local red-team harness. |
/usr/lib/enodia-sentinel/enodia_sentinel/ |
Stdlib-only Python package. |
/etc/enodia-sentinel.toml |
Operator configuration, preserved as a pacman backup file. |
/usr/lib/systemd/system/enodia-sentinel.service |
Hardened daemon unit. |
/usr/lib/systemd/system/enodia-sentinel-web.service |
Read-only dashboard unit. |
/usr/share/libalpm/hooks/enodia-sentinel-fim.hook |
Post-transaction FIM baseline refresh hook. |
/usr/lib/tmpfiles.d/enodia-sentinel.conf |
Runtime log directory definition. |
/usr/share/doc/enodia-sentinel/ |
Versioned operator docs and examples. |
/var/log/enodia-sentinel/ |
Alert snapshots, events, incidents, response plans, and audit logs. |
The pacman hook calls /usr/bin/enodia-sentinel fim-update after package
transactions so legitimate package changes refresh the FIM baseline. It does
not silence unexplained non-package drift.
Optional Arch packages:
python-bpfccfor eBPF exec/syscall telemetry.bpftracefor short-lived exec capture inside forensic snapshots.libnotifyfor local desktop notifications.libarchivefor signed-cache-package.MTREEverification helpers.
The default service is hardened for polling mode. To enable eBPF, copy the packaged drop-in example and reload systemd:
sudo install -Dm644 /usr/share/doc/enodia-sentinel/examples/enodia-sentinel-ebpf.conf \
/etc/systemd/system/enodia-sentinel.service.d/ebpf.conf
sudo systemctl daemon-reload
sudo systemctl restart enodia-sentinel.service
Go Migration Sidecar (opt-in)
The Go agent has a separate validation service and is never installed by the
default make install target or the Arch package. Build and install it
explicitly from a checkout with Go 1.25 or newer:
make build-go
sudo make install-go PREFIX=/usr/local
sudo make enable-go
The static enodia-sentinel-go binary emits enodia.event.v1 JSONL to the
system journal. Its service owns /var/lib/enodia-sentinel-go for baseline
state and a bounded retained event stream. events.jsonl rotates to one
events.jsonl.1 segment before crossing 64 MiB; both are private to root, and
non-status records are synchronized before emission succeeds. The service
requests the embedded native exec and syscall probes and fails open to polling
when the kernel refuses a probe. It does not write the production Python
daemon's /var/log/enodia-sentinel state or replace
enodia-sentinel.service. Systemd readiness is emitted only after baseline
initialization, event-log and snapshot-store preflight, and both requested probe
load attempts complete.
Alert events are additionally retained as private
alert-YYYYMMDD-HHMMSS.{json,log} pairs in /var/lib/enodia-sentinel-go.
Same-second events are merged into one snapshot, required
enodia.alert.snapshot.v1 fields are preserved, and the shared
max_snapshots / max_snapshot_age_days settings bound retention. The current
sidecar also writes a private atomic incidents.json with the required
enodia.incident.v1 fields, process-lineage/time-window grouping, and additive
correlation evidence. Hot-path Go enrichment is bounded and no-I/O: process and
parent context, lineage, remote classification, and candidate paths come from
already-captured records. A bounded asynchronous worker subsequently hashes
regular executables no larger than 8 MiB and records file metadata; a full queue
skips those optional fields without delaying an alert. Python remains
authoritative for package ownership, richer integrity metadata, notifications,
and management consumers.
Each snapshot text/JSON revision is SHA-256 hashed into a synchronized private
hash-chain.jsonl using the stable enodia.hash_chain.v1 record schema.
Each successful sweep atomically refreshes
/var/lib/enodia-sentinel-go/heartbeat as a Unix timestamp with mode 0600;
the retained value becomes stale when the sidecar stops or wedges.
enodia-sentinel-go --health reports that state as JSON and exits nonzero when
it is unavailable or older than the configured heartbeat_max_age.
Inspect the retained event stream without depending on journald:
sudo tail -n 50 /var/lib/enodia-sentinel-go/events.jsonl
sudo enodia-sentinel-go --events-tail 50
The native reader includes events.jsonl.1, preserves chronological order, and
fails nonzero if either retained segment contains malformed JSON.
Inspect or remove the validation service with:
sudo make status-go
sudo make disable-go
sudo make uninstall-go
Uninstalling preserves the shared configuration and sidecar state for forensic review or a later reinstall.
Debian and Ubuntu
There is no native .deb package yet. Use the source install path:
sudo apt install python3 iproute2 procps
sudo make install PREFIX=/usr/local
sudo systemctl daemon-reload
sudo systemctl enable --now enodia-sentinel.service
Notes:
- The installed launcher does not require pip or a virtualenv.
fim-check --packagesuses the available package-manager backend; Debian package verification support should be validated for the target host before relying on it operationally.- The source install path includes the pacman hook file for parity with Arch source installs. On non-Arch systems it is inert unless pacman/libalpm is installed; Debian installs should manage FIM baseline refresh through operator procedure or a future dpkg trigger package.
RPM-family Linux
There is no native RPM package yet. Use the same source install path:
sudo dnf install python3 iproute procps-ng
sudo make install PREFIX=/usr/local
sudo systemctl daemon-reload
sudo systemctl enable --now enodia-sentinel.service
Notes:
- Native RPM packaging should eventually install systemd units under the distro
unit path, preserve
/etc/enodia-sentinel.toml, and create a package-manager trigger equivalent to the Arch FIM refresh hook. - Validate package verification behavior on the target distro before enabling signed-package mismatch alerting.
Desktop Tray Applet (optional)
The [tray] optional extra (pip install 'enodia-sentinel[tray]') pulls in
pystray and Pillow and provides the enodia-sentinel-tray console script.
The extra is never required by the daemon; core runtime dependencies stay
empty.
packaging/enodia-sentinel-tray.desktop is an opt-in autostart entry. It is
not installed to a system autostart path by default — desktop users copy it to
~/.config/autostart/ themselves.
Terminal TUI and Completion
The terminal dashboard is stdlib-only and available through
enodia-sentinel tui in source/wrapper installs. Python packaging metadata also
declares enodia-sentinel-tui = enodia_sentinel.tui:main for pip-style script
generation.
Shell completion has no runtime dependency: operators generate scripts with
enodia-sentinel completion bash or enodia-sentinel completion zsh and install
them in their normal shell completion path.
Package Hardening Checklist
- Package version matches
pyproject.tomlandenodia_sentinel.__version__. - Config is preserved across upgrades.
- Log directory is created with mode
0750. - Service units remain hardened and read-mostly by default.
- eBPF privilege relaxation is shipped only as an opt-in drop-in example.
- Package-manager hooks use absolute paths and do not depend on ambient
PATH. - Versioned operator docs are installed with the package.
Release Artifacts
Release artifacts are built with:
make release-artifacts
The release target writes to dist/ by default:
| Artifact | Purpose |
|---|---|
enodia-sentinel-<version>.tar.gz |
Versioned source release. |
SHA256SUMS |
SHA-256 checksums for the source tarball and release manifest. |
RELEASE_MANIFEST.json |
Project/version/git metadata for the generated release. |
SHA256SUMS.asc |
Optional detached GPG signature over SHA256SUMS. |
The script refuses a dirty git worktree by default so a release maps to a known
commit. For local packaging smoke tests only, set RELEASE_ALLOW_DIRTY=1.
To sign checksum artifacts:
RELEASE_SIGN=1 make release-artifacts
To select a specific GPG key:
RELEASE_SIGN=1 RELEASE_SIGNING_KEY=<key-id-or-fingerprint> make release-artifacts
Verification flow for operators:
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c SHA256SUMS