Skip to main content

Lightweight process sandbox using Landlock, seccomp, and seccomp user notification

Project description

sandlock Python SDK

Python bindings for sandlock, a lightweight process sandbox using Landlock and seccomp. No root, no Docker, no namespaces required.

Requires Linux 6.7+ with Landlock ABI v6.

pip install sandlock

Quick start

from sandlock import Sandbox

sandbox = Sandbox(
    fs_readable=["/usr", "/lib", "/lib64", "/bin", "/etc", "/proc", "/dev"],
    fs_writable=["/tmp"],
)
result = sandbox.run(["echo", "hello"], timeout=10)
assert result.success
print(result.stdout)  # b"hello\n"

API reference

Platform

sandlock.landlock_abi_version() -> int

Return the Landlock ABI version supported by the running kernel. Returns -1 if Landlock is unavailable.

sandlock.min_landlock_abi() -> int

Return the minimum Landlock ABI version required by sandlock (currently 6).

Confine

Apply a Sandbox's Landlock rules to the current process, in place. No fork, no exec.

from sandlock import Sandbox, confine

confine(Sandbox(
    fs_readable=["/usr", "/lib"],
    fs_writable=["/tmp"],
))

sandlock.confine(sandbox) -> None

Set PR_SET_NO_NEW_PRIVS and install the sandbox's Landlock ruleset on the live process. The confinement is irreversible.

Only Landlock fields are honored (fs_readable, fs_writable, fs_denied); IPC and signal scoping are always applied. Sandbox config that requires a supervisor or a fresh child (seccomp, network, resource limits, COW, env, policy_fn, etc.) is rejected rather than silently ignored. Raises ConfinementError on failure.

Sandbox

sandlock.Sandbox(**kwargs)

Sandbox configuration and runtime handle. Holds both the policy (filesystem, network, resource limits, etc.) and runtime state. Construct once, then call run() (blocking) or spawn() + lifecycle methods, or use as a context manager.

All config fields are optional. Unset fields mean "no restriction" unless noted otherwise. Runtime kwargs (name, policy_fn, init_fn, work_fn) are set at construction time alongside config fields.

A single Sandbox instance holds at most one running process at a time. For concurrent execution, create multiple instances.

Runtime kwargs:

  • name -- sandbox name (also its virtual hostname inside the sandbox). Auto-generated as sandbox-{pid} when omitted.
  • policy_fn -- optional callback for dynamic per-event policy decisions (see Dynamic policy).
  • init_fn / work_fn -- callbacks for COW fork mode (see Fork).

Sandbox is a context manager:

with Sandbox(fs_readable=["/usr", "/lib"]) as sb:
    result = sb.run(["echo", "hello"])

Filesystem (Landlock)

Parameter Type Default Description
fs_readable list[str] [] Paths the sandbox can read
fs_writable list[str] [] Paths the sandbox can write
fs_denied list[str] [] Paths explicitly denied
workdir str | None None Working directory; enables COW protection
chroot str | None None Path to chroot into before confinement
fs_mount dict[str, str] {} Map virtual paths to host directories inside chroot
cwd str | None None Child working directory

Network

Parameter Type Default Description
net_allow list[str] [] Outbound endpoint rules. Bare host:port is TCP; protocol prefixes opt others in: tcp://host:port, udp://host:port (or udp://*:* for any UDP), icmp://host (or icmp://* for any ICMP echo via the kernel ping socket — gated by net.ipv4.ping_group_range on the host). Empty = deny all. Raw ICMP is not exposed.
net_bind list[int | str] [] TCP ports the sandbox may bind (empty = deny all)
port_remap bool False Transparent TCP port virtualization

HTTP ACL

Enforce method + host + path rules on HTTP traffic via a transparent MITM proxy. When http_allow is set, all non-matching HTTP requests are denied by default. Block rules are checked first and take precedence.

