mirror of
https://github.com/garrytan/gstack.git
synced 2026-07-18 05:27:32 +02:00
fix(browse): identity-based terminal-agent kill replaces pkill regex
Commit 0 of the v1.44 long-lived-sidebar PR — foundation for the watchdog
and removes a latent cross-session footgun.
`pkill -f terminal-agent\.ts` (cli.ts spawn site + server.ts shutdown) matched
by argv regex and would kill ANY process whose argv contained the string —
sibling gstack sessions on the same host, an editor with the file open, a
second `$B connect` run. Identity-based PID kill via a new helper module
removes that whole class of bug.
* New `browse/src/terminal-agent-control.ts`: `readAgentRecord`,
`writeAgentRecord`, `clearAgentRecord`, `killAgentByRecord`. Validates
PID liveness via `isProcessAlive` before signaling (PID-reuse defense).
* `terminal-agent.ts` writes `<stateDir>/terminal-agent-pid` (JSON
`{pid, gen, startedAt}`) at boot; clears on SIGTERM/SIGINT.
* New per-boot `CURRENT_GEN` (16-byte random); `/internal/*` callers can
include `X-Browse-Gen` to defend against split-brain in the upcoming
watchdog. Absent header is accepted (backward compat); mismatch returns
409. New `checkInternalAuth` helper centralizes bearer + gen checks.
* New `/internal/healthz` route — agent liveness probe used by the
upcoming watchdog (returns pid/gen/sessions, no claude-binary lookup).
* `cli.ts` and `server.ts` both call `killAgentByRecord` instead of pkill.
* `ServerConfig.ownsTerminalAgent` JSDoc updated; the gated teardown now
runs 4 side effects (was 3) — adds the new agent-record unlink.
Test changes:
* New `browse/test/terminal-agent-pid-identity.test.ts` — static-grep
tripwire that fails CI if any source file re-introduces `pkill ...
terminal-agent` or `spawnSync('pkill', ...)`; round-trips
write/read/clear; verifies killAgentByRecord no-ops on dead PIDs.
* `browse/test/server-embedder-terminal-port.test.ts` rewritten to
intercept `process.kill` (not `child_process.spawnSync`); writes a
sentinel agent-record with a guaranteed-dead PID; asserts probe-only
(signal 0) calls, no termination signals; verifies all 3 discovery
files including the new terminal-agent-pid.
Closes TODOS.md P3 ("Identity-based terminal-agent kill").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -236,19 +236,23 @@ Activity / Refs / Inspector as debug overlays behind the footer's
|
||||
flow, dual-token model, and threat-model boundary — silent failures
|
||||
here usually trace to not understanding the cross-component flow.
|
||||
|
||||
**Embedder terminal-agent ownership** (v1.42.1.0+). `buildFetchHandler`
|
||||
in `browse/src/server.ts` accepts `ServerConfig.ownsTerminalAgent?:
|
||||
boolean` (default `true`). When `true`, factory shutdown runs the full
|
||||
teardown: `pkill -f terminal-agent\.ts` plus `safeUnlinkQuiet` on
|
||||
`<stateDir>/terminal-port` and `<stateDir>/terminal-internal-token`.
|
||||
Embedders (e.g. the gbrowser phoenix overlay) that pre-launch their
|
||||
own PTY server must pass `false` so their discovery files survive
|
||||
gstack teardown cycles. The flag is the third caller-owned teardown
|
||||
gate in `ServerConfig` (alongside `xvfb?` and `proxyBridge?`); polarity
|
||||
is inverted (explicit bool vs presence) and documented in the field's
|
||||
JSDoc. CLI `start()` always passes `true` explicitly — the static-grep
|
||||
test in `browse/test/server-embedder-terminal-port.test.ts` fails CI
|
||||
if a refactor drops it.
|
||||
**Embedder terminal-agent ownership** (v1.42.1.0+, identity-based kill v1.44.0.0+).
|
||||
`buildFetchHandler` in `browse/src/server.ts` accepts `ServerConfig.ownsTerminalAgent?:
|
||||
boolean` (default `true`). When `true`, factory shutdown runs the full teardown:
|
||||
identity-based kill via `killAgentByRecord(readAgentRecord(stateDir))` from
|
||||
`browse/src/terminal-agent-control.ts` plus `safeUnlinkQuiet` on
|
||||
`<stateDir>/terminal-port`, `<stateDir>/terminal-internal-token`, and
|
||||
`<stateDir>/terminal-agent-pid` (the per-boot agent record introduced in v1.44).
|
||||
Embedders (e.g. the gbrowser phoenix overlay) that pre-launch their own PTY
|
||||
server must pass `false` so their discovery files survive gstack teardown cycles.
|
||||
The flag is the third caller-owned teardown gate in `ServerConfig` (alongside
|
||||
`xvfb?` and `proxyBridge?`); polarity is inverted (explicit bool vs presence) and
|
||||
documented in the field's JSDoc. CLI `start()` always passes `true` explicitly —
|
||||
the static-grep test in `browse/test/server-embedder-terminal-port.test.ts` fails
|
||||
CI if a refactor drops it. Pre-v1.44 used `pkill -f terminal-agent\.ts` (regex
|
||||
match) which would kill sibling gstack sessions on the same host; the new
|
||||
`browse/test/terminal-agent-pid-identity.test.ts` static-grep tripwire fails CI
|
||||
if any source file re-introduces `pkill ... terminal-agent` or `spawnSync('pkill', ...)`.
|
||||
|
||||
**WebSocket auth uses Sec-WebSocket-Protocol, not cookies.** Browsers
|
||||
can't set `Authorization` on a WebSocket upgrade, but they CAN set
|
||||
|
||||
Reference in New Issue
Block a user