Files
codex/codex-rs/core/src/agents_md_manager.rs
T
Dylan Hurd bd19459358 Ignore project instructions for untrusted projects (#39837)
## What changed

- Skip project-scoped `AGENTS.md` discovery when the active project is untrusted, while preserving user-level instructions.
- Include the active project trust level in the instruction cache key so runtime trust changes reload the applicable instructions.
- Preserve updated project trust metadata during runtime configuration refreshes.

## Testing

Add coverage for initially untrusted projects and for switching between trusted and untrusted states at runtime.

GitOrigin-RevId: 284bf7693943f585013fb5fe4b6aa3309bc50cf3
2026-08-21 02:33:50 +00:00

86 lines
2.9 KiB
Rust

use crate::agents_md::LoadedAgentsMd;
use crate::agents_md::load_project_instructions;
use crate::config::Config;
use crate::environment_selection::TurnEnvironmentSnapshot;
use codex_extension_api::UserInstructions;
use codex_protocol::config_types::TrustLevel;
use codex_protocol::config_types::WindowsSandboxLevel;
use codex_protocol::protocol::TurnEnvironmentSelection;
use std::io;
use std::sync::Arc;
use tokio::sync::Mutex;
/// Owns the inputs and cached result of AGENTS.md discovery for a session.
pub(crate) struct AgentsMdManager {
user_instructions: Option<UserInstructions>,
cache: Mutex<AgentsMdCache>,
}
#[derive(Default)]
struct AgentsMdCache {
selections: Option<Vec<TurnEnvironmentSelection>>,
active_project_trust_level: Option<TrustLevel>,
windows_sandbox_level: Option<WindowsSandboxLevel>,
loaded: Option<Arc<LoadedAgentsMd>>,
}
impl AgentsMdManager {
pub(crate) fn new(user_instructions: Option<UserInstructions>) -> Self {
Self {
user_instructions: user_instructions
.filter(|instructions| !instructions.text.trim().is_empty()),
cache: Mutex::new(AgentsMdCache::default()),
}
}
#[tracing::instrument(name = "agents_md.refresh", skip_all)]
pub(crate) async fn refresh(
&self,
config: &Config,
environments: &TurnEnvironmentSnapshot,
windows_sandbox_level: WindowsSandboxLevel,
) -> io::Result<()> {
let selections = environments
.turn_environments()
.map(|environment| environment.selection.clone())
.collect::<Vec<_>>();
let active_project_trust_level = config.active_project.trust_level;
{
let mut cache = self.cache.lock().await;
if cache.selections.as_ref() == Some(&selections)
&& cache.active_project_trust_level == active_project_trust_level
&& cache.windows_sandbox_level == Some(windows_sandbox_level)
{
return Ok(());
}
cache.selections = None;
cache.active_project_trust_level = None;
cache.windows_sandbox_level = None;
cache.loaded = None;
}
let loaded = load_project_instructions(
config,
self.user_instructions.clone(),
environments,
windows_sandbox_level,
)
.await?
.map(Arc::new);
let mut cache = self.cache.lock().await;
cache.selections = Some(selections);
cache.active_project_trust_level = active_project_trust_level;
cache.windows_sandbox_level = Some(windows_sandbox_level);
cache.loaded = loaded;
Ok(())
}
pub(crate) async fn get_loaded(&self) -> Option<Arc<LoadedAgentsMd>> {
self.cache.lock().await.loaded.clone()
}
pub(crate) fn user_instructions(&self) -> Option<UserInstructions> {
self.user_instructions.clone()
}
}