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

execution

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package execution defines the versioned agent execution contract used by sshx run and shared by compatibility adapters for single-host paths.

Index

Constants

View Source
const (
	RequestSchemaVersion = "sshx.request.v1"
	ResultSchemaVersion  = "sshx.result.v1"
	EventSchemaVersion   = "sshx.event.v1"

	DefaultConcurrency = 4
	MaxConcurrency     = 32
	DefaultMaxOutput   = 10 << 20 // 10 MiB
	DefaultMaxPayload  = 10 << 20 // 10 MiB

	ActionCommand  = "command"
	ActionScript   = "script"
	ActionInspect  = "inspect"
	ActionSFTP     = "sftp"
	ActionTransfer = "transfer"
	ActionApply    = "apply"

	IntentRead    = "read"
	IntentChange  = "change"
	IntentUnknown = "unknown"

	FailureContinue = "continue"
	FailureFailFast = "fail_fast"

	StatusSucceeded = "succeeded"
	StatusFailed    = "failed"
	StatusSkipped   = "skipped"

	CompletionNotStarted           = "not_started"
	CompletionPartial              = "partial"
	CompletionCompleted            = "completed"
	CompletionCompletedUnconfirmed = "completed_unconfirmed"
	CompletionUnknown              = "unknown"

	PhaseResolve      = "resolve"
	PhaseAdmission    = "admission"
	PhaseConnect      = "connect"
	PhaseAuthenticate = "authenticate"
	PhaseExecute      = "execute"
	PhaseCollect      = "collect"
	PhasePersist      = "persist"
	PhaseComplete     = "complete"

	EventRunStarted     = "run_started"
	EventTargetStarted  = "target_started"
	EventTargetFinished = "target_finished"
	EventRunFinished    = "run_finished"

	RetrySafe        = "safe"
	RetryUnsafe      = "unsafe"
	RetryVerifyFirst = "verify_first"
	RetryUnknown     = "unknown"

	ErrorKindConnect      = "connect"
	ErrorKindAuth         = "auth"
	ErrorKindHostKey      = "host_key"
	ErrorKindBlocked      = "blocked"
	ErrorKindTimeout      = "timeout"
	ErrorKindRemoteExit   = "remote_exit"
	ErrorKindExitMissing  = "exit_missing"
	ErrorKindProtocol     = "protocol"
	ErrorKindConfig       = "config"
	ErrorKindLocalIO      = "local_io"
	ErrorKindRemoteIO     = "remote_io"
	ErrorKindPrecondition = "precondition"
	ErrorKindUnknown      = "unknown"

	ScriptRunnerSH = "sh"
)

Variables

View Source
var (
	// ErrConfig indicates a request/schema/selector configuration failure.
	ErrConfig = errors.New("execution config error")
	// ErrLocalIO indicates a local file/stdin failure before network access.
	ErrLocalIO = errors.New("local io error")
	// ErrRemoteIO indicates a remote filesystem/protocol I/O failure.
	ErrRemoteIO = errors.New("remote io error")
	// ErrBlocked indicates the safety policy refused the action.
	ErrBlocked = errors.New("action blocked by safety policy")
	// ErrNoTargets indicates selector resolution matched zero hosts.
	ErrNoTargets = fmt.Errorf("%w: no targets matched", ErrConfig)
)

Functions

func Classify

func Classify(err error) string

Classify maps an error to a stable machine-readable kind. Typed/sentinel errors are preferred; free-form matching is only a fallback at external-library boundaries.

func CompletionFor

func CompletionFor(phase, kind string, remoteStarted bool, exitObserved bool) string

CompletionFor maps phase + error kind onto observed execution certainty.

func IsRequestLevelError

func IsRequestLevelError(err error) bool

IsRequestLevelError reports whether err should become process exit 255.

func NewRunID

func NewRunID() string

NewRunID returns a random opaque run identifier.

func NormalizeRequest

func NormalizeRequest(req *Request) error

NormalizeRequest fills defaults and validates the internal request shape. It does not resolve hosts or read secrets.

func ProcessExitCode

