Skip to content

fix: keep a process's identity valid across exec on macOS - #125

Open
behruznassre wants to merge 1 commit into
sendbird:mainfrom
behruznassre:fix/105-macos-identity-survives-exec
Open

behruznassre wants to merge 1 commit into
sendbird:mainfrom
behruznassre:fix/105-macos-identity-survives-exec

Conversation

@behruznassre

Copy link
Copy Markdown
Contributor

Summary

  • on macOS, getProcessIdentity records the process start time alone (ps -o lstart=), so a legitimate exec no longer invalidates a live process's identity
  • validateProcessIdentity still matches an identity recorded in the old lstart + comm form on its start time, so a job that is running while the plugin updates is not reaped
  • regression rows in tests/process.test.mjs

Root cause

The macOS identity was ps -o lstart=,comm=. An exec keeps the PID and the start time but changes comm. With CC_PLUGIN_CODEX_CLAUDE_BIN pointing at a shell wrapper that execs Claude, runClaudeTurn() captured the wrapper's identity right after spawn. The identity then stopped matching once the wrapper exec'd, and reapStaleJobs() marked the live job failed.

PID-reuse protection is unchanged in kind: a reused PID has a different start time. comm added nothing a start time does not already rule out, short of a PID reused within the same second (lstart has one-second resolution). Linux already used the /proc/<pid>/stat start time alone.

Validation

  • the issue's reproduction on main (19e5651): {"before":"… /bin/zsh","after":"… node","alive":true,"identityValidated":false}
  • new rows fail on main and pass with the fix:
    • still validates a process after it execs another program runs a real /bin/sh that execs node, waiting on output markers rather than sleeps, so it has no timing race
    • matches an identity recorded with comm (v1.5.0 and earlier) on its start time covers the old format
  • kept: the different-start-time rejection, dead PID, mismatched identity, and both denied-probe rows (fix: fall back to the liveness probe when the identity probe is denied #88)
  • npm run check: unit 517 passed, integration 45 passed, Codex E2E 23 passed; lint, typecheck, version-sync and changelog OK
  • git diff --check: clean

Not verified end to end: a real Claude turn through a wrapper. The fix is in the shared identity function that runClaudeTurn, reapStaleJobs and cancellation all use.

Fixes #105

🤖 Generated with Claude Code

On macOS the process identity was `ps -o lstart=,comm=`. A legitimate exec
keeps the PID and start time but changes comm, so a CC_PLUGIN_CODEX_CLAUDE_BIN
shell wrapper that execs Claude failed validateProcessIdentity while alive,
and reapStaleJobs marked the running job failed (sendbird#105).

The identity is now the start time alone, which a reused PID cannot share.
An identity recorded in the old lstart+comm form still matches on its start
time, so a job running while the plugin updates is not reaped.

Fixes sendbird#105

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS: live wrapper PID fails identity validation after exec, risking auto-reap and missing results

1 participant