* fix(gateway): permission modes work on rootless sessions via workspace default root Session permission modes hard-required a recorded sessionRoot, which only the sessions.create RPC ever records. Channel sessions, pre-#124909 rows, and exec-node sessions are rootless, so runs failed closed with 'session permission mode requires a recorded session root' (rows poisoned before the #128149 guards were permanently bricked) and operators could not set a mode on channel sessions at all. The mode semantics are root-free; every containment consumer already falls back to the workspace, and the remote worker launcher already derives its containment root from placement.remoteWorkspaceDir. Make that the canonical rule: a recorded sessionRoot pins worktree/explicit-cwd boundaries, and a rootless session's boundary is the agent's canonical workspace resolved where the run is prepared. - embedded runner + compaction: default policy root to realpath(workspace) instead of throwing/dropping the mode; bricked rows self-heal - gateway: delete the patch/create/reset rejection guards and session-permission-policy.ts entirely - codex plugin: helpers take a required defaultRoot (agent workspace fact, never a requested thread cwd); delete the four root throws; sandbox context for conversation bindings now derives from the agent workspace - ui: drop the rootless-rejection surface from the permission picker - docs: permission-modes boundary contract updated * fix(agents): split workspace path identity out of the kysely state store Heals main: #116650 made memory-host-sdk/dreaming.ts import resolveWorkspaceStateIdentity from workspace-state-store, statically pulling kysely into the memory-core doctor-contract closure and failing the doctor-contract-closure-guard lane on origin/main. The identity helpers are pure path/crypto code; move them to workspace-state-identity.ts and repoint all importers (dreaming, event-store, onboarding recommendations, workspace migrations, legacy state). * fix(ui): drop the unused permission picker sessionRoot prop and dead i18n keys check-prod-types caught the New Session dialog still passing the removed sessionRoot picker prop; the prop and the permissionControls.rootLabel / sessionRoot strings have had no consumers since #124301. * fix(codex): resolve rootless permission boundaries from agent config, not bind cwd ClawSweeper P1: /codex bind --cwd stores the requested path as the binding workspaceDir, which the previous commit then trusted as defaultRoot — letting a bound thread's requested cwd become (and widen) the rootless permission boundary. resolveConversationAppServerRuntime now owns the fact: it resolves the selected agent's canonical workspace from config (falling back to the plugin's configured default workspace), and the caller-supplied agentWorkspaceDir parameter chain is deleted so no call site can pass a tainted value. Recovery of recorded roots is unchanged (pinned roots stay pinned); the moved-history test now proves the bind-cwd clamp lands on the agent workspace.
2.9 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| Session permission modes, workspace boundaries, and escalation reviewers |
|
Session permission modes |
Session permission modes set one session's filesystem boundary and exec escalation reviewer. The boundary is the session's recorded canonical sessionRoot, or the selected agent's canonical workspace when no root is recorded. The mode determines what may happen inside or outside that boundary.
| Mode | Filesystem access | Exec escalation reviewer |
|---|---|---|
read-only |
Reads under sessionRoot; mutation tools omitted |
None; exec is denied |
guarded |
Reads and writes under sessionRoot |
A human after the allowlist fast path |
workspace |
Reads and writes under sessionRoot |
LLM review, with human fallback |
full |
Unrestricted filesystem access | None |
full requires operator.admin. The other modes require operator.write.
Session root and defaults
A permission mode can be set on any session. When a session has a recorded sessionRoot, that canonical path is its filesystem boundary. An explicit working directory and a managed worktree each pin their session's root. When no root is recorded, the boundary defaults to the selected agent's canonical workspace when the run is prepared.
Managed worktree sessions use the worktree checkout as sessionRoot. A nested working directory remains the runtime cwd, so relative paths start there while filesystem containment covers the whole checkout.
A new managed worktree session defaults to workspace when no mode is specified. Other sessions with no recorded mode keep the existing config-driven behavior.
Policy precedence and clamping
An explicit session mode takes precedence over the session's legacy execSecurity and execAsk overrides. When the mode is unset, those fields and the normal global or per-agent configuration continue to work as before.
An explicit full mode is the admin-authorized exception to host approval-file floors: its OpenClaw exec policy remains full with approvals off. Approval-file floors continue to tighten config-driven exec policy, legacy session overrides, unset modes, and every non-full session mode. Sandbox restrictions and tool allow/deny policy remain independent, and a harness may clamp an unsupported mode to a compatible safer policy tuple. Codex also continues to honor externally enforced requirements.toml constraints.
For the independent sandbox, tool-policy, and elevated-exec controls, see Sandbox vs tool policy vs elevated.