Skip to main content

Minisandbox for Python interpreter.

Project description

DCNR Minisandbox

A secure, lightweight Python sandbox interpreter that allows safe execution of untrusted Python code with strict limitations, plus a global object registry for application data management.

Features

  • Secure AST-based execution - Uses Python's AST parser to validate and execute code without using eval() or exec()
  • Restricted syntax - Only allows a safe subset of Python constructs
  • Built-in safety limits - Prevents infinite loops with iteration limits
  • Customizable environment - Pre-populate variables and control available functions
  • Comprehensive error handling - Clear error messages for syntax and runtime violations
  • Global object registry - Hierarchical storage and access system for application objects and data

Installation

pip install dcnr-minisandbox

Components

This package provides two main components:

  1. Sandbox Interpreter (sandbox_exec) - Secure execution of Python code with AST validation
  2. Object Registry (get_registry, register_object) - Global hierarchical storage for application objects

Quick Start

Sandbox Execution

from dcnr.minisandbox import sandbox_exec

# Simple calculation
code = """
x = 10
y = 20
result = x + y * 2
"""

variables = {}
result = sandbox_exec(code, variables)
print(result)  # {'x': 10, 'y': 20, 'result': 50}

# Pre-populate with variables
initial_vars = {'data': [1, 2, 3, 4, 5]}
code = """
total = sum(data)
average = total / len(data)
"""

result = sandbox_exec(code, initial_vars)
print(result)  # {'data': [1, 2, 3, 4, 5], 'total': 15, 'average': 3.0}

# Using attribute access and method calls
code = """
text = "hello world"
upper_text = text.upper()
words = text.split()
data = [1, 2, 3]
data.append(4)
"""

result = sandbox_exec(code, {})
print(result)  # {'text': 'hello world', 'upper_text': 'HELLO WORLD', 'words': ['hello', 'world'], 'data': [1, 2, 3, 4]}

Global Object Registry

from dcnr.minisandbox import register_object, get_registry

# Register functions and data
def fetchone():
    return {"id": 1, "name": "Alice"}

register_object("database.prod.fetchone", fetchone)
register_object("database.prod.version", "1.0")
register_object("config.debug", True)

# Access through registry
registry = get_registry()
print(registry.database.prod.fetchone())  # {'id': 1, 'name': 'Alice'}
print(registry.database.prod.version)     # '1.0'
print(registry.config.debug)              # True

Allowed Features

Data Types

  • Numbers: int, float
  • Strings: str
  • Collections: list, tuple, dict, set
  • Booleans: bool

Operators

  • Arithmetic: +, -, *, /, //, %, **
  • Comparison: ==, !=, <, <=, >, >=, in, not in, is, is not
  • Logical: and, or, not

Control Flow

  • Conditional statements: if, elif, else
  • Loops: for, while (with iteration limits)
  • Loop control: break, continue

Built-in Functions

  • Math: abs(), min(), max(), sum()
  • Type conversion: int(), float(), str(), bool()
  • Collections: len(), range(), list(), tuple(), dict(), set(), sorted()

Variable Operations

  • Assignment: x = value
  • Augmented assignment: x += 1, x -= 1, etc.
  • Tuple/list unpacking: a, b = (1, 2)
  • Subscript access: data[0], data[1:3]
  • Attribute access: obj.attr, obj.method()

Prohibited Features

For security reasons, the following are not allowed:

  • Imports: No import or from ... import statements
  • Function definitions: No def, lambda, or class definitions
  • Dangerous attribute access: No access to __class__, __dict__, __module__, etc.
  • Exception handling: No try, except, finally, raise
  • File I/O: No file operations or system calls
  • Advanced features: No comprehensions, generators, decorators, or async code

Global Object Registry

The registry provides a hierarchical namespace for storing and accessing application objects, functions, and configuration data.

Registry Features

  • Dot-notation access - Navigate the registry like registry.database.prod.version
  • Safe path validation - Prevents conflicts with Python keywords and reserved names
  • Singleton pattern - Single global registry instance across your application
  • Type safety - Automatic wrapping of nested dictionaries for consistent access

Registry API

from dcnr.minisandbox import get_registry, register_object

# Get the global registry instance
registry = get_registry()

# Register objects at various paths
register_object("app.config.debug", True)
register_object("app.database.host", "localhost")
register_object("app.database.port", 5432)

