Surface skill permission profiles in zsh-fork exec approvals (#12753)

## Summary

- Preserve each skill’s raw permissions block as a permission_profile on
SkillMetadata during skill loading.
- Keep compiling that same metadata into the existing runtime
Permissions object, so current enforcement
    behavior stays intact.
- When zsh-fork intercepts execution of a script that belongs to a
skill, include the skill’s
    permission_profile in the exec approval request.
- This lets approval UIs show the extra filesystem access the skill
declared when prompting for approval.
This commit is contained in:
Celia Chen
2026-02-25 01:23:10 -08:00
committed by GitHub
Unverified
parent c4ec6be4ab
commit 6a3233da64
10 changed files with 137 additions and 23 deletions
@@ -17,6 +17,7 @@ use codex_execpolicy::Decision;
use codex_execpolicy::Policy;
use codex_execpolicy::RuleMatch;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::models::PermissionProfile;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::NetworkPolicyRuleAction;
use codex_protocol::protocol::RejectConfig;
@@ -179,6 +180,7 @@ impl CoreShellActionProvider {
argv: &[String],
workdir: &AbsolutePathBuf,
stopwatch: &Stopwatch,
additional_permissions: Option<PermissionProfile>,
) -> anyhow::Result<ReviewDecision> {
let command = join_program_and_argv(program, argv);
let workdir = workdir.to_path_buf();
@@ -198,7 +200,7 @@ impl CoreShellActionProvider {
None,
None,
None,
None,
additional_permissions,
)
.await
})
@@ -238,6 +240,7 @@ impl CoreShellActionProvider {
program: &AbsolutePathBuf,
argv: &[String],
workdir: &AbsolutePathBuf,
additional_permissions: Option<PermissionProfile>,
) -> anyhow::Result<EscalateAction> {
let action = match decision {
Decision::Forbidden => EscalateAction::Deny {
@@ -253,7 +256,16 @@ impl CoreShellActionProvider {
reason: Some("Execution forbidden by policy".to_string()),
}
} else {
match self.prompt(program, argv, workdir, &self.stopwatch).await? {
match self
.prompt(
program,
argv,
workdir,
&self.stopwatch,
additional_permissions,
)
.await?
{
ReviewDecision::Approved
| ReviewDecision::ApprovedExecpolicyAmendment { .. }
| ReviewDecision::ApprovedForSession => {
@@ -326,7 +338,14 @@ impl EscalationPolicy for CoreShellActionProvider {
// skill matches.
let needs_escalation = true;
return self
.process_decision(Decision::Prompt, needs_escalation, program, argv, workdir)
.process_decision(
Decision::Prompt,
needs_escalation,
program,
argv,
workdir,
skill.permission_profile.clone(),
)
.await;
}
@@ -366,6 +385,7 @@ impl EscalationPolicy for CoreShellActionProvider {
program,
argv,
workdir,
None,
)
.await
}