mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
## What changed - Handle `openai/userVerification` requests through `openai/elicitation/create` when the client advertises `userVerification` support. - Validate request fields, size limits, and base64url encoding. Require a correctly shaped, bounded proof for acceptance; cancel invalid acceptance responses and discard proof material on decline or cancellation. - Handle request and service cancellation, including cancellation received before request dispatch. Bound early-cancellation storage and cancel new verifications when capacity is exceeded. - Keep verification inactive in Codex: cancel requests without prompting until the typed app-server and UI path is available. ## Testing Add tests for request and proof validation, malformed modes, cancellation races and capacity limits, timeout-pause cleanup, and independent concurrent requests. Add integration coverage showing that verification does not prompt or prevent tool and turn completion before activation. GitOrigin-RevId: 6313c1be40fae0b33cc3ce0f8fe025b4124ed2ef
113 lines
3.6 KiB
Rust
113 lines
3.6 KiB
Rust
use super::*;
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn user_verification_request_preserves_signed_bytes_and_display_text() {
|
|
assert_eq!(
|
|
parse_request(CustomRequest::new(
|
|
"openai/elicitation/create",
|
|
Some(json!({
|
|
"mode": MODE,
|
|
"title": "Approve purchase",
|
|
"description": "Pay $200 to Example Store",
|
|
"challenge": "AQID",
|
|
})),
|
|
))
|
|
.unwrap(),
|
|
Elicitation::UserVerification {
|
|
title: "Approve purchase".to_string(),
|
|
description: "Pay $200 to Example Store".to_string(),
|
|
challenge: "AQID".to_string(),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn user_verification_rejects_invalid_or_unbounded_requests_without_echoing_values() {
|
|
for (field, value) in [
|
|
("mode", json!("unknown")),
|
|
("title", json!("")),
|
|
("title", json!("x".repeat(257))),
|
|
("description", json!("x".repeat(4097))),
|
|
("challenge", json!("")),
|
|
("challenge", json!("not base64url!")),
|
|
("challenge", json!(URL_SAFE_NO_PAD.encode(vec![0; 4097]))),
|
|
("unexpected", json!("secret")),
|
|
] {
|
|
let mut params = json!({
|
|
"mode": MODE, "title": "Approve", "description": "", "challenge": "AQID"
|
|
});
|
|
params[field] = value;
|
|
assert_eq!(
|
|
parse_request(CustomRequest::new(
|
|
"openai/elicitation/create",
|
|
Some(params)
|
|
)),
|
|
Err(invalid_request()),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn user_verification_acceptance_returns_proof_only_in_content() {
|
|
let content = Some(json!({"credentialId": "credential:用户/1=", "signature": "BAUG"}));
|
|
assert_eq!(
|
|
validate_response(ElicitationResponse {
|
|
action: ElicitationAction::Accept,
|
|
content: content.clone(),
|
|
meta: Some(json!({"untrusted": "ignored"})),
|
|
}),
|
|
ElicitationResponse {
|
|
action: ElicitationAction::Accept,
|
|
content,
|
|
meta: None,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn user_verification_cancels_acceptance_without_a_valid_bounded_proof() {
|
|
for content in [
|
|
None,
|
|
Some(json!({})),
|
|
Some(json!({"credentialId": "AQID", "signature": ""})),
|
|
Some(json!({"credentialId": "AQID", "signature": "BAUG="})),
|
|
Some(json!({"credentialId": "é".repeat(513), "signature": "BAUG"})),
|
|
Some(json!({"credentialId": "", "signature": "BAUG"})),
|
|
Some(json!({"credentialId": "AQID", "signature": URL_SAFE_NO_PAD.encode(vec![0; 129])})),
|
|
Some(json!({"credentialId": "AQID", "signature": "BAUG", "extra": true})),
|
|
] {
|
|
assert_eq!(
|
|
validate_response(ElicitationResponse {
|
|
action: ElicitationAction::Accept,
|
|
content,
|
|
meta: None,
|
|
}),
|
|
ElicitationResponse {
|
|
action: ElicitationAction::Cancel,
|
|
content: None,
|
|
meta: None,
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn user_verification_decline_and_cancel_discard_proof_material() {
|
|
for action in [ElicitationAction::Decline, ElicitationAction::Cancel] {
|
|
assert_eq!(
|
|
validate_response(ElicitationResponse {
|
|
action: action.clone(),
|
|
content: Some(json!({"credentialId": "AQID", "signature": "BAUG"})),
|
|
meta: Some(json!({"secret": "discarded"})),
|
|
}),
|
|
ElicitationResponse {
|
|
action,
|
|
content: None,
|
|
meta: None
|
|
}
|
|
);
|
|
}
|
|
}
|