Repository navigation
fix(host): count a destroy that cannot read its session id as inside - #259
Conversation
On Linux a CLI that could not read /proc/self/stat counted as outside the program's session. A destroy typed into the session's shell with the session variable unset then stopped its own session and died before it printed. Now it runs again in a new session. The copy skips the check (DESTROY_RERUN_ENV_KEY), so a needless copy costs one re-run and never another copy. Refs #220
|
@codex review |
|
@codex security review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (1)ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
In a PID namespace whose session leader runs outside it, /proc/self/stat shows session id 0, and ownLinuxSessionId's assertion crashed destroy. Refs #220
In a PID namespace whose session leader runs outside it (unshare -p -f, bwrap without --new-session), /proc/self/stat shows session id 0. ownLinuxSessionId asserted a positive id, so destroy crashed. Now it returns null for 0, and the CLI re-runs in a new session. Refs #220
…d-inside # Conflicts: # .agents/skills/verify-session-lifecycle/coverage.json
|
@codex review |
|
@codex security review |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6fd34746d9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…d-inside # Conflicts: # .agents/skills/verify-session-lifecycle/SKILL.md # .agents/skills/verify-session-lifecycle/coverage.json # src/host/lifecycle.ts # test/unit/host/lifecycle.test.ts
|
@codex review |
|
@codex security review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fcd8a4f417
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
A CLI in a pid namespace other than the host's, for example one that reads session id 0 and re-runs, read the program's childPid in its own namespace, so destroy --force could SIGKILL an unrelated process group through the tokenless fallback. Now readProgramGroup names no group when host.json records another pid namespace, and judgeHost keeps that host unknown, so the session gets no terminal write. Refs #220
|
@codex review |
|
@codex security review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2655d71b83
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
🛡️ Codex Security Review
Here are some automated security review suggestions for this pull request.
Reviewed commit: 2655d71b83
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
Why
The operator's goal is to land the open lifecycle issues he filed. #233 made
destroysurvive an unreadable/proc/self/statby counting the CLI as outside the program's session. That choice has a gap: adestroytyped into the session's own interactive shell, withAGENT_TTY_SESSION_IDunset, then destroys in place. It stops its own session and dies before it prints its result.What changed
cliRunsInsideProgramSessioncounts a Linux CLI that cannot read its session id as inside.destroythen runs again in a new session, as for any destroy from inside.ownLinuxSessionIdreads session id 0 as unknown too. In a PID namespace whose session leader runs outside it (unshare -p -f, bwrap without--new-session), the kernel shows 0, and the old assertion of a positive id madedestroyexit 1 withINTERNAL_ERROR.AGENT_TTY_DESTROY_RERUN=1and skips the check, so a needless copy costs one re-run and never starts another copy.readProgramGroupnames no tokenless group whenhost.jsonrecords a pid namespace other than the CLI's (sharesHostPidNamespaceinsrc/host/hostRecord.ts). Such a CLI would read the program'schildPidas another process group.facts.mjschecks the Linux branch statement by statement, andSKILL.md,docs/USAGE.mdandsrc/host/README.mddescribe the new rules.Scope
psand the controlling terminal, as before.destroy. The re-run exits with the same code. Ctrl-C does not reach that copy (tracked as a follow-up).destroy --forcethen cannot kill an unrelated process thathostPidnames there, because fix(host): prove the host pid with a start-up record before reconcile or destroy --force trusts it #260 (merged into this branch) kills only a host that its start-up record proves. Without a token, it also kills no group through the program'schildPidthere.Verification
on linux reads the caller as inside when /proc/self/stat fails(ENOENT and EACCES) and the integration testdestroy typed into an interactive shell that cannot read its session id prints its result. Both pass here. The second test commit,on linux reads the caller as inside when /proc/self/stat shows session id 0, fails on 40b423e with the assertion and passes here.destroy --force that reads session id 0 kills no unrelated process that hostPid names: a preload makes/proc/self/statshow session id 0, andhostPidnames an unrelatedsleep. It fails before the merge of fix(host): prove the host pid with a start-up record before reconcile or destroy --force trusts it #260 (thesleepgets SIGKILL) and passes after it.destroy --forceundersudo unshare -pf --mount-proc setpriv(session id 0): exit 5HOST_TIMEOUT, nothing killed, the host and the program's group stay alive.childPidis forged to the pgid of asetsid sleepinside the namespace: fcd8a4f kills that group, and 9e8de3c leaves it alive. The unit testsreadProgramGroup without a tokencover the same rule, and the namespace case fails on fcd8a4f.--maxWorkers=1 --retry=2): unit 1731, integration 335, e2e 34 passed. The only later commit syncs coverage.json.npm run typecheck,npm run lintandnpm run format:checkexit 0.bash -isession,unset AGENT_TTY_SESSION_IDand a preload that fails/proc/self/stat, thendestroy <id> --json > outtyped into the shell. On mainoutstays empty, because the destroy died. On this branchoutholdsok: trueanddestroyed: true. Both enddestroyedwith the group gone.destroyrun undersudo unshare -pf --mount-proc setpriv --reuid=<me>, where/proc/self/statshows session id 0: main exits 1 withINTERNAL_ERROR("own session id must be a positive integer") and the session staysrunning. This branch exits 0 withok: true, and the session readsdestroyedwith the group gone..agents/skills/verify-session-lifecycle/scripts/check.sh --update-coverage: exit 0, 64 runs as expected, 22,897,048 and 22,308,620 distinct states, after merging main0945021(fix(host): prove the host pid with a start-up record before reconcile or destroy --force trusts it #260). The model does not change.Refs #220
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:xhigh