mirror of
https://github.com/openai/codex.git
synced 2026-05-01 20:02:05 +03:00
fix: prepare ExecPolicy in exec-server for execpolicy2 cutover (#6888)
This PR introduces an extra layer of abstraction to prepare us for the migration to execpolicy2: - introduces a new trait, `EscalationPolicy`, whose `determine_action()` method is responsible for producing the `EscalateAction` - the existing `ExecPolicy` typedef is changed to return an intermediate `ExecPolicyOutcome` instead of `EscalateAction` - the default implementation of `EscalationPolicy`, `McpEscalationPolicy`, composes `ExecPolicy` - the `ExecPolicyOutcome` includes `codex_execpolicy2::Decision`, which has a `Prompt` variant - when `McpEscalationPolicy` gets `Decision::Prompt` back from `ExecPolicy`, it prompts the user via an MCP elicitation and maps the result into an `ElicitationAction` - now that the end user can reply to an elicitation with `Decline` or `Cancel`, we introduce a new variant, `EscalateAction::Deny`, which the client handles by returning exit code `1` without running anything Note the way the elicitation is created is still not quite right, but I will fix that once we have things running end-to-end for real in a follow-up PR.
This commit is contained in:
@@ -64,25 +64,17 @@ use tracing_subscriber::{self};
|
||||
|
||||
use crate::posix::escalate_protocol::EscalateAction;
|
||||
use crate::posix::escalate_server::EscalateServer;
|
||||
use crate::posix::escalation_policy::EscalationPolicy;
|
||||
use crate::posix::mcp_escalation_policy::ExecPolicyOutcome;
|
||||
|
||||
mod escalate_client;
|
||||
mod escalate_protocol;
|
||||
mod escalate_server;
|
||||
mod escalation_policy;
|
||||
mod mcp;
|
||||
mod mcp_escalation_policy;
|
||||
mod socket;
|
||||
|
||||
fn dummy_exec_policy(file: &Path, argv: &[String], _workdir: &Path) -> EscalateAction {
|
||||
// TODO: execpolicy
|
||||
if file == Path::new("/opt/homebrew/bin/gh")
|
||||
&& let [_, arg1, arg2, ..] = argv
|
||||
&& arg1 == "issue"
|
||||
&& arg2 == "list"
|
||||
{
|
||||
return EscalateAction::Escalate;
|
||||
}
|
||||
EscalateAction::Run
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version)]
|
||||
pub struct Cli {
|
||||
@@ -135,7 +127,7 @@ pub async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
Some(Commands::ShellExec(args)) => {
|
||||
let bash_path = mcp::get_bash_path()?;
|
||||
let escalate_server = EscalateServer::new(bash_path, dummy_exec_policy);
|
||||
let escalate_server = EscalateServer::new(bash_path, DummyEscalationPolicy {});
|
||||
let result = escalate_server
|
||||
.exec(
|
||||
args.command.clone(),
|
||||
@@ -162,3 +154,59 @@ pub async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: replace with execpolicy2
|
||||
|
||||
struct DummyEscalationPolicy;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl EscalationPolicy for DummyEscalationPolicy {
|
||||
async fn determine_action(
|
||||
&self,
|
||||
file: &Path,
|
||||
argv: &[String],
|
||||
workdir: &Path,
|
||||
) -> Result<EscalateAction, rmcp::ErrorData> {
|
||||
let outcome = dummy_exec_policy(file, argv, workdir);
|
||||
let action = match outcome {
|
||||
ExecPolicyOutcome::Allow {
|
||||
run_with_escalated_permissions,
|
||||
} => {
|
||||
if run_with_escalated_permissions {
|
||||
EscalateAction::Escalate
|
||||
} else {
|
||||
EscalateAction::Run
|
||||
}
|
||||
}
|
||||
ExecPolicyOutcome::Forbidden => EscalateAction::Deny {
|
||||
reason: Some("Execution forbidden by policy".to_string()),
|
||||
},
|
||||
ExecPolicyOutcome::Prompt { .. } => EscalateAction::Deny {
|
||||
reason: Some("Could not prompt user for permission".to_string()),
|
||||
},
|
||||
};
|
||||
Ok(action)
|
||||
}
|
||||
}
|
||||
|
||||
fn dummy_exec_policy(file: &Path, argv: &[String], _workdir: &Path) -> ExecPolicyOutcome {
|
||||
if file.ends_with("/rm") {
|
||||
ExecPolicyOutcome::Forbidden
|
||||
} else if file.ends_with("/git") {
|
||||
ExecPolicyOutcome::Prompt {
|
||||
run_with_escalated_permissions: false,
|
||||
}
|
||||
} else if file == Path::new("/opt/homebrew/bin/gh")
|
||||
&& let [_, arg1, arg2, ..] = argv
|
||||
&& arg1 == "issue"
|
||||
&& arg2 == "list"
|
||||
{
|
||||
ExecPolicyOutcome::Allow {
|
||||
run_with_escalated_permissions: true,
|
||||
}
|
||||
} else {
|
||||
ExecPolicyOutcome::Allow {
|
||||
run_with_escalated_permissions: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user