Let the audit emit its state, for a watcher that keeps the baseline elsewhere
tests / runner-env (pull_request_target) Successful in 41s
tests / tests (pull_request_target) Successful in 1m18s

`drift` compares against a baseline kept on this machine, and root here can
rewrite that as easily as read it - which is the case being looked for. The
program says so, and says the half that fixes it runs elsewhere.

This is the interface that half needs: `drift --state` prints the collected
state and compares nothing, so a watcher on another machine can keep the
baseline and do the diff where the devbox cannot reach it.

To stdout unconditionally, terminal or not, because this is data rather than
a verdict.

The partial-state refusal survives the emitter, and that is the point of one
of the tests: a watcher diffing a partial state against a full baseline sees
a list of removals and calls it an intruder deleting things. Exit 2 there, as
everywhere else in this program, means could-not-determine.

`bats test/` 161 passing, 3 new.
This commit is contained in:
2026-08-27 23:55:45 -07:00
parent f76e8a11eb
commit 23e1c247f7
2 changed files with 52 additions and 3 deletions
+21 -3
View File
@@ -675,9 +675,12 @@ drift_dpkg() {
}
cmd_drift() {
local accept=0 missing state work added removed rc=0 verdict unread
local accept=0 emit=0 missing state work added removed rc=0 verdict unread
[ "${1:-}" = --accept ] && accept=1
case "${1:-}" in
--accept) accept=1 ;;
--state) emit=1 ;;
esac
missing=$(drift_missing)
work=$(mktemp -d) || return 2
@@ -700,6 +703,21 @@ cmd_drift() {
return 2
fi
# --state prints the state and compares nothing.
#
# It exists for a watcher on another machine, which keeps the baseline and
# does the diff itself. That is the half this program cannot do: root here
# can rewrite a baseline kept here, and root here is the case being looked
# for. What it cannot do is alter what another machine recorded last week.
#
# To stdout unconditionally, terminal or not, because this is data rather
# than a verdict. A caller asked for it.
if [ "$emit" = 1 ]; then
cat "$state"
rm -rf "$work"
return 0
fi
if [ "$accept" = 1 ]; then
install -m 0755 -d "$BASELINE_DIR"
{
@@ -824,7 +842,7 @@ main() {
cmd_drift || rc=$?
cmd_reach || rc=$?
return $rc ;;
*) say "usage: $PROG [reach|radius|drift [--accept]]"; return 64 ;;
*) say "usage: $PROG [reach|radius|drift [--accept|--state]]"; return 64 ;;
esac
}
+31
View File
@@ -176,6 +176,37 @@ stub_state() {
[ -s "$DRIFT_ERRS" ]
}
# --- the state emitter, which is what a watcher on another machine reads -----
@test "--state prints the state and compares nothing" {
# No baseline needed and none consulted: the watcher keeps that, because a
# baseline kept here is one root here can rewrite, and root here is the
# case being looked for.
stub_state "FILE aaa /etc/one" "UNIT foo.service"
run cmd_drift --state
[ "$status" -eq 0 ]
[[ "$output" == *"FILE aaa /etc/one"* ]]
[[ "$output" == *"UNIT foo.service"* ]]
[[ "$output" != *CLEAN* ]]
[[ "$output" != *INDETERMINATE* ]]
}
@test "--state still refuses when the state would be partial" {
# A watcher diffing a partial state against a full baseline sees a list of
# removals and calls it an intruder. The refusal has to survive the emitter.
stub_state "FILE aaa /etc/one"
drift_state() { printf 'FILE aaa /etc/one\n'; echo "denied" >> "$DRIFT_ERRS"; }
run cmd_drift --state
[ "$status" -eq 2 ]
[[ "$output" == *INDETERMINATE* ]]
}
@test "--state does not write a baseline" {
stub_state "FILE aaa /etc/one"
run cmd_drift --state
[ ! -e "$BASELINE" ]
}
# --- exit status ------------------------------------------------------------
@test "all does not lose a drift finding behind a clean reach" {