fix: address review report across security, architecture, quality, tests
Implements the fixes from docs/REVIEW_REPORT.md (4-agent parallel review). typecheck clean; 341 tests pass (16 files, +113); build:web ok; coverage thresholds (80%) enforced in vitest.config.ts. Critical: - multi-device approval race: release held approval only when the last client detaches (closing one mirror no longer cancels another's prompt) - unbounded session creation (DoS): Config.maxSessions cap (env MAX_SESSIONS), enforced in manager via the existing M4 exit(-1) path - signal-handler leak: named SIGINT/SIGTERM/uncaughtException refs removed in close() - terminal-session initialInput timer tracked + cleared on dispose - tabs.addEntry null-as-cast type hole removed (build session before entry) Should-fix: - security-headers middleware + Origin/CSRF guard on DELETE /live-sessions[/:id] - history.ts converted to fs/promises (async /sessions handler) - removed dead clientDims map + blur protocol message end-to-end - per-connection WS message rate limit (Config.maxMsgsPerSec) - /sessions behavior kept; documented as accepted LAN risk (TECH_DOC §7) Tests: - new tmux / preview-grid / terminal-session (jsdom) / tabs (jsdom) suites - extended history/config/manager/integration coverage incl. regressions Hygiene: - parsePositiveInt -> parseNonNegativeInt; ALLOWED_ORIGINS scheme validation - log-injection sanitize; isLoopback handles 127.0.0.0/8 + IPv4-mapped - operational constants moved into Config - extracted public/preview-grid.ts (DRY launcher/manage) - doc sweeps: ARCHITECTURE §8 runtime-handle exception, stale comments
This commit is contained in:
@@ -108,7 +108,6 @@ export function createSession(
|
||||
meta,
|
||||
buffer: createRingBuffer(cfg.scrollbackBytes),
|
||||
clients: new Set(),
|
||||
clientDims: new Map(),
|
||||
detachedAt: null,
|
||||
lastOutputAt: now,
|
||||
exitedAt: null,
|
||||
@@ -161,7 +160,6 @@ export function attachWs(session: Session, ws: WebSocketLike): void {
|
||||
*/
|
||||
export function detachWs(session: Session, ws: WebSocketLike, now: number): void {
|
||||
session.clients.delete(ws);
|
||||
session.clientDims.delete(ws);
|
||||
// A client leaving does NOT resize the PTY — whatever device is still actively
|
||||
// viewing keeps its size. Start the idle clock only when the last client goes.
|
||||
if (session.clients.size === 0) {
|
||||
@@ -175,36 +173,26 @@ export function writeInput(session: Session, data: string): void {
|
||||
session.pty.write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record one client's requested dims and resize the PTY to the new min across
|
||||
* all clients (tmux-style). No-op after exit (L4); idempotent when unchanged.
|
||||
*/
|
||||
/**
|
||||
* Latest-writer-wins: the device that most recently fit/focused drives the PTY
|
||||
* size, so whichever device you are actively using is full-screen. (A shared
|
||||
* PTY can only be one size; min-sizing letterboxed the bigger screen.) The
|
||||
* frontend re-sends dims when a pane is shown or its window regains focus, so
|
||||
* switching devices reclaims full size. No-op after exit (L4) / when unchanged.
|
||||
*
|
||||
* The `ws` argument identifies the requesting client; the size is applied
|
||||
* directly to the PTY (no per-client dims map — latest writer wins).
|
||||
*/
|
||||
export function setClientDims(
|
||||
session: Session,
|
||||
ws: WebSocketLike,
|
||||
_ws: WebSocketLike,
|
||||
cols: number,
|
||||
rows: number,
|
||||
): void {
|
||||
if (session.exitedAt !== null) return;
|
||||
session.clientDims.set(ws, { cols, rows });
|
||||
applyDims(session, cols, rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forget a client's size when its tab goes hidden — but do NOT resize: the
|
||||
* device still actively viewing keeps its size (no letterboxing of a mirror).
|
||||
*/
|
||||
export function clearClientDims(session: Session, ws: WebSocketLike): void {
|
||||
session.clientDims.delete(ws);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill the session (idle reclaim). Under tmux this ends the actual shell via
|
||||
* `tmux kill-session` (H1); killing only the client pty would leave the tmux
|
||||
|
||||
Reference in New Issue
Block a user