Skip to content

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Nov 19, 2025

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.

@bolinfest bolinfest force-pushed the pr6888 branch 3 times, most recently from 9ed0ab7 to 000ae54 Compare November 19, 2025 19:16
@bolinfest bolinfest marked this pull request as ready for review November 19, 2025 19:25
@bolinfest bolinfest requested a review from zhao-oai November 19, 2025 19:26
Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 91 to 103
match result.action {
ElicitationAction::Accept => EscalateAction::Escalate,
ElicitationAction::Decline => EscalateAction::Deny {
Copy link
Contributor

Choose a reason for hiding this comment

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

P1 Badge Honor escalation flag for accepted prompts

When an exec policy returns Decision::Prompt with run_with_escalated_permissions set to false, an accepted elicitation is still mapped to EscalateAction::Escalate here, so prompted commands always run with elevated permissions even when the policy only intended an in-sandbox run. This over-privileges approved commands and changes the policy’s decision; the prompt branch should respect the run_with_escalated_permissions flag when translating an Accept.

Useful? React with 👍 / 👎.

Run,
/// The command should be escalated to the server for execution.
Escalate,
/// The command should be denied.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// The command should be denied.
/// The command should not be executed.

Comment on lines 34 to 36
pub fn new(bash_path: PathBuf, policy: Arc<dyn EscalationPolicy>) -> Self {
Self { bash_path, policy }
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: i feel like this should just take dyn EscalationPolicy and we can do the Arc::new internally? the fact that it's wrapped in Arc is kind of an implementation detail.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But then we have to wrap it in Box, which I don't think is any better?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a bit more ceremony, but it works:

    pub fn new<P>(bash_path: PathBuf, policy: P) -> Self
    where
        P: EscalationPolicy + Send + Sync + 'static,
    {
        Self {
            bash_path,
            policy: Arc::new(policy),
        }
    }

Comment on lines 25 to 28
pub(crate) struct ExecPolicyOutcome {
pub(crate) decision: Decision,
pub(crate) run_with_escalated_permissions: bool,
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be an enum; decision: Deny, run_with_escalated_permissions: true e.g. makes no sense

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do.

@bolinfest bolinfest merged commit 056c8f8 into main Nov 19, 2025
69 of 71 checks passed
@bolinfest bolinfest deleted the pr6888 branch November 19, 2025 21:55
@github-actions github-actions bot locked and limited conversation to collaborators Nov 19, 2025
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