mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Include sandbox mode in response metadata (#37507)
## What changed - Add the effective permission profile as `sandbox_mode` in turn metadata for regular, prewarm, compaction, and detached memory requests. - Reserve `sandbox_mode` so client-provided metadata cannot override the computed value. ## Testing - Cover metadata headers and request bodies for read-only and danger-full-access modes. GitOrigin-RevId: 13c690cc99bc2691023f281ca527af049bb1286f
This commit is contained in:
1 parent
45f8cafa4e
commit
4ca25a2c4e
10 files changed
+124
-15
No files matched your search
@@ -600,6 +600,7 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> {
|
||||
compact_metadata["request_kind"].as_str(),
|
||||
Some("compaction")
|
||||
);
|
||||
assert_eq!(compact_metadata["sandbox_mode"].as_str(), Some("read-only"));
|
||||
assert_eq!(
|
||||
compact_metadata["window_id"].as_str(),
|
||||
compact_request.header("x-codex-window-id").as_deref()
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ Scenario: After five varied API-key-auth turns, remote manual compaction omits s
|
||||
- "thread_id": "<UUID>",
|
||||
- "turn_id": "<UUID>",
|
||||
- "x-codex-installation-id": "<UUID>",
|
||||
- "x-codex-turn-metadata": "{\"installation_id\":\"<UUID>\",\"session_id\":\"<UUID>\",\"thread_id\":\"<UUID>\",\"turn_id\":\"<UUID>\",\"window_id\":\"<UUID>:0\",\"request_kind\":\"turn\",\"sandbox\":\"<SANDBOX>\",\"turn_started_at_unix_ms\":<UNIX_MS>}",
|
||||
- "x-codex-turn-metadata": "{\"installation_id\":\"<UUID>\",\"session_id\":\"<UUID>\",\"thread_id\":\"<UUID>\",\"turn_id\":\"<UUID>\",\"window_id\":\"<UUID>:0\",\"request_kind\":\"turn\",\"sandbox\":\"<SANDBOX>\",\"sandbox_mode\":\"read-only\",\"turn_started_at_unix_ms\":<UNIX_MS>}",
|
||||
- "x-codex-window-id": "<UUID>:0"
|
||||
- },
|
||||
- "include": [
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ Scenario: After five varied ChatGPT-auth turns, remote manual compaction reuses
|
||||
- "thread_id": "<UUID>",
|
||||
- "turn_id": "<UUID>",
|
||||
- "x-codex-installation-id": "<UUID>",
|
||||
- "x-codex-turn-metadata": "{\"installation_id\":\"<UUID>\",\"session_id\":\"<UUID>\",\"thread_id\":\"<UUID>\",\"turn_id\":\"<UUID>\",\"window_id\":\"<UUID>:0\",\"request_kind\":\"turn\",\"sandbox\":\"<SANDBOX>\",\"turn_started_at_unix_ms\":<UNIX_MS>}",
|
||||
- "x-codex-turn-metadata": "{\"installation_id\":\"<UUID>\",\"session_id\":\"<UUID>\",\"thread_id\":\"<UUID>\",\"turn_id\":\"<UUID>\",\"window_id\":\"<UUID>:0\",\"request_kind\":\"turn\",\"sandbox\":\"<SANDBOX>\",\"sandbox_mode\":\"read-only\",\"turn_started_at_unix_ms\":<UNIX_MS>}",
|
||||
- "x-codex-window-id": "<UUID>:0"
|
||||
- },
|
||||
- "include": [
|
||||
|
||||
@@ -94,6 +94,7 @@ async fn websocket_turn_state_persists_within_turn_and_resets_after() -> Result<
|
||||
|
||||
let server = start_websocket_server_with_headers(vec![WebSocketConnectionConfig {
|
||||
requests: vec![
|
||||
vec![ev_response_created("warm-1"), ev_completed("warm-1")],
|
||||
vec![
|
||||
json!({
|
||||
"type": "response.metadata",
|
||||
@@ -110,9 +111,9 @@ async fn websocket_turn_state_persists_within_turn_and_resets_after() -> Result<
|
||||
ev_completed("resp-2"),
|
||||
],
|
||||
vec![
|
||||
ev_response_created("resp-3"),
|
||||
ev_response_created("resp-4"),
|
||||
ev_assistant_message("msg-2", "done"),
|
||||
ev_completed("resp-3"),
|
||||
ev_completed("resp-4"),
|
||||
],
|
||||
],
|
||||
response_headers: Vec::new(),
|
||||
@@ -123,22 +124,74 @@ async fn websocket_turn_state_persists_within_turn_and_resets_after() -> Result<
|
||||
|
||||
let mut builder = test_codex();
|
||||
let test = builder.build_with_websocket_server(&server).await?;
|
||||
// Phase 1: the first response mints state for its same-turn tool follow-up.
|
||||
// Phase 1: startup prewarm uses the connection without generating a response.
|
||||
// Phase 2: the first turn mints state for its same-turn tool follow-up.
|
||||
test.submit_turn("run the echo command").await?;
|
||||
// Phase 2: the follow-up replays that state on the same physical connection.
|
||||
// Phase 3: the next logical turn reuses the connection but starts with empty state.
|
||||
// Phase 3: the follow-up replays that state on the same physical connection.
|
||||
// Phase 4: the next logical turn reuses the connection but starts with empty state.
|
||||
test.submit_turn("start another turn").await?;
|
||||
|
||||
assert_eq!(server.handshakes().len(), 1);
|
||||
let requests = server.single_connection();
|
||||
assert_eq!(requests.len(), 3);
|
||||
assert_eq!(requests.len(), 4);
|
||||
let bodies = requests
|
||||
.iter()
|
||||
.map(core_test_support::responses::WebSocketRequest::body_json)
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
requests
|
||||
bodies
|
||||
.iter()
|
||||
.map(|request| request.body_json()["client_metadata"][TURN_STATE_HEADER].clone())
|
||||
.map(|body| body["client_metadata"][TURN_STATE_HEADER].clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![json!(null), json!("ts-1"), json!(null)]
|
||||
vec![json!(null), json!(null), json!("ts-1"), json!(null)]
|
||||
);
|
||||
let turn_metadata = bodies
|
||||
.iter()
|
||||
.map(|body| {
|
||||
serde_json::from_str::<Value>(
|
||||
body["client_metadata"]["x-codex-turn-metadata"]
|
||||
.as_str()
|
||||
.expect("websocket request should include turn metadata"),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
assert_eq!(
|
||||
turn_metadata
|
||||
.iter()
|
||||
.map(|metadata| metadata["request_kind"].clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
json!("prewarm"),
|
||||
json!("turn"),
|
||||
json!("turn"),
|
||||
json!("turn"),
|
||||
]
|
||||
);
|
||||
assert_eq!(bodies[0]["generate"], json!(false));
|
||||
assert!(bodies[1..].iter().all(|body| body["generate"].is_null()));
|
||||
assert_eq!(
|
||||
turn_metadata
|
||||
.iter()
|
||||
.map(|metadata| metadata["sandbox_mode"].clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
json!("read-only"),
|
||||
json!("danger-full-access"),
|
||||
json!("danger-full-access"),
|
||||
json!("danger-full-access"),
|
||||
]
|
||||
);
|
||||
let first_turn_id = turn_metadata[1]["turn_id"]
|
||||
.as_str()
|
||||
.expect("first turn should include turn_id");
|
||||
let follow_up_turn_id = turn_metadata[2]["turn_id"]
|
||||
.as_str()
|
||||
.expect("same-turn follow-up should include turn_id");
|
||||
let next_turn_id = turn_metadata[3]["turn_id"]
|
||||
.as_str()
|
||||
.expect("next turn should include turn_id");
|
||||
assert_eq!(first_turn_id, follow_up_turn_id);
|
||||
assert_ne!(follow_up_turn_id, next_turn_id);
|
||||
|
||||
server.shutdown().await;
|
||||
Ok(())
|
||||
|
||||
Reference in new issue
Block a user