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
169
170
171
172
173
174
175
//! `koda-fs-worker` — long-lived FS worker process spawned by the
//! sandbox shim (Phase 2c of #934).
//!
//! ## Transport selection
//!
//! - **`--socket <path>`** (production): bind a Unix domain socket at
//! `<path>`, write "ready\n" to stdout, accept one connection,
//! serve it. Used by [`koda_sandbox::worker_client::WorkerClient`].
//! - **No arguments** (legacy / tests): run against stdin/stdout.
//! The `worker_binary` integration tests still use this path.
//!
//! ## Policy injection (Phase 2f)
//!
//! When spawned with `--root <path>` the worker enforces write-policy
//! for every `Write`/`Edit` request. The full [`SandboxPolicy`] is
//! passed via the `KODA_FS_WORKER_POLICY` environment variable as a
//! JSON string. Both are set by
//! [`koda_sandbox::worker_client::WorkerClient::spawn_with_policy`].
//!
//! If `--root` is absent the worker runs with no enforcement (legacy
//! behavior, used by `WorkerClient::spawn()` and stdio tests).
//!
//! ## Accepted arguments
//!
//! ```text
//! koda-fs-worker # stdin/stdout, no policy
//! koda-fs-worker --socket <sock> # Unix socket, no policy
//! koda-fs-worker --socket <sock> --root <root> # Unix socket + policy
//! ```
//!
//! ## Lifecycle
//!
//! Spawned by `WorkerClient::spawn()` for each sandbox slot. Exits
//! when the host closes the connection (clean EOF) or sends
//! [`koda_sandbox::ipc::Request::Shutdown`].
//!
//! ## Why a binary not a library function?
//!
//! Crash isolation. A panicking FS handler kills the worker, not the
//! host process driving the LLM session.
use ;
use SandboxPolicy;
use PathBuf;
async
// ── Argument parsing ──────────────────────────────────────────────────────
/// Minimal flag parser for the two supported flags.
///
/// We intentionally avoid adding a CLI-parsing dep (clap et al.) to the
/// worker binary — the arg surface is tiny and the dep would meaningfully
/// bloat the binary's startup time for every slot spawn.
// ── Policy env var ────────────────────────────────────────────────────────
/// Read `KODA_FS_WORKER_POLICY` and deserialize it as a [`SandboxPolicy`].
///
/// Returns [`SandboxPolicy::default()`] when the variable is unset \u2014 this
/// produces a permissive policy that only enforces the absolute deny list
/// (koda credential DB and dangerous system paths).
///
/// Returns an error when the variable is set but cannot be parsed \u2014 a
/// malformed policy env var is a programming error in the host, not a
/// user error, so we fail hard rather than silently falling back.
///
/// # Architectural note: sole authorized SandboxPolicy deserialization site
///
/// Koda is **config-free at runtime** — every behavioral dial is
/// derived from the trust mode at compile time via
/// `koda_core::sandbox::policy_for_agent`. There is no JSON config file,
/// no CLI override, no env-var dial.
///
/// This function is the **single legitimate exception**: it deserializes
/// `SandboxPolicy` purely to receive an in-memory policy across a
/// process boundary (the host crashes the worker and respawns to keep
/// the sandbox crash-isolated, so the policy must travel as bytes).
/// The host built that policy in-memory via `policy_for_agent` — the
/// JSON is just the wire format, not user-facing config.
///
/// A regression test in `koda_sandbox::policy::tests` mechanically
/// enforces that no other deserialization site exists. If you need a
/// new IPC boundary, update its allowlist with a comment explaining
/// why the new site is IPC and not user-facing config.