Skip to main content

Prebuilt google nsjail executable file packaged as Python wheels with simple Python APIs

Project description

python-nsjail

Prebuilt nsjail executable file packaged as Python wheels with simple Python APIs

CI GitHub tags PyPI version PyPI - Python Version PyPI - Implementation PyPI - Status PyPI - License

Overview

Just install and use — no compilation required. python-nsjail provides prebuilt nsjail binaries as Python wheels, making the powerful Linux namespace sandbox immediately available.

System Requirements

  • OS: Linux only
  • Kernel: Linux 5.10+ (some nsjail features require newer kernel syscalls)
  • Permissions: Using nsjail requires CAP_SYS_ADMIN or root
  • Python: Python 3.9+

Platform Compatibility

Platform libc Compatible With CPU Requirement
manylinux_2_34_x86_64 glibc 2.34 Ubuntu 22.04+, Debian 12+, RHEL 9+ x86-64-v2* (SSE4.2, POPCNT)
manylinux_2_34_aarch64 glibc 2.34 ARM64 systems ARM64 (v8+)
musllinux_1_2_x86_64 musl 1.2 Alpine Linux, other musl-based x86-64-v2* (SSE4.2, POPCNT)
musllinux_1_2_aarch64 musl 1.2 Alpine Linux ARM64 ARM64 (v8+)

⚠️ x86-64-v2 Note:
The x86_64 wheels are built with manylinux_2_34 containers which use x86-64-v2 by default. This requires a CPU from ~2010 or later (supports SSE4.2 and POPCNT instructions). Most modern systems support this. If you need to run on older x86-64 hardware (pre-2010), please use the source distribution or build from source.

Installation

pip install python-nsjail

Now run:

nsjail --help

You got nsjail installed!

Verify Installation

nsjail --help
nsjail-status

Where is the nsjail binary?

The nsjail command is installed as a console script in your environment's bin/ directory (e.g., .venv/bin, ~/.local/bin, or /usr/local/bin). The underlying binary is bundled with the Python package.

For development, after building the wheel with python setup.py bdist_wheel, the binary will be at src/nsjail/bin/nsjail.

Getting the Binary Path from Python

If you need the nsjail binary path in your scripts:

from nsjail import bundled_nsjail

nsjail_path = bundled_nsjail()
print(nsjail_path)  # /absolute/path/to/nsjail

Or use locate_nsjail() which respects the NSJAIL environment variable and checks system paths:

from nsjail import locate_nsjail

nsjail_path = locate_nsjail()  # Returns path with priority: env var > system > bundled

Priority:

  1. NSJAIL environment variable (if set)
  2. System paths: /usr/local/bin, /usr/bin
  3. Bundled binary (fallback)

Python API

The library provides simple functions for creating nsjail subprocesses. Both synchronous and asynchronous APIs are available.

Basic Usage

Async API:

import asyncio
import subprocess
from nsjail import async_create_nsjail, NsjailOptions

async def main():
    # Basic usage - output to terminal
    proc = await async_create_nsjail(
        command=["/bin/echo", "hello"],
        options=NsjailOptions(chroot="/"),
    )
    await proc.wait()

    # Capture output
    proc = await async_create_nsjail(
        command=["/bin/cat", "/etc/hostname"],
        options=NsjailOptions(chroot="/", user="nobody"),
        stdout=subprocess.PIPE,
    )
    output = await proc.stdout.read()
    print(output.decode())

asyncio.run(main())

Sync API:

import subprocess
from nsjail import create_nsjail, NsjailOptions

# Capture output synchronously
proc = create_nsjail(
    command=["/bin/echo", "hello"],
    options=NsjailOptions(chroot="/"),
    stdout=subprocess.PIPE,
)
output, _ = proc.communicate()
print(output.decode())

Stream Merging

For processes that output to both stdout and stderr, use merge_streams:

import asyncio
import subprocess
from nsjail import async_create_nsjail, merge_streams, NsjailOptions

async def main():
    proc = await async_create_nsjail(
        command=["/bin/sh", "-c", "echo out; echo err >&2"],
        options=NsjailOptions(chroot="/"),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )

    async for source, chunk in merge_streams(proc):
        if source == "stdout":
            print(f"stdout: {chunk.decode()}")
        else:
            print(f"stderr: {chunk.decode()}", file=sys.stderr)

asyncio.run(main())

Using nsenter

Enter an existing container's namespace with async_create_nsenter:

import asyncio
import subprocess
from nsjail import async_create_nsenter

async def main():
    # Run 'ip addr' inside container 1234's network namespace
    proc = await async_create_nsenter(
        target_pid=1234,
        namespaces=["net"],
        command=["ip", "addr"],
        stdout=subprocess.PIPE,
    )
    output = await proc.stdout.read()
    print(output.decode())

asyncio.run(main())

Inspect Command Arguments

For debugging or testing, you can build the nsjail arguments without executing:

from nsjail import build_nsjail_args, NsjailOptions

args = build_nsjail_args(
    options=NsjailOptions(chroot="/", user="nobody"),
    config_file="/path/to/config.cfg",
)
print("nsjail", *args, "--", "/bin/echo", "hello")
# Output: nsjail --chroot / --user nobody --config /path/to/config.cfg -- /bin/echo hello

Passing Additional Arguments

All *args and **kwargs are passed directly to the underlying subprocess creation functions:

import subprocess
from nsjail import async_create_nsjail, NsjailOptions

# Pass cwd, env, and other subprocess.Popen / asyncio.create_subprocess_exec arguments
proc = await async_create_nsjail(
    command=["/bin/sh", "-c", "echo $FOO"],
    options=NsjailOptions(chroot="/"),
    stdout=subprocess.PIPE,
    cwd="/tmp",
    env={"FOO": "value"},
)

NsjailOptions

Configure nsjail with NsjailOptions:

from nsjail import NsjailOptions

options = NsjailOptions(
    chroot="/srv/jail",           # Chroot directory
    user=65534,                    # Run as user (UID)
    group=65534,                   # Run as group (GID)
    hostname="sandbox",            # Set hostname
    cwd="/tmp",                    # Working directory inside jail
    env={"HOME": "/tmp"},          # Environment variables
    bindmount=["/tmp:/tmp"],       # Read-write bind mounts
    bindmount_ro=["/lib:/lib"],    # Read-only bind mounts
    tmpfsmount=["/tmp"],           # Temporary filesystem mounts
    time_limit=60,                 # Wall time limit in seconds
    memory_limit=512,              # Memory limit in MB
    # ... see NsjailOptions for all options
)

Environment Variable

NSJAIL - Override the nsjail binary path (for Python API only)

export NSJAIL=/custom/path/to/nsjail

Supports ~ and $VAR expansion:

export NSJAIL=~/local/bin/nsjail
export NSJAIL=$XDG_DATA_HOME/nsjail/bin/nsjail

API Reference

Async Functions

  • async_create_nsjail(command, options=None, config_file=None, *args, **kwargs) - Create async nsjail subprocess
  • async_create_nsenter(target_pid, namespaces, command, options=None, *args, **kwargs) - Create async nsenter subprocess

Sync Functions

  • create_nsjail(command, options=None, config_file=None, *args, **kwargs) - Create sync nsjail subprocess
  • create_nsenter(target_pid, namespaces, command, options=None, *args, **kwargs) - Create sync nsenter subprocess

Helper Functions

  • build_nsjail_args(options=None, config_file=None) - Build nsjail command-line arguments
  • build_nsenter_args(target_pid, namespaces, options=None) - Build nsenter command-line arguments

Classes

  • NsjailOptions - nsjail configuration options
  • NsenterOptions - nsenter configuration options

Locator Functions

  • locate_nsjail() - Find nsjail binary (respects NSJAIL env var)
  • bundled_nsjail() - Get bundled nsjail binary path

Building from Source

For development or building from source, see CONTRIBUTING.md.

For Developers

If you're working on a clone of this repository and want to run/debug nsjail locally, you need to build the wheel first to generate the nsjail binary:

python setup.py bdist_wheel
# or: python -m build --wheel
# or: uv build --wheel

This compiles the nsjail binary and places it at src/nsjail/bin/nsjail, which is required for the package to function in place.

License

  • nsjail: Apache-2.0 (see google/nsjail)
  • python-nsjail packaging: Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

python_nsjail-0.3.0b1-py3-none-musllinux_1_2_x86_64.whl (3.1 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

python_nsjail-0.3.0b1-py3-none-musllinux_1_2_aarch64.whl (3.0 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

python_nsjail-0.3.0b1-py3-none-manylinux_2_34_x86_64.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.34+ x86-64

python_nsjail-0.3.0b1-py3-none-manylinux_2_34_aarch64.whl (1.7 MB view details)

Uploaded Python 3manylinux: glibc 2.34+ ARM64

File details

Details for the file python_nsjail-0.3.0b1-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for python_nsjail-0.3.0b1-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 c7da23e8abe0de2fcbd35398fc296db85491a17aad804c75e3c2b0615e6c6c85
MD5 1462edf1695f7023528f0fa60f2276ae
BLAKE2b-256 bc1479982bf806ad39d58c2b01a5f81e85e84b53244466fd26c919823ded02d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_nsjail-0.3.0b1-py3-none-musllinux_1_2_x86_64.whl:

Publisher: build-and-publish.yml on tanbro/python-nsjail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_nsjail-0.3.0b1-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for python_nsjail-0.3.0b1-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 8739ca91e92cb09b51e6a93ae85ff142c04185fadc9ea6eff302b2e961ce0c21
MD5 8732217641ed008c786979b43363015a
BLAKE2b-256 f9b7f7bfd7b11e68089e37cb171e6925a087a025bc5119366fd74ce552efa1c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_nsjail-0.3.0b1-py3-none-musllinux_1_2_aarch64.whl:

Publisher: build-and-publish.yml on tanbro/python-nsjail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_nsjail-0.3.0b1-py3-none-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for python_nsjail-0.3.0b1-py3-none-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 0b61bc0b317c9ad85984b0cca506cb31865d8a9a4c534baac502cf0b3e75404e
MD5 4adde47869318b7f374bc887c8705e95
BLAKE2b-256 cc3f837746ad18499a55d7c89f164fa0a2ddd1d83337957600f139eb2ebb423a

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_nsjail-0.3.0b1-py3-none-manylinux_2_34_x86_64.whl:

Publisher: build-and-publish.yml on tanbro/python-nsjail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file python_nsjail-0.3.0b1-py3-none-manylinux_2_34_aarch64.whl.

File metadata

File hashes

Hashes for python_nsjail-0.3.0b1-py3-none-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 97642fbbc4f02f465b3c400c5da5c50812b71de3e1e865a1d286cf60f15da589
MD5 b66adb3770543c7a0891ea8c956e5362
BLAKE2b-256 0ce09687e1e5b26d230f90d5bb3f2064f51a47297124f4e8845ca85b6adf255d

See more details on using hashes here.

Provenance

The following attestation bundles were made for python_nsjail-0.3.0b1-py3-none-manylinux_2_34_aarch64.whl:

Publisher: build-and-publish.yml on tanbro/python-nsjail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page