A GraalPy FileSystem that gives the Python sandbox REAL filesystem access
CONFINED to the session's filesystem roots.
Security model — every path-accessing operation canonicalizes its arguments and refuses anything that does not resolve UNDER a current filesystem root:
.. traversal is defeated by normalize.roots-fn on every check, so
/fs add|remove takes effect immediately.GraalPy's own stdlib / internal resources live OUTSIDE the roots, so the
confined FS is wrapped with allowLanguageHomeAccess +
allowInternalResourceAccess (read-only access to the language home and
bundled resources) before it reaches the Context.
OUTBOX tap — an optional engine-managed capture directory ($VIS_OUTBOX,
distinct from the user /fs roots): the sandbox may WRITE there and every
file it closes is handed to on-close so the engine can persist it as a
session_iteration_attachment (the implicit twin of vis_attach). Reads,
and writes anywhere else, are untouched.
Empty/zero roots ⇒ DENY everything (fail closed).
A GraalPy `FileSystem` that gives the Python sandbox REAL filesystem access
CONFINED to the session's filesystem roots.
Security model — every path-accessing operation canonicalizes its arguments
and refuses anything that does not resolve UNDER a current filesystem root:
- `..` traversal is defeated by `normalize`.
- symlink escapes are defeated by resolving the path through the REAL path
of its nearest existing ancestor (so a symlink inside a root that points
outside is rejected, and a symlink whose target is inside is allowed).
- the root set is read LIVE via `roots-fn` on every check, so
`/fs add|remove` takes effect immediately.
GraalPy's own stdlib / internal resources live OUTSIDE the roots, so the
confined FS is wrapped with `allowLanguageHomeAccess` +
`allowInternalResourceAccess` (read-only access to the language home and
bundled resources) before it reaches the Context.
OUTBOX tap — an optional engine-managed capture directory (`$VIS_OUTBOX`,
distinct from the user `/fs` roots): the sandbox may WRITE there and every
file it closes is handed to `on-close` so the engine can persist it as a
`session_iteration_attachment` (the implicit twin of `vis_attach`). Reads,
and writes anywhere else, are untouched.
Empty/zero roots ⇒ DENY everything (fail closed).(confined-filesystem roots-fn)(confined-filesystem roots-fn outbox)A GraalPy FileSystem confined to the filesystem roots returned by roots-fn
(a 0-arg fn → seq of root path strings). Delegates real I/O to the default FS
after confining every path argument. Wrapped so GraalPy's own stdlib / bundled
resources stay readable. Uses proxy (runtime dispatch) so the interface's
overloaded parsePath + varargs + void methods bind cleanly.
root-cache lives for the FS's lifetime and memoizes the per-root toRealPath
so confinement doesn't re-stat every root on every path operation.
outbox (optional) — {:dir <existing dir path string> :on-close (fn [^Path])}.
Its real path is treated as an always-allowed root (so the sandbox can write
there even though it is not a user /fs root); a WRITE channel closed under it
fires on-close with the file path. Nil ⇒ no tap.
A GraalPy `FileSystem` confined to the filesystem roots returned by `roots-fn`
(a 0-arg fn → seq of root path strings). Delegates real I/O to the default FS
after confining every path argument. Wrapped so GraalPy's own stdlib / bundled
resources stay readable. Uses `proxy` (runtime dispatch) so the interface's
overloaded `parsePath` + varargs + void methods bind cleanly.
`root-cache` lives for the FS's lifetime and memoizes the per-root `toRealPath`
so confinement doesn't re-stat every root on every path operation.
`outbox` (optional) — `{:dir <existing dir path string> :on-close (fn [^Path])}`.
Its real path is treated as an always-allowed root (so the sandbox can write
there even though it is not a user `/fs` root); a WRITE channel closed under it
fires `on-close` with the file path. Nil ⇒ no tap.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |