mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
windows-sandbox: send permission profiles to elevated runner (#22918)
## Why This is the next PR in the Windows sandbox migration stack after #22896. The bottom PR introduces a Windows-local resolved permissions helper while existing callers still start from legacy `SandboxPolicy`. This PR moves the elevated runner IPC boundary to `PermissionProfile`, which makes the direction of the stack visible without changing the public core call sites yet. Because that changes the CLI-to-command-runner message shape, the framed IPC protocol version is bumped in the same PR so the boundary change is explicit. ## What changed - Replaced elevated IPC `policy_json_or_preset`/`sandbox_policy_cwd` fields with `permission_profile`/`permission_profile_cwd`. - Bumped the elevated command-runner IPC protocol to `IPC_PROTOCOL_VERSION = 2` and switched parent/runner frames to use the shared constant. - Converted the parent elevated paths from the parsed legacy policy into a materialized `PermissionProfile` before sending the runner request. - Added `WindowsSandboxTokenMode` resolution for managed `PermissionProfile` values and made the runner choose read-only vs writable-root capability tokens from that resolved profile. - Rejected disabled, external, unrestricted, and full-disk-write profiles before token selection. - Added IPC JSON coverage for tagged `PermissionProfile` payloads and token-mode unit coverage for the resolved permission helper. ## Verification - `cargo test -p codex-windows-sandbox` - `just fix -p codex-windows-sandbox` - `cargo check -p codex-windows-sandbox --target x86_64-pc-windows-msvc --tests` was attempted locally but blocked before crate type-checking because the macOS compiler environment lacks Windows C headers such as `windows.h` and `assert.h`; GitHub Windows CI is the required verification for the runner path. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22918). * #23715 * #23714 * #23167 * #22923 * __->__ #22918
This commit is contained in:
1 parent
cb05de6724
commit
729bdf3c8d
8 files changed
+273
-27
No files matched your search
@@ -10,6 +10,7 @@
|
||||
use anyhow::Result;
|
||||
use base64::Engine as _;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
@@ -23,6 +24,9 @@ use std::path::PathBuf;
|
||||
/// obviously invalid frames.
|
||||
const MAX_FRAME_LEN: usize = 8 * 1024 * 1024;
|
||||
|
||||
/// Protocol version shared by the parent process and elevated command runner.
|
||||
pub const IPC_PROTOCOL_VERSION: u8 = 2;
|
||||
|
||||
/// Length-prefixed, JSON-encoded frame.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct FramedMessage {
|
||||
@@ -55,8 +59,8 @@ pub struct SpawnRequest {
|
||||
pub command: Vec<String>,
|
||||
pub cwd: PathBuf,
|
||||
pub env: HashMap<String, String>,
|
||||
pub policy_json_or_preset: String,
|
||||
pub sandbox_policy_cwd: PathBuf,
|
||||
pub permission_profile: PermissionProfile,
|
||||
pub permission_profile_cwd: PathBuf,
|
||||
pub codex_home: PathBuf,
|
||||
pub real_codex_home: PathBuf,
|
||||
pub cap_sids: Vec<String>,
|
||||
@@ -164,11 +168,12 @@ pub fn read_frame<R: Read>(mut reader: R) -> Result<Option<FramedMessage>> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn framed_round_trip() {
|
||||
let msg = FramedMessage {
|
||||
version: 1,
|
||||
version: IPC_PROTOCOL_VERSION,
|
||||
message: Message::Output {
|
||||
payload: OutputPayload {
|
||||
data_b64: encode_bytes(b"hello"),
|
||||
@@ -179,7 +184,7 @@ mod tests {
|
||||
let mut buf = Vec::new();
|
||||
write_frame(&mut buf, &msg).expect("write");
|
||||
let decoded = read_frame(buf.as_slice()).expect("read").expect("some");
|
||||
assert_eq!(decoded.version, 1);
|
||||
assert_eq!(decoded.version, IPC_PROTOCOL_VERSION);
|
||||
match decoded.message {
|
||||
Message::Output { payload } => {
|
||||
assert_eq!(payload.stream, OutputStream::Stdout);
|
||||
@@ -189,4 +194,43 @@ mod tests {
|
||||
other => panic!("unexpected message: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spawn_request_serializes_permission_profile() {
|
||||
let msg = FramedMessage {
|
||||
version: IPC_PROTOCOL_VERSION,
|
||||
message: Message::SpawnRequest {
|
||||
payload: Box::new(SpawnRequest {
|
||||
command: vec!["cmd.exe".to_string(), "/c".to_string(), "ver".to_string()],
|
||||
cwd: PathBuf::from(r"C:\workspace"),
|
||||
env: HashMap::new(),
|
||||
permission_profile: PermissionProfile::read_only(),
|
||||
permission_profile_cwd: PathBuf::from(r"C:\workspace"),
|
||||
codex_home: PathBuf::from(r"C:\codex"),
|
||||
real_codex_home: PathBuf::from(r"C:\Users\codex"),
|
||||
cap_sids: vec!["S-1-15-3-1024-1".to_string()],
|
||||
timeout_ms: Some(1000),
|
||||
tty: false,
|
||||
stdin_open: false,
|
||||
use_private_desktop: false,
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
let encoded = serde_json::to_value(&msg).expect("serialize");
|
||||
assert_eq!("spawn_request", encoded["type"]);
|
||||
assert_eq!("managed", encoded["payload"]["permission_profile"]["type"]);
|
||||
assert_eq!(None, encoded["payload"].get("policy_json_or_preset"));
|
||||
assert_eq!(None, encoded["payload"].get("sandbox_policy_cwd"));
|
||||
|
||||
let decoded: FramedMessage = serde_json::from_value(encoded).expect("deserialize");
|
||||
let Message::SpawnRequest { payload } = decoded.message else {
|
||||
panic!("unexpected message");
|
||||
};
|
||||
assert_eq!(PermissionProfile::read_only(), payload.permission_profile);
|
||||
assert_eq!(
|
||||
PathBuf::from(r"C:\workspace"),
|
||||
payload.permission_profile_cwd
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::identity::SandboxCreds;
|
||||
use crate::ipc_framed::FramedMessage;
|
||||
use crate::ipc_framed::IPC_PROTOCOL_VERSION;
|
||||
use crate::ipc_framed::Message;
|
||||
use crate::ipc_framed::SpawnRequest;
|
||||
use crate::ipc_framed::read_frame;
|
||||
@@ -56,7 +57,7 @@ pub(crate) struct RunnerTransport {
|
||||
impl RunnerTransport {
|
||||
pub(crate) fn send_spawn_request(&mut self, request: SpawnRequest) -> Result<()> {
|
||||
let spawn_request = FramedMessage {
|
||||
version: 1,
|
||||
version: IPC_PROTOCOL_VERSION,
|
||||
message: Message::SpawnRequest {
|
||||
payload: Box::new(request),
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user