Skip to content

fix(host): count a destroy that cannot read its session id as inside - #259

Merged
ThomasK33 merged 14 commits into
mainfrom
fix/220-unreadable-sid-inside
Nov 3, 2026
Merged

ThomasK33 merged 14 commits into
mainfrom
fix/220-unreadable-sid-inside

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Why

The operator's goal is to land the open lifecycle issues he filed. #233 made destroy survive an unreadable /proc/self/stat by counting the CLI as outside the program's session. That choice has a gap: a destroy typed into the session's own interactive shell, with AGENT_TTY_SESSION_ID unset, then destroys in place. It stops its own session and dies before it prints its result.

What changed

  • cliRunsInsideProgramSession counts a Linux CLI that cannot read its session id as inside. destroy then runs again in a new session, as for any destroy from inside.
  • ownLinuxSessionId reads 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 made destroy exit 1 with INTERNAL_ERROR.
  • The copy gets AGENT_TTY_DESTROY_RERUN=1 and skips the check, so a needless copy costs one re-run and never starts another copy.
  • readProgramGroup names no tokenless group when host.json records a pid namespace other than the CLI's (sharesHostPidNamespace in src/host/hostRecord.ts). Such a CLI would read the program's childPid as another process group.
  • facts.mjs checks the Linux branch statement by statement, and SKILL.md, docs/USAGE.md and src/host/README.md describe the new rules.

Scope

  • Only Linux changes. Other POSIX systems compare through ps and the controlling terminal, as before.
  • An unreadable session id outside the program's session now costs one detached re-run of destroy. The re-run exits with the same code. Ctrl-C does not reach that copy (tracked as a follow-up).
  • A CLI that reads session id 0 can run in another PID namespace than the host. Its destroy --force then cannot kill an unrelated process that hostPid names 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's childPid there.

Verification

  • The first test commit fails on main: the unit test on linux reads the caller as inside when /proc/self/stat fails (ENOENT and EACCES) and the integration test destroy 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.
  • New integration test destroy --force that reads session id 0 kills no unrelated process that hostPid names: a preload makes /proc/self/stat show session id 0, and hostPid names an unrelated sleep. 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 (the sleep gets SIGKILL) and passes after it.
  • Live, host in the parent namespace, destroy --force under sudo unshare -pf --mount-proc setpriv (session id 0): exit 5 HOST_TIMEOUT, nothing killed, the host and the program's group stay alive.
  • Live, the same with a tokenless session whose childPid is forged to the pgid of a setsid sleep inside the namespace: fcd8a4f kills that group, and 9e8de3c leaves it alive. The unit tests readProgramGroup without a token cover the same rule, and the namespace case fails on fcd8a4f.
  • CI-shaped gate on 9e8de3c (unit, integration in 4 shards, e2e in 3 shards, --maxWorkers=1 --retry=2): unit 1731, integration 335, e2e 34 passed. The only later commit syncs coverage.json. npm run typecheck, npm run lint and npm run format:check exit 0.
  • Live, bash -i session, unset AGENT_TTY_SESSION_ID and a preload that fails /proc/self/stat, then destroy <id> --json > out typed into the shell. On main out stays empty, because the destroy died. On this branch out holds ok: true and destroyed: true. Both end destroyed with the group gone.
  • Live, destroy run under sudo unshare -pf --mount-proc setpriv --reuid=<me>, where /proc/self/stat shows session id 0: main exits 1 with INTERNAL_ERROR ("own session id must be a positive integer") and the session stays running. This branch exits 0 with ok: true, and the session reads destroyed with 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 main 0945021 (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

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
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T03:39:52.472950Z 2655d71 Manual request
🔒 Security Review ✅ Completed 2026-11-03T03:41:43.931576Z 2655d71 Manual request

Security findings

Advisory findings (1)

ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 40b423eccf

ℹ️ 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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 40b423eccf

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

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
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 6fd34746d9

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/host/lifecycle.ts Resolved
Comment thread src/host/lifecycle.ts Resolved
…hostPid names

The manifest's hostPid of a host in another PID namespace can name an
unrelated process in the CLI's namespace. Red until the host identity
check of #260 lands: the forced destroy SIGKILLs the unrelated process.

Refs #220
…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
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/host/lifecycle.ts Resolved
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: fcd8a4f417

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

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
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/host/hostRecord.ts Resolved

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛡️ 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.

Comment thread src/host/lifecycle.ts Resolved
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.

1 participant