feat: add Landlock sandbox for sidecar process isolation

SandboxConfig with RW/RO paths applied via pre_exec() in sidecar child
process. Requires kernel 6.2+ with graceful fallback. Per-project toggle
in SettingsTab. 9 unit tests.
This commit is contained in:
Hibryda 2026-03-12 04:57:29 +01:00 committed by DexterFromLab
parent f868f6f148
commit 871fd0385f
8 changed files with 363 additions and 12 deletions

View file

@ -1,6 +1,7 @@
use tauri::State;
use crate::AppState;
use crate::sidecar::AgentQueryOptions;
use bterminal_core::sandbox::SandboxConfig;
#[tauri::command]
#[tracing::instrument(skip(state, options), fields(session_id = %options.session_id))]
@ -27,3 +28,31 @@ pub fn agent_ready(state: State<'_, AppState>) -> bool {
pub fn agent_restart(state: State<'_, AppState>) -> Result<(), String> {
state.sidecar_manager.restart()
}
/// Update sidecar sandbox configuration and restart to apply.
/// `project_cwds` — directories needing read+write access.
/// `worktree_roots` — optional worktree directories.
/// `enabled` — whether Landlock sandboxing is active.
#[tauri::command]
#[tracing::instrument(skip(state))]
pub fn agent_set_sandbox(
state: State<'_, AppState>,
project_cwds: Vec<String>,
worktree_roots: Vec<String>,
enabled: bool,
) -> Result<(), String> {
let cwd_refs: Vec<&str> = project_cwds.iter().map(|s| s.as_str()).collect();
let wt_refs: Vec<&str> = worktree_roots.iter().map(|s| s.as_str()).collect();
let mut sandbox = SandboxConfig::for_projects(&cwd_refs, &wt_refs);
sandbox.enabled = enabled;
state.sidecar_manager.set_sandbox(sandbox);
// Restart sidecar so Landlock restrictions take effect on the new process
if state.sidecar_manager.is_ready() {
state.sidecar_manager.restart()?;
}
Ok(())
}