mirror of
https://github.com/openai/codex.git
synced 2026-04-24 22:54:54 +00:00
Assume that we trust codex for worktrees spawned from a repo that we already trust codex with
This commit is contained in:
@@ -261,7 +261,8 @@ pub fn set_project_trusted(codex_home: &Path, project_path: &Path) -> anyhow::Re
|
||||
|
||||
// Mark the project as trusted. toml_edit is very good at handling
|
||||
// missing properties
|
||||
let project_key = project_path.to_string_lossy().to_string();
|
||||
let normalized = crate::util::normalized_trust_project_root(project_path);
|
||||
let project_key = normalized.to_string_lossy().to_string();
|
||||
doc["projects"][project_key.as_str()]["trust_level"] = toml_edit::value("trusted");
|
||||
|
||||
// ensure codex_home exists
|
||||
@@ -454,8 +455,13 @@ impl ConfigToml {
|
||||
pub fn is_cwd_trusted(&self, resolved_cwd: &Path) -> bool {
|
||||
let projects = self.projects.clone().unwrap_or_default();
|
||||
|
||||
// Prefer a normalized project key that points to the main git repo root when applicable.
|
||||
let normalized_root = crate::util::normalized_trust_project_root(resolved_cwd);
|
||||
let normalized_key = normalized_root.to_string_lossy().to_string();
|
||||
|
||||
projects
|
||||
.get(&resolved_cwd.to_string_lossy().to_string())
|
||||
.get(&normalized_key)
|
||||
.or_else(|| projects.get(&resolved_cwd.to_string_lossy().to_string()))
|
||||
.map(|p| p.trust_level.clone().unwrap_or("".to_string()) == "trusted")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use rand::Rng;
|
||||
@@ -42,3 +44,87 @@ pub fn is_inside_git_repo(base_dir: &Path) -> bool {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Try to resolve the main git repository root for `base_dir`.
|
||||
///
|
||||
/// - For a normal repo (where `.git` is a directory), returns the directory
|
||||
/// that contains the `.git` directory.
|
||||
/// - For a worktree (where `.git` is a file with a `gitdir:` pointer), reads
|
||||
/// the referenced git directory and, if present, its `commondir` file to
|
||||
/// locate the common `.git` directory of the main repository. Returns the
|
||||
/// parent of that common directory.
|
||||
/// - Returns `None` when no enclosing repo is found.
|
||||
pub fn git_main_repo_root(base_dir: &Path) -> Option<PathBuf> {
|
||||
// Walk up from base_dir to find the first ancestor containing a `.git` entry.
|
||||
let mut dir = base_dir.to_path_buf();
|
||||
loop {
|
||||
let dot_git = dir.join(".git");
|
||||
if dot_git.is_dir() {
|
||||
// Standard repository. The repo root is the directory containing `.git`.
|
||||
return Some(dir);
|
||||
} else if dot_git.is_file() {
|
||||
// Worktree case: `.git` is a file like: `gitdir: /path/to/worktrees/<name>`
|
||||
if let Ok(contents) = fs::read_to_string(&dot_git) {
|
||||
// Extract the path after `gitdir:` and trim whitespace.
|
||||
let gitdir_prefix = "gitdir:";
|
||||
let line = contents
|
||||
.lines()
|
||||
.find(|l| l.trim_start().starts_with(gitdir_prefix));
|
||||
if let Some(line) = line {
|
||||
let path_part = line.split_once(':').map(|(_, r)| r.trim());
|
||||
if let Some(gitdir_str) = path_part {
|
||||
// Resolve relative paths against the directory containing `.git` (the worktree root).
|
||||
let gitdir_path = Path::new(gitdir_str);
|
||||
let gitdir_abs = if gitdir_path.is_absolute() {
|
||||
gitdir_path.to_path_buf()
|
||||
} else {
|
||||
dir.join(gitdir_path)
|
||||
};
|
||||
|
||||
// In worktrees, the per-worktree gitdir typically contains a `commondir`
|
||||
// file that points (possibly relatively) to the common `.git` directory.
|
||||
let commondir_path = gitdir_abs.join("commondir");
|
||||
if let Ok(common_dir_rel) = fs::read_to_string(&commondir_path) {
|
||||
let common_dir_rel = common_dir_rel.trim();
|
||||
let common_dir_path = Path::new(common_dir_rel);
|
||||
let common_dir_abs = if common_dir_path.is_absolute() {
|
||||
common_dir_path.to_path_buf()
|
||||
} else {
|
||||
gitdir_abs.join(common_dir_path)
|
||||
};
|
||||
// The main repo root is the parent of the common `.git` directory.
|
||||
if let Some(parent) = common_dir_abs.parent() {
|
||||
return Some(parent.to_path_buf());
|
||||
}
|
||||
} else {
|
||||
// Fallback: if no commondir file, use the parent of `gitdir_abs` if it looks like a `.git` dir.
|
||||
if let Some(parent) = gitdir_abs.parent() {
|
||||
return Some(parent.to_path_buf());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If parsing fails, continue the walk upwards in case of nested repos (rare).
|
||||
}
|
||||
|
||||
if !dir.pop() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Normalize a path for trust configuration lookups.
|
||||
///
|
||||
/// If inside a git repo, returns the main repository root; otherwise returns the
|
||||
// canonicalized `base_dir` (or `base_dir` if canonicalization fails).
|
||||
pub fn normalized_trust_project_root(base_dir: &Path) -> PathBuf {
|
||||
if let Some(repo_root) = git_main_repo_root(base_dir) {
|
||||
return repo_root.canonicalize().unwrap_or(repo_root);
|
||||
}
|
||||
base_dir
|
||||
.canonicalize()
|
||||
.unwrap_or_else(|_| base_dir.to_path_buf())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user