Architecture
| Class | Role |
|---|---|
SecureRunner |
Validates the command, builds the Bubblewrap argv, starts it with proc_open() (array form, no shell) and supervises it. |
SandboxConfig |
Immutable policy: bwrap/prlimit locations, extra read-only paths, environment allow-list, network opt-in. |
JobWorkspace |
A random 0700 directory per job, mounted at /work; safe path building; output resolution; symlink-safe cleanup. |
ResourceLimits |
Wall-clock deadline, CPU, file size, open files, optional address space, output cap. Core dumps always off. |
ProcessResult |
Exit code, captured stdout/stderr, timedOut, outputLimitExceeded, duration. |
SelfTest |
Canary-based verification used by bin/pdfx-sandbox-check. |
Exceptions\* |
SandboxUnavailableException, InvalidWorkspaceException, InvalidCommandException, ProcessFailedException, all extending SecureRunnerException. |
Execution flow
- Validate: executable is an absolute, existing, executable file; arguments are NUL-free strings; workspace is a real directory.
- Resolve
bwrap(andprlimit). Missingbwrap→SandboxUnavailableException. Nothing runs. - Build:
[prlimit …] bwrap --unshare-all --die-with-parent --new-session --cap-drop ALL --clearenv --setenv … --dev /dev --tmpfs /tmp --ro-bind <exe> <exe> --bind <workspace> /work --chdir /work -- <exe> <args…>. - Supervise: non-blocking reads with an output cap; on deadline or cap, SIGKILL the bwrap process. The PID namespace and
--die-with-parenttake every descendant with it. - Return a
ProcessResult. The caller decides what a non-zero exit means.