feat(approvals) RejectConfig for request_permissions (#14118)
## Summary We need to support allowing request_permissions calls when using `Reject` policy <img width="1133" height="588" alt="Screenshot 2026-03-09 at 12 06 40 PM" src="https://github.com/user-attachments/assets/a8df987f-c225-4866-b8ab-5590960daec5" /> Note that this is a backwards-incompatible change for Reject policy. I'm not sure if we need to add a default based on our current use/setup ## Testing - [x] Added tests - [x] Tested locally
This commit is contained in:
parent
c1defcc98c
commit
6da84efed8
28 changed files with 285 additions and 1 deletions
|
|
@ -57,6 +57,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -66,6 +69,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4683,6 +4683,10 @@
|
|||
"description": "Reject MCP elicitation prompts.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"description": "Reject approval prompts related to built-in permission requests.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"description": "Reject prompts triggered by execpolicy `prompt` rules.",
|
||||
"type": "boolean"
|
||||
|
|
@ -4694,6 +4698,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -6752,6 +6752,10 @@
|
|||
"description": "Reject MCP elicitation prompts.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"description": "Reject approval prompts related to built-in permission requests.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"description": "Reject prompts triggered by execpolicy `prompt` rules.",
|
||||
"type": "boolean"
|
||||
|
|
@ -6763,6 +6767,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
@ -9232,6 +9237,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -9241,6 +9249,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -731,6 +731,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -740,6 +743,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -157,6 +160,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -29,6 +32,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -29,6 +32,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -33,6 +36,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -29,6 +32,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -33,6 +36,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -29,6 +32,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -33,6 +36,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
"mcp_elicitations": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -33,6 +36,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ sandbox_approval: boolean,
|
|||
* Reject prompts triggered by execpolicy `prompt` rules.
|
||||
*/
|
||||
rules: boolean,
|
||||
/**
|
||||
* Reject approval prompts related to built-in permission requests.
|
||||
*/
|
||||
request_permissions: boolean,
|
||||
/**
|
||||
* Reject MCP elicitation prompts.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "reject": { sandbox_approval: boolean, rules: boolean, mcp_elicitations: boolean, } } | "never";
|
||||
export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "reject": { sandbox_approval: boolean, rules: boolean, request_permissions: boolean, mcp_elicitations: boolean, } } | "never";
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ pub enum AskForApproval {
|
|||
Reject {
|
||||
sandbox_approval: bool,
|
||||
rules: bool,
|
||||
request_permissions: bool,
|
||||
mcp_elicitations: bool,
|
||||
},
|
||||
Never,
|
||||
|
|
@ -207,10 +208,12 @@ impl AskForApproval {
|
|||
AskForApproval::Reject {
|
||||
sandbox_approval,
|
||||
rules,
|
||||
request_permissions,
|
||||
mcp_elicitations,
|
||||
} => CoreAskForApproval::Reject(CoreRejectConfig {
|
||||
sandbox_approval,
|
||||
rules,
|
||||
request_permissions,
|
||||
mcp_elicitations,
|
||||
}),
|
||||
AskForApproval::Never => CoreAskForApproval::Never,
|
||||
|
|
@ -227,6 +230,7 @@ impl From<CoreAskForApproval> for AskForApproval {
|
|||
CoreAskForApproval::Reject(reject_config) => AskForApproval::Reject {
|
||||
sandbox_approval: reject_config.sandbox_approval,
|
||||
rules: reject_config.rules,
|
||||
request_permissions: reject_config.request_permissions,
|
||||
mcp_elicitations: reject_config.mcp_elicitations,
|
||||
},
|
||||
CoreAskForApproval::Never => AskForApproval::Never,
|
||||
|
|
@ -5832,6 +5836,30 @@ mod tests {
|
|||
assert_eq!(back_to_v2, v2_policy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ask_for_approval_reject_round_trips_request_permissions_flag() {
|
||||
let v2_policy = AskForApproval::Reject {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: true,
|
||||
mcp_elicitations: false,
|
||||
};
|
||||
|
||||
let core_policy = v2_policy.to_core();
|
||||
assert_eq!(
|
||||
core_policy,
|
||||
CoreAskForApproval::Reject(CoreRejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: true,
|
||||
mcp_elicitations: false,
|
||||
})
|
||||
);
|
||||
|
||||
let back_to_v2 = AskForApproval::from(core_policy);
|
||||
assert_eq!(back_to_v2, v2_policy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_server_elicitation_response_round_trips_rmcp_result() {
|
||||
let rmcp_result = rmcp::model::CreateElicitationResult {
|
||||
|
|
|
|||
|
|
@ -928,6 +928,8 @@ Only the granted subset matters on the wire. Any permissions omitted from `resul
|
|||
|
||||
Within the same turn, granted permissions are sticky: later shell-like tool calls can automatically reuse the granted subset without reissuing a separate permission request.
|
||||
|
||||
If the session approval policy uses `Reject` with `request_permissions: true`, the server does not send `item/permissions/requestApproval` to the client. Instead, the tool is auto-denied and resolves with an empty granted-permissions payload.
|
||||
|
||||
### Dynamic tool calls (experimental)
|
||||
|
||||
`dynamicTools` on `thread/start` and the corresponding `item/tool/call` request/response flow are experimental APIs. To enable them, set `initialize.params.capabilities.experimentalApi = true`.
|
||||
|
|
|
|||
|
|
@ -1316,6 +1316,10 @@
|
|||
"description": "Reject MCP elicitation prompts.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"request_permissions": {
|
||||
"description": "Reject approval prompts related to built-in permission requests.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"rules": {
|
||||
"description": "Reject prompts triggered by execpolicy `prompt` rules.",
|
||||
"type": "boolean"
|
||||
|
|
@ -1327,6 +1331,7 @@
|
|||
},
|
||||
"required": [
|
||||
"mcp_elicitations",
|
||||
"request_permissions",
|
||||
"rules",
|
||||
"sandbox_approval"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -2831,6 +2831,25 @@ impl Session {
|
|||
call_id: String,
|
||||
args: RequestPermissionsArgs,
|
||||
) -> Option<RequestPermissionsResponse> {
|
||||
match turn_context.approval_policy.value() {
|
||||
AskForApproval::Never => {
|
||||
return Some(RequestPermissionsResponse {
|
||||
permissions: PermissionProfile::default(),
|
||||
});
|
||||
}
|
||||
AskForApproval::Reject(reject_config)
|
||||
if reject_config.rejects_request_permissions() =>
|
||||
{
|
||||
return Some(RequestPermissionsResponse {
|
||||
permissions: PermissionProfile::default(),
|
||||
});
|
||||
}
|
||||
AskForApproval::OnFailure
|
||||
| AskForApproval::OnRequest
|
||||
| AskForApproval::UnlessTrusted
|
||||
| AskForApproval::Reject(_) => {}
|
||||
}
|
||||
|
||||
let (tx_response, rx_response) = oneshot::channel();
|
||||
let prev_entry = {
|
||||
let mut active = self.active_turn.lock().await;
|
||||
|
|
|
|||
|
|
@ -2165,6 +2165,128 @@ async fn notify_request_permissions_response_ignores_unmatched_call_id() {
|
|||
assert_eq!(session.granted_turn_permissions().await, None);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn request_permissions_emits_event_when_reject_policy_allows_requests() {
|
||||
let (session, mut turn_context, rx) = make_session_and_context_with_rx().await;
|
||||
*session.active_turn.lock().await = Some(ActiveTurn::default());
|
||||
Arc::get_mut(&mut turn_context)
|
||||
.expect("single turn context ref")
|
||||
.approval_policy
|
||||
.set(crate::protocol::AskForApproval::Reject(
|
||||
crate::protocol::RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: true,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: true,
|
||||
},
|
||||
))
|
||||
.expect("test setup should allow updating approval policy");
|
||||
|
||||
let session = Arc::new(session);
|
||||
let turn_context = Arc::new(turn_context);
|
||||
let call_id = "call-1".to_string();
|
||||
let expected_response = codex_protocol::request_permissions::RequestPermissionsResponse {
|
||||
permissions: codex_protocol::models::PermissionProfile {
|
||||
network: Some(codex_protocol::models::NetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
let handle = tokio::spawn({
|
||||
let session = Arc::clone(&session);
|
||||
let turn_context = Arc::clone(&turn_context);
|
||||
let call_id = call_id.clone();
|
||||
async move {
|
||||
session
|
||||
.request_permissions(
|
||||
turn_context.as_ref(),
|
||||
call_id,
|
||||
codex_protocol::request_permissions::RequestPermissionsArgs {
|
||||
reason: Some("need network".to_string()),
|
||||
permissions: codex_protocol::models::PermissionProfile {
|
||||
network: Some(codex_protocol::models::NetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
});
|
||||
|
||||
let request_event = tokio::time::timeout(StdDuration::from_secs(1), rx.recv())
|
||||
.await
|
||||
.expect("request_permissions event timed out")
|
||||
.expect("request_permissions event missing");
|
||||
let EventMsg::RequestPermissions(request) = request_event.msg else {
|
||||
panic!("expected request_permissions event");
|
||||
};
|
||||
assert_eq!(request.call_id, call_id);
|
||||
|
||||
session
|
||||
.notify_request_permissions_response(&request.call_id, expected_response.clone())
|
||||
.await;
|
||||
|
||||
let response = tokio::time::timeout(StdDuration::from_secs(1), handle)
|
||||
.await
|
||||
.expect("request_permissions future timed out")
|
||||
.expect("request_permissions join error");
|
||||
|
||||
assert_eq!(response, Some(expected_response));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn request_permissions_returns_empty_grant_when_reject_policy_blocks_requests() {
|
||||
let (session, mut turn_context, rx) = make_session_and_context_with_rx().await;
|
||||
*session.active_turn.lock().await = Some(ActiveTurn::default());
|
||||
Arc::get_mut(&mut turn_context)
|
||||
.expect("single turn context ref")
|
||||
.approval_policy
|
||||
.set(crate::protocol::AskForApproval::Reject(
|
||||
crate::protocol::RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: true,
|
||||
mcp_elicitations: false,
|
||||
},
|
||||
))
|
||||
.expect("test setup should allow updating approval policy");
|
||||
|
||||
let response = session
|
||||
.request_permissions(
|
||||
&turn_context,
|
||||
"call-1".to_string(),
|
||||
codex_protocol::request_permissions::RequestPermissionsArgs {
|
||||
reason: Some("need network".to_string()),
|
||||
permissions: codex_protocol::models::PermissionProfile {
|
||||
network: Some(codex_protocol::models::NetworkPermissions {
|
||||
enabled: Some(true),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
response,
|
||||
Some(
|
||||
codex_protocol::request_permissions::RequestPermissionsResponse {
|
||||
permissions: codex_protocol::models::PermissionProfile::default(),
|
||||
}
|
||||
)
|
||||
);
|
||||
assert!(
|
||||
tokio::time::timeout(StdDuration::from_millis(50), rx.recv())
|
||||
.await
|
||||
.is_err(),
|
||||
"unexpected request_permissions event emitted",
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn submit_with_id_captures_current_span_trace_context() {
|
||||
let (session, _turn_context) = make_session_and_context().await;
|
||||
|
|
|
|||
|
|
@ -1569,6 +1569,7 @@ prefix_rule(pattern=["git"], decision="prompt")
|
|||
AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
&SandboxPolicy::new_read_only_policy(),
|
||||
|
|
@ -1590,6 +1591,7 @@ prefix_rule(pattern=["git"], decision="prompt")
|
|||
approval_policy: AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
sandbox_policy: &SandboxPolicy::new_read_only_policy(),
|
||||
|
|
@ -1626,6 +1628,7 @@ prefix_rule(pattern=["git"], decision="prompt")
|
|||
approval_policy: AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
sandbox_policy: &SandboxPolicy::new_read_only_policy(),
|
||||
|
|
@ -1660,6 +1663,7 @@ prefix_rule(pattern=["git"], decision="prompt")
|
|||
approval_policy: AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: true,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
sandbox_policy: &SandboxPolicy::new_read_only_policy(),
|
||||
|
|
|
|||
|
|
@ -1739,6 +1739,7 @@ mod tests {
|
|||
RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}
|
||||
)));
|
||||
|
|
@ -1751,6 +1752,7 @@ mod tests {
|
|||
RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: true,
|
||||
}
|
||||
)));
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ mod tests {
|
|||
AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
&policy_workspace_only,
|
||||
|
|
@ -348,6 +349,7 @@ mod tests {
|
|||
AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}),
|
||||
&policy_workspace_only,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ mod tests {
|
|||
!runtime.wants_no_sandbox_approval(AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}))
|
||||
);
|
||||
|
|
@ -225,6 +226,7 @@ mod tests {
|
|||
runtime.wants_no_sandbox_approval(AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -398,6 +398,7 @@ mod tests {
|
|||
let policy = AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
});
|
||||
|
||||
|
|
@ -417,6 +418,7 @@ mod tests {
|
|||
let policy = AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: true,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: true,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ async fn shell_zsh_fork_skill_script_reject_policy_with_sandbox_approval_false_s
|
|||
let approval_policy = AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: true,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
});
|
||||
let server = start_mock_server().await;
|
||||
|
|
@ -380,6 +381,7 @@ async fn shell_zsh_fork_skill_script_reject_policy_with_sandbox_approval_true_sk
|
|||
let approval_policy = AskForApproval::Reject(RejectConfig {
|
||||
sandbox_approval: true,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
});
|
||||
let server = start_mock_server().await;
|
||||
|
|
|
|||
|
|
@ -453,12 +453,14 @@ impl DeveloperInstructions {
|
|||
let on_request_instructions = on_request_instructions();
|
||||
let sandbox_approval = reject_config.sandbox_approval;
|
||||
let rules = reject_config.rules;
|
||||
let request_permissions = reject_config.request_permissions;
|
||||
let mcp_elicitations = reject_config.mcp_elicitations;
|
||||
format!(
|
||||
"{on_request_instructions}\n\n\
|
||||
Approval policy is `reject`.\n\
|
||||
- `sandbox_approval`: {sandbox_approval}\n\
|
||||
- `rules`: {rules}\n\
|
||||
- `request_permissions`: {request_permissions}\n\
|
||||
- `mcp_elicitations`: {mcp_elicitations}\n\
|
||||
When a category is `true`, requests in that category are auto-rejected instead of prompting the user."
|
||||
)
|
||||
|
|
|
|||
|
|
@ -526,6 +526,8 @@ pub struct RejectConfig {
|
|||
pub sandbox_approval: bool,
|
||||
/// Reject prompts triggered by execpolicy `prompt` rules.
|
||||
pub rules: bool,
|
||||
/// Reject approval prompts related to built-in permission requests.
|
||||
pub request_permissions: bool,
|
||||
/// Reject MCP elicitation prompts.
|
||||
pub mcp_elicitations: bool,
|
||||
}
|
||||
|
|
@ -539,6 +541,10 @@ impl RejectConfig {
|
|||
self.rules
|
||||
}
|
||||
|
||||
pub const fn rejects_request_permissions(self) -> bool {
|
||||
self.request_permissions
|
||||
}
|
||||
|
||||
pub const fn rejects_mcp_elicitations(self) -> bool {
|
||||
self.mcp_elicitations
|
||||
}
|
||||
|
|
@ -3298,6 +3304,7 @@ mod tests {
|
|||
RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: true,
|
||||
}
|
||||
.rejects_mcp_elicitations()
|
||||
|
|
@ -3306,12 +3313,35 @@ mod tests {
|
|||
!RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}
|
||||
.rejects_mcp_elicitations()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reject_config_request_permissions_flag_is_field_driven() {
|
||||
assert!(
|
||||
RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: true,
|
||||
mcp_elicitations: false,
|
||||
}
|
||||
.rejects_request_permissions()
|
||||
);
|
||||
assert!(
|
||||
!RejectConfig {
|
||||
sandbox_approval: false,
|
||||
rules: false,
|
||||
request_permissions: false,
|
||||
mcp_elicitations: false,
|
||||
}
|
||||
.rejects_request_permissions()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn workspace_write_restricted_read_access_includes_effective_writable_roots() {
|
||||
let cwd = if cfg!(windows) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue