execution

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 17 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"

	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"
	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.

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"`
	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
}

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
}

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:"-"`
}

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"`
}

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"`
}

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