func ProcessExitCode(counts RunCounts, requestErr error) int

ProcessExitCode maps a run outcome to the multi-target process exit code.

0   all selected targets completed successfully
1   run accepted but at least one selected target failed, was skipped, or is uncertain
255 request-level failure before a valid run could execute

func SafetyCheck

func SafetyCheck(req *Request, payload []byte) error

SafetyCheck evaluates command/script safety without connecting.

func SupportedScriptRunner added in v0.12.0

func SupportedScriptRunner(name string) bool

SupportedScriptRunner reports whether name can be used as a script runner.

Types

type ActionSpec

type ActionSpec struct {
	Kind            string `json:"kind"`
	Intent          string `json:"intent"`
	Command         string `json:"command,omitempty"`
	ScriptPath      string `json:"script_path,omitempty"`
	ScriptFromStdin bool   `json:"script_from_stdin,omitempty"`
	ScriptRunner    string `json:"script_runner,omitempty"`
	UseSudo         bool   `json:"use_sudo,omitempty"`
	PayloadSHA256   string `json:"payload_sha256,omitempty"`
	PayloadBytes    int    `json:"payload_bytes,omitempty"`
	SftpAction      string `json:"sftp_action,omitempty"`
	LocalPath       string `json:"local_path,omitempty"`
	RemotePath      string `json:"remote_path,omitempty"`
}

ActionSpec describes the single action admitted by one request.

type DefaultDialer

type DefaultDialer struct{}

DefaultDialer uses sshclient.NewSSHClient + ConnectDirect.

func (DefaultDialer) Connect

Connect implements Dialer.

type Dialer

type Dialer interface {
	Connect(cfg *sshclient.Config) (*sshclient.SSHClient, error)
}

Dialer creates and connects an SSH client for one target.

type DryRunPlan

type DryRunPlan struct {
	SchemaVersion       string         `json:"schema_version"`
	DryRun              bool           `json:"dry_run"`
	Valid               bool           `json:"valid"`
	RequestID           string         `json:"request_id,omitempty"`
	Action              ActionSpec     `json:"action"`
	Limits              Limits         `json:"limits"`
	Policy              PolicyPublic   `json:"policy"`
	Snapshot            TargetSnapshot `json:"snapshot"`
	WouldConnect        bool           `json:"would_connect"`
	WouldExecute        bool           `json:"would_execute"`
	WouldReadSecret     bool           `json:"would_read_secret"`
	WouldWriteLocal     bool           `json:"would_write_local_state"`
	WouldMutateRemote   bool           `json:"would_mutate_remote"`
	MayMutateKnownHosts bool           `json:"may_mutate_known_hosts"`
	SecretBackend       string         `json:"secret_backend,omitempty"`
	SecretUnlock        string         `json:"secret_unlock,omitempty"`
	Notes               []string       `json:"notes,omitempty"`
	Error               *ErrorInfo     `json:"error,omitempty"`
}

DryRunPlan is the validated local plan for sshx run --dry-run.

func BuildDryRunPlan

func BuildDryRunPlan(req *Request, hosts []HostRecord, defaults HostRecord, payload *Payload) DryRunPlan

BuildDryRunPlan resolves selectors and reports effects without secrets/network.

type ErrorInfo

type ErrorInfo struct {
	Kind        string `json:"kind"`
	Message     string `json:"message"`
	Retryable   bool   `json:"retryable"`
	RetrySafety string `json:"retry_safety"`
}

ErrorInfo is the structured failure surface for one target or run.

func BuildError

func BuildError(err error, kind, intent, completion string) *ErrorInfo

BuildError constructs ErrorInfo with retry classification based on action intent and completion certainty.

type Event

type Event struct {
	SchemaVersion  string          `json:"schema_version"`
	RunID          string          `json:"run_id"`
	RequestID      string          `json:"request_id,omitempty"`
	Sequence       int64           `json:"sequence"`
	Kind           string          `json:"kind"`
	Timestamp      string          `json:"timestamp"`
	Target         *ResolvedTarget `json:"target,omitempty"`
	Result         *TargetResult   `json:"result,omitempty"`
	Counts         *RunCounts      `json:"counts,omitempty"`
	SelectorDigest string          `json:"selector_digest,omitempty"`
	Concurrency    int             `json:"concurrency,omitempty"`
	FailureMode    string          `json:"failure_mode,omitempty"`
	Action         *ActionSpec     `json:"action,omitempty"`
	Error          *ErrorInfo      `json:"error,omitempty"`
}

Event is one JSONL stream record for multi-target runs.

type EventWriter

type EventWriter interface {
	WriteEvent(Event) error
}

EventWriter receives ordered JSONL events.

type HostRecord

type HostRecord struct {
	Name            string
	Address         string
	Port            string
	User            string
	KeyPath         string
	SSHPasswordKey  string
	SudoPasswordKey string
	Groups          []string
	Tags            map[string]string
	Bind            string
	BindSet         bool
}

HostRecord is the inventory shape required by selector resolution. The app package adapts settings HostConfig into this type.

type HumanWriter

type HumanWriter struct {
	W io.Writer
	// contains filtered or unexported fields
}

HumanWriter prints target-prefixed human output without interleaving lines.

func (*HumanWriter) WriteEvent

func (h *HumanWriter) WriteEvent(ev Event) error

WriteEvent implements EventWriter for human mode (subset of events).

type JSONLWriter

type JSONLWriter struct {
	W io.Writer
	// contains filtered or unexported fields
}

JSONLWriter writes one JSON object per line to w.

func (*JSONLWriter) WriteEvent

func (j *JSONLWriter) WriteEvent(ev Event) error

WriteEvent implements EventWriter.

type Limits

type Limits struct {
	Concurrency             int           `json:"concurrency"`
	Timeout                 time.Duration `json:"timeout,omitempty"`
	MaxOutputBytesPerTarget int           `json:"max_output_bytes_per_target"`
	MaxPayloadBytes         int           `json:"max_payload_bytes,omitempty"`
}

Limits bounds one process run.

type Payload

type Payload struct {
	Bytes  []byte
	SHA256 string
	Size   int
	// Shebang is the interpreter basename declared by a leading `#!` line,
	// empty when the payload declares none.
	Shebang string
}

Payload holds a byte-preserving script body and its digest metadata.

func LoadScriptFile

func LoadScriptFile(path string, maxBytes int) (Payload, error)

LoadScriptFile reads one local regular file as a script payload.

func LoadScriptStdin

func LoadScriptStdin(r io.Reader, maxBytes int) (Payload, error)

LoadScriptStdin reads process stdin as a script payload.

type Policy

type Policy struct {
	FailureMode          string `json:"failure_mode"`
	SafetyCheckEnabled   bool   `json:"safety_check_enabled"`
	SafetyBypass         bool   `json:"safety_bypass"`
	BypassReason         string `json:"bypass_reason,omitempty"`
	AcceptUnknownHost    bool   `json:"accept_unknown_host"`
	AllowInsecureHostKey bool   `json:"allow_insecure_host_key"`
	KnownHostsPath       string `json:"known_hosts_path,omitempty"`
	UseKeyAuth           bool   `json:"use_key_auth"`
	KeyPath              string `json:"key_path,omitempty"`
	// SSHPasswordKey is a typed keyring reference for SSH login only.
	SSHPasswordKey string `json:"ssh_password_key,omitempty"`
	// SudoPasswordKey is a typed keyring reference for sudo auto-fill only.
	SudoPasswordKey string `json:"sudo_password_key,omitempty"`
	// SSHPassword is an already-resolved login password (for example SSH_PASSWORD).
	// It is never serialized into dry-run or audit payloads.
	SSHPassword string `json:"-"`
	// Bind is a local source address (literal IP or interface name).
	Bind string `json:"bind,omitempty"`
	// BindSet is true when the request explicitly set bind, including empty.
	BindSet bool `json:"-"`
}

Policy captures high-risk decisions that must be explicit per request.

type PolicyPublic

