Skip to content

fix(daemon): survive bad commands, lock socket to owner - #4

Merged
wmehanna merged 1 commit into
mainfrom
fix/daemon-robustness-and-socket-perms
Aug 7, 2026
Merged

fix(daemon): survive bad commands, lock socket to owner#4
wmehanna merged 1 commit into
mainfrom
fix/daemon-robustness-and-socket-perms

Conversation

@wmehanna

@wmehanna wmehanna commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the two findings from the PR #3 self-audit.

Changes

  • Daemon survives recoverable errors (was: Medium — one bad command killed it). Validation now throws CommandError instead of calling the global die()/exit(). The one-shot CLI catches it and dies as before (exit 1, unchanged); the daemon returns ERR and keeps its warm Vision model + held session. An out-of-bounds coordinate, a non-numeric arg, or Mirroring being closed no longer terminate the process — trivial for an agent to hit, and it was silently defeating the daemon's whole purpose.
  • Socket locked to owner (was: Low — perms depended on ambient umask). chmod 0600 right after bind(), so no other local user can connect and drive the phone, write PNGs anywhere (shot), or read files as keystrokes (text).
  • Regression coverage: tests/test_daemon.bats (survival across bad-command classes + socket perms), plus a CI step to build the native engine so those tests run instead of skipping on a fresh checkout.

Testing

  • Daemon confirmed alive after out-of-bounds / bad-arg / unknown-verb / a burst of all three; same pid throughout
  • Socket verified srw------- (0600)
  • One-shot CLI behavior unchanged (still exits 1 with the error on bad input)
  • bats 179/179 (0 skips with the engine built), MCP vitest 43/43, shellcheck clean
  • Live device suite 14/14

Two audit findings from PR #3.

The daemon called the global die() (which exit()s) on any recoverable
per-command error - an out-of-bounds coordinate, a non-numeric argument,
or Mirroring being closed - so a single bad command killed the whole
daemon and discarded the warm Vision model and held input session it
exists to preserve. An agent doing exploratory taps triggered it
constantly. Validation now throws CommandError: the one-shot CLI still
turns that into die() (behavior unchanged, still exits 1), while the
daemon returns it as an ERR reply and keeps running. Confirmed: an
out-of-bounds tap, a bad arg, and an unknown verb all return ERR with
the same warm daemon alive throughout.

The daemon's UNIX socket was bound without an explicit chmod, so its
connect-permission depended on the ambient umask; under a permissive
umask another local user could drive the phone, write PNGs to arbitrary
paths (shot), or read files as keystrokes (text). It is now chmod 0600
right after bind.

Adds tests/test_daemon.bats (survival + socket perms) and a CI step to
build the native engine so those tests run instead of skipping.
@wmehanna
wmehanna merged commit 78fa769 into main Aug 7, 2026
1 check passed
@wmehanna
wmehanna deleted the fix/daemon-robustness-and-socket-perms branch August 7, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant