mirror of
https://github.com/openai/codex.git
synced 2026-04-26 23:55:25 +00:00
Feat: Preserve network access on read-only sandbox policies (#13409)
## Summary
`PermissionProfile.network` could not be preserved when additional or
compiled permissions resolved to
`SandboxPolicy::ReadOnly`, because `ReadOnly` had no network_access
field. This change makes read-only + network
enabled representable directly and threads that through the protocol,
app-server v2 mirror, and permission-
merging logic.
## What changed
- Added `network_access: bool` to `SandboxPolicy::ReadOnly` in the core
protocol and app-server v2 protocol.
- Kept backward compatibility by defaulting the new field to false, so
legacy read-only payloads still
deserialize unchanged.
- Updated `has_full_network_access()` and sandbox summaries to respect
read-only network access.
- Preserved PermissionProfile.network when:
- compiling skill permission profiles into sandbox policies
- normalizing additional permissions
- merging additional permissions into existing sandbox policies
- Updated the approval overlay to show network in the rendered
permission rule when requested.
- Regenerated app-server schema fixtures for the new v2 wire shape.
This commit is contained in:
@@ -626,6 +626,11 @@ pub enum SandboxPolicy {
|
||||
skip_serializing_if = "ReadOnlyAccess::has_full_disk_read_access"
|
||||
)]
|
||||
access: ReadOnlyAccess,
|
||||
|
||||
/// When set to `true`, outbound network access is allowed. `false` by
|
||||
/// default.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
network_access: bool,
|
||||
},
|
||||
|
||||
/// Indicates the process is already in an external sandbox. Allows full
|
||||
@@ -715,6 +720,7 @@ impl SandboxPolicy {
|
||||
pub fn new_read_only_policy() -> Self {
|
||||
SandboxPolicy::ReadOnly {
|
||||
access: ReadOnlyAccess::FullAccess,
|
||||
network_access: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,7 +741,7 @@ impl SandboxPolicy {
|
||||
match self {
|
||||
SandboxPolicy::DangerFullAccess => true,
|
||||
SandboxPolicy::ExternalSandbox { .. } => true,
|
||||
SandboxPolicy::ReadOnly { access } => access.has_full_disk_read_access(),
|
||||
SandboxPolicy::ReadOnly { access, .. } => access.has_full_disk_read_access(),
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
read_only_access, ..
|
||||
} => read_only_access.has_full_disk_read_access(),
|
||||
@@ -755,7 +761,7 @@ impl SandboxPolicy {
|
||||
match self {
|
||||
SandboxPolicy::DangerFullAccess => true,
|
||||
SandboxPolicy::ExternalSandbox { network_access } => network_access.is_enabled(),
|
||||
SandboxPolicy::ReadOnly { .. } => false,
|
||||
SandboxPolicy::ReadOnly { network_access, .. } => *network_access,
|
||||
SandboxPolicy::WorkspaceWrite { network_access, .. } => *network_access,
|
||||
}
|
||||
}
|
||||
@@ -766,7 +772,7 @@ impl SandboxPolicy {
|
||||
return false;
|
||||
}
|
||||
match self {
|
||||
SandboxPolicy::ReadOnly { access } => access.include_platform_defaults(),
|
||||
SandboxPolicy::ReadOnly { access, .. } => access.include_platform_defaults(),
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
read_only_access, ..
|
||||
} => read_only_access.include_platform_defaults(),
|
||||
@@ -782,7 +788,7 @@ impl SandboxPolicy {
|
||||
pub fn get_readable_roots_with_cwd(&self, cwd: &Path) -> Vec<AbsolutePathBuf> {
|
||||
let mut roots = match self {
|
||||
SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } => Vec::new(),
|
||||
SandboxPolicy::ReadOnly { access } => access.get_readable_roots_with_cwd(cwd),
|
||||
SandboxPolicy::ReadOnly { access, .. } => access.get_readable_roots_with_cwd(cwd),
|
||||
SandboxPolicy::WorkspaceWrite {
|
||||
read_only_access, ..
|
||||
} => {
|
||||
@@ -3131,6 +3137,18 @@ mod tests {
|
||||
assert!(enabled.has_full_network_access());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_only_reports_network_access_flags() {
|
||||
let restricted = SandboxPolicy::new_read_only_policy();
|
||||
assert!(!restricted.has_full_network_access());
|
||||
|
||||
let enabled = SandboxPolicy::ReadOnly {
|
||||
access: ReadOnlyAccess::FullAccess,
|
||||
network_access: true,
|
||||
};
|
||||
assert!(enabled.has_full_network_access());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reject_config_mcp_elicitation_flag_is_field_driven() {
|
||||
assert!(
|
||||
|
||||
Reference in New Issue
Block a user