Help us shape the future of Go! Take the 2026 Go Developer Survey

script

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package script is Atlas's in-process worker for polyglot script tasks (PowerShell, Python, JavaScript — ADR-0047). A script task compiles to a job carrying the language's reserved job type (compiler.PwshJobType / PythonJobType / JsJobType); this worker subscribes to a type via a job.Runner and for each job runs the script off the processor goroutine — after fsync — through an Exec, then writes the script's result back into the instance as the task's result variable.

Keeping the interpreter here, not in an engine behavior, is what lets a general -purpose language run without breaking the engine's invariants: the processor stays allocation-free (I1) and side-effect-free on the recovery path (I4), and the result is frozen into the job completion so replay re-applies it verbatim (I6). It mirrors the DMN worker (ADR-0014): one handler per language serves every deployed process, resolving each job's script from the compiled process. The handler itself is language-agnostic; only the Exec differs per language.

Index

Constants

View Source
const (

	// LanguagesEnv limits the language handlers registered by an out-of-process
	// script worker. Empty keeps the standalone worker's backwards-compatible
	// default of serving every language.
	LanguagesEnv = "ATLAS_SCRIPT_LANGUAGES"
)

Environment variables the bootstrap programs read. Passing both the variables and the user source out-of-band (env, not interpolated into the command line) keeps values and script text from being spliced together — no escaping, no injection of one into the other.

Variables

View Source
var (
	PowerShell = Lang{
		Name: "powershell", JobTypeName: compiler.PwshJobType, JobType: compiler.PwshJobTypeIndex, Bin: "pwsh",
		Args: func(b string) []string { return []string{"-NoProfile", "-NonInteractive", "-Command", b} },
		Wrap: powershellBootstrap,
	}
	Python = Lang{
		Name: "python", JobTypeName: compiler.PythonJobType, JobType: compiler.PythonJobTypeIndex, Bin: "python3",
		Args: func(b string) []string { return []string{"-c", b} },
		Wrap: pythonBootstrap,
	}
	JavaScript = Lang{
		Name: "javascript", JobTypeName: compiler.JsJobType, JobType: compiler.JsJobTypeIndex, Bin: "node",
		Args: func(b string) []string { return []string{"-e", b} },
		Wrap: javascriptBootstrap,
	}
)

The three supported languages. Adding one is a new Lang here plus its reserved job type in the compiler — the worker, engine behavior, and recovery are shared.

View Source
var ErrSandboxInterpreter = errors.New("script sandbox: interpreter cannot start inside the sandbox")

ErrSandboxInterpreter marks an installed interpreter that cannot start inside the selected profile. It is deliberately distinct from a missing interpreter: that one parks a language's jobs and is worth a warning, while this one is the operator's explicit security choice failing to work at all, and ADR-0303's contract is that strict fails closed rather than degrading quietly.

Langs is every supported language, in a stable order.

Functions

func CheckSandbox added in v0.7.0

func CheckSandbox(mode SandboxMode) error

CheckSandbox reports whether the current operating system can enforce mode. Strict callers use it at startup so selecting a boundary can never degrade to the historical unsandboxed path without being noticed.

func CheckSandboxDataPath added in v0.7.0

func CheckSandboxDataPath(mode SandboxMode, path string) error

CheckSandboxDataPath prevents a strict filesystem allowlist from accidentally containing Atlas state. The normal locations (/data, /var/lib/atlas and a working-directory-relative atlas-data) are outside the runtime roots.

func CheckSandboxLanguages added in v0.7.0

func CheckSandboxLanguages(mode SandboxMode, names []string) error

CheckSandboxLanguages proves at startup that each language this process will serve can start under mode, by starting it. It is called once by the command layer, where this process's own executable is the Atlas binary that implements the launcher.

A language whose interpreter is simply not installed is skipped rather than refused: that host parks those jobs, as it always has, and is not a sandbox that does not work.

func Handler

