mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-19 09:44:07 +00:00
Audit finding F7 (LOW): lib/tui/session.mjs hardcoded SESSION_PREFIX =
"ocp-tui-" as a bare, host-wide constant. The boot-reap and periodic
idle-reap in server.mjs used it to decide which tmux sessions to
kill-session and whether to kill-server (which flushes defunct <claude>
zombies but tears down the WHOLE tmux server, including any live pane).
The coexistence guard only ever spared foreign product prefixes
(olp-tui-*); a SECOND OCP instance on the same host — e.g. a temporary
verification instance stood up alongside production, a real pattern
used during PR #144/#146 verification — was indistinguishable from
"ours" and could have its LIVE sessions reaped/kill-server'd by the
other instance's boot or periodic sweep.
Fix: scope the session-name prefix to this instance's own listen port
(the natural stable per-instance discriminator on one host — two OCP
instances cannot share a port): `ocp-tui-<port>-`. A sibling instance's
`ocp-tui-<otherPort>-*` sessions now fail the own-prefix startsWith
check and fall into the same "othersRemain" bucket as olp-tui-*,
so they are never touched and never used to justify kill-server.
lib/tui/session.mjs:
- sessionPrefixForPort(port) replaces the bare SESSION_PREFIX export.
- reapStaleTuiSessions({ tmux, port, includeLegacy }) now requires
port and computes its own prefix from it.
- runTuiTurn({ ..., port }) builds the tmux session name from
sessionPrefixForPort(port) instead of the old bare constant.
- LEGACY_SESSION_PREFIX / LEGACY_SESSION_NAME_RE (exact
"ocp-tui-<8-hex>" shape, no port segment) describe the OLD
pre-fix session-name shape, retained only for the migration below.
Legacy migration rule (chosen + reasoning): a bare-prefix legacy
session cannot be created by any post-fix OCP process, so if one is
seen it is presumed to be an orphaned zombie from THIS instance's own
PRE-fix process generation (left behind across an in-place upgrade),
not a stranger's. reapStaleTuiSessions() therefore accepts an
includeLegacy flag: server.mjs's one-time BOOT reap passes
includeLegacy: true (claims exact-legacy-shape sessions as its own,
enabling cleanup right after an upgrade); the periodic 15-min idle
sweep does NOT set it, so a lingering legacy-shaped session during
steady-state is conservatively treated as foreign and cannot trigger
kill-server on a routine tick. Residual (documented, accepted): a
genuinely-still-running PRE-fix OCP instance coexisting on the host at
the exact moment a new instance boots could have its live legacy
session reaped — the same class of residual risk the audit finding
itself accepts ("no live instance of the new version creates them");
this PR does not regress that scenario, it only removes the far more
common same-version collision that is the actual F7 finding.
LEGACY_SESSION_NAME_RE (`^ocp-tui-[0-9a-f]{8}$`) can never match the
new shape: the new shape always inserts a literal "-" between the
port digits and the 8-hex suffix, which the anchored 8-hex-only legacy
regex cannot satisfy.
server.mjs changes are local TUI session-lifecycle infrastructure
(tmux session naming, boot/periodic reap, kill-server) with no cli.js
wire analogue — verified via `strings` against the compiled claude
CLI 2.1.198 binary (this machine ships cli.js as a Mach-O binary per
ALIGNMENT.md's "OAuth token-host verification" precedent): cli.js
contains only `env.TMUX` detection (whether IT is running inside a
tmux pane) and an unrelated `--remote-control-session-name-prefix`
flag for its own remote-control feature — no session-prefix/reap/
kill-server mechanism of any kind. Per ALIGNMENT.md Rule 2, this is
declared absent: no endpoint, header, request, or response shape
changed; only OCP's own local process-lifecycle bookkeeping. No PORT
literal was hardcoded (CI port-SPOT check) — PORT is threaded through
from the existing server.mjs SPOT (lib/constants.mjs DEFAULT_PORT via
CLAUDE_PROXY_PORT).
test-features.mjs: rewrote the reaper suite's fixture session names to
the new port-scoped shape, added tests for sessionPrefixForPort(),
LEGACY_SESSION_NAME_RE's non-collision with the new shape, a sibling
same-host OCP instance being treated as foreign (F7 regression test),
and the includeLegacy boot-migration behavior (claims legacy zombies,
still spares a sibling instance's port-scoped session).
Verified: node --check server.mjs && node --check lib/tui/session.mjs
&& npm test → 243 passed, 0 failed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>