Decouple session isolation from subagent attribution (#44521)

## Why

Session isolation relied on Guardian source attribution. An explicit policy lets callers control inherited capabilities independently of how a session is attributed.

## What changed

- Add `SessionIsolation` with default `Inherit` and opt-in `Isolated` modes, captured at session startup through `ExtensionDataInit`.
- Use the policy to control inherited instructions, extensions, execution rules, and MCP resources. Isolated sessions retain managed execution rules and omit executor-discovered MCP servers.
- Explicitly isolate Guardian reviewers while preserving source-based fallback for older callers and saved reviewers.

## Testing

Extend delegate tests to cover isolation independently of attribution, update execution-policy coverage to supply the explicit policy, and assert that managed reviewers do not inherit the parent's configured MCP tools.

GitOrigin-RevId: f0ab42fa2f0237860ec661e72693ab191216afbf
This commit is contained in:
jif authored and copyberry committed 2026-09-10 12:52:27 +00:00
1 parent 9688359977
commit ed6dde9fda
14 files changed
+83 -18

No files matched your search

+4 -1
View File
@@ -56,6 +56,7 @@ pub(crate) async fn run_codex_thread_interactive(
parent_environments: TurnEnvironmentSnapshot,
cancel_token: CancellationToken,
subagent_source: SubAgentSource,
isolation: codex_extension_api::SessionIsolation,
initial_history: Option<InitialHistory>,
git_enrichment_policy: GitEnrichmentPolicy,
windows_sandbox_proxy_settings_mode: codex_sandboxing::WindowsSandboxProxySettingsMode,
@@ -79,7 +80,7 @@ pub(crate) async fn run_codex_thread_interactive(
};
let session_source = SessionSource::SubAgent(subagent_source.clone());
let is_guardian_reviewer = crate::guardian::is_basic_session_source(&session_source);
let extensions = if is_guardian_reviewer {
let extensions = if isolation == codex_extension_api::SessionIsolation::Isolated {
codex_extension_api::empty_extension_registry()
} else {
Arc::clone(&parent_session.services.extensions)
@@ -87,6 +88,7 @@ pub(crate) async fn run_codex_thread_interactive(
// Inline delegates never register with ThreadManager or receive on_thread_ready.
// Bind their standalone spawn path before inherited extensions run.
let mut thread_extension_init = codex_extension_api::ExtensionDataInit::default();
thread_extension_init.insert(isolation);
thread_extension_init.insert(crate::guardian::GuardianReviewSessionHost::default());
let (session, io) = Session::spawn(SessionSpawnArgs {
config,
@@ -213,6 +215,7 @@ pub(crate) async fn run_codex_thread_one_shot(
parent_environments,
child_cancel.clone(),
subagent_source,
codex_extension_api::SessionIsolation::Inherit,
initial_history,
GitEnrichmentPolicy::Fresh,
codex_sandboxing::WindowsSandboxProxySettingsMode::Reconcile,