//! L2 integration tests for [`FsPermissionStore`] against a real temp project. use std::path::PathBuf; use std::sync::Arc; use domain::ids::{AgentId, ProjectId}; use domain::ports::{FileSystem, PermissionStore}; use domain::project::{Project, ProjectPath}; use domain::remote::RemoteRef; use domain::{ AgentPermissionOverride, PermissionSet, Posture, ProjectPermissions, PERMISSIONS_VERSION, }; use infrastructure::{FsPermissionStore, LocalFileSystem}; use uuid::Uuid; /// A unique scratch project directory under the OS temp dir, cleaned up on drop. struct TempDir(PathBuf); impl TempDir { fn new() -> Self { let p = std::env::temp_dir().join(format!("idea-l2-permissions-{}", Uuid::new_v4())); std::fs::create_dir_all(&p).unwrap(); Self(p) } fn project_root(&self) -> String { self.0.to_string_lossy().into_owned() } } impl Drop for TempDir { fn drop(&mut self) { let _ = std::fs::remove_dir_all(&self.0); } } fn store() -> FsPermissionStore { let fs: Arc = Arc::new(LocalFileSystem::new()); FsPermissionStore::new(fs) } fn project(tmp: &TempDir) -> Project { Project::new( ProjectId::new_random(), "permissions", ProjectPath::new(tmp.project_root()).unwrap(), RemoteRef::local(), 1_700_000_000_000, ) .unwrap() } #[tokio::test] async fn missing_permissions_file_returns_default_document() { let tmp = TempDir::new(); let project = project(&tmp); let loaded = store().load_permissions(&project).await.unwrap(); assert_eq!(loaded, ProjectPermissions::default()); assert_eq!(loaded.version, PERMISSIONS_VERSION); } #[tokio::test] async fn save_then_load_roundtrips_project_defaults_and_agent_override() { let tmp = TempDir::new(); let project = project(&tmp); let agent = AgentId::new_random(); let doc = ProjectPermissions::new( Some(PermissionSet::new(vec![], Posture::Ask)), vec![AgentPermissionOverride::new( agent, PermissionSet::new(vec![], Posture::Deny), )], ); let store = store(); store.save_permissions(&project, &doc).await.unwrap(); let loaded = store.load_permissions(&project).await.unwrap(); assert_eq!(loaded, doc); assert_eq!(loaded.resolve_for(agent).unwrap().fallback(), Posture::Deny); let path = tmp.0.join(".ideai").join("permissions.json"); assert!(path.exists(), "store writes under .ideai/permissions.json"); }