sandboxa
sandboxa runs a command inside a restricted environment scoped to a
target project directory.
It is designed to reduce accidental host exposure while still allowing practical project work.
What it does
- Launches via
systemd-run --user --pty. - Applies isolation properties:
ProtectHome=tmpfsTemporaryFileSystem=$HOME:rw,mode=700,...PrivateTmp=truePrivateDevices=true
- Sets the command working directory to the target project path.
- Binds the target project path into the sandbox.
- Optionally binds extra paths (
--extra-data-path/ YAMLextra_data_paths). - Optionally binds OpenCode configuration paths when
allow_featuresincludesopencode. - Optionally forwards Wayland/X11 clipboard access when
allow_featuresincludesclipboard. - Applies
InaccessiblePathsfor YAMLexcluded_pathsentries. - Refuses to run if a marker path exists in project (default:
.profile).
Security model
- Uses
systemd-run --userisolation properties to reduce what the launched process can see from the host (ProtectHome=tmpfs, a writable tmpfs mounted at$HOME,PrivateTmp=true,PrivateDevices=true). - Grants filesystem access by explicit bind mounts only:
- target project path
- optional OpenCode config paths when
allow_featuresincludesopencode - optional
extra_data_paths
- Supports explicit deny-listing inside project scope via
excluded_paths(InaccessiblePaths) for paths that currently exist. allow_features: [clipboard]/--allow-feature clipboardexposes desktop-session IPC for clipboard integration. On Wayland this requires access to the compositor socket, which can allow more than clipboard-only interaction depending on the compositor.- Adds a safety guard against accidentally sandboxing a complete home-like
directory by refusing to run when the marker path exists
(default:
.profile). - Applies strict config validation (
pydantic, unknown YAML keys are rejected) to prevent silent misconfiguration.
Non-goals
- Not a full container/VM boundary; this is a practical isolation wrapper, not a hardened multi-tenant sandbox.
- Not a replacement for system-level mandatory access controls or seccomp policy authoring.
- Not a network isolation tool; networking behavior is not managed here.
- Not a privilege-escalation mechanism; it runs as the invoking user via
systemd-run --user. - Not a generic policy engine; supported controls are intentionally narrow and centered on path exposure for local development workflows.
Requirements
- Linux with user
systemdsession support (systemd-run --user). - Python 3.
- Python packages:
ruamel.yamlpydantic
Installation
Dependencies:
pip install pydantic ruamel.yaml
Install sandboxa from PyPI:
pipx install sandboxa
Install/upgrade from source:
pipx install git+ssh://gitlab@gitlab.silicann.systems:2224/silicann/infrastructure/sandboxa.git
Install/upgrade via cloning the repository:
git clone ssh://gitlab@gitlab.silicann.systems:2224/silicann/infrastructure/sandboxa.git
cd sandboxa
pipx install .
Usage
./sandboxa \
[RUN_COMMAND] \
[--project-path PATH] \
[--extra-data-path PATH ...] \
[--excluded-path PATH ...] \
[--allow-feature NAME ...] \
[--refuse-if-exists NAME] \
[--config-file FILE] \
[--no-reconnect] \
[--dry-run] \
[-- COMMAND_ARGS...]
Common examples:
# Run default command (opencode) in current directory
./sandboxa
# Run bash in current directory sandbox
./sandboxa bash
# Target explicit project directory
./sandboxa --project-path /path/to/project
# Pass args to run command
./sandboxa bash -- -lc "echo smoke-ok"
# Add extra bind paths
./sandboxa --extra-data-path /data/shared --extra-data-path /mnt/cache
# Override excluded paths from CLI
./sandboxa --excluded-path build/ --excluded-path secrets/
# Do not check for existing sessions to be resumed.
./sandboxa opencode --no-reconnect
# Allow Wayland/X11 clipboard tools such as wl-copy/wl-paste
./sandboxa --allow-feature clipboard
# Preview effective config and command without executing
./sandboxa bash --dry-run -- -lc "echo smoke-ok"
Configuration file
By default the script reads user config from ~/.config/sandboxa.yaml and
project config from .sandboxa.yaml in the target project directory.
Use --config-file to override the project config path; absolute paths are
supported.
Supported keys:
allow_features: <list[string]>(see Feature Templates below)extra_data_paths: <list[path]>excluded_paths: <list[string]>refuse_if_exists: <string>
Example:
allow_features:
- opencode
extra_data_paths: []
excluded_paths:
- build/
- secrets/
refuse_if_exists: .profile
Precedence:
- CLI arguments override YAML values, except
--allow-featureadds to the configured/default feature set. - Project YAML values override user YAML values for most keys.
- For
allow_featuresandexcluded_paths, user and project YAML values are merged. - YAML values override built-in defaults.
Feature Templates (allow_features)
Even in a constrained environment there is sometimes the need to use data from your real home directory. This could be the configuration of your favorite editor or the cache of your userspace package manager.
Some popular use-cases are implemented in sandboxa in order to ease the burden of finding the required files to be accessible in the sandbox.
The following contexts are supported.
Keyword for allow_features |
Purpose | Limitations |
|---|---|---|
clipboard |
Wayland/X11 clipboard integration | exposes desktop-session IPC; disabled by default |
opencode |
OpenCode | - |
podman |
Podman | not working for root-less containers (see issue) |
ssh |
OpenSSH agent and key material | exposes ~/.ssh and optionally SSH_AUTH_SOCK if set |
vim |
VIM | without history (use extra-data_path: [~/.vim/] if you really need it) |
License
This project is licensed under GNU GPL v3 or later.
See LICENSE for the full text.
Metadata
Release files for sandboxa 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sandboxa-0.3.0.tar.gz | 24.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sandboxa-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.0 kB
Release files / sandboxa-0.3.0.tar.gz
| Download URL | sandboxa-0.3.0.tar.gz |
|---|---|
| Size | 24.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7cc3bd96b362fdbc232fd13569adb0ed5b6092e3c012c29742220250361bae49
|
|
BLAKE2b-256 checksum How to use checksums |
82eb680d62b447d8093a905e91e7efacda1d7f37b69dd889d0ecc7e9a3b5f513
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-httpx/0.28.1
|
Release files / sandboxa-0.3.0-py3-none-any.whl
| Download URL | sandboxa-0.3.0-py3-none-any.whl |
|---|---|
| Size | 20.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
564ebdcbd0d6c14d178ee0b837a8676c48c228ba679b786a6ca5da6b807947b2
|
|
BLAKE2b-256 checksum How to use checksums |
b71a8e66887ae9d62ca49044b1af6dcf106b3a498dd25f42e19693260ef33397
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-httpx/0.28.1
|
Security for sandboxa 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.