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()orexec() - 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:
- Sandbox Interpreter (
sandbox_exec) - Secure execution of Python code with AST validation - 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
importorfrom ... importstatements - Function definitions: No
def,lambda, orclassdefinitions - 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:
- Clone the repository
- Install development dependencies
- Run tests with your changes
- 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25596205c31759112669e00aeffd939410e6616121373b67d55c91e9161be3df
|
|
| MD5 |
6ea445462e3fbf022d790a1e958ce4e4
|
|
| BLAKE2b-256 |
e08cc90562e76bc6e4d8d23f370296b5307da7620da732ffd4a882f584ee6060
|
File details
Details for the file dcnr_minisandbox-1.0.2-py3-none-any.whl.
File metadata
- Download URL: dcnr_minisandbox-1.0.2-py3-none-any.whl
- Upload date:
- Size: 10.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efa351d050593e2e54c57b98ec550c00cda3ea40058850c0a635d9e5bd8842e0
|
|
| MD5 |
5dc23a1ae34adeec94167653df36890e
|
|
| BLAKE2b-256 |
c4aaa3d390a40643ae6d2a81330bf00863498ff5a591210397c124e5ccc3431f
|