Respect turn filesystem permissions during executor skill discovery (#59291)

## Why

Direct executor skill discovery used unrestricted filesystem access, bypassing the turn's permission context. Cached catalogs also needed to account for changes in filesystem access within a turn.

## What changed

- Bind selected capability roots to callback-scoped filesystem access through `AccessedSelectedCapabilityRoot`.
- Pass accessors built with the turn's granted permissions into skill preparation and discovery, removing the executor skill provider's environment lookup and unrestricted accessor.
- Include filesystem access keys in the direct discovery cache so permission changes trigger rediscovery.

## Testing

Extend tests to verify that restricted discovery returns no skills when sandbox access is unavailable, restoring access restores discovery, and changing or restoring access invalidates the catalog cache.

GitOrigin-RevId: 0f7aa7646f65923f65f0cfc0b387d94bd7f2db05
This commit is contained in:
Dmitriy Kovalenko
2026-11-04 02:00:01 +00:00
committed by copyberry
parent db3c44414c
commit 007f668c34
29 changed files with 294 additions and 254 deletions
+20 -1
View File
@@ -4413,11 +4413,30 @@ impl Session {
&turn_context.disabled_plugin_ids,
)
.await;
let mut filesystem_access = HashMap::new();
for environment in environments.turn_environments() {
let environment_id = &environment.selection.environment_id;
let grants = turn_context.granted_permissions(environment_id);
filesystem_access.insert(environment_id, environment.fs_accessor(grants));
}
let accessed_roots = ready_selected_capability_roots
.iter()
.filter_map(|root| {
let codex_protocol::capabilities::CapabilityRootLocation::Environment {
environment_id,
..
} = &root.location;
Some(codex_extension_api::AccessedSelectedCapabilityRoot {
root,
fs: filesystem_access.get(environment_id)?,
})
})
.collect::<Vec<_>>();
for contributor in self.services.extensions.tool_contributors() {
contributor
.prepare_for_step(codex_extension_api::StepPreparationInput {
turn_id: &turn_context.sub_id,
ready_selected_capability_roots: &ready_selected_capability_roots,
ready_selected_capability_roots: &accessed_roots,
executor_capability_discovery: executor_capability_discovery.as_deref(),
executor_capability_discovery_v2: executor_capability_discovery_v2
.as_deref(),