func Handler(store state.Reader, lookup ProcessLookup, exec Exec) job.OutputHandler

Handler builds a job handler that runs a script task in one language. Register it with a job.Runner via HandleWithOutput for that language's reserved job type (e.g. compiler.PwshJobTypeIndex); the runner then pulls activatable script jobs, and for each the handler:

  • resolves the script source and result variable from the compiled process,
  • reads the instance's variables as the script's inputs,
  • runs the script through exec (off the processor goroutine, after fsync), and
  • returns the result as the process variable named by the result variable, which the job completion writes back into the instance so a downstream gateway can route on it.

Returning an error leaves the job pending, exactly as for any worker; the runner completes it only on success.

func RunSandbox added in v0.7.0

func RunSandbox(args []string) error

RunSandbox is the internal launcher entered by the Atlas executable. It is exported only because cmd/atlas owns subcommand dispatch; operators should use --script-sandbox on serve or worker instead of invoking this directly.

Types

type CmdExec

type CmdExec struct {
	Lang    Lang          // language spec
	Bin     string        // interpreter override; empty means Lang.Bin
	Timeout time.Duration // per-script wall-clock limit; <= 0 means defaultTimeout
	// Sandbox is the operating-system isolation profile. Empty/off preserves the
	// historical path; strict is the fail-closed Linux profile from
	// ADR-0303.
	Sandbox SandboxMode
	// MaxOutput bounds what one script may write to stdout, in bytes; <= 0 means
	// defaultMaxOutput. The server sets it from the installation's budgets.
	MaxOutput int64
	// contains filtered or unexported fields
}

CmdExec runs script tasks by shelling out to a real interpreter for its Lang. It is the production Exec; tests use a fake instead so they need no interpreter.

Security posture (ADR-0047): the interpreter runs with -NoProfile / -NonInteractive (or the language equivalent), the instance's variables and the source arrive as environment values (not interpolated), each run is bounded by Timeout (the process is killed at the deadline), and it runs in the worker's trust domain. Run gives the interpreter an allowlisted runtime environment, never the worker's Atlas token or deployment secrets. The eventual isolation boundary is an external worker in the customer's environment.

func New

func New(l Lang) *CmdExec

New returns a CmdExec for the given language.

func (*CmdExec) Check

func (e *CmdExec) Check() error

Check reports whether the interpreter is resolvable on PATH and whether the host can enforce the selected profile at all. The server calls it once at startup so an operator whose host lacks the interpreter sees a clear warning, rather than watching script tasks park silently.

It deliberately stays a cheap predicate and launches nothing. Whether the interpreter can actually start *inside* the profile is a separate question, asked once per process by CheckSandboxLanguages, because answering it means spawning the sandbox launcher — which only the Atlas executable is.

func (*CmdExec) Run

func (e *CmdExec) Run(ctx context.Context, source string, input map[string]any) (any, error)

Run passes the source and the variables to the interpreter's bootstrap via the environment, runs it under a deadline, and decodes its stdout as the result. A non-zero exit or a runner error leaves the job pending; an empty stdout decodes to a null result; overrunning the timeout kills the process and errors.

type CodedError added in v0.15.0

type CodedError struct {
	Code    string // the code, trimmed; never empty
	Message string // the error's own message, without the interpreter's framing
	Err     error  // the failure as the interpreter reported it
}

CodedError is a script failure that carries the code the script gave its error: the ErrorId of a PowerShell error, the code attribute of a Python exception, the code property of a JavaScript error. It reads as the interpreter's own failure, so an incident shows what it showed before. Whether the code makes the failure a BPMN error is Run's decision, because only the codes the task's process catches do (ADR-0461).

func (*CodedError) Error added in v0.15.0

func (e *CodedError) Error() string

func (*CodedError) Unwrap added in v0.15.0

func (e *CodedError) Unwrap() error

type Exec

type Exec interface {
	Run(ctx context.Context, source string, input map[string]any) (any, error)
}