# Alternative: use registry methods directly
registry.register_object("services.auth.enabled", True)

# Access registered objects
print(registry.app.config.debug)      # True
print(registry.app.database.host)     # 'localhost'
print(registry.services.auth.enabled) # True

# Check if path exists
if registry.has_path("app.config.debug"):
    print("Debug mode is configured")

# Get object programmatically
db_host = registry.get_object("app.database.host")

# Remove objects
registry.unregister_object("app.config.debug")

# Clear entire registry
registry.clear()

Path Restrictions

For safety and consistency, certain path components are not allowed:

# ❌ These will raise ValueError:
register_object("app.items.test", 1)      # 'items' is reserved (dict method)
register_object("app.__class__.x", 1)     # Names starting with '_' not allowed
register_object("app.for.x", 1)          # 'for' is a Python keyword
register_object("app..x", 1)             # Empty components not allowed

Error Handling

Sandbox Errors

The sandbox raises specific exceptions for different types of violations:

from dcnr.minisandbox import sandbox_exec, SandboxSyntaxError, SandboxRuntimeError

try:
    # This will raise SandboxSyntaxError
    sandbox_exec("import os", {})
except SandboxSyntaxError as e:
    print(f"Syntax violation: {e}")

try:
    # This will raise SandboxRuntimeError  
    sandbox_exec("unknown_variable", {})
except SandboxRuntimeError as e:
    print(f"Runtime error: {e}")

Registry Errors

The registry raises standard Python exceptions for invalid operations:

from dcnr.minisandbox import register_object, get_registry

try:
    # Invalid path component
    register_object("app.for.test", 1)  # 'for' is a Python keyword
except ValueError as e:
    print(f"Invalid path: {e}")

try:
    # Path not found
    registry = get_registry()
    value = registry.get_object("nonexistent.path")
except KeyError as e:
    print(f"Path not found: {e}")

Safety Features

Iteration Limits

Loops are automatically limited to 100,000 iterations to prevent infinite loops:

# This will raise SandboxRuntimeError after 100,000 iterations
code = """
i = 0
while True:
    i += 1
"""

Memory Safety

Only safe data types and operations are allowed. No access to system resources or dangerous built-ins.

Use Cases

Sandbox Execution

  • Educational platforms - Safe execution of student code
  • Code challenges - Running untrusted submissions
  • Configuration scripts - Controlled execution of user-defined logic
  • Expression evaluation - Safe calculation of mathematical expressions
  • Templating - Dynamic value computation in templates

Object Registry

  • Application configuration - Centralized storage of settings and parameters
  • Service registration - Registry for application services and dependencies
  • Plugin systems - Dynamic registration and discovery of plugins
  • Feature flags - Hierarchical feature toggle management
  • Resource management - Centralized access to database connections, APIs, etc.

Limitations

  • No custom function definitions
  • No module imports or external libraries
  • Limited to basic Python constructs
  • No file system or network access
  • Fixed iteration limits for loops

Development

To contribute to dcnr-minisandbox:

  1. Clone the repository
  2. Install development dependencies
  3. Run tests with your changes
  4. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Peter Kollath (peter.kollath@gopal.home.sk)

Links

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

dcnr_minisandbox-1.0.2.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

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

dcnr_minisandbox-1.0.2-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file dcnr_minisandbox-1.0.2.tar.gz.

File metadata

  • Download URL: dcnr_minisandbox-1.0.2.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.4

File hashes

Hashes for dcnr_minisandbox-1.0.2.tar.gz
Algorithm Hash digest
SHA256 25596205c31759112669e00aeffd939410e6616121373b67d55c91e9161be3df
MD5 6ea445462e3fbf022d790a1e958ce4e4
BLAKE2b-256 e08cc90562e76bc6e4d8d23f370296b5307da7620da732ffd4a882f584ee6060

See more details on using hashes here.

File details

Details for the file dcnr_minisandbox-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dcnr_minisandbox-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 efa351d050593e2e54c57b98ec550c00cda3ea40058850c0a635d9e5bd8842e0
MD5 5dc23a1ae34adeec94167653df36890e
BLAKE2b-256 c4aaa3d390a40643ae6d2a81330bf00863498ff5a591210397c124e5ccc3431f

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