feat(permissions): LP4-1/LP4-2 — enforcer Landlock OS + consommation PTY du plan

LP4-1 : adaptateurs SandboxEnforcer concrets (LandlockSandbox Linux via le LSM
Landlock, NoopSandbox ailleurs) + default_enforcer() cfg-sélectionné, prêts à
être injectés au composition root (LP4-3). Aucun changement de comportement
runtime tant que rien n'est câblé : SpawnSpec.sandbox reste None.

LP4-2 : PortablePtyAdapter consomme SpawnSpec.sandbox via spawn_command_sandboxed
(thread jetable restreint par enforce() puis fork → le domaine Landlock est hérité
par l'enfant à travers execve ; les autres threads d'IdeA ne sont jamais sandboxés).
Builder additif with_sandbox_enforcer ; fail-closed si enforce() échoue.

Tests : domain + infrastructure verts (dont les tests Landlock réels de fencing
read-only/write-only et la confine-au-thread).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 08:00:47 +02:00
parent b05d04ab7a
commit 17ca65ed0f
7 changed files with 653 additions and 8 deletions

View File

@ -22,6 +22,10 @@ serde = { workspace = true }
serde_json = { workspace = true }
portable-pty = "0.9"
git2 = { workspace = true }
# OS sandbox (lot LP4-1) — Linux Landlock LSM, best-effort/ABI-compat. Linux-only
# target dep so the Windows/macOS builds (and the Noop fallback) compile nothing
# extra. `landlock` is a thin, dependency-light wrapper over the kernel ABI.
# Filesystem change notifications used to *wake* the orchestrator poll loop early
# (the poll loop remains the robust cross-platform correctness guarantee).
notify = "6"
@ -36,6 +40,9 @@ reqwest = { version = "0.12", default-features = false, features = ["json", "rus
# `vector-onnx` feature; the zero-dependency default compiles nothing extra.
fastembed = { version = "5", default-features = false, features = ["hf-hub-rustls-tls", "ort-download-binaries-rustls-tls"], optional = true }
[target.'cfg(target_os = "linux")'.dependencies]
landlock = "0.4.5"
[features]
# Real HTTP-backed embedders (`localServer` Ollama/llama.cpp, `api` OpenAI/Voyage…).
# OFF by default: the founding posture is `none` ⇒ naïve recall, zero dependency.