Java FFM (java.lang.foreign) bindings over the libcvisor C ABI. Linux-only
at runtime; requires JDK 22+ (the FFM API is final as of JDK 22). The
pinned toolchain is in mise.toml — run mise install to get it.
Published on Clojars as io.github.tsirysndr/cvisor.
(require '[cvisor.core :as cvisor])
(with-open [sb (cvisor/sandbox)]
(let [out (cvisor/run sb "echo hello")]
(print (:stdout out)) ; "hello\n"
(print (:stderr out)))) ; ""
run blocks until the sandboxed command exits and returns a map with
:stdout / :stderr (String), :exit-code (long — shell convention: status,
or 128 + signal), and :stdout-bytes / :stderr-bytes. sandbox returns a
Closeable, so with-open frees it; close is also exposed directly and is
idempotent.
;; Exit codes:
(:exit-code (cvisor/run sb "exit 3")) ; => 3
;; Timeout — SIGKILL the guest after N ms; a timed-out run reports 137:
(:exit-code (cvisor/run sb "sleep 60" {:timeout-ms 500})) ; => 137
;; Egress kill switch — deny outbound INET/INET6 sockets (default allowed):
(cvisor/set-allow-network! sb false)
Add --enable-native-access=ALL-UNNAMED to your JVM options to silence the
FFM restricted-method warning (the :test and :console aliases already do).
Launch a rebel-readline REPL with a live sandbox preloaded:
clojure -M:console
cVisor interactive console
sb -> a live Sandbox
(sh "cmd") -> run a shell command in the sandbox, printing stdout/stderr
(cvisor.core/sandbox) -> create your own
user=> (sh "echo hello; uname -n")
hello
cvisor
The sandbox only runs on Linux; from any host, build the native library once
(cargo xtask ffi from the repo root) and drop into the console in a musl
JDK 22 container (multi-arch; installs the Clojure CLI on first run):
docker run -it --rm --security-opt seccomp=unconfined \
-v "$PWD":/sdk -w /sdk bellsoft/liberica-openjdk-alpine-musl:22 \
sh -c 'apk add --no-cache bash curl >/dev/null &&
curl -sLO https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh &&
bash linux-install.sh >/dev/null && clojure -M:console'
The SDK loads libcvisor.so. Build it from the repo root (cargo xtask ffi),
which drops a copy into resources/cvisor/native/, or point the SDK at one
via the CVISOR_LIB environment variable.
Run the e2e test in a musl JDK container (Linux syscalls + seccomp required):
docker run --rm --security-opt seccomp=unconfined \
-v "$PWD":/sdk -w /sdk bellsoft/liberica-openjdk-alpine-musl:22 \
sh -c 'apk add --no-cache bash curl >/dev/null &&
curl -sLO https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh &&
bash linux-install.sh >/dev/null && clojure -M:test'
cargo xtask ffi && cargo xtask ffi --arch x86_64 # from the repo root: both arches
clojure -T:build jar # bundles both .so files
CLOJARS_USERNAME=... CLOJARS_PASSWORD=... clojure -T:build deploy
Can you improve this documentation?Edit on GitHub
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 |