e2e: cross-OS supervised-daemon reboot survival (real VMs, recorded) - #1013
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | 6f4f991 | Commit Preview URL Branch Preview URL |
Jun 14 2026, 07:13 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | 6f4f991 | Jun 14 2026, 07:14 AM |
Cloudflare previewTorn down — the PR is closed. |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
Greptile SummaryThis PR codifies supervised-daemon reboot survival as automated e2e scenarios against real VMs, replacing a hand-driven bash harness. The VM substrate (
Confidence Score: 5/5Safe to merge — all changes are additive test infrastructure with no modifications to production application logic; the projects are excluded from the default test chain. The new VM substrate and test scenarios are well-isolated from production paths. The build.ts change is narrow and the --target flag integrates cleanly with the existing binary-build path. No data-path or auth changes. e2e/setup/cli.globalsetup.ts — the readToken/waitForHttp ordering (flagged in a prior thread) is the most fragile piece of the setup path. Important Files Changed
Sequence DiagramsequenceDiagram
participant GS as cli.globalsetup
participant VM as VmHandle (tart/ec2)
participant D as OS Daemon
participant T as SSH Tunnel
participant W as Test Worker
GS->>VM: provision()
VM-->>GS: handle (ip, ssh, tunnel, reboot)
GS->>VM: ssh(prep + push + postPush)
GS->>VM: ssh(service install)
VM->>D: OS registers and starts daemon
GS->>VM: ssh(readToken) → auth.json
GS->>VM: tunnel(PORT)
VM-->>T: spawn reconnecting ssh -L forward
GS->>T: waitForHttp(baseUrl)
T-->>GS: HTTP 200
Note over GS: Publishes env: BASE_URL, AUTH_TOKEN, VM_HOST
W->>W: cliTarget.restart()
W->>VM: sshRebootGuest / ec2RebootGuest
W->>T: waitForHttpDown(baseUrl)
T-->>W: connection refused (guest rebooting)
Note over VM: OS boots, service manager starts daemon
T->>VM: SSH tunnel reconnects
W->>T: waitForHttp(baseUrl, 240s)
T-->>W: HTTP 200 (daemon auto-started)
W->>T: after.integrations.list()
T->>D: GET /integrations
D-->>W: slug still present ✓
Reviews (3): Last reviewed commit: "e2e/desktop + cli tests: bearer auth tok..." | Re-trigger Greptile |
| const freePort = (): Promise<number> => | ||
| new Promise((resolve, reject) => { | ||
| const srv = net.createServer(); | ||
| srv.on("error", reject); | ||
| srv.listen(0, "127.0.0.1", () => { | ||
| const port = (srv.address() as net.AddressInfo).port; | ||
| srv.close(() => resolve(port)); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Duplicate
freePort implementation
The identical freePort() function already exists verbatim in e2e/src/vm/tart.ts. Both files open a port-0 server, grab the address, close the listener, and return the number. e2e/AGENTS.md directs "extract shared logic only when the shared behavior is real" — here the behaviour is exactly the same. Extracting it to a small shared utility (e.g. e2e/src/vm/types.ts or a dedicated e2e/src/net.ts) would avoid the copy diverging if the timeout or bind-address ever needs updating.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
04595d7 to
3203153
Compare
9a0841a to
a030e91
Compare
3203153 to
50c18a9
Compare
…rget
Foundation for codifying the supervised-daemon reboot-survival proof as e2e
tests (today it's only a by-hand bash harness). Adds a VM substrate that can
provision a guest, drive it over SSH, REBOOT the OS for real, and tear it down:
- e2e/src/vm/{types,tart,build-binary}.ts — the tart provider (macOS + Linux
guests on an Apple-Silicon host) with a reconnecting SSH forward that survives
a guest reboot, plus a helper to compile the guest's `executor` binary.
- apps/cli/src/build.ts: a first-class `--target <name>` flag so the harness can
build a specific platform's binary (replaces a throwaway env hack).
Validated standalone: provision macOS guest → ssh → real reboot (boottime
changes) → clean discard. Next: the `cli` target wires this into the scenario
suite so restart-persistence runs against a real reboot.
Wires the VM substrate into the scenario suite as a `cli` target (one project per guest OS: cli-macos / cli-linux / cli-windows). The globalsetup builds the guest's executor binary, provisions a VM, `executor service install`s the supervised daemon, and forwards its loopback port over a reconnecting SSH tunnel — so target.baseUrl works unchanged for the api surface. restart() reboots the guest OS for REAL and waits for the daemon to auto-start, so the existing restart-persistence scenario now proves the boot-time auto-start path (launchd RunAtLoad / systemd linger / Task Scheduler AtStartup), not a process restart. Because globalsetup (main process) and restart() (test worker) are different processes, restart() re-derives the guest address from env and reboots statelessly, mirroring how selfhost-docker's restart re-derives container ops. Verified: `vitest run --project cli-macos` boots a macOS guest, installs the daemon, addSpec's an integration, reboots the guest, and asserts the data survived — green, with a run-record in the matrix. cli-linux reuses the tart provider; cli-windows awaits the ec2 provider.
A watchable companion to restart-persistence: drives the same register → reboot → survived flow through the chat theater so the on-screen tool spinner runs for the ACTUAL guest reboot. Produces a terminal.cast the viewer plays in the matrix — press-play evidence instead of trusting a green check. Runs against the cli-* VM targets; verified on cli-macos (357-event cast).
… a sidecar) Films the desktop ATTACHING to an already-running OS-supervised daemon instead of spawning its own sidecar: starts a real cli-daemon (the desktop sidecar server in EXECUTOR_SUPERVISED mode → kind "cli-daemon") against a throwaway HOME, launches Electron pointed at the same HOME, and proves the attach — the server manifest still names OUR daemon's pid (a spawned sidecar would be a new pid + kind "desktop-sidecar"). session.mp4 is the artifact. The daemon half is verified (EXECUTOR_READY + kind cli-daemon + 401). Like the existing desktop scenario it drives Electron via Playwright, so it needs a GUI display session to run (the desktop project is already display-gated, not in the default test chain) — run on a real desktop / CI-with-display to capture the video.
…or Windows - cli target authenticates with the daemon's auth.json bearer (was Basic from service.key); globalsetup reads the token from the guest and publishes it. - restart() gates on the daemon going DOWN before polling it back up, so an orderly shutdown / reconnecting tunnel can't false-pass a reboot that never happened (waitForHttpDown). - EC2 VmProvider (e2e/src/vm/ec2.ts) + cli-windows globalsetup unblock Windows: launch, key-based SSH/PowerShell drive, real boot-time-gated reboot, terminate.
The supervised-attach film passed EXECUTOR_AUTH_PASSWORD, a dead env the sidecar no longer reads (it reads EXECUTOR_AUTH_TOKEN and otherwise mints/loads the bearer from auth.json). Pin a real bearer instead. Fix two stale launchd/wrapper comments that still pointed the secret at service.key.
a030e91 to
6f4f991
Compare
What
Codifies the supervised local daemon's reboot survival as e2e scenarios that run against real virtual machines — replacing a by-hand bash harness. The daemon (added by the PRs below this in the stack) is installed as an OS service (launchd / systemd / Task Scheduler); these tests prove it auto-starts after a genuine machine reboot and that integration data survives.
How it's built
e2e/src/vm/) — provision a guest, drive it over SSH, reboot the OS for real, tear it down. A tart provider covers macOS + Linux; the SSH forward reconnects across the reboot.clitarget (e2e/targets/cli.ts, one project per guest OS) — globalsetup builds the guest'sexecutorbinary,executor service installs the daemon, and tunnels its loopback port totarget.baseUrl.restart()is a real guest reboot, so the existingrestart-persistencescenario runs unchanged and proves the boot-time auto-start path.--targetflag on the CLI build so the harness can compile a specific platform's binary.e2e/cli/service-lifecycle.test.ts— register an integration → reboot → survived, where the on-screen spinner runs for the actual reboot (terminal cast).e2e/desktop/supervised-attach.test.ts— the desktop app attaching to a running supervised daemon instead of spawning its own sidecar (proven by the manifest pid staying put).Verified
vitest run --project cli-macosand--project cli-linux— green, each doing build → provision → install → addSpec → real reboot → assert survived → clean teardown.EXECUTOR_READY+ manifestkind: cli-daemon+401).Coverage notes (honest)
bun run testchain — same as the existingdesktopandselfhost-dockerprojects. Run them explicitly on a host with tart / a display.ec2.tsprovider (the Windows reboot path was proven by hand; porting it into the substrate is the remaining piece).session.mp4.Stacked on top of the supervised-daemon PRs.