flatten project hook trust metadata

This commit is contained in:
Abhinav Vedmala
2026-05-08 11:18:26 -04:00
parent 327f449cc6
commit 01890edc1e
6 changed files with 39 additions and 49 deletions
-1
View File
@@ -115,7 +115,6 @@ pub use state::ConfigLayerEntry;
pub use state::ConfigLayerStack;
pub use state::ConfigLayerStackOrdering;
pub use state::LoaderOverrides;
pub use state::ProjectTrustScope;
pub use thread_config::NoopThreadConfigLoader;
pub use thread_config::RemoteThreadConfigLoader;
pub use thread_config::SessionThreadConfig;
+10 -10
View File
@@ -22,7 +22,6 @@ use crate::project_root_markers::project_root_markers_from_config;
use crate::state::ConfigLayerEntry;
use crate::state::ConfigLayerStack;
use crate::state::LoaderOverrides;
use crate::state::ProjectTrustScope;
use crate::thread_config::ThreadConfigContext;
use crate::thread_config::ThreadConfigLoader;
use codex_app_server_protocol::ConfigLayerSource;
@@ -718,7 +717,8 @@ fn project_layer_entry(
dot_codex_folder: &AbsolutePathBuf,
config: TomlValue,
disabled_reason: Option<String>,
project_trust_scope: ProjectTrustScope,
project_trust_key: String,
project_root: AbsolutePathBuf,
) -> ConfigLayerEntry {
let source = ConfigLayerSource::Project {
dot_codex_folder: dot_codex_folder.clone(),
@@ -729,7 +729,7 @@ fn project_layer_entry(
} else {
ConfigLayerEntry::new(source, config)
};
entry.with_project_trust_scope(project_trust_scope)
entry.with_project_trust(project_trust_key, project_root)
}
fn sanitize_project_config(config: &mut TomlValue) -> Vec<String> {
@@ -997,10 +997,7 @@ async fn load_project_layers(
let decision = trust_context.decision_for_dir(&dir);
let disabled_reason = trust_context.disabled_reason_for_decision(&decision);
let project_trust_scope = ProjectTrustScope {
trust_key: decision.trust_key.clone(),
project_root: project_root.clone(),
};
let project_trust_key = decision.trust_key.clone();
let dot_codex_normalized =
normalize_path(dot_codex_abs.as_path()).unwrap_or_else(|_| dot_codex_abs.to_path_buf());
if dot_codex_abs == codex_home_abs || dot_codex_normalized == codex_home_normalized {
@@ -1025,7 +1022,8 @@ async fn load_project_layers(
&dot_codex_abs,
TomlValue::Table(toml::map::Map::new()),
disabled_reason.clone(),
project_trust_scope.clone(),
project_trust_key.clone(),
project_root.clone(),
));
continue;
}
@@ -1044,7 +1042,8 @@ async fn load_project_layers(
&dot_codex_abs,
config,
disabled_reason.clone(),
project_trust_scope.clone(),
project_trust_key.clone(),
project_root.clone(),
);
layers.push(entry);
}
@@ -1057,7 +1056,8 @@ async fn load_project_layers(
&dot_codex_abs,
TomlValue::Table(toml::map::Map::new()),
disabled_reason,
project_trust_scope,
project_trust_key,
project_root.clone(),
));
} else {
let config_file_display = config_file.as_path().display();
+15 -13
View File
@@ -66,14 +66,8 @@ pub struct ConfigLayerEntry {
pub raw_toml: Option<String>,
pub version: String,
pub disabled_reason: Option<String>,
pub project_trust_scope: Option<ProjectTrustScope>,
}
/// Worktree-aware trust scope resolved while loading one project layer.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProjectTrustScope {
pub trust_key: String,
pub project_root: AbsolutePathBuf,
pub project_trust_key: Option<String>,
pub project_root: Option<AbsolutePathBuf>,
}
impl ConfigLayerEntry {
@@ -85,7 +79,8 @@ impl ConfigLayerEntry {
raw_toml: None,
version,
disabled_reason: None,
project_trust_scope: None,
project_trust_key: None,
project_root: None,
}
}
@@ -97,7 +92,8 @@ impl ConfigLayerEntry {
raw_toml: Some(raw_toml),
version,
disabled_reason: None,
project_trust_scope: None,
project_trust_key: None,
project_root: None,
}
}
@@ -113,12 +109,18 @@ impl ConfigLayerEntry {
raw_toml: None,
version,
disabled_reason: Some(disabled_reason.into()),
project_trust_scope: None,
project_trust_key: None,
project_root: None,
}
}
pub fn with_project_trust_scope(mut self, project_trust_scope: ProjectTrustScope) -> Self {
self.project_trust_scope = Some(project_trust_scope);
pub fn with_project_trust(
mut self,
project_trust_key: String,
project_root: AbsolutePathBuf,
) -> Self {
self.project_trust_key = Some(project_trust_key);
self.project_root = Some(project_root);
self
}
@@ -330,7 +330,8 @@ async fn returns_empty_when_all_layers_missing() {
raw_toml: None,
version: version_for_toml(&TomlValue::Table(toml::map::Map::new())),
disabled_reason: None,
project_trust_scope: None,
project_trust_key: None,
project_root: None,
},
user_layer,
);
@@ -1499,10 +1500,8 @@ async fn project_layer_is_added_when_dot_codex_exists_without_config_toml() -> s
raw_toml: None,
version: version_for_toml(&TomlValue::Table(toml::map::Map::new())),
disabled_reason: None,
project_trust_scope: Some(codex_config::ProjectTrustScope {
trust_key: project_root.display().to_string(),
project_root: AbsolutePathBuf::from_absolute_path(project_root.clone())?,
}),
project_trust_key: Some(project_root.display().to_string()),
project_root: Some(AbsolutePathBuf::from_absolute_path(project_root.clone())?),
}],
project_layers
);
@@ -1607,10 +1606,8 @@ async fn codex_home_within_project_tree_is_not_double_loaded() -> std::io::Resul
raw_toml: None,
version: version_for_toml(&child_config),
disabled_reason: None,
project_trust_scope: Some(codex_config::ProjectTrustScope {
trust_key: project_root.display().to_string(),
project_root: AbsolutePathBuf::from_absolute_path(project_root.clone())?,
}),
project_trust_key: Some(project_root.display().to_string()),
project_root: Some(AbsolutePathBuf::from_absolute_path(project_root.clone())?),
}],
project_layers
);
+6 -10
View File
@@ -507,20 +507,16 @@ fn hook_key_sources_for_config_layer(
source_path: &AbsolutePathBuf,
) -> (String, Option<String>) {
let legacy_key_source = source_path.display().to_string();
let Some(project_trust_scope) = layer.project_trust_scope.as_ref() else {
let (Some(project_trust_key), Some(project_root)) = (
layer.project_trust_key.as_ref(),
layer.project_root.as_ref(),
) else {
return (legacy_key_source, None);
};
let Ok(relative_path) = source_path
.as_path()
.strip_prefix(project_trust_scope.project_root.as_path())
else {
let Ok(relative_path) = source_path.as_path().strip_prefix(project_root.as_path()) else {
return (legacy_key_source, None);
};
let key_source = format!(
"project:{}:{}",
project_trust_scope.trust_key,
relative_path.display()
);
let key_source = format!("project:{project_trust_key}:{}", relative_path.display());
(key_source, Some(legacy_key_source))
}
+2 -6
View File
@@ -14,7 +14,6 @@ use codex_config::HookEventsToml;
use codex_config::HookHandlerConfig;
use codex_config::ManagedHooksRequirementsToml;
use codex_config::MatcherGroup;
use codex_config::ProjectTrustScope;
use codex_config::RequirementSource;
use codex_config::TomlValue;
use codex_plugin::PluginHookSource;
@@ -368,7 +367,7 @@ fn user_disablement_does_not_filter_managed_layer_hooks() {
}
#[test]
fn project_hook_keys_share_project_trust_scope_across_worktrees() {
fn project_hook_keys_share_project_trust_across_worktrees() {
let trust_key = test_path_buf("/repo").display().to_string();
let project_a = test_project_layer("/tmp/worktree-a", &trust_key);
let project_b = test_project_layer("/tmp/worktree-b", &trust_key);
@@ -482,10 +481,7 @@ fn test_project_layer(project_root: &str, trust_key: &str) -> ConfigLayerEntry {
ConfigLayerSource::Project { dot_codex_folder },
config_with_pre_tool_use_hook("python3 /tmp/project.py"),
)
.with_project_trust_scope(ProjectTrustScope {
trust_key: trust_key.to_string(),
project_root,
})
.with_project_trust(trust_key.to_string(), project_root)
}
fn expected_project_hook_key(trust_key: &str) -> String {