feat: Workspace filesystem cleanup #391
3 issues
code-review: Found 3 issues (2 medium, 1 low)
Medium
Fire-and-forget runStartupLifecycleSweep can crash the daemon via unhandledRejection - `src/daemon.ts:493`
The setImmediate block invokes void runStartupLifecycleSweep() without attaching a .catch() handler, while enrichSentryMetadata() directly above it is properly wrapped with .catch(). Because process.on('unhandledRejection', handleCrash) is registered immediately afterward, any rejection from the lifecycle sweep would be treated as a daemon crash and trigger shutdown(1). This defeats the stated intent in the comment that the sweep is fire-and-forget and should not impact request serving — a transient filesystem error during reconciliation would terminate a freshly started daemon.
Socket path relocation breaks discovery of existing daemons - `src/daemon/socket-path.ts:33-44`
The socket file location changed from ~/.xcodebuildmcp/daemons/{key}/daemon.sock to {tmpdir}/xcodebuildmcp-{compactKey}/d.sock, and the registry/log paths also moved. Any daemon process started before this change will not be discoverable by the new code, and vice versa. Without a migration path or fallback lookup, upgrading users may end up with orphaned daemon processes and duplicate daemons being spawned for the same workspace.
Also found at:
src/daemon/socket-path.ts:21-23
Low
TOCTOU between statSync and chmodSync in validateSocketDir - `src/daemon/socket-path.ts:84-86`
validateSocketDir reads stat.mode via statSync, then conditionally calls chmodSync(dir, 0o700). Between these two syscalls, the directory could be replaced (e.g., on filesystems where the user has write access to the parent). Since the uid check has already passed, exploitability is limited, but using fchmod on an opened directory descriptor or re-stat'ing after open would be more robust. The greater concern is that detecting loose perms and silently fixing them masks unexpected state instead of failing closed.
Duration: 16m 17s · Tokens: 1.3M in / 14.3k out · Cost: $3.99 (+merge: $0.00)
Annotations
Check warning on line 493 in src/daemon.ts
sentry-warden / warden: code-review
Fire-and-forget runStartupLifecycleSweep can crash the daemon via unhandledRejection
The `setImmediate` block invokes `void runStartupLifecycleSweep()` without attaching a `.catch()` handler, while `enrichSentryMetadata()` directly above it is properly wrapped with `.catch()`. Because `process.on('unhandledRejection', handleCrash)` is registered immediately afterward, any rejection from the lifecycle sweep would be treated as a daemon crash and trigger `shutdown(1)`. This defeats the stated intent in the comment that the sweep is fire-and-forget and should not impact request serving — a transient filesystem error during reconciliation would terminate a freshly started daemon.
Check warning on line 44 in src/daemon/socket-path.ts
sentry-warden / warden: code-review
Socket path relocation breaks discovery of existing daemons
The socket file location changed from `~/.xcodebuildmcp/daemons/{key}/daemon.sock` to `{tmpdir}/xcodebuildmcp-{compactKey}/d.sock`, and the registry/log paths also moved. Any daemon process started before this change will not be discoverable by the new code, and vice versa. Without a migration path or fallback lookup, upgrading users may end up with orphaned daemon processes and duplicate daemons being spawned for the same workspace.
Check warning on line 23 in src/daemon/socket-path.ts
sentry-warden / warden: code-review
[94M-TJS] Socket path relocation breaks discovery of existing daemons (additional location)
The socket file location changed from `~/.xcodebuildmcp/daemons/{key}/daemon.sock` to `{tmpdir}/xcodebuildmcp-{compactKey}/d.sock`, and the registry/log paths also moved. Any daemon process started before this change will not be discoverable by the new code, and vice versa. Without a migration path or fallback lookup, upgrading users may end up with orphaned daemon processes and duplicate daemons being spawned for the same workspace.