feat: record whether a skill script is approved for the session (#12756)

## Why

`unix_escalation.rs` checks a session-scoped approval cache before
prompting again for an execve-intercepted skill script. Without also
recording `ReviewDecision::ApprovedForSession`, that cache never gets
populated, so the same skill script can still trigger repeated approval
prompts within one session.

## What Changed

- Add `execve_session_approvals` to `SessionServices` so the session can
track approved skill script paths.
- Record the script path when a skill-script prompt returns
`ReviewDecision::ApprovedForSession`, but only for the skill-script path
rather than broader prefix-rule approvals.
- Reuse the cached approval on later execve callbacks by treating an
already-approved skill script as `Decision::Allow`.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/12756).
* #12758
* __->__ #12756
This commit is contained in:
Michael Bolin
2026-02-25 02:17:22 -08:00
committed by GitHub
parent 6d6570d89d
commit 93efcfd50d
3 changed files with 56 additions and 3 deletions

View File

@@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::sync::Arc;
use crate::AuthManager;
@@ -17,6 +18,7 @@ use crate::tools::sandboxing::ApprovalStore;
use crate::unified_exec::UnifiedExecProcessManager;
use codex_hooks::Hooks;
use codex_otel::OtelManager;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::path::PathBuf;
use tokio::sync::Mutex;
use tokio::sync::RwLock;
@@ -42,6 +44,8 @@ pub(crate) struct SessionServices {
pub(crate) models_manager: Arc<ModelsManager>,
pub(crate) otel_manager: OtelManager,
pub(crate) tool_approvals: Mutex<ApprovalStore>,
#[cfg_attr(not(unix), allow(dead_code))]
pub(crate) execve_session_approvals: RwLock<HashSet<AbsolutePathBuf>>,
pub(crate) skills_manager: Arc<SkillsManager>,
pub(crate) file_watcher: Arc<FileWatcher>,
pub(crate) agent_control: AgentControl,