Skip to content

fix(state): ACL guard names the principal and the remedy; context suite gets an owner-only tmp_root (CC-695, refs #778, #782) - #786

Merged
screenleon merged 2 commits into
mainfrom
fix/state-root-acl-message-778
Nov 5, 2026
Merged

screenleon merged 2 commits into
mainfrom
fix/state-root-acl-message-778

Conversation

@screenleon

@screenleon screenleon commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Refs #778 and #782 (CC-695). #778's third suggestion (a configurable allow list for known sandbox groups) is a security decision and is not done, so #778 stays open for it; #782 is fixed for the 7 telemetry cases it lists.

#778: 守衛的訊息

守衛本身是對的(繼承來的 CodexSandboxUsers Modify 確實讓別的主體能寫 run state),不放寬。要改的是訊息:

  • PowerShell 檢查在 UNSAFE 時輸出第一個違規主體與 inherited/explicit(UNSAFE|<identity>|<inherited|explicit>,bash 端仍接受單純的 UNSAFE)。
  • 守衛與 pmctl state status 透過同一個 _sw_acl_unsafe_reason 顯示:... (ACL grants write to a non-owner principal: BUILTIN\Users, inherited)。
  • 守衛另印一行:PM_DISPATCH_STATE_ROOT 指到只有自己能寫的目錄;繼承的授權可能屬於別的工具(例如 Codex 沙箱),不要未經確認就改父目錄。
  • docs/platform-support.md 補一條,含 icacls 建立目錄的做法與不要用 PM_DISPATCH_ALLOW_UNSAFE_STATE_ROOT=1 的提醒。

#782: 測試隔離

test-pmctl-context.sh 的 state root 建在 %TEMP% 底下,繼承 CodexSandboxUsers:(M);改為呼叫既有的 th_secure_state_root "$tmp_root"(test-pmctl-gate.sh 已這樣做),不放寬守衛。

驗證(原生 Windows,%TEMP% 實際含 CodexSandboxUsers:(OI)(CI)(M))

  • 真實繼承授權(父目錄 BUILTIN\Users:(M),子目錄繼承):拒絕訊息為 ... non-owner principal: BUILTIN\Users, inherited,後接補救行。
  • 測試隔離:%TEMP% 對 CodexSandboxUsers 有寫入權限時,test-pmctl-context.sh 的 telemetry 案例被 ACL 守衛拒絕 #782 的 7 個案例在 main 上失敗、改後通過:context.queried 2、reuse-scan 2、pack 3(各 filter 的 main 失敗數 2 / 2+1 / 3+2,改後只剩下面列的既有失敗)。
  • test-state-store.sh --filter ACL 7 通過;真實 ACL 的四個案例通過,並新增斷言:UNSAFE 時 _SW_ACL_OFFENDER 以 |explicit 結尾。test-state-status.sh 21 通過 2 略過。
  • 突變:原因不帶主體 → 具名案例失敗;PowerShell 不輸出主體 → real Modify ACE 案例失敗。
  • 仍失敗(main 上也一樣,與 ACL 無關):兩個 no-arg ... external git repo 案例(隔離守衛 exit 99)、marker round-trip reports stale then fresh。整個 test-pmctl-context.sh 超過 900 秒上限,沒有完整跑。
  • 沒有跑 pr-gate(本機規則:未經要求不跑),沒有跑 WSL。

Review (commands/ship.md Step 2.5)

CHANGED: the rejection text for the writer and for pmctl state status is built by one helper (_sw_acl_unsafe_reason); the harness helper th_secure_state_root was reused instead of a new ACL setup.

  • Permanent test admissions: no pr-gate round was run, so there is no gate finding; no new test function was added. The stubbed case state_store_init: Windows ACL write-grant rejected was folded to run both PowerShell answers (the bare UNSAFE of before and the named one) and the real-ACL helper _acl_writemask_case got one assertion on the named principal (criteria 1, 2, 4, 6: the observable contract is the rejection text and rc; no source grep). Both were mutation-tested.

🤖 Generated with Claude Code

Review (commands/ship.md Steps 2.5 and 3)

  • Refactor/reuse audit, second pass over the final diff: PASS: no warranted refactor/reuse change (the one consolidation, _sw_acl_unsafe_reason, was made earlier; the harness helper th_secure_state_root is reused).
  • Review executor/model: codex (gate-resolved), tier standard (auto), mode sequential, reviewers: critic, qa-tester, architecture-reviewer, security-reviewer (risk-reviewer was not selected; the report says it certifies nothing on that dimension)
  • Rounds: 1
  • Final verdict: GO (critic approve, qa-tester advise, architecture approve, security approve; Must-Fix: none, no finding id)
  • Result file: gate-20261105-130216.md (gate-20261105-040137-269c1b), pmctl gate wait verified it
  • Advisory kept as is: qa-tester-TG002, the reviewer sandbox stopped test-state-store at the same inherited-ACL rejection this PR is about, could not read git metadata (two test-state-status repository-identity assertions failed there; they pass here, 21 passed 2 skipped, and in CI) and hit its 280 s deadline on the inventory suite (the inventory lint itself passed). All of those suites passed natively and in CI. No new test requested.

screenleon and others added 2 commits November 5, 2026 11:59
…text suite gets an owner-only tmp_root (CC-695, refs #778, #782)

#778: the Windows state-root guard said only "a non-owner principal". The PowerShell check now reports the first
offending principal and whether the grant is inherited; the guard and `pmctl state status` show it through one
helper, and the guard adds a line on PM_DISPATCH_STATE_ROOT and on not editing a parent ACL another tool may need.
The guard is not loosened.

#782: test-pmctl-context.sh built its state roots under %TEMP%, which inherits CodexSandboxUsers:(M) on a host
with the Codex sandbox, so 7 telemetry cases were refused by the guard. It now calls th_secure_state_root on
tmp_root, as test-pmctl-gate.sh does.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ESW7P9wHJRbhxx3v7XyQuq
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ESW7P9wHJRbhxx3v7XyQuq
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