type PolicyPublic struct {
	FailureMode          string `json:"failure_mode"`
	SafetyCheckEnabled   bool   `json:"safety_check_enabled"`
	SafetyBypass         bool   `json:"safety_bypass"`
	BypassReason         string `json:"bypass_reason,omitempty"`
	AcceptUnknownHost    bool   `json:"accept_unknown_host"`
	AllowInsecureHostKey bool   `json:"allow_insecure_host_key"`
	KnownHostsPath       string `json:"known_hosts_path,omitempty"`
	UseKeyAuth           bool   `json:"use_key_auth"`
	KeyPath              string `json:"key_path,omitempty"`
	SSHPasswordKey       string `json:"ssh_password_key,omitempty"`
	SudoPasswordKey      string `json:"sudo_password_key,omitempty"`
	SSHPasswordProvided  bool   `json:"ssh_password_provided"`
	Bind                 string `json:"bind,omitempty"`
	BindSet              bool   `json:"bind_set,omitempty"`
}

PolicyPublic is the audit/dry-run view of Policy without secret values.

func PublicPolicy

func PublicPolicy(p Policy) PolicyPublic

PublicPolicy projects Policy without secret material.

type Request

type Request struct {
	SchemaVersion string         `json:"schema_version"`
	RequestID     string         `json:"request_id,omitempty"`
	Targets       TargetSelector `json:"targets"`
	Action        ActionSpec     `json:"action"`
	Limits        Limits         `json:"limits"`
	Policy        Policy         `json:"policy"`
	JSONOutput    bool           `json:"json_output,omitempty"`
	JSONLOutput   bool           `json:"jsonl_output,omitempty"`
	DryRun        bool           `json:"dry_run,omitempty"`
	AuditEnabled  bool           `json:"audit_enabled,omitempty"`
	AuditOutput   string         `json:"audit_output,omitempty"`
}

Request is the versioned internal execution unit.

type ResolvedTarget

type ResolvedTarget struct {
	Index              int               `json:"index"`
	Alias              string            `json:"alias,omitempty"`
	Address            string            `json:"address"`
	Port               string            `json:"port"`
	User               string            `json:"user"`
	KeyPath            string            `json:"key_path,omitempty"`
	SSHPasswordKey     string            `json:"ssh_password_key,omitempty"`
	SudoPasswordKey    string            `json:"sudo_password_key,omitempty"`
	Groups             []string          `json:"groups,omitempty"`
	Tags               map[string]string `json:"tags,omitempty"`
	HostKeyFingerprint string            `json:"host_key_fingerprint,omitempty"`
	Literal            bool              `json:"literal,omitempty"`
	Bind               string            `json:"bind,omitempty"`
}

ResolvedTarget is one frozen host from selector resolution.

type Result

type Result struct {
	SchemaVersion string         `json:"schema_version"`
	RunID         string         `json:"run_id"`
	RequestID     string         `json:"request_id,omitempty"`
	Target        ResolvedTarget `json:"target"`
	Action        ActionSpec     `json:"action"`
	Status        string         `json:"status"`
	Phase         string         `json:"phase"`
	Completion    string         `json:"completion"`
	ExitCode      int            `json:"exit_code"`
	Success       bool           `json:"success"`
	Error         *ErrorInfo     `json:"error,omitempty"`
	// Compatibility fields retained for current major version agents.
	Host            string `json:"host"`
	Port            string `json:"port"`
	User            string `json:"user"`
	Command         string `json:"command,omitempty"`
	Stdout          string `json:"stdout,omitempty"`
	Stderr          string `json:"stderr,omitempty"`
	StdoutTruncated bool   `json:"stdout_truncated,omitempty"`
	StderrTruncated bool   `json:"stderr_truncated,omitempty"`
	DurationMs      int64  `json:"duration_ms"`
	AuthMethod      string `json:"auth_method,omitempty"`
	// ErrorKind is a compatibility projection of Error.Kind for agents that
	// still branch on the flat field from single-command JSON.
	ErrorKind string `json:"error_kind,omitempty"`
}

Result is the single-target versioned document (and compatibility envelope).

func ToResult

func ToResult(runID, requestID string, tr TargetResult) *Result

ToResult projects a TargetResult into the versioned single-target document with compatibility fields.

type RunCounts

type RunCounts struct {
	Selected  int `json:"selected"`
	Started   int `json:"started"`
	Succeeded int `json:"succeeded"`
	Failed    int `json:"failed"`
	Skipped   int `json:"skipped"`
	Uncertain int `json:"uncertain"`
}

RunCounts summarizes a finished multi-target run.

type RunOptions

type RunOptions struct {
	Request  *Request
	Snapshot TargetSnapshot
	Payload  *Payload
	Secrets  SecretResolver
	Dialer   Dialer
	Events   EventWriter
	// ActiveSessions is optional instrumentation for tests.
	ActiveSessions *atomic.Int64
	// MaxObserved is optional peak concurrent sessions counter.
	MaxObserved *atomic.Int64
}

RunOptions configures one executor invocation.

type RunOutcome

type RunOutcome struct {
	RunID   string
	Counts  RunCounts
	Results []TargetResult
	// Single is set when exactly one target finished and JSON mode is requested.
	Single *Result
}

RunOutcome is the process-level summary for one accepted run.

func Execute

func Execute(ctx context.Context, opts RunOptions) (RunOutcome, error)

Execute runs the validated request against the frozen snapshot.

type SecretResolver

type SecretResolver interface {
	// GetSSHPassword returns an SSH login password for the given keyring key.
	GetSSHPassword(key string) (string, error)
	// GetSudoPassword returns a sudo password for the given keyring key.
	GetSudoPassword(key string) (string, error)
}

SecretResolver reads typed keyring references. Implementations must not be called during dry-run or selector-only operations.

type SkippedTarget

type SkippedTarget struct {
	Alias  string `json:"alias,omitempty"`
	Reason string `json:"reason"`
}

SkippedTarget records a selector candidate that was not admitted.

type TargetResult

type TargetResult struct {
	Target          ResolvedTarget `json:"target"`
	Action          ActionSpec     `json:"action"`
	Status          string         `json:"status"`
	Phase           string         `json:"phase"`
	Completion      string         `json:"completion"`
	ExitCode        int            `json:"exit_code"`
	Error           *ErrorInfo     `json:"error,omitempty"`
	Stdout          string         `json:"stdout,omitempty"`
	Stderr          string         `json:"stderr,omitempty"`
	StdoutTruncated bool           `json:"stdout_truncated,omitempty"`
	StderrTruncated bool           `json:"stderr_truncated,omitempty"`
	DurationMs      int64          `json:"duration_ms"`
	AuthMethod      string         `json:"auth_method,omitempty"`
}

TargetResult is the finished-target document embedded in events and single-target results.

type TargetSelector

type TargetSelector struct {
	Names    []string          `json:"names,omitempty"`
	Groups   []string          `json:"groups,omitempty"`
	Tags     map[string]string `json:"tags,omitempty"`
	AllHosts bool              `json:"all_hosts,omitempty"`
	// Address is an explicit single-target literal address path. It may not
	// combine with multi-host selectors.
	Address string `json:"address,omitempty"`
	Port    string `json:"port,omitempty"`
	User    string `json:"user,omitempty"`
}

TargetSelector describes how hosts are chosen for one execution request.

type TargetSnapshot

type TargetSnapshot struct {
	Targets        []ResolvedTarget `json:"targets"`
	Skipped        []SkippedTarget  `json:"skipped,omitempty"`
	Count          int              `json:"count"`
	SelectorDigest string           `json:"selector_digest"`
}

TargetSnapshot is the frozen, deterministic target set for one run.

func ResolveTargets

func ResolveTargets(hosts []HostRecord, sel TargetSelector, defaults HostRecord) (TargetSnapshot, error)

ResolveTargets freezes a deterministic target snapshot from configured hosts.

Semantics:

  • names and groups form a candidate union
  • every tag predicate is an AND filter
  • if only tags are provided, all configured hosts are the candidate set
  • --all-hosts selects the full inventory before tag filters
  • multi-host selectors never accept literal addresses
  • zero matches is a request-level failure (returned as error)

Jump to

Keyboard shortcuts

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