feat(permissions): voie projection CLI (LP0→LP3) + checkpoint Codex/input
Jalon vert regroupant deux chantiers entrelacés dans le working tree, indissociables au niveau fichier mais tous deux verts (cargo test --workspace + tests frontend permissions au vert). Permissions — voie « projection CLI » (advisory), complète : - LP0 domaine pur : modèle PermissionSet/EffectivePermissions, resolve deny-wins + postures Allow<Ask<Deny (crates/domain/src/permission.rs). - LP1 store : FsPermissionStore (.ideai/permissions.json). - LP2 use cases : Get/Update project, Update agent override, Resolve. - LP3 projecteurs Claude/Codex (settings.local.json / config.toml), câblage launch-path + PermissionProjectorRegistry, nettoyage des fichiers Replace orphelins au swap de profil (LP3-4), composition root + commandes Tauri, UI PermissionsPanel (projet + override agent). - ports.rs : PermissionStore + FileSystem::remove_file (cleanup au swap). Reste ouvert (hors scope, marqué dans le code) : LP4 enforcement OS airtight (Landlock fichiers) + résumé de permissions injecté. Inclut aussi le chantier Codex/input/sessions structurées en cours (McpConfigStrategy, StructuredAdapter, gestion d'input) partageant les mêmes fichiers (lifecycle.rs, commands.rs, dto.rs, state.rs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
mod context;
|
||||
mod embedder;
|
||||
mod memory;
|
||||
mod permission;
|
||||
mod profile;
|
||||
mod project;
|
||||
mod skill;
|
||||
@ -24,6 +25,7 @@ pub use embedder::{
|
||||
RECOMMENDED_ONNX_MODELS, VECTOR_HTTP_ENABLED, VECTOR_ONNX_ENABLED,
|
||||
};
|
||||
pub use memory::{index_token_size, FsMemoryStore, NaiveMemoryRecall};
|
||||
pub use permission::FsPermissionStore;
|
||||
pub use profile::{FsEmbedderProfileStore, FsProfileStore};
|
||||
pub use project::FsProjectStore;
|
||||
pub use skill::FsSkillStore;
|
||||
|
||||
65
crates/infrastructure/src/store/permission.rs
Normal file
65
crates/infrastructure/src/store/permission.rs
Normal file
@ -0,0 +1,65 @@
|
||||
//! Filesystem-backed [`PermissionStore`] for project agent permissions.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use domain::ports::{FileSystem, FsError, PermissionStore, RemotePath, StoreError};
|
||||
use domain::{Project, ProjectPermissions};
|
||||
|
||||
const PERMISSIONS_FILE: &str = "permissions.json";
|
||||
|
||||
/// JSON-file implementation for `<project>/.ideai/permissions.json`.
|
||||
#[derive(Clone)]
|
||||
pub struct FsPermissionStore {
|
||||
fs: Arc<dyn FileSystem>,
|
||||
}
|
||||
|
||||
impl FsPermissionStore {
|
||||
/// Builds the store from an injected filesystem port.
|
||||
#[must_use]
|
||||
pub fn new(fs: Arc<dyn FileSystem>) -> Self {
|
||||
Self { fs }
|
||||
}
|
||||
|
||||
fn path(project: &Project) -> RemotePath {
|
||||
let root = project.root.as_str().trim_end_matches(['/', '\\']);
|
||||
RemotePath::new(format!("{root}/.ideai/{PERMISSIONS_FILE}"))
|
||||
}
|
||||
|
||||
async fn ensure_ideai(&self, project: &Project) -> Result<(), StoreError> {
|
||||
let root = project.root.as_str().trim_end_matches(['/', '\\']);
|
||||
self.fs
|
||||
.create_dir_all(&RemotePath::new(format!("{root}/.ideai")))
|
||||
.await
|
||||
.map_err(|e| StoreError::Io(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl PermissionStore for FsPermissionStore {
|
||||
async fn load_permissions(&self, project: &Project) -> Result<ProjectPermissions, StoreError> {
|
||||
match self.fs.read(&Self::path(project)).await {
|
||||
Ok(bytes) => {
|
||||
serde_json::from_slice(&bytes).map_err(|e| StoreError::Serialization(e.to_string()))
|
||||
}
|
||||
Err(FsError::NotFound(_)) => Ok(ProjectPermissions::default()),
|
||||
Err(e) => Err(StoreError::Io(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
async fn save_permissions(
|
||||
&self,
|
||||
project: &Project,
|
||||
permissions: &ProjectPermissions,
|
||||
) -> Result<(), StoreError> {
|
||||
self.ensure_ideai(project).await?;
|
||||
let mut bytes = serde_json::to_vec_pretty(permissions)
|
||||
.map_err(|e| StoreError::Serialization(e.to_string()))?;
|
||||
bytes.push(b'\n');
|
||||
self.fs
|
||||
.write(&Self::path(project), &bytes)
|
||||
.await
|
||||
.map_err(|e| StoreError::Io(e.to_string()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user