Exec runs a script off the hot path and returns its result. It is the seam between the worker and the real interpreter: CmdExec shells out to the language's interpreter, but tests inject a deterministic fake so they need no interpreter installed. input is the instance's variables keyed by name; the returned value is the script's result, a JSON-shaped Go value (nil, bool, json.Number, string, []any, or map[string]any) that becomes the result variable.

type Job added in v0.3.0

type Job struct {
	Source string `json:"source"`
	// Input is the scope chain flattened for the script, nearest scope winning
	// (ADR-0068) — resolved by the engine, which is the only one that can walk it.
	Input map[string]any `json:"input,omitempty"`
	// Result names the process variable the script's output is written to; empty
	// means the task writes nothing back.
	Result string `json:"resultVariable,omitempty"`
	// ErrorCodes are the codes an error boundary or error event subprocess of the
	// task's process catches. A script that fails with one of them threw a BPMN error;
	// any other failure is a failure (ADR-0461). They travel with
	// the job because a worker has no compiled process to ask.
	ErrorCodes []string `json:"errorCodes,omitempty"`
}

Job is a script task with everything already looked up: the source to run and the variables it sees. It is what travels with a leased job.

func Resolve added in v0.3.0

func Resolve(store state.Reader, cp *compiler.CompiledProcess, detail *compiler.ScriptJobTaskDetail, elementInstanceKey uint64) (Job, error)

Resolve turns a compiled script task into a Job. Engine work by necessity: the source lives in the compiled process and the variables are reached by walking the element instance's scope chain in the store.

type Lang

type Lang struct {
	Name        string // model/UI name, e.g. "python"
	JobTypeName string // reserved job-type name (compiler.*JobType)
	JobType     int32  // reserved job-type index (compiler.*JobTypeIndex)
	Bin         string // default interpreter binary
	Args        func(bootstrap string) []string
	Wrap        string // the bootstrap program
}

Lang describes how to run one scripting language: the reserved job type its worker subscribes to, the default interpreter binary, the interpreter arguments that run a bootstrap program, and that bootstrap. The bootstrap is a fixed program (never the author's source) that reads the source and variables from the environment, exposes the variables, runs the source, and prints the result as JSON on stdout (empty output = null). Each language keeps its own idiomatic result convention (see the bootstraps).

func LangByName

func LangByName(name string) (Lang, bool)

LangByName returns the language spec for a (lower-cased) language name, and whether it is one of the supported languages.

type ProcessLookup

type ProcessLookup func(defKey uint64) *compiler.CompiledProcess

ProcessLookup resolves a process-definition key to its compiled process. The worker uses it to find the script source and result variable a job belongs to, so one handler serves every deployed process.

type Result added in v0.3.0

type Result struct {
	ResultVariable string
	Output         any
}

Result is what running a Job produces.

func Run added in v0.3.0

func Run(ctx context.Context, j Job, exec Exec) (Result, error)

Run executes a resolved job through the caller's own interpreter. The in-process path calls it too, so there is one definition of what running a script task means rather than two that drift — only the machine the interpreter sits on differs.

type SandboxMode added in v0.7.0

type SandboxMode string

SandboxMode selects the operating-system boundary around an interpreter.

const (
	// SandboxOff preserves the historical execution contract. It is the initial
	// default because existing models may deliberately use files or the network.
	SandboxOff SandboxMode = "off"
	// SandboxStrict permits only the installed runtime and a private per-run
	// scratch directory, and denies creation of every network socket.
	SandboxStrict SandboxMode = "strict"

	// SandboxEnv configures the built-in script Worker Instance. A supervised
	// worker receives the equivalent typed command-line flag from its parent.
	SandboxEnv = "ATLAS_SCRIPT_SANDBOX"
)

func ParseSandboxMode added in v0.7.0

func ParseSandboxMode(raw string) (SandboxMode, error)

ParseSandboxMode parses the operator-facing script sandbox setting. Empty is off for compatibility; there is deliberately no best-effort security mode.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL