use std::path::{Path, PathBuf};
pub const TRUST_PROJECT_HOOKS_ENV: &str = "RHO_TRUST_PROJECT_HOOKS";
pub const TRUST_PROJECT_AGENTS_ENV: &str = "RHO_TRUST_PROJECT_AGENTS";
pub const TRUST_PROJECT_PLUGINS_ENV: &str = "RHO_TRUST_PROJECT_PLUGINS";
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProjectTrust {
Trusted,
Untrusted,
}
impl ProjectTrust {
fn from_env(value: Option<&str>) -> Self {
if value == Some("1") {
Self::Trusted
} else {
Self::Untrusted
}
}
fn from_env_var(name: &str) -> Self {
Self::from_env(std::env::var(name).ok().as_deref())
}
pub fn from_hooks_env() -> Self {
Self::from_env_var(TRUST_PROJECT_HOOKS_ENV)
}
pub fn from_agents_env() -> Self {
Self::from_env_var(TRUST_PROJECT_AGENTS_ENV)
}
pub fn from_plugins_env() -> Self {
Self::from_env_var(TRUST_PROJECT_PLUGINS_ENV)
}
pub const fn is_trusted(self) -> bool {
matches!(self, Self::Trusted)
}
}
pub fn project_ancestor_dirs(cwd: &Path) -> Vec<PathBuf> {
let ancestors: Vec<_> = cwd.ancestors().map(Path::to_path_buf).collect();
let Some(root_index) = ancestors.iter().position(|path| path.join(".git").exists()) else {
return vec![cwd.to_path_buf()];
};
ancestors[..=root_index].iter().rev().cloned().collect()
}
#[cfg(test)]
mod tests {
use tempfile::TempDir;
use super::*;
#[test]
fn returns_git_root_through_cwd() {
let repo = TempDir::new().unwrap();
std::fs::create_dir(repo.path().join(".git")).unwrap();
let child = repo.path().join("src/nested");
std::fs::create_dir_all(&child).unwrap();
let dirs = project_ancestor_dirs(&child);
assert_eq!(
dirs,
vec![repo.path().to_path_buf(), repo.path().join("src"), child]
);
}
#[test]
fn returns_only_cwd_outside_git_worktree() {
let dir = TempDir::new().unwrap();
let child = dir.path().join("src");
std::fs::create_dir_all(&child).unwrap();
let dirs = project_ancestor_dirs(&child);
assert_eq!(dirs, vec![child]);
}
#[test]
fn project_trust_requires_exact_opt_in() {
assert_eq!(ProjectTrust::from_env(Some("1")), ProjectTrust::Trusted);
for value in [Some("0"), Some("true"), Some("yes"), Some(""), None] {
assert_eq!(
ProjectTrust::from_env(value),
ProjectTrust::Untrusted,
"{value:?}"
);
}
}
}