1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! Process-sandbox backend slot (shape only).
//!
//! This module defines the *interface* a future shared `saorsa-sandbox` crate
//! will implement. It mirrors the contract designed in x0x-symphony's
//! XSY-0027 (`wrap(argv) + probe()`), with four shape refinements (C1–C4)
//! fed back to the symphony team:
//!
//! - **C1:** `wrap` returns a [`WrappedCommand`] (argv **and** env additions),
//! not bare argv — the runner's `env_clear()` would otherwise drop a
//! backend's proxy/CA vars.
//! - **C2:** the backend is **stateful** ([`ProcessSandbox::prepare`] /
//! [`ProcessSandbox::shutdown`]) — fluers spawns dozens of short-lived
//! commands per turn; per-exec boot (e.g. srt's Node) is too expensive.
//! - **C3:** [`ProcessSandbox::probe`] is `async` — it spawns children, and all
//! fluers/runtime consumers are tokio.
//! - **C4:** [`ExecSandboxContext`] carries an optional per-call `cwd` — a
//! parent's `current_dir` does not survive a mount-namespace pivot
//! (e.g. bubblewrap `--chdir`).
//!
//! **No backends are implemented here.** When the shared `saorsa-sandbox` crate
//! publishes (WP-5/4e), this slot is replaced by, re-exported from, or adapted
//! to that crate's final API. NOTE: as of 2026-07, symphony's runner-shell
//! `Sandbox` trait (XSY-0027 M2) and this trait are *semantically* aligned on
//! C1–C4 (env-returning wrap, stateful lifecycle, async probe, per-call cwd)
//! but differ concretely — notably lifecycle scope (fluers prepares once per
//! session + cheap per-command `wrap`; symphony prepares per command). The
//! shared-crate reconciliation is tracked for WP-5/4e; until then this local
//! trait preserves the C1–C4 semantics fluers needs.
use BTreeMap;
use PathBuf;
use async_trait;
use crateRuntimeResult;
/// How strongly a backend enforces a given [`SandboxProfile`].
///
/// Mirrors the intended `saorsa-sandbox` (XSY-0027) semantics; the concrete
/// shared-crate shape is reconciled at WP-5/4e. [`SandboxPolicy`] decides
/// what to do when enforcement falls short of the requested profile.
/// A coarse capability profile a caller may request of the sandbox.
///
/// Intentionally a small, stable set; `saorsa-sandbox` may refine it. The
/// variants describe *what* the caller wants confined, not *how*.
/// Per-session/per-call context handed to a [`ProcessSandbox`].
///
/// `cwd` is `Option` per C4: `None` means "use `workspace_path`".
/// The result of [`ProcessSandbox::wrap`]: the (possibly rewritten) argv plus
/// any environment the backend needs present in the child.
///
/// Per C1, the env additions survive the runner's `env_clear()`: fluers applies
/// them on top of its safe allowlist at the spawn site.
/// A process-sandbox backend. **Shape only** — no implementations ship in
/// fluers; this is the slot `saorsa-sandbox` will replace/re-export/adapt to
/// (WP-5/4e).
///
/// Lifecycle (C2): a backend is constructed once, [`prepare`](Self::prepare)d
/// at session construction, and [`wrap`](Self::wrap) is called cheaply per
/// command. [`shutdown`](Self::shutdown) tears down per-session state when the
/// session ends.
///
/// **WP-2 limitation:** fluers calls `prepare` and `wrap` but does **not**
/// yet call `shutdown` (no real backend to leak in this milestone). Wiring the
/// shutdown call — a best-effort cleanup at session end — is part of WP-5/4e
/// when a stateful backend lands. Until then the session owns the backend's
/// lifecycle and a consumer that constructs a stateful backend itself is
/// responsible for calling `shutdown`.
/// What to do when a requested profile cannot be fully enforced.
/// A caller's sandbox requirements, paired with a fallback policy.