mirror of
https://github.com/openai/codex.git
synced 2026-05-05 22:01:37 +03:00
fix(subagents) share execpolicy by default (#13702)
## Summary If a subagent requests approval, and the user persists that approval to the execpolicy, it should (by default) propagate. We'll need to rethink this a bit in light of coming Permissions changes, though I think this is closer to the end state that we'd want, which is that execpolicy changes to one permissions profile should be synced across threads. ## Testing - [x] Added integration test --------- Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
@@ -32,8 +32,10 @@ use tracing::instrument;
|
||||
|
||||
use crate::bash::parse_shell_lc_plain_commands;
|
||||
use crate::bash::parse_shell_lc_single_command_prefix;
|
||||
use crate::config::Config;
|
||||
use crate::sandboxing::SandboxPermissions;
|
||||
use crate::tools::sandboxing::ExecApprovalRequirement;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use shlex::try_join as shlex_try_join;
|
||||
|
||||
const PROMPT_CONFLICT_REASON: &str =
|
||||
@@ -94,6 +96,24 @@ static BANNED_PREFIX_SUGGESTIONS: &[&[&str]] = &[
|
||||
&["osascript"],
|
||||
];
|
||||
|
||||
pub(crate) fn child_uses_parent_exec_policy(parent_config: &Config, child_config: &Config) -> bool {
|
||||
fn exec_policy_config_folders(config: &Config) -> Vec<AbsolutePathBuf> {
|
||||
config
|
||||
.config_layer_stack
|
||||
.get_layers(
|
||||
ConfigLayerStackOrdering::LowestPrecedenceFirst,
|
||||
/*include_disabled*/ false,
|
||||
)
|
||||
.into_iter()
|
||||
.filter_map(codex_config::ConfigLayerEntry::config_folder)
|
||||
.collect()
|
||||
}
|
||||
|
||||
exec_policy_config_folders(parent_config) == exec_policy_config_folders(child_config)
|
||||
&& parent_config.config_layer_stack.requirements().exec_policy
|
||||
== child_config.config_layer_stack.requirements().exec_policy
|
||||
}
|
||||
|
||||
fn is_policy_match(rule_match: &RuleMatch) -> bool {
|
||||
match rule_match {
|
||||
RuleMatch::PrefixRuleMatch { .. } => true,
|
||||
@@ -170,6 +190,7 @@ pub enum ExecPolicyUpdateError {
|
||||
|
||||
pub(crate) struct ExecPolicyManager {
|
||||
policy: ArcSwap<Policy>,
|
||||
update_lock: tokio::sync::Mutex<()>,
|
||||
}
|
||||
|
||||
pub(crate) struct ExecApprovalRequest<'a> {
|
||||
@@ -185,6 +206,7 @@ impl ExecPolicyManager {
|
||||
pub(crate) fn new(policy: Arc<Policy>) -> Self {
|
||||
Self {
|
||||
policy: ArcSwap::from(policy),
|
||||
update_lock: tokio::sync::Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,11 +314,11 @@ impl ExecPolicyManager {
|
||||
codex_home: &Path,
|
||||
amendment: &ExecPolicyAmendment,
|
||||
) -> Result<(), ExecPolicyUpdateError> {
|
||||
let _update_guard = self.update_lock.lock().await;
|
||||
let policy_path = default_policy_path(codex_home);
|
||||
let prefix = amendment.command.clone();
|
||||
spawn_blocking({
|
||||
let policy_path = policy_path.clone();
|
||||
let prefix = prefix.clone();
|
||||
let prefix = amendment.command.clone();
|
||||
move || blocking_append_allow_prefix_rule(&policy_path, &prefix)
|
||||
})
|
||||
.await
|
||||
@@ -306,8 +328,25 @@ impl ExecPolicyManager {
|
||||
source,
|
||||
})?;
|
||||
|
||||
let mut updated_policy = self.current().as_ref().clone();
|
||||
updated_policy.add_prefix_rule(&prefix, Decision::Allow)?;
|
||||
let current_policy = self.current();
|
||||
let match_options = MatchOptions {
|
||||
resolve_host_executables: true,
|
||||
};
|
||||
let existing_evaluation = current_policy.check_multiple_with_options(
|
||||
[&amendment.command],
|
||||
&|_| Decision::Forbidden,
|
||||
&match_options,
|
||||
);
|
||||
let already_allowed = existing_evaluation.decision == Decision::Allow
|
||||
&& existing_evaluation.matched_rules.iter().any(|rule_match| {
|
||||
is_policy_match(rule_match) && rule_match.decision() == Decision::Allow
|
||||
});
|
||||
if already_allowed {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut updated_policy = current_policy.as_ref().clone();
|
||||
updated_policy.add_prefix_rule(&amendment.command, Decision::Allow)?;
|
||||
self.policy.store(Arc::new(updated_policy));
|
||||
Ok(())
|
||||
}
|
||||
@@ -320,6 +359,7 @@ impl ExecPolicyManager {
|
||||
decision: Decision,
|
||||
justification: Option<String>,
|
||||
) -> Result<(), ExecPolicyUpdateError> {
|
||||
let _update_guard = self.update_lock.lock().await;
|
||||
let policy_path = default_policy_path(codex_home);
|
||||
let host = host.to_string();
|
||||
spawn_blocking({
|
||||
|
||||
Reference in New Issue
Block a user