Per-deployment sensor: run FIFO + atime baits together (#100, dual-plant 1/3)#164
Conversation
…100) Increment 1 of dual-plant: each deployment record carries an optional 6th `sensor` field (fifo|atime|inotify). The agent now plants and watches EACH bait under its own sensor, so a FIFO bait (canonical, definitive pid) and an atime bait (companion, normal-file detection) run side by side from one agent — the foundation for always deploying the pair. Backward-compatible: an absent field falls back to today's global behavior (`effective_sensor` → per-deployment value, else the auto-probe/--sensor default), so this merges safely before the server sends pairs. The existing homogeneous FIFO/atime/inotify paths are byte-for-byte unchanged; the new `watch_mixed` dispatcher only engages when the server sends explicit sensors. - Parse the `sensor` field -> `dep_sensor_$i`; `effective_sensor`, `has_explicit_sensors` helpers. - `plant()` keys FIFO-vs-regular on the deployment's sensor, not global FIFO_MODE. - Refactor `watch_atime` -> `atime_poll "<indices>"` so a subset can be polled; `watch_atime()` keeps polling all (homogeneous + degradation fallback). - `watch_mixed`: FIFO baits served individually, the rest atime-polled as a group. - verify's FIFO-tamper check keys on the deployment's sensor too. New test: a fifo+atime pair from one agent — both plant as the right type and both fire. Full suite: 261 passed, 1 skipped; shellcheck -S error clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
… Linux) Same fix as the atime-rearm branch: `touch -a` creates the file if missing, so arming a failed-plant dep's path left an empty file behind and verify_planted stopped re-planting it. Broke test_replant_is_bounded on Linux. Add `-c`. Verified in a Debian/dash container: agent suite 32 passed, 9 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Propagate main's #162 up the stack; clean auto-merge. Verified: 41 agent tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
AnguIar
left a comment
There was a problem hiding this comment.
Finding 1 — Re-planted FIFO baits go unserved on Linux (line 904)
The watcher restart after a re-plant checks FIFO_MODE=1, but probe_fifo_mode() only sets that flag on macOS. When the server sends sensor=fifo for a Linux deployment, effective_sensor() bypasses the platform check and returns fifo — so the FIFO is planted and served correctly. But if the bait is later deleted and re-planted by verify_planted, the restart guard fails (FIFO_MODE is 0 on Linux) and the new FIFO is never served. The coverage gap is silent and permanent until manual restart.
Finding 2 — --sensor atime override silently bypassed by per-deployment sensors (line 694)
In start_watcher, has_explicit_sensors is checked before $SENSOR = atime. Once the server starts sending sensor fields (increment 2), an operator's explicit --sensor atime flag will be ignored — the agent enters watch_mixed and plants FIFO baits even though the operator specifically asked to avoid them. No warning is logged.
- F1: sweep stale FIFOs at startup regardless of sensor mode, and have plant() rm a leftover FIFO before `curl -o` into it. A FIFO→atime restart after a hard-kill no longer hangs writing into a no-reader pipe. - F2 (+ #164 F1): restart the watcher on ANY re-plant, not just FIFO_MODE=1, so a re-planted atime bait is re-armed (no ghost alert from the stale year-2000 baseline) and a re-planted FIFO is re-served on Linux too. - F3: `--sensor fifo` now FORCES a pipe wherever mkfifo works (incl. Linux/CI) via a platform-agnostic mkfifo_works() probe, instead of silently falling through to auto-detection; errors out loudly if mkfifo is unavailable. New regression tests: atime mode doesn't hang on a leftover FIFO; --sensor fifo forces a named pipe. 42 agent tests pass; shellcheck -S error clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
…server #164 F2: an operator's explicit `--sensor fifo|atime` is an intentional override and must win over the server's per-deployment `sensor` field. effective_sensor precedence is now: explicit --sensor -> per-deployment -> platform default, so `--sensor atime` reliably opts a host out of FIFOs even when the server sends sensor=fifo. (#164 F1 — re-planted FIFO unserved on Linux — is fixed by the mode-independent watcher restart propagated from the #160 fixes.) New test: --sensor atime plants a regular file even when the server asks for fifo. 44 agent tests pass; shellcheck -S error clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
fixes) effective_sensor condition (#164) + re-plant-on-tamper body (#123 F1) auto-merged correctly. 46 agent tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
Clean merge of the reconciled #160 (main/#178/#177 already resolved below). ruff-format + fix test_agent_mixed.py. Tree-wide ruff clean; 50 agent tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018DARDAxeg4NM8FKoyGMQZy
|
@AnguIar all of your findings are addressed, and the branch is now reconciled with current |
avivhalfon11
left a comment
There was a problem hiding this comment.
LGTM - checked both findings, F1 (re-plant restart is now unconditional) and F2 (effective_sensor honors the operator --sensor override first) are both properly fixed.
Increment 1 of 3 for the dual-plant pair (FIFO canonical · atime companion). Stacked on #160.
What
Each deployment record gains an optional 6th
sensorfield (fifo|atime|inotify). The agent plants and watches each bait under its own sensor, so a FIFO bait (definitive pid) and an atime bait (normal-file detection) run side by side from one agent — the foundation for always deploying the pair.sensor→dep_sensor_$i;effective_sensor/has_explicit_sensorshelpers.plant()keys FIFO-vs-regular on the deployment's sensor, not globalFIFO_MODE.watch_atime→atime_poll "<indices>"(poll a subset);watch_atime()still polls all (homogeneous + degradation fallback).watch_mixed: FIFO baits served individually, the rest atime-polled as a group.Backward-compatible
An absent
sensorfield → today's global behavior. The existing homogeneous FIFO/atime/inotify paths are byte-for-byte unchanged;watch_mixedonly engages once the server sends explicit sensors. So this merges safely before the server (increment 2) sends pairs.Tests
tests/test_agent_mixed.py: a fifo+atime pair from one agent — both plant as the right type (named pipe + armed regular file) and both fire.shellcheck -S errorclean.Next
sensor/pair_idcolumns + migration; deploying a tripwire emits the FIFO-canonical + atime-companion pair.pair_id.🤖 Generated with Claude Code
Part of #100 (sensor refactor, dual-plant 1/3).