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:
@ -32,6 +32,7 @@ use crate::events::DomainEvent;
|
||||
use crate::ids::{AgentId, SessionId};
|
||||
use crate::markdown::MarkdownDoc;
|
||||
use crate::memory::{Memory, MemoryIndexEntry, MemoryLink, MemorySlug};
|
||||
use crate::permission::ProjectPermissions;
|
||||
use crate::profile::{AgentProfile, EmbedderProfile};
|
||||
use crate::project::{Project, ProjectPath};
|
||||
use crate::remote::RemoteKind;
|
||||
@ -617,6 +618,21 @@ pub trait FileSystem: Send + Sync {
|
||||
/// [`FsError`] on failure.
|
||||
async fn exists(&self, path: &RemotePath) -> Result<bool, FsError>;
|
||||
|
||||
/// Removes a single file. A **missing** file is treated as success (idempotent
|
||||
/// delete), so this is safe to call best-effort.
|
||||
///
|
||||
/// Defaults to a **no-op `Ok(())`** so existing adapters and in-memory test
|
||||
/// doubles keep compiling unchanged; the real adapter overrides it with an
|
||||
/// actual delete. Callers that rely on the file actually being gone must use an
|
||||
/// adapter that overrides this (the local FS does).
|
||||
///
|
||||
/// # Errors
|
||||
/// [`FsError`] on a failure other than not-found.
|
||||
async fn remove_file(&self, path: &RemotePath) -> Result<(), FsError> {
|
||||
let _ = path;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a directory and all missing parents.
|
||||
///
|
||||
/// # Errors
|
||||
@ -1063,6 +1079,27 @@ pub trait AgentContextStore: Send + Sync {
|
||||
) -> Result<(), StoreError>;
|
||||
}
|
||||
|
||||
/// Reads/writes a project's `.ideai/permissions.json`.
|
||||
#[async_trait]
|
||||
pub trait PermissionStore: Send + Sync {
|
||||
/// Loads the project's permission document. Missing file returns the default
|
||||
/// empty document.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`StoreError`] on I/O or deserialisation failure.
|
||||
async fn load_permissions(&self, project: &Project) -> Result<ProjectPermissions, StoreError>;
|
||||
|
||||
/// Saves the project's permission document.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`StoreError`] on I/O or serialisation failure.
|
||||
async fn save_permissions(
|
||||
&self,
|
||||
project: &Project,
|
||||
permissions: &ProjectPermissions,
|
||||
) -> Result<(), StoreError>;
|
||||
}
|
||||
|
||||
/// Git operations for a project. Named `GitPort` to avoid clashing with the
|
||||
/// [`crate::git::GitRepository`] *entity* (state image).
|
||||
#[async_trait]
|
||||
|
||||
Reference in New Issue
Block a user