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
- Variables
- func Classify(err error) string
- func CompletionFor(phase, kind string, remoteStarted bool, exitObserved bool) string
- func IsRequestLevelError(err error) bool
- func NewRunID() string
- func NormalizeRequest(req *Request) error
- func ProcessExitCode(counts RunCounts, requestErr error) int
- func SafetyCheck(req *Request, payload []byte) error
- type ActionSpec
- type DefaultDialer
- type Dialer
- type DryRunPlan
- type ErrorInfo
- type Event
- type EventWriter
- type HostRecord
- type HumanWriter
- type JSONLWriter
- type Limits
- type Payload
- type Policy
- type PolicyPublic
- type Request
- type ResolvedTarget
- type Result
- type RunCounts
- type RunOptions
- type RunOutcome
- type SecretResolver
- type SkippedTarget
- type TargetResult
- type TargetSelector
- type TargetSnapshot
Constants ¶
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 ¶
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 ¶
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 ¶
CompletionFor maps phase + error kind onto observed execution certainty.
func IsRequestLevelError ¶
IsRequestLevelError reports whether err should become process exit 255.
func NormalizeRequest ¶
NormalizeRequest fills defaults and validates the internal request shape. It does not resolve hosts or read secrets.
func ProcessExitCode ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
Payload holds a byte-preserving script body and its digest metadata.
func LoadScriptFile ¶
LoadScriptFile reads one local regular file 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 ¶
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)