Two scenarios:
* broker_t2_attach_through_home_daemon: alpha + beta share perimeter
"wg-test"; beta lists alpha in allow_inbound. Test attaches to beta's
session via alpha's /api/attach/:id and verifies the PTY echoes back.
* broker_rejects_when_target_doesnt_allow_inbound: same setup but beta's
allow_inbound is empty; the broker WS handshake succeeds at alpha
(which has no reason to refuse) but beta drops the pair JWT, so the
proxied stream closes without any PTY bytes flowing.
Extends maestro-e2e::Daemon with DaemonOptions and a spawn_at variant
that fixes the bind address, so the daemon's advertised private_addr
matches the port the broker will dial.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New `crates/maestro-e2e` exercises the full headless stack — registry,
two daemons, real HTTP+WS — as actual subprocesses.
Harness pieces:
- `Registry::spawn` and `Daemon::spawn` launch the real built binaries
with `env_clear()` plus an isolated `$HOME`, `XDG_CONFIG_HOME`,
`XDG_STATE_HOME`, and (for daemons) `TMUX_TMPDIR`. Drop guards kill
the child and clean the temp dirs.
- `Daemon::stop` + `Daemon::restart` swap the process without losing
the state dirs, so the recovery test exercises a real tmux
re-adoption.
- A `build::workspace_target_bin` helper re-invokes cargo from the
test process to build `maestrod` / `maestro-registry` on demand
(cargo only ships libs as path-dep of e2e by default).
- `TestClient` wraps reqwest + tokio-tungstenite for the public
HTTP+WS surface — list/spawn/kill/connect-info/attach + events WS.
Scenarios covered (`tests/e2e.rs`):
- list sessions from two daemons through one registry
- multi-attach: two WS clients see the same PTY output
- worktree with `cleanup_on_kill: true` is removed after kill
- daemon restart: catalog drops then repopulates from `recover()`
- concurrent spawns all get distinct ids
All five pass in ~0.7s in parallel; cleanup confirmed (no leftover
processes or temp dirs).