Files
codex/codex-rs/app-server-protocol/schema/json/v1/SendUserTurnParams.json
Michael Bolin 425fff7ad6 feat: add Reject approval policy with granular prompt rejection controls (#12087)
## Why

We need a way to auto-reject specific approval prompt categories without
switching all approvals off.

The goal is to let users independently control:
- sandbox escalation approvals,
- execpolicy `prompt` rule approvals,
- MCP elicitation prompts.

## What changed

- Added a new primary approval mode in `protocol/src/protocol.rs`:

```rust
pub enum AskForApproval {
    // ...
    Reject(RejectConfig),
    // ...
}

pub struct RejectConfig {
    pub sandbox_approval: bool,
    pub rules: bool,
    pub mcp_elicitations: bool,
}
```

- Wired `RejectConfig` semantics through approval paths in `core`:
  - `core/src/exec_policy.rs`
    - rejects rule-driven prompts when `rules = true`
    - rejects sandbox/escalation prompts when `sandbox_approval = true`
- preserves rule priority when both rule and sandbox prompt conditions
are present
  - `core/src/tools/sandboxing.rs`
- applies `sandbox_approval` to default exec approval decisions and
sandbox-failure retry gating
  - `core/src/safety.rs`
- keeps `Reject { all false }` behavior aligned with `OnRequest` for
patch safety
    - rejects out-of-root patch approvals when `sandbox_approval = true`
  - `core/src/mcp_connection_manager.rs`
    - auto-declines MCP elicitations when `mcp_elicitations = true`

- Ensured approval policy used by MCP elicitation flow stays in sync
with constrained session policy updates.

- Updated app-server v2 conversions and generated schema/TypeScript
artifacts for the new `Reject` shape.

## Verification

Added focused unit coverage for the new behavior in:
- `core/src/exec_policy.rs`
- `core/src/tools/sandboxing.rs`
- `core/src/mcp_connection_manager.rs`
- `core/src/safety.rs`
- `core/src/tools/runtimes/apply_patch.rs`

Key cases covered include rule-vs-sandbox prompt precedence, MCP
auto-decline behavior, and patch/sandbox retry behavior under
`RejectConfig`.
2026-02-19 11:41:49 -08:00

482 lines
14 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"AbsolutePathBuf": {
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
{
"description": "Under this policy, only \"known safe\" commands—as determined by `is_safe_command()`—that **only read files** are autoapproved. Everything else will ask the user to approve.",
"enum": [
"untrusted"
],
"type": "string"
},
{
"description": "DEPRECATED: *All* commands are autoapproved, but they are expected to run inside a sandbox where network access is disabled and writes are confined to a specific set of paths. If the command fails, it will be escalated to the user to approve execution without a sandbox. Prefer `OnRequest` for interactive runs or `Never` for non-interactive runs.",
"enum": [
"on-failure"
],
"type": "string"
},
{
"description": "The model decides when to ask the user for approval.",
"enum": [
"on-request"
],
"type": "string"
},
{
"additionalProperties": false,
"description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.",
"properties": {
"reject": {
"$ref": "#/definitions/RejectConfig"
}
},
"required": [
"reject"
],
"title": "RejectAskForApproval",
"type": "object"
},
{
"description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.",
"enum": [
"never"
],
"type": "string"
}
]
},
"InputItem": {
"oneOf": [
{
"properties": {
"data": {
"properties": {
"text": {
"type": "string"
},
"text_elements": {
"default": [],
"description": "UI-defined spans within `text` used to render or persist special elements.",
"items": {
"$ref": "#/definitions/V1TextElement"
},
"type": "array"
}
},
"required": [
"text"
],
"type": "object"
},
"type": {
"enum": [
"text"
],
"title": "TextInputItemType",
"type": "string"
}
},
"required": [
"data",
"type"
],
"title": "TextInputItem",
"type": "object"
},
{
"properties": {
"data": {
"properties": {
"image_url": {
"type": "string"
}
},
"required": [
"image_url"
],
"type": "object"
},
"type": {
"enum": [
"image"
],
"title": "ImageInputItemType",
"type": "string"
}
},
"required": [
"data",
"type"
],
"title": "ImageInputItem",
"type": "object"
},
{
"properties": {
"data": {
"properties": {
"path": {
"type": "string"
}
},
"required": [
"path"
],
"type": "object"
},
"type": {
"enum": [
"localImage"
],
"title": "LocalImageInputItemType",
"type": "string"
}
},
"required": [
"data",
"type"
],
"title": "LocalImageInputItem",
"type": "object"
}
]
},
"NetworkAccess": {
"description": "Represents whether outbound network access is available to the agent.",
"enum": [
"restricted",
"enabled"
],
"type": "string"
},
"ReadOnlyAccess": {
"description": "Determines how read-only file access is granted inside a restricted sandbox.",
"oneOf": [
{
"description": "Restrict reads to an explicit set of roots.\n\nWhen `include_platform_defaults` is `true`, platform defaults required for basic execution are included in addition to `readable_roots`.",
"properties": {
"include_platform_defaults": {
"default": true,
"description": "Include built-in platform read roots required for basic process execution.",
"type": "boolean"
},
"readable_roots": {
"description": "Additional absolute roots that should be readable.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
},
"type": {
"enum": [
"restricted"
],
"title": "RestrictedReadOnlyAccessType",
"type": "string"
}
},
"required": [
"type"
],
"title": "RestrictedReadOnlyAccess",
"type": "object"
},
{
"description": "Allow unrestricted file reads.",
"properties": {
"type": {
"enum": [
"full-access"
],
"title": "FullAccessReadOnlyAccessType",
"type": "string"
}
},
"required": [
"type"
],
"title": "FullAccessReadOnlyAccess",
"type": "object"
}
]
},
"ReasoningEffort": {
"description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning",
"enum": [
"none",
"minimal",
"low",
"medium",
"high",
"xhigh"
],
"type": "string"
},
"ReasoningSummary": {
"description": "A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#reasoning-summaries",
"oneOf": [
{
"enum": [
"auto",
"concise",
"detailed"
],
"type": "string"
},
{
"description": "Option to disable reasoning summaries.",
"enum": [
"none"
],
"type": "string"
}
]
},
"RejectConfig": {
"properties": {
"mcp_elicitations": {
"description": "Reject MCP elicitation prompts.",
"type": "boolean"
},
"rules": {
"description": "Reject prompts triggered by execpolicy `prompt` rules.",
"type": "boolean"
},
"sandbox_approval": {
"description": "Reject approval prompts related to sandbox escalation.",
"type": "boolean"
}
},
"required": [
"mcp_elicitations",
"rules",
"sandbox_approval"
],
"type": "object"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
{
"description": "No restrictions whatsoever. Use with caution.",
"properties": {
"type": {
"enum": [
"danger-full-access"
],
"title": "DangerFullAccessSandboxPolicyType",
"type": "string"
}
},
"required": [
"type"
],
"title": "DangerFullAccessSandboxPolicy",
"type": "object"
},
{
"description": "Read-only access configuration.",
"properties": {
"access": {
"allOf": [
{
"$ref": "#/definitions/ReadOnlyAccess"
}
],
"description": "Read access granted while running under this policy."
},
"type": {
"enum": [
"read-only"
],
"title": "ReadOnlySandboxPolicyType",
"type": "string"
}
},
"required": [
"type"
],
"title": "ReadOnlySandboxPolicy",
"type": "object"
},
{
"description": "Indicates the process is already in an external sandbox. Allows full disk access while honoring the provided network setting.",
"properties": {
"network_access": {
"allOf": [
{
"$ref": "#/definitions/NetworkAccess"
}
],
"default": "restricted",
"description": "Whether the external sandbox permits outbound network traffic."
},
"type": {
"enum": [
"external-sandbox"
],
"title": "ExternalSandboxSandboxPolicyType",
"type": "string"
}
},
"required": [
"type"
],
"title": "ExternalSandboxSandboxPolicy",
"type": "object"
},
{
"description": "Same as `ReadOnly` but additionally grants write access to the current working directory (\"workspace\").",
"properties": {
"exclude_slash_tmp": {
"default": false,
"description": "When set to `true`, will NOT include the `/tmp` among the default writable roots on UNIX. Defaults to `false`.",
"type": "boolean"
},
"exclude_tmpdir_env_var": {
"default": false,
"description": "When set to `true`, will NOT include the per-user `TMPDIR` environment variable among the default writable roots. Defaults to `false`.",
"type": "boolean"
},
"network_access": {
"default": false,
"description": "When set to `true`, outbound network access is allowed. `false` by default.",
"type": "boolean"
},
"read_only_access": {
"allOf": [
{
"$ref": "#/definitions/ReadOnlyAccess"
}
],
"description": "Read access granted while running under this policy."
},
"type": {
"enum": [
"workspace-write"
],
"title": "WorkspaceWriteSandboxPolicyType",
"type": "string"
},
"writable_roots": {
"description": "Additional folders (beyond cwd and possibly TMPDIR) that should be writable from within the sandbox.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
},
"type": "array"
}
},
"required": [
"type"
],
"title": "WorkspaceWriteSandboxPolicy",
"type": "object"
}
]
},
"ThreadId": {
"type": "string"
},
"V1ByteRange": {
"properties": {
"end": {
"description": "End byte offset (exclusive) within the UTF-8 text buffer.",
"format": "uint",
"minimum": 0.0,
"type": "integer"
},
"start": {
"description": "Start byte offset (inclusive) within the UTF-8 text buffer.",
"format": "uint",
"minimum": 0.0,
"type": "integer"
}
},
"required": [
"end",
"start"
],
"type": "object"
},
"V1TextElement": {
"properties": {
"byteRange": {
"allOf": [
{
"$ref": "#/definitions/V1ByteRange"
}
],
"description": "Byte range in the parent `text` buffer that this element occupies."
},
"placeholder": {
"description": "Optional human-readable placeholder for the element, displayed in the UI.",
"type": [
"string",
"null"
]
}
},
"required": [
"byteRange"
],
"type": "object"
}
},
"properties": {
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"conversationId": {
"$ref": "#/definitions/ThreadId"
},
"cwd": {
"type": "string"
},
"effort": {
"anyOf": [
{
"$ref": "#/definitions/ReasoningEffort"
},
{
"type": "null"
}
]
},
"items": {
"items": {
"$ref": "#/definitions/InputItem"
},
"type": "array"
},
"model": {
"type": "string"
},
"outputSchema": {
"description": "Optional JSON Schema used to constrain the final assistant message for this turn."
},
"sandboxPolicy": {
"$ref": "#/definitions/SandboxPolicy"
},
"summary": {
"$ref": "#/definitions/ReasoningSummary"
}
},
"required": [
"approvalPolicy",
"conversationId",
"cwd",
"items",
"model",
"sandboxPolicy",
"summary"
],
"title": "SendUserTurnParams",
"type": "object"
}