Skip to main content

safely execute python come. built in safety checker. use it as cli, library, server

Project description

Code Cantation

A safe, embeddable code executor for Python—usable both as a library and via a CLI.


Features

  • Script execution: Run arbitrary Python scripts with stdout capture.
  • Function execution: Define functions in code snippets and invoke them (with or without parameters).
  • Safety checks: Static AST-based analysis blocks imports of unsafe modules (e.g. os, subprocess) and calls to dangerous functions (eval, exec, etc.).
  • Error reporting: Any runtime errors are captured and returned in the output object.
  • Process isolation: Code runs in a separate process with configurable timeout and resource limits.
  • Dual usage: Importable as a Python package, or installed as a cantation CLI tool.

Installation

Install from PyPI:

pip install code-cantation

Or install from source in editable mode:

git clone https://github.com/your-repo/code-cantation.git
cd code-cantation
pip install -e .

Usage as a Library

Import and invoke the Executor directly in your code:

from code_cantation import Executor

exe = Executor()

# 1. Run a simple script:
script = """
a = 10
b = 20
print('sum =', a + b)
"""  # note: no `return` in script mode
result = exe.execute(code=script)
print("Console:", result.console_log)

# 2. Call a function without parameters:
func_no_args = """
def greet():
    print('hello')
    return 'hello'
"""
res2 = exe.execute(code=func_no_args, code_type="FUNCTION")
print("Return:", res2.captured_output)

# 3. Call a function with parameters:
func_with_args = """
def add(a, b):
    print('adding', a, b)
    return a + b
"""
res3 = exe.execute(
    code=func_with_args,
    code_type="FUNCTION",
    input_values=[5, 7]
)
print("Return:", res3.captured_output)

# 4. Restrict file access to a specific folder:
restricted = exe.execute(
    code="open('data.txt', 'w').write('ok')",
    allowed_root="/sandbox/work"  # work_dir defaults to allowed_root
)
print("Error:", restricted.exec_error)

# 5. Check safety violation:
unsafe = "import requests"
res4 = exe.execute(code=unsafe)
print("Safety error:", res4.safety_violation)

The execute(...) method returns a CodeExecutorOutput object with the following attributes:

  • console_log (str): Captured stdout from the snippet.
  • captured_output (any): Return value of a FUNCTION snippet (or None for scripts).
  • exec_error (str): Runtime error message if execution failed.
  • safety_violation (str): Description if safety checks failed.

By default, execution runs in a separate process with a 5s timeout, 5s CPU limit, and a 256MB memory limit. These can be overridden per call. If allowed_root is set, file access is restricted to that directory (read/write), which can also block imports from outside the allowed root.


Usage via CLI

Once installed, the cantation command is available on your PATH. All options mirror the library’s Executor.execute() parameters and always emit a JSON representation of the CodeExecutorOutput.

cantation [--code CODE  | --file FILE]
          [--no-safety]
          [--code-type {SCRIPT,FUNCTION}]
          [--input JSON_LIST]
          [--unsafe-modules MODULE [MODULE ...]]
          [--unsafe-functions FUNC [FUNC ...]]
          [--override-default-safety]
          [--timeout-sec SECONDS]
          [--cpu-time-limit-sec SECONDS]
          [--memory-limit-mb MB]
          [--allowed-root DIR]
          [--work-dir DIR]

Common Examples

  1. Run an inline script

    cantation \
      --code "print('Hello from CLI'); x = 1 + 2; print('x =', x)"
    

    Output

    {
      "console_log": "Hello from CLI x = 3",
      "captured_output": null,
      "exec_error": null,
      "safety_violation": null
    }
    
  2. Execute a Python file

    cantation --file path/to/script.py
    
  3. Invoke a no-arg function

    cantation \
      --code "def greet():
     print('Hi there'); return 'Hi'" \
      --code-type FUNCTION
    

    Output

    {
      "console_log": "Hi there",
      "captured_output": "Hi",
      "exec_error": null,
      "safety_violation": null
    }
    
  4. Invoke a function with parameters

    cantation \
      --code "def add(a, b):
     return a + b" \
      --code-type FUNCTION \
      --input '[5, 7]'
    

    Output

    {
      "console_log": "",
      "captured_output": 12,
      "exec_error": null,
      "safety_violation": null
    }
    
  5. Disable safety checks

    cantation --file my_script.py --no-safety
    
  6. Override unsafe modules/functions

    # Disallow use of 'os' and 'eval'
    cantation --file my_script.py \
      --unsafe-modules os \
      --unsafe-functions eval
    
  7. Install Libraries Required For Code Execution

    cantation \
     --install pyfiglet \
    --code "import pyfiglet; print(pyfiglet.figlet_format('Hello'))"
    
  8. Set resource limits

    cantation \
      --code "print('hello')" \
      --timeout-sec 3 \
      --cpu-time-limit-sec 2 \
      --memory-limit-mb 128
    

    Set any of these to 0 to disable that limit.

  9. Restrict file access

    cantation \
      --code "open('data.txt','w').write('ok')" \
      --allowed-root /sandbox/work
    

Usage As Server

Code Cantation can be run as a server/rest api. The server execute one code at time and therefore has an internal queue for requests.

Start server (basic)

cantation --server --install pyfiglet fastapi uvicorn \
          --host 127.0.0.1 --port 9000

Start server with allowed root (client-enforced)

The server reads allowed_root and work_dir from each request. Use these in your API payloads to restrict file access to a specific directory.

Start server securely (no Docker)

Run as a dedicated user with a restricted working directory:

sudo useradd -m cantation
sudo mkdir -p /srv/cantation/work
sudo chown -R cantation:cantation /srv/cantation
sudo -u cantation cantation --server --host 127.0.0.1 --port 9000

Optionally apply OS limits in the same shell:

ulimit -t 5 -v 1048576 -n 128 -u 64
sudo -u cantation cantation --server --host 127.0.0.1 --port 9000

Start server with Docker hardening (recommended)

docker run --rm -it \
  --read-only \
  --cap-drop=ALL \
  --security-opt no-new-privileges \
  --user 1000:1000 \
  --pids-limit 256 \
  --memory 1g \
  --cpus 2 \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  -p 9000:9000 \
  -v /host/allowed:/sandbox/work:rw \
  your-image \
  cantation --server --host 0.0.0.0 --port 9000

Call The API

curl -X POST http://127.0.0.1:9000/execute \
     -H "Content-Type: application/json" \
     -d '{
           "code": "import pyfiglet; print(pyfiglet.figlet_format(\"API\"))",
           "timeout_sec": 3,
           "cpu_time_limit_sec": 2,
           "memory_limit_mb": 128,
           "allowed_root": "/sandbox/work",
           "work_dir": "/sandbox/work"
         }'

Use 0 to disable a limit per request.

Recommended: always set allowed_root (and optionally work_dir) in requests to restrict file access to a specific directory. Combine this with container-level restrictions for stronger isolation.


Docker Run Recipes

These examples assume your app is installed inside the container and that you want to restrict file access to a single host directory mounted at /sandbox/work.

Library / CLI (interactive)

docker run --rm -it \
  --read-only \
  --cap-drop=ALL \
  --security-opt no-new-privileges \
  --user 1000:1000 \
  --pids-limit 128 \
  --memory 512m \
  --cpus 1 \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  -v /host/allowed:/sandbox/work:rw \
  your-image \
  cantation \
    --code "open('data.txt','w').write('ok')" \
    --allowed-root /sandbox/work

FastAPI Server

docker run --rm -it \
  --read-only \
  --cap-drop=ALL \
  --security-opt no-new-privileges \
  --user 1000:1000 \
  --pids-limit 256 \
  --memory 1g \
  --cpus 2 \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  -p 9000:9000 \
  -v /host/allowed:/sandbox/work:rw \
  your-image \
  cantation --server --host 0.0.0.0 --port 9000

Recommended: set allowed_root to /sandbox/work in your requests so file access is restricted to the mounted directory.

How It Works

If you don't provide the code type, the library will try to figure it out itself.

Executor Code Flow Logic

Internal Code Flow

Testing

A test script (test/test.py) is provided to exercise:

  1. Script execution
  2. Function execution (no args)
  3. Function execution (with args)
  4. Safety-check failures
  5. CLI behaviors

Run:

python test/test.py

Contributing

  1. Fork the repo and create your branch: git checkout -b feature/YourFeature
  2. Make your changes & add tests
  3. Run tests: python sample_test.py
  4. Submit a pull request

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

code_cantation-0.1.0.tar.gz (17.7 kB view details)

Uploaded Source

Built Distribution

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

code_cantation-0.1.0-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file code_cantation-0.1.0.tar.gz.

File metadata

  • Download URL: code_cantation-0.1.0.tar.gz
  • Upload date:
  • Size: 17.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.0

File hashes

Hashes for code_cantation-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8f02addc1c236a1250025f5eddfd7918ea09247c7882147d1043f2057f0d5208
MD5 502bacab276b11dcb75cb6e58745412f
BLAKE2b-256 477ba13ac6c8c23bd1db424a0bc521ca6ac12bc213645a3813507797b20e6140

See more details on using hashes here.

File details

Details for the file code_cantation-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: code_cantation-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.0

File hashes

Hashes for code_cantation-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f94009b6475df07af9a4ad2f4b51fd91cabc6f4e358a97b750093083a054a9eb
MD5 c05939d7e2a1646ce201704c535b66dc
BLAKE2b-256 d0a8d181b161475ac0c418dd6621a5541df4c26f2985b68d86fb6fd695dd575c

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