Files
automaton/tasks/complete/add-status-brakes/ADVERSARIAL_BUG_REPORT.md
T
Lap Tran 4a2301b077
CI / build (push) Has been cancelled
Archive completed tasks, add cleanup commands, self-documenting dashboard UI
- Archive 79 completed framework-dev tasks from tasks/ -> tasks/complete/
- status.py: add --cleanup-done and --install-cleanup-schedule commands
- Add scripts/automaton-cleanup.sh for periodic task archiving
- Dashboard: rename 'Background' tab -> 'Agent', 'Cleanup' agent -> 'Completed Task Archiver', remove redundant group headers and pill badges, dim inactive agent placeholders
- .rules.md: add Self-Documenting UI Names rule
- New tests: test_cleanup_done.py, expanded test_app.py and test_task.py
2026-06-24 22:43:33 -04:00

4.1 KiB

Adversarial Bug Report: add-status-brakes

Adversarial pass: attack the brakes layer as a hostile agent would, looking for ways to escape enforcement.

Attack vectors tried

A1 — Can a halted loop be silently resumed by re-running --create-loop with the same name?

cmd_create_loop refuses duplicates (exit 2). Attacker cannot overwrite a halted loop's state via create. Defended.

A2 — Can a hostile harness skip --check-gate and just call --transition?

Not if the loop owns the task — R8 refuses the transition until --approve --loop clears the halt. Defended.

BUT: if the loop never current_task-claimed the task, _loop_owning_task returns None and the transition proceeds. The agent can edit a task that isn't claimed by any loop. That is correct behavior (humans and ad-hoc agents can still work), but it means a hostile agent could race the loop runner to claim a task. Mitigation: loop runner should call a --claim-loop-task (not in v1) or set current_task atomically before transitioning. Not a brakes-layer bug — it's a runner-layer concern (task 3). Note for task 3.

A3 — Can --pause-loop be used to bypass the worktree drift gate?

No — pausing just stops the scheduler; .state.loop remains the source of truth. --check-gate still runs all gates; a paused loop's gates return paused: (not ok). The runner will not tick. Defended.

A4 — Can the agent hand-write .state.loop to fake "running"?

Yes — .state.loop is a plain JSON file. A fully local adversary with filesystem access can edit it. This is an accepted threat model: the framework assumes the harness is cooperative for state files but enforces via the pre-edit hook (--can-edit) for source edits. .state.loop is not in any task's file_scope, so it's never editable by a loop agent. Defended by file-scope design.

A5 — Race: two concurrent --check-gate invocations both halt the loop

Both call _halt_loop which uses atomic tmp+rename. Last writer wins. Both write the same halt_reason (deterministic from gate), so the result is consistent. No corruption. Defended.

A6 — Can --approve --loop be called while the loop is mid-tick?

--approve does tmp+rename. If a tick is concurrently writing iteration_count, the approve's write wins and the tick's increment is lost. Window is small (subprocess boundary). Acceptable for v1; the next tick re-reads and re-increments. Not a corruption vector. Note for v1.1: file-locking (fcntl) on .state.loop would close this race. Add to BACKLOG.

A7 — Can --install-schedule be pointed at a different project than the loop?

--install-schedule uses _find_project_dir(args.project) and writes the stub at loop_path / run-tick.*. The stub cds into the project root and invokes the runner with the loop name. An attacker could swap the loop_name in the stub after generation, but that's just running an arbitrary loop — not a privilege escalation. Not an attack.

A8 — Can the schedule wake the loop after it's halted?

Yes — the OS unit fires run-tick on schedule. run-tick invokes loop-runner.py --mode tick --loop NAME, which must call --check-gate first and exit 1 if not ok. The runner's contract (task 3) is: gate first, then work. The OS unit itself cannot refuse. So a halted loop's schedule will fire run-tick, which will no-op via the runner's gate check. The --pause-loop best-effort disable is belt-and-braces. Defended by runner contract (must be enforced in task 3).

Hardening recommendations (for BACKLOG)

  1. fcntl file-lock on .state.loop for tick/approve race (A6) — v1.1.
  2. --claim-loop-task to atomically set current_task before a runner touches the task (A2) — task 3.
  3. _enable_schedule Linux parity with Darwin/Windows (O4) — task 5 / v1.1.
  4. blast_radius.base_branch parameterization for drift diff (O3) — task 5.

Verdict

PASS — no exploitable escape from the brakes layer. All adversarial vectors are either defended today or have explicit runner-contract mitigations landing in tasks 3/5. Hardening items routed to design/loops/BACKLOG.md.