Skip to content

App Builder Sandbox SDK (Python)

PyPIDownloads/weekPython CILicenseCodecov Coverage

Python SDK for Adobe Runtime Sandboxes.

A sandbox is an ephemeral, isolated compute environment. You create one, run commands and read/write files inside it over a WebSocket session, then destroy it.

Pre-requisites

To use this library, you must have Sandboxes enabled for your Runtime namespace. Please contact Michael Goberling (mgoberling@adobe.com) or Cosmin Stanciu (stanciu@adobe.com) to request this.

Install

pip install aio-lib-sandbox

Quickstart

Inside a Runtime action, no configuration is needed to use the SDK as credentials are read automatically from the environment.

fromaio_lib_sandboximportSandboxasyncdefmain(params):
sandbox=awaitSandbox.create(name="my-sandbox")
result=awaitsandbox.exec("python --version", timeout=10_000)
awaitsandbox.destroy()
return {"stdout": result.stdout.strip()}

Configuration

When running inside a Runtime action, the SDK reads credentials from the environment automatically:

VariableDescription
__OW_API_HOSTRuntime API host
__OW_NAMESPACERuntime namespace
__OW_API_KEYRuntime API key (basic auth)

You can override any of these by passing them explicitly to Sandbox.create() or Sandbox.get():

sandbox=awaitSandbox.create(
api_host="https://adobeioruntime.net",
namespace="my-namespace",
auth="my-api-key",
name="my-sandbox",
)

Usage

Create Sandbox

fromaio_lib_sandboximportSandboxsandbox=awaitSandbox.create(
name="my-sandbox",
type="cpu:default",
idle_timeout=900,
max_lifetime=3600,
ports=[3000, 8080],
envs={"API_KEY": "your-api-key"},
)

Sandbox lifetime model

A sandbox is always deleted when max_lifetime has elapsed. It will also be deleted after the idle_timeout has elapsed, if there has been no activity.

To keep a sandbox alive, send at least one command or check the status every idle_timeout seconds.

Get Status

sandbox=awaitSandbox.get(sandbox.id)
print("status:", sandbox.status)

Exec

result=awaitsandbox.exec("ls -al", timeout=10_000)
print("stdout:", result.stdout.strip())
print("exit code:", result.exit_code)

Note: Commands run in the /workspace directory by default, this is not configurable

Detached Commands

Pass detached=True to run a long-lived background process.

# Start a background serverhandle=awaitsandbox.exec("python server.py", detached=True)
# Wait for it to exit (e.g. after you stop it)result=awaithandle.wait()
print("exit code:", result.exit_code)
# Send a signal to stop itawaithandle.kill()

If the process is still running and you need a handle to it from a different context, use get_command() to re-attach by exec_id:

handle=awaitsandbox.get_command(exec_id, on_output=lambdadata, stream: print(data, end=""))
awaithandle.wait()

Note: Only 5 background processes are allowed to run at once currently.

File Management

script="console.log('hello from sandbox script', process.version)\n"awaitsandbox.write_file("hello.js", script)
content=awaitsandbox.read_file("hello.js")
print("read_file content:", content.strip())
entries=awaitsandbox.list_files(".")
print("list_files entries:", entries)

Exec a File

result=awaitsandbox.exec("node hello.js", timeout=10_000)
print("stdout:", result.stdout.strip())
print("stderr:", result.stderr.strip())
print("exit code:", result.exit_code)

Write to Stdin

Command start

result=awaitsandbox.exec(
"python process_csv.py",
stdin="col1,col2\nval1,val2\n",
timeout=10_000,
)
print("stdout:", result.stdout.strip())

Running command

task=sandbox.exec("cat -n", timeout=10_000)
awaitsandbox.write_stdin(task.exec_id, "line 1\n")
awaitsandbox.write_stdin(task.exec_id, "line 2\n")
awaitsandbox.close_stdin(task.exec_id)
result=awaittaskprint("stdout:", result.stdout.strip())

Destroy

awaitsandbox.destroy()

Preview URLs

Ports that should be publicly accessible must be declared at creation time via the ports list.

sandbox=awaitSandbox.create(
name="web-sandbox",
ports=[3000, 8080],
)
# Start a server inside the sandbox on the declared portawaitsandbox.exec("python -m http.server 3000 &", timeout=5_000)
# Retrieve the pre-provisioned preview URL — synchronous, no network callurl=sandbox.get_url(3000)
print("preview:", url)
# https://sb-abc123-va6-0-xK3mPq2nAeB-3000.sandbox-adobeioruntime.net

Network Policies

Sandboxes are default-deny. All outbound traffic is blocked unless explicitly allowed.

Pass a policy.network.egress array at creation time to allowlist outbound endpoints, paths, or HTTP verbs.

sandbox=awaitSandbox.create(
name="policy-sandbox",
max_lifetime=300,
policy={
"network": {
"egress": [
{"host": "httpbin.org", "port": 443},
{
"host": "api.github.com",
"port": 443,
"rules": [
{"methods": ["GET"], "pathPattern": "/repos/**"},
],
},
]
}
},
)

Development

Install development dependencies:

pip install -e ".[dev]"

To run the same checks used by CI:

hatch run test

Linting is powered by Ruff:

hatch run lint
hatch run lint-fix

About

Python SDK for Adobe App Builder Sandboxes.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages