sandbox¶
The security layer: AST validation of formulas and code blocks, module classification, and inspection of a workbook file without executing anything in it. The threat model is in Security plan.
sandbox
¶
Security sandbox for formula evaluation and module loading.
FileInfo
dataclass
¶
FileInfo(
has_code: bool = False,
code_preview: str = "",
code_lines: int = 0,
requires: list[str] = list(),
formula_count: int = 0,
cell_count: int = 0,
blocked_modules: list[str] = list(),
side_effect_modules: list[str] = list(),
unknown_modules: list[str] = list(),
)
Metadata extracted from a spreadsheet file without executing it.
LoadPolicy
dataclass
¶
LoadPolicy(
load_code: bool = False,
approved_modules: list[str] = list(),
allow_unknown: bool = False,
)
Controls what gets loaded from a spreadsheet file.
trust_all
staticmethod
¶
trust_all(requires: list[str] | None = None) -> LoadPolicy
Approve everything -- code block and all requested modules.
formulas_only
staticmethod
¶
formulas_only() -> LoadPolicy
configure_sandbox
¶
Set sandbox state from config. Env var GRIDCALC_SANDBOX takes precedence.
validate_formula
¶
Validate a formula expression against security rules.
Returns (is_valid, error_message). Blocks dunder attribute access, dangerous names, and known internal attributes used in sandbox escapes.
Source code in src/gridcalc/sandbox.py
validate_code
¶
Validate a code block (statements) against security rules.
Applies the same AST checks as validate_formula (dunder access, dangerous names/attrs) plus blocks import of blocked modules and dangerous builtins used as statements (eval/exec/open calls).
Source code in src/gridcalc/sandbox.py
classify_module
¶
Classify a module as 'safe', 'side_effect', 'blocked', or 'unknown'.
Source code in src/gridcalc/sandbox.py
load_modules
¶
load_modules(
specs: list[str], allow_unknown: bool = False
) -> tuple[dict[str, object], list[str]]
Import modules by spec. Returns (alias_to_module, error_messages).
Each spec is either a bare module name (numpy) or a name with a
version specifier (numpy>=1.24, pandas==2.0.3). Supported
operators: ==, >=, <=, >, <, ~=.
A module that no list classifies is refused unless allow_unknown.
The blocklist cannot be the only gate: it names the dangerous modules
known when it was written, so anything omitted -- runpy, which runs
a Python file, or sqlite3, which writes one -- was loaded on a
workbook's say-so. Refusing happens before the import, so a module with
import-time side effects does not get to run either.
Source code in src/gridcalc/sandbox.py
inspect_file
¶
inspect_file(filename: str) -> FileInfo | None
Inspect a spreadsheet file without executing anything.
Returns a FileInfo with metadata about code blocks, required modules, and cell/formula counts, or None if the file cannot be parsed.