Parameter Type Default Description
http_allow list[str] [] Allow rules in "METHOD host/path" format
http_deny list[str] [] Block rules in "METHOD host/path" format
http_ports list[int] [80] TCP ports to intercept (443 added when http_ca is set)
http_ca str | None None CA certificate for HTTPS MITM
http_key str | None None CA private key for HTTPS MITM

Rule format: "METHOD host/path" where method and host can be * for wildcard, and path supports trailing * for prefix matching. Paths are normalized (percent-decoding, .. resolution, // collapsing) before matching to prevent bypasses.

sandbox = Sandbox(
    fs_readable=["/usr", "/lib", "/etc"],
    http_allow=[
        "GET docs.python.org/*",
        "POST api.openai.com/v1/chat/completions",
    ],
    http_deny=["* */admin/*"],
)
result = sandbox.run(["python3", "agent.py"])

Chroot with mount mapping

Map host directories into a chroot — like Docker's -v /host:/container but without kernel bind mounts or root privileges. Each sandbox gets its own persistent workspace while sharing a read-only rootfs.

sandbox = Sandbox(
    chroot="/opt/rootfs",
    fs_mount={"/work": "/tmp/sandbox-1/work"},
    fs_readable=["/usr", "/bin", "/lib", "/etc"],
    cwd="/work",
)
result = sandbox.run(["python3", "task.py"])

Combine with workdir + max_disk for quota-enforced writes:

sandbox = Sandbox(
    chroot="/opt/rootfs",
    fs_mount={"/work": "/tmp/sandbox-1/work"},
    workdir="/tmp/sandbox-1/work",
    fs_storage="/tmp/sandbox-1/cow",
    max_disk="100M",
    on_exit="commit",
    fs_readable=["/usr", "/bin", "/lib", "/etc"],
)

Resource limits

Parameter Type Default Description
max_memory str | int | None None Memory limit, e.g. "512M" or int bytes
max_processes int 64 Peak concurrent process limit
max_open_files int | None None Max file descriptors (RLIMIT_NOFILE)
max_cpu int | None None CPU throttle as percentage of one core (1-100)
cpu_cores list[int] | None None CPU cores to pin sandbox to
num_cpus int | None None Visible CPU count in /proc/cpuinfo

Syscall filtering (seccomp)

Parameter Type Default Description
extra_deny_syscalls list[str] [] Extra syscall names to block in addition to Sandlock defaults
extra_allow_syscalls list[str] [] Syscall groups to allow that are blocked by default (e.g. "sysv_ipc" to enable SysV shared memory, semaphores, and message queues)

Sandlock always applies its default syscall blocklist.

Deterministic execution

Parameter Type Default Description
random_seed int | None None Seed for deterministic getrandom()
time_start datetime | float | str | None None Start timestamp for time virtualization
no_randomize_memory bool False Disable ASLR
no_huge_pages bool False Disable Transparent Huge Pages
deterministic_dirs bool False Sort directory entries lexicographically

Environment

Parameter Type Default Description
clean_env bool False Start with minimal environment
env dict[str, str] {} Variables to set/override in the child

GPU access

Parameter Type Default Description
gpu_devices list[int] | None None GPU device indices to expose ([] = all)

Misc

Parameter Type Default Description
uid int | None None Map to given UID inside a user namespace (e.g. 0 for fake root)
no_coredump bool False Disable core dumps

COW filesystem isolation

Parameter Type Default Description
fs_isolation FsIsolation NONE NONE, BRANCHFS, or OVERLAYFS
fs_storage str | None None Storage directory for BranchFS deltas
max_disk str | None None Disk quota for BranchFS (e.g. "1G")
on_exit BranchAction COMMIT COMMIT, ABORT, or KEEP
on_error BranchAction ABORT COMMIT, ABORT, or KEEP

sandbox.run(cmd, timeout=None) -> Result

Run a command, capturing stdout and stderr.

  • cmd -- list of strings (command and arguments).
  • timeout -- max execution time in seconds (float). None = no timeout.
result = sandbox.run(["python3", "-c", "print(42)"], timeout=10.0)

sandbox.spawn(cmd) -> None

Spawn cmd without waiting. Use pid, pause(), resume(), kill(), and wait() to manage the process lifecycle.

Raises RuntimeError if a process is already running.

Sugar for create(cmd) + start(); use those directly when you need the fork-park-exec split (e.g. starting several sandboxes in lockstep, or attaching external tracing to the parked PID before the child execs).

sandbox.create(cmd) -> None

Fork the sandboxed child and install policy. The child is parked between policy install and execve; call start() to release it. pid is available after this call but the child is not yet running user code.

Raises RuntimeError if a process is already running.

sandbox.start() -> None

Release a previously create()d child to execve.

Raises RuntimeError if no child has been created.

sandbox.wait() -> Result

Wait for the running process to finish and return its Result.

sandbox.dry_run(cmd, timeout=None) -> DryRunResult

Run a command in a temporary COW layer, then discard all writes. Returns the list of filesystem changes that would have been made.

result = sandbox.dry_run(["sh", "-c", "echo hi > /tmp/out.txt"])
for change in result.changes:
    print(change.kind, change.path)  # "A /tmp/out.txt"

sandbox.run_interactive(cmd) -> int

Run with inherited stdio (no capture). Returns the exit code.

sandbox.name -> str | None

The sandbox name.

sandbox.pid -> int | None

The child PID while running, None otherwise.

sandbox.is_running -> bool

True if a process is currently running in this sandbox.

sandbox.ports() -> dict[int, int]

Current port mappings {virtual_port: real_port} while running. Only contains entries where port remapping occurred. Requires port_remap=True.

sandbox.pause() / sandbox.resume() / sandbox.kill()

Send SIGSTOP / SIGCONT / SIGKILL to the sandbox process group. Raises RuntimeError if the sandbox is not running.

sandbox.checkpoint(save_fn=None) -> Checkpoint

Capture a checkpoint of the running sandbox. See Checkpoint.

Result

Returned by sandbox.run().

Attribute Type Description
success bool True if exit code is 0
exit_code int Process exit code
stdout bytes Captured standard output
stderr bytes Captured standard error
error str | None Error message on failure

DryRunResult

Returned by sandbox.dry_run().

Same attributes as Result, plus:

Attribute Type Description
changes list[Change] Filesystem changes detected

Change

Attribute Type Description
kind str "A" (added), "M" (modified), or "D" (deleted)
path str Path relative to workdir

Stage and Pipeline

Chain sandboxed commands with pipes using the | operator:

result = (
    sandbox_a.cmd(["echo", "hello"])
    | sandbox_b.cmd(["tr", "a-z", "A-Z"])
).run()
assert result.stdout == b"HELLO\n"

sandbox.cmd(args) -> Stage

Create a lazy Stage bound to this sandbox.

pipeline.run(stdout=None, timeout=None) -> Result

Run the pipeline. Each stage's stdout feeds the next stage's stdin.

Gather

Fan multiple producers into one consumer via named pipes. Each producer's stdout is delivered to the consumer under a label the consumer reads from a sandlock.inputs dict. This is the structural primitive behind the XOA pattern: producers and consumer are independent sandboxes, and the consumer never executes producer code inside its own LLM call.

from sandlock import Sandbox

planner  = Sandbox(...)   # writes code
searcher = Sandbox(...)   # produces data
executor = Sandbox(...)   # consumes both

result = (
    searcher.cmd(["python3", "-c", "..."]).as_("data")
    + planner.cmd(["python3", "-c", "..."]).as_("code")
    | executor.cmd(["python3", "consume.py"])
).run()

Inside consume.py:

from sandlock import inputs

code = inputs["code"]
data = inputs["data"]
exec(compile(code, "<planner>", "exec"), {"data": data})

stage.as_(name) -> NamedStage

Label a Stage's stdout so the consumer can address it by name.

named_stage + named_stage_or_gather -> Gather

Combine two or more NamedStage values into a Gather. Repeated + extends the gather:

g = a.as_("x") + b.as_("y") + c.as_("z")

gather | consumer_stage -> GatherPipeline

Compose a Gather with a consumer Stage to form the runnable pipeline.

gather_pipeline.run(timeout=None) -> Result

Run all producers in parallel; each producer's stdout is wired to a pipe the consumer reads via inputs[name]. Returns the consumer's Result.

sandlock.inputs

Lazy dict-like accessor available inside the consumer process. Reads each producer's pipe on first access and caches the value.

from sandlock import inputs

inputs["code"]        # str: the producer's full stdout, decoded as utf-8
"data" in inputs      # bool
list(inputs.keys())   # ["data", "code"]

The pipe fds are passed via the _SANDLOCK_GATHER env var (name:fd,name:fd,...); the inputs object parses it on first access. Users do not interact with the env var directly.

Dynamic policy

Use policy_fn to make per-syscall decisions at runtime:

from sandlock import Sandbox, SyscallEvent, PolicyContext

def my_policy(event: SyscallEvent, ctx: PolicyContext):
    if event.category == "network" and event.host == "evil.com":
        return True   # deny
    if event.category == "file" and "/secrets" in (event.path or ""):
        ctx.deny_path("/secrets")
        return True   # deny
    return False      # allow

sb = Sandbox(..., policy_fn=my_policy)

SyscallEvent

Attribute Type Description
syscall str Syscall name (e.g. "openat", "connect")
category str "file", "network", "process", or "memory"
pid int Process ID
parent_pid int Parent process ID
path str | None File path (for file events)
host str | None Hostname (for network events)
port int Port number (for network events)
argv tuple[str, ...] | None Command arguments (for execve)
denied bool Whether this event was already denied by static policy

Helper methods:

  • event.path_contains(s) -- True if path contains substring s
  • event.argv_contains(s) -- True if any argv element contains s

PolicyContext

Methods available inside policy_fn:

Method Description
ctx.restrict_network(ips) Restrict to given IP addresses
ctx.grant_network(ips) Allow additional IP addresses
ctx.restrict_max_memory(bytes) Lower memory limit
ctx.restrict_max_processes(n) Lower process limit
ctx.restrict_pid_network(pid, ips) Per-PID network restriction
ctx.deny_path(path) Deny access to a path
ctx.allow_path(path) Remove a previously denied path

Callback return values:

Return Meaning
None, False, 0 Allow
True, -1 Deny (EPERM)
positive int Deny with that errno
"audit", -2 Allow but flag for audit

Fork

COW fork for parallel execution with shared initialization:

sb = Sandbox(
    fs_readable=[...],
    init_fn=lambda: load_model(),
    work_fn=lambda clone_id: process(clone_id),
)
clones = sb.fork(4)  # returns ForkResult with .pids

sandbox.reduce(cmd, fork_result) -> Result

Pipe combined clone output into a reducer command:

result = sandbox.reduce(["python3", "sum.py"], clones)

Checkpoint

Save and restore sandbox state:

sb = Sandbox(...)
# ... start a long-running process ...
cp = sb.checkpoint(save_fn=lambda: my_state_bytes())
cp.save("my-snapshot")

# Later:
cp2 = Checkpoint.load("my-snapshot")
Checkpoint.restore("my-snapshot", restore_fn=lambda data: rebuild(data))
Method Description
cp.save(name, store=None) Persist checkpoint to disk
Checkpoint.load(name, store=None) Load from disk
Checkpoint.restore(name, restore_fn, store=None) Load and call restore_fn with app_state
Checkpoint.list(store=None) List saved checkpoint names
Checkpoint.delete(name, store=None) Delete a saved checkpoint

Properties: cp.name (str), cp.app_state (bytes or None).

Default store: ~/.sandlock/checkpoints/.

Profiles

Load sandbox configuration from TOML files: Profiles contain sandbox config only; pass the sandbox name at construction: Sandbox(..., name=...).

from sandlock import load_profile, list_profiles

sandbox = load_profile("web-scraper")
names = list_profiles()

Exceptions

SandlockError (base)
  +-- SandboxError         invalid sandbox configuration
  +-- SandboxRuntimeError  sandbox lifecycle errors
        +-- ForkError          fork failed
        +-- ChildError         child exited abnormally
        +-- BranchError        BranchFS operation failed
        |     +-- BranchConflictError   sibling branch committed (ESTALE)
        +-- ConfinementError   Landlock/seccomp setup failed
              +-- LandlockUnavailableError   no Landlock support
              +-- SeccompError               seccomp filter failed
                    +-- NotifError           notif supervisor error
  +-- MemoryProtectError   mprotect failed

All exceptions are importable from sandlock.exceptions or directly from sandlock:

from sandlock import SandlockError, SandboxError, SandboxRuntimeError

Enums

FsIsolation

  • FsIsolation.NONE -- direct host writes (default)
  • FsIsolation.BRANCHFS -- BranchFS COW isolation
  • FsIsolation.OVERLAYFS -- OverlayFS COW

BranchAction

  • BranchAction.COMMIT -- merge writes on exit
  • BranchAction.ABORT -- discard writes
  • BranchAction.KEEP -- leave branch as-is

MCP integration

Sandboxed tool execution for AI agents. Each tool runs in a per-call sandbox with deny-by-default permissions.

pip install 'sandlock[mcp]'

McpSandbox

from sandlock.mcp import McpSandbox

mcp = McpSandbox(workspace="/tmp/agent", timeout=30.0)
  • workspace -- directory the sandbox can read (default: "/tmp/sandlock").
  • timeout -- default timeout in seconds per tool call (default: 30.0).

mcp.add_tool(name, func, *, description="", capabilities=None, input_schema=None)

Register a local tool. func must be a top-level function in an import-safe module: the worker imports that module by name and calls the function in a fresh per-call sandbox. Module-level imports, helpers, constants, and state are all fine; lambdas, methods, and nested functions are rejected. Guard any module startup logic under if __name__ == "__main__":.

A tool that declares a parameter named workspace receives the sandbox's workspace path automatically (injected at call time, hidden from the LLM schema, and not overridable by the model). No env wiring needed.

# tools.py  (an importable module)
import os

def read_file(path: str, *, workspace: str) -> str:
    with open(os.path.join(workspace, path)) as f:
        return f.read()
import tools

mcp.add_tool("read_file", tools.read_file,
    description="Read a file from the workspace",
)

No capabilities = read-only, clean environment, no network. Grant permissions explicitly:

Capability Example Description
fs_writable ["/tmp/agent"] Paths the tool can write to
net_allow ["api.example.com:443", "udp://1.1.1.1:53"] Outbound endpoints. Bare host:port is TCP; udp://... / icmp://... schemes opt UDP / ICMP echo in.
env {"KEY": "val"} Environment variables to pass
max_memory "256M" Memory limit

Any Sandbox field name is accepted as a capability key.

await mcp.add_mcp_session(session)

Discover tools from a remote MCP server. Capabilities are read from sandlock:* keys in the tool's annotations or meta dict.

await mcp.call_tool(name, arguments=None, *, timeout=None) -> str

Call a tool by name. Local tools run in a per-call sandbox. MCP tools are forwarded to their server session.

result = await mcp.call_tool("read_file", {"path": "data.txt"})

mcp.get_policy(tool_name) -> Sandbox

Return the computed Sandbox for a registered tool.

mcp.tool_definitions_openai() -> list[dict]

Tool definitions in OpenAI function-calling format, for use with chat completion APIs.

mcp.tools -> dict[str, Any]

All registered tools (local and MCP).

MCP server

A standalone MCP server with built-in sandboxed tools (shell, python, read_file, write_file, list_files):

# stdio (for Claude Desktop / Cursor)
sandlock-mcp --workspace /tmp/sandbox

# SSE (remote)
pip install 'sandlock[mcp-remote]'
sandlock-mcp --transport sse --host 0.0.0.0 --port 8080 --workspace /tmp/sandbox

Claude Desktop configuration:

{
  "mcpServers": {
    "sandlock": {
      "command": "sandlock-mcp",
      "args": ["--workspace", "/tmp/sandbox"]
    }
  }
}

policy_for_tool(*, workspace, capabilities=None) -> Sandbox

Build a deny-by-default Sandbox from explicit capabilities. Used internally by McpSandbox but available for direct use.

capabilities_from_mcp_tool(tool) -> dict

Extract sandlock:* capabilities from an MCP tool's annotations/meta.

License

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 Distribution

sandlock-0.8.0.tar.gz (97.7 kB view details)

Uploaded Source

Built Distributions

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

sandlock-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

sandlock-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

sandlock-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

sandlock-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

sandlock-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

sandlock-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

sandlock-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

sandlock-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64

File details

Details for the file sandlock-0.8.0.tar.gz.

File metadata

  • Download URL: sandlock-0.8.0.tar.gz
  • Upload date:
  • Size: 97.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for sandlock-0.8.0.tar.gz
Algorithm Hash digest
SHA256 6b782122f0069375950c4dfdb1711e5dd9c5f3241810a6bc4dc32f3f04d1e6bb
MD5 cf78646f5ec5078536c88905f077ba9d
BLAKE2b-256 591a6e2d42789d343dc92498beb285866078dc22528742dc2c08a783d08e781c

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c3a62dde9dcc93008a913ce94b36cf9c0fa46bd525cfa3b4ff22aaa1209d0119
MD5 216d74e26fd01ad0afda872d3cb96119
BLAKE2b-256 75059da7027e17dd0d2c3b73b1c3087df229fee3a161176c1a694b3708d9d13a

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2bacd7e4084ef4aee95a94aaa7b979ebe81e86010b320307dcfd333c97318b4e
MD5 ce3f85905600ca0830c58b583a229e08
BLAKE2b-256 0d6caa0bb59a21b6b5c5e934e43e5bbb5dc71bd40a1b58f17bc87e3d3bfa474c

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 bcc18b817a14fa7d00a41c66510bdc7d9baa7990fa4272e69a0136402e92db36
MD5 d96d0a3987fb0d751390a6b880743b21
BLAKE2b-256 714075e70eebd4ac1530a4a3246c4e0144cb8dc1366a99f05d0955d316741f07

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 9e86ed4806d37796e5cc26a2e3f109042f5410c6e41d4fb24f494e3a219f87d9
MD5 398a79f79ed96e2a8786ee8a3188ef14
BLAKE2b-256 a4b2afb6c2a7ce95375e9f37c77de17f86346742784b00b93cc1f5f0c5ba10d0

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7a0905529a7b8b0a331da61e627005fdef48ac45783292e85df0dc140972db5f
MD5 29955c2083c75dcc32f8da05c98fede2
BLAKE2b-256 896883a4452056f29588c468faa228a1dc34dac85f12a6b9a82a8677bb8c9ebe

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 43eeb3ffede9a924672f4ce10b34ee5af9d56f7d18c38bb666ef5cd6cebba123
MD5 b28660095aafaae459a9d2774c5d9b7b
BLAKE2b-256 96dd5bb7d73f691b1953aaa8789b4884b7fdfaef56004c20cb9d338f98e6fd60

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9f94118256a4e06fc92066ee369dc25283ec44fe3060ead20eeb6b442c65f7d3
MD5 f66ece1151006a49b1f6f866ef1c9a8a
BLAKE2b-256 efe593bdbd57f86d23b2d52c034f5d75912cb2037455dadc692e63262c1aa56f

See more details on using hashes here.

File details

Details for the file sandlock-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for sandlock-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e375f0b4bcf62162c1a27711a343c7dc1d3a9c0aa9b42ce15eb04aacd4cf8dc0
MD5 db2ba09c4bd849c0c235e6e762116b68
BLAKE2b-256 0fdb2f68667d967e4a5d3eeb78418581ee96953fd47a4956f9548a158f5f447c

See more details on using hashes here.

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