Skip to content

core: adopt host_executable() rules in zsh-fork#13046

Merged
bolinfest merged 1 commit intomainfrom
pr13046
Feb 28, 2026
Merged

core: adopt host_executable() rules in zsh-fork#13046
bolinfest merged 1 commit intomainfrom
pr13046

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Feb 27, 2026

Why

#12964 added host_executable() support to codex-execpolicy, but the zsh-fork interception path in unix_escalation.rs was still evaluating commands with the default exact-token matcher.

That meant an intercepted absolute executable such as /usr/bin/git status could still miss basename rules like prefix_rule(pattern = ["git", "status"]), even when the policy also defined a matching host_executable(name = "git", ...) entry.

This PR adopts the new matching behavior in the zsh-fork runtime only. That keeps the rollout intentionally narrow: zsh-fork already requires explicit user opt-in, so it is a safer first caller to exercise the new host_executable() scheme before expanding it to other execpolicy call sites.

It also brings zsh-fork back in line with the current prefix_rule() execution model. Until prefix rules can carry their own permission profiles, a matched prefix_rule() is expected to rerun the intercepted command unsandboxed on allow, or after the user accepts prompt, instead of merely continuing inside the inherited shell sandbox.

What Changed

  • added evaluate_intercepted_exec_policy() in core/src/tools/runtimes/shell/unix_escalation.rs to centralize execpolicy evaluation for intercepted commands
  • switched intercepted direct execs in the zsh-fork path to check_multiple_with_options(...) with MatchOptions { resolve_host_executables: true }
  • added commands_for_intercepted_exec_policy() so zsh-fork policy evaluation works from intercepted (program, argv) data instead of reconstructing a synthetic command before matching
  • left shell-wrapper parsing intentionally disabled by default behind ENABLE_INTERCEPTED_EXEC_POLICY_SHELL_WRAPPER_PARSING, so path-sensitive matching relies on later direct exec interception rather than shell-script parsing
  • made matched prefix_rule() decisions rerun intercepted commands with EscalationExecution::Unsandboxed, while unmatched-command fallback keeps the existing sandbox-preserving behavior
  • extracted the zsh-fork test harness into core/tests/common/zsh_fork.rs so both the skill-focused and approval-focused integration suites can exercise the same runtime setup
  • limited this change to the intercepted zsh-fork path rather than changing every execpolicy caller at once
  • added runtime coverage in core/src/tools/runtimes/shell/unix_escalation_tests.rs for allowed and disallowed host_executable() mappings and the wrapper-parsing modes
  • added integration coverage in core/tests/suite/approvals.rs to verify a saved prefix_rule(pattern=["touch"], decision="allow") reruns under zsh-fork outside a restrictive WorkspaceWrite sandbox

Stack created with Sapling. Best reviewed with ReviewStack.

@bolinfest bolinfest force-pushed the pr13046 branch 2 times, most recently from 4369a27 to 72e67da Compare February 28, 2026 00:55
Copy link
Collaborator

@owenlin0 owenlin0 left a comment

Choose a reason for hiding this comment

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

love it, it's all coming together!

@bolinfest bolinfest enabled auto-merge (squash) February 28, 2026 01:14
@bolinfest bolinfest merged commit 1a8d930 into main Feb 28, 2026
78 of 84 checks passed
@bolinfest bolinfest deleted the pr13046 branch February 28, 2026 01:41
@github-actions github-actions bot locked and limited conversation to collaborators Feb 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants