Bac à sable multiplateforme (sandbox)
codex isole l'exécution des commandes dans le sandbox natif de la plateforme : sandbox-exec (seatbelt) sur macOS, bubblewrap + seccomp sur Linux, restricted token sur Windows. Le crate sandboxing fournit l'abstraction unifiée ; linux-sandbox/, bwrap/, windows-sandbox-rs/, process-hardening/ sont les implémentations par plateforme. Avant chaque exec, core calcule un SandboxType puis le confie à SandboxManager::transform qui construit le véritable argv à spawner.
Responsabilités
- Selon
PermissionProfile, décider d'activer le sandbox et quel backend :codex-rs/sandboxing/src/manager.rs:273-319 - Sur macOS, construire la policy seatbelt et l'argv de
sandbox-exec:codex-rs/sandboxing/src/seatbelt.rs:21-30 - Sur Linux, passer par le helper
codex-linux-sandbox: d'abord no_new_privs + seccomp, puis exec bubblewrap :codex-rs/linux-sandbox/src/lib.rs:1-30 - Sur Windows, isoler système de fichiers et réseau via restricted token / elevated backend :
codex-rs/windows-sandbox-rs/src/lib.rs:13-50 - Appliquer un durcissement processus avant main (couper les core dump, refuser ptrace, nettoyer
LD_PRELOAD/DYLD_*) :codex-rs/process-hardening/src/lib.rs:12-25
Motivations de conception
Pourquoi ne pas se contenter de faire confiance au blocage d'execpolicy ? Parce que le modèle peut construire un shell arbitraire, et qu'un moteur de règles aura toujours des cas aux limites. Forcer chaque commande dans un sandbox OS natif est le filet de sécurité « même si le modèle contourne, le kernel bloque ». SandboxablePreference::Auto permet aux profiles workspace-write / read-only d'activer le sandbox, tandis que le profile full-access dégénère directement en SandboxType::None, évitant un emballage de processus inutile.
Les backends diffèrent par plateforme parce qu'il n'existe pas de primitive de sandbox unique multiplateforme : seatbelt sur macOS est déclaratif .sbpl, bubblewrap sur Linux repose sur user namespace + bind mount, restricted token sur Windows est token + ACL. L'énum SandboxType unifie ces trois backends et None sous un même label ; core/exec-server ne voient que le label, indifférents aux détails de plateforme.
Fichiers clés
codex-rs/sandboxing/src/lib.rs:1-46— entrée du module, décide quel backend compiler selontarget_os.codex-rs/sandboxing/src/manager.rs:35-75— l'énumSandboxTypeetget_platform_sandbox.codex-rs/sandboxing/src/manager.rs:273-329—SandboxManageravecselect_initial/should_sandbox.codex-rs/sandboxing/src/manager.rs:321-413—transformconvertit l'argv brut en argv emballé selon le type de sandbox.codex-rs/sandboxing/src/seatbelt.rs:21-30— le chemin macOSsandbox-execest codé dur à/usr/bin/sandbox-execcontre l'injection PATH.codex-rs/linux-sandbox/src/launcher.rs:36-67— Linux bubblewrap launcher : priorité au bwrap système, repli sur le bwrap bundled.codex-rs/process-hardening/src/lib.rs:43-61— durcissement Linux :prctl(PR_SET_DUMPABLE, 0)+ nettoyageLD_*.codex-rs/core/src/exec.rs:117-130— entrée côté core appelantselect_initial.
SandboxType unifie les trois backends plateforme et « pas de sandbox » en un seul label, core ne voit que le label.
pub enum SandboxType {
None,
MacosSeatbelt,
LinuxSeccomp,
WindowsRestrictedToken,
}Dans select_initial, on décide d'abord avec should_sandbox si sandbox il y a, puis on demande à la plateforme quel backend elle peut fournir :
pub fn select_initial(
&self,
file_system_policy: &FileSystemSandboxPolicy,
network_policy: NetworkSandboxPolicy,
pref: SandboxablePreference,
windows_sandbox_level: WindowsSandboxLevel,
has_managed_network_requirements: bool,
) -> SandboxType {
if self.should_sandbox(
file_system_policy,
network_policy,
pref,
has_managed_network_requirements,
) {
get_platform_sandbox(windows_sandbox_level != WindowsSandboxLevel::Disabled)
.unwrap_or(SandboxType::None)
} else {
SandboxType::None
}
}Le launcher Linux choisit entre bwrap système et bwrap bundled, et panic si absent — sans bubblewrap, toute la chaîne sandbox Linux est cassée.
pub(crate) fn exec_bwrap(argv: Vec<String>, preserved_files: Vec<File>) -> ! {
match preferred_bwrap_launcher() {
BubblewrapLauncher::System(launcher) => {
exec_system_bwrap(&launcher.program, argv, preserved_files)
}
BubblewrapLauncher::Bundled(launcher) => launcher.exec(argv, preserved_files),
BubblewrapLauncher::Unavailable => {
panic!(
"bubblewrap is unavailable: no system bwrap was found on PATH and no bundled \
codex-resources/bwrap binary was found next to the Codex executable"
)
}
}
}Flux de données
Limites et échecs
SandboxablePreference::Forbidforce sandbox off,Requireforce on ; seulAutoconsulte la policy :codex-rs/sandboxing/src/manager.rs:303-319- Sur macOS, le chemin
sandbox-execest codé dur à/usr/bin/sandbox-exec, pour esquiver l'attaque PATH :codex-rs/sandboxing/src/seatbelt.rs:26-30 - Sur Linux, bubblewrap absent → panic plutôt que dégradation silencieuse, pour éviter un état insécurisé « on croit avoir un sandbox, en fait non » :
codex-rs/linux-sandbox/src/launcher.rs:42-48 - Le bundle de confiance MITM CA est ajouté explicitement aux readable roots, sinon le processus sandboxé ne peut pas valider TLS :
codex-rs/sandboxing/src/manager.rs:76-95 - Dans
core::exec,is_likely_sandbox_deniedinspecte stderr après exécution pour savoir si le sandbox a bloqué, et renvoie au modèle une erreur lisible :codex-rs/core/src/exec.rs:768-810
Récapitulatif
SandboxManager est l'entrée unifiée du sandbox multiplateforme de codex : il traduit PermissionProfile en SandboxType puis en argv emballé. Les backends plateforme isolent chacun à leur manière, mais dérivent tous de la même FileSystemSandboxPolicy / NetworkSandboxPolicy. Pour remonter « pourquoi cette commande a été refusée », voir Classification execpolicy et Exécution exec-server.