Constrain Guardian reviews to parent filesystem permissions (#38377)

## Why

Guardian review sessions must not gain access to paths that the parent turn is
not allowed to read.

## What changed

- Derive Guardian permissions by intersecting managed parent filesystem rules
  with read-only access, preserving denied paths and restricting network access.
- Offer Guardian execution tools only when a managed sandbox can enforce those
  rules.
- Include the selected environment IDs in the review-session reuse key so a
  session is not reused across different environment sets.

## Testing

Update the Guardian reuse integration test to verify that a review cannot read
a parent-denied file or write a local file while consecutive reviews still
reuse the same session.

GitOrigin-RevId: 20f17a6c379f1eda651e8508459d642a51e4ce94
This commit is contained in:
jif authored and copyberry committed 2026-08-13 13:41:08 +00:00
1 parent a7b8c074b5
commit a7e9fb5480
4 files changed
+140 -100

No files matched your search

+9 -1
View File
@@ -70,6 +70,7 @@ use codex_protocol::dynamic_tools::DynamicToolNamespaceTool;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::error::CodexErrorDetails;
use codex_protocol::error::Result as CodexResult;
use codex_protocol::models::PermissionProfile;
use codex_protocol::openai_models::ConfigShellToolType;
use codex_protocol::openai_models::InputModality;
use codex_protocol::openai_models::ToolMode;
@@ -890,9 +891,16 @@ fn code_mode_namespace_descriptions(
#[instrument(level = "trace", skip_all)]
fn add_core_tool_sources(context: &CoreToolPlanContext<'_>, registry: &mut ToolRegistry) {
// Guardian reviewers receive only `exec_command`, `write_stdin`, and `view_image`
// when an environment is available; all general tool sources stay excluded.
// when a managed sandbox can enforce the parent's filesystem restrictions;
// all general tool sources stay excluded.
if crate::guardian::is_guardian_reviewer_source(&context.turn_context.session_source) {
let turn_context = context.turn_context;
if !matches!(
turn_context.permission_profile(),
PermissionProfile::Managed { .. }
) {
return;
}
let environment_mode = tool_environment_mode(context.environments);
if environment_mode.has_environment() {
let include_environment_id = matches!(environment_mode, ToolEnvironmentMode::Multiple);