Changeset 0.38.0 (#233)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-25 09:20:06 +00:00
committed by xcaliber
parent be67feaa8e
commit 10acadc9d0
13 changed files with 556 additions and 49 deletions

View File

@@ -79,18 +79,28 @@ func New(cfg Config) *Sandbox {
return &Sandbox{config: cfg}
}
// LoadFunc resolves load("path") calls to Starlark source.
// Returns the module's globals. The sandbox caches results per
// thread (Starlark handles this via thread.Load dedup).
type LoadFunc func(thread *starlark.Thread, module string) (starlark.StringDict, error)
// Exec executes a Starlark script within the sandbox.
// load() is disabled — all dependencies must be provided via modules.
// For load() support, use ExecWithLoader.
func (s *Sandbox) Exec(ctx context.Context, filename, source string, modules map[string]starlark.Value) (*Result, error) {
return s.ExecWithLoader(ctx, filename, source, modules, nil)
}
// ExecWithLoader executes a Starlark script within the sandbox with
// an optional load callback. If loader is nil, load() returns an error.
//
// Parameters:
// - ctx: context for timeout/cancellation
// - filename: used in error messages and stack traces
// - source: Starlark source code
// - modules: predeclared modules injected into the script's namespace
// (e.g., {"secrets": secretsModule, "notifications": notifModule})
//
// The script cannot use load() — all dependencies must be provided
// via the modules parameter.
func (s *Sandbox) Exec(ctx context.Context, filename, source string, modules map[string]starlark.Value) (*Result, error) {
// - loader: resolves load() calls; nil = load() disabled
func (s *Sandbox) ExecWithLoader(ctx context.Context, filename, source string, modules map[string]starlark.Value, loader LoadFunc) (*Result, error) {
var output strings.Builder
var outputMu sync.Mutex
@@ -101,6 +111,14 @@ func (s *Sandbox) Exec(ctx context.Context, filename, source string, modules map
// json.encode / json.decode — universal, no permissions required (pure computation)
predeclared["json"] = starlarkjson.Module
// Default: load() disabled. If loader provided, delegate to it.
loadFn := func(_ *starlark.Thread, module string) (starlark.StringDict, error) {
return nil, fmt.Errorf("load() is disabled in sandbox (requested %q)", module)
}
if loader != nil {
loadFn = loader
}
thread := &starlark.Thread{
Name: s.config.Name,
Print: func(_ *starlark.Thread, msg string) {
@@ -109,9 +127,7 @@ func (s *Sandbox) Exec(ctx context.Context, filename, source string, modules map
output.WriteString(msg)
output.WriteByte('\n')
},
Load: func(_ *starlark.Thread, module string) (starlark.StringDict, error) {
return nil, fmt.Errorf("load() is disabled in sandbox (requested %q)", module)
},
Load: loadFn,
}
if s.config.MaxSteps > 0 {