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 ClassifyLocalRisk(mode, action string) (Risk, Effects, bool)
- func ClassifyRisk(action, command string, sudo bool) (Risk, Effects)
- func CompletionFor(phase, kind string, remoteStarted bool, exitObserved bool) string
- func CompletionForAttempt(phase, kind string, startAttempted, remoteStarted, exitObserved bool) string
- func Digest(data []byte) 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
- func SupportedScriptRunner(name string) bool
- func ValidatePlanHash(value string) error
- func WithScopedTimeout(parent context.Context, timeout time.Duration, scope string) (context.Context, context.CancelFunc)
- type ActionSpec
- type BoundaryError
- type Condition
- type DefaultDialer
- type Dialer
- type DryRunPlan
- type Effects
- type ErrorInfo
- type Event
- type EventWriter
- type HostRecord
- type HumanWriter
- type JSONLWriter
- type Limits
- type Metadata
- type Payload
- type PeerIdentity
- type Plan
- type PlanTarget
- type Policy
- type PolicyPublic
- type Request
- type ResolvedTarget
- type Result
- type Risk
- 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" 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" ErrorKindCancelled = "cancelled" //nolint:misspell // Preserve the machine-readable cancellation category. ErrorKindRemoteExit = "remote_exit" ErrorKindExitMissing = "exit_missing" ErrorKindProtocol = "protocol" ErrorKindConfig = "config" ErrorKindLocalIO = "local_io" ErrorKindRemoteIO = "remote_io" ErrorKindPrecondition = "precondition" ErrorKindUnknown = "unknown" ScriptRunnerSH = "sh" )
const MaxJumpHops = 4
MaxJumpHops is the maximum number of intermediate bastion hops, not counting the target. Longer chains are a config error and never touch the network.
const PlanSchemaVersion = "sshx.plan.v1"
Variables ¶
var ( // ErrConfig indicates a request/schema/selector configuration failure. ErrConfig = errors.New("execution config error") // ErrLocalIO indicates local file, stdin, or result-delivery failure. 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 ClassifyLocalRisk ¶ added in v0.15.0
ClassifyLocalRisk describes supported local management actions, not observed state changes. Remote host diagnostics and unknown actions are excluded.
func ClassifyRisk ¶ added in v0.15.0
ClassifyRisk is deliberately narrower than shell validation: admission to the command guardrail does not establish that a command is read-only.
func CompletionFor ¶
CompletionFor maps phase + error kind onto observed execution certainty.
func CompletionForAttempt ¶ added in v0.15.0
func CompletionForAttempt(phase, kind string, startAttempted, remoteStarted, exitObserved bool) string
CompletionForAttempt also accounts for an exec request whose acknowledgement was never received. This is not evidence that remote execution did not start.
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.
func SupportedScriptRunner ¶ added in v0.12.0
SupportedScriptRunner reports whether name can be used as a script runner.
func ValidatePlanHash ¶ added in v0.15.0
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 BoundaryError ¶ added in v0.15.0
BoundaryError has a stable machine category independent of diagnostic text.
func (*BoundaryError) Error ¶ added in v0.15.0
func (e *BoundaryError) Error() string
func (*BoundaryError) ErrorKind ¶ added in v0.15.0
func (e *BoundaryError) ErrorKind() string
type DefaultDialer ¶
type DefaultDialer struct{}
DefaultDialer uses sshclient.NewSSHClient + Connect.
type DryRunPlan ¶
type DryRunPlan struct {
Plan *Plan `json:"plan,omitempty"`
PlanHash string `json:"plan_hash,omitempty"`
Risk Risk `json:"risk,omitempty"`
Effects Effects `json:"effects"`
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 Effects ¶ added in v0.15.0
type Effects struct {
Unknown bool `json:"unknown"`
RemoteWrite bool `json:"remote_write"`
LocalWrite bool `json:"local_write"`
Privileged bool `json:"privileged"`
Destructive bool `json:"destructive"`
}
Effects retain facts that cannot be represented by a single risk level.
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 treats unknown intent as potentially mutating. Callers with a reviewed plan should pass its risk instead of trusting a declared read intent.
type Event ¶
type Event struct {
Metadata
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"`
MaxFailures int `json:"max_failures,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
Bind string
BindSet bool
// Via is the named next hop toward the operator. Empty means direct TCP.
Via 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"`
HostTimeout time.Duration `json:"host_timeout,omitempty"`
GlobalTimeout time.Duration `json:"global_timeout,omitempty"`
MaxOutputBytesPerTarget int `json:"max_output_bytes_per_target"`
MaxPayloadBytes int `json:"max_payload_bytes,omitempty"`
}
Limits bounds one process run.
type Metadata ¶ added in v0.15.0
type Metadata struct {
PlanHash string `json:"plan_hash,omitempty"`
Risk Risk `json:"risk,omitempty"`
Effects Effects `json:"effects"`
ExecutionID string `json:"execution_id,omitempty"`
ParentExecutionID string `json:"parent_execution_id,omitempty"`
ExecutionFingerprint string `json:"execution_fingerprint,omitempty"`
TargetFingerprints []string `json:"target_fingerprints,omitempty"`
Peers []PeerIdentity `json:"peers,omitempty"`
CancellationCause string `json:"cancellation_cause,omitempty"`
DeadlineScope string `json:"deadline_scope,omitempty"`
StartedAt string `json:"started_at,omitempty"`
FinishedAt string `json:"finished_at,omitempty"`
ChangeState string `json:"change_state"`
Executed *bool `json:"executed"`
Verified bool `json:"verified"`
Verification string `json:"verification"`
Preconditions []Condition `json:"preconditions,omitempty"`
Postconditions []Condition `json:"postconditions,omitempty"`
}
func NewMetadata ¶ added in v0.15.0
func (*Metadata) Finish ¶ added in v0.15.0
Finish hashes redacted outcome facts, never stdout, stderr or raw errors.
func (*Metadata) ObserveContext ¶ added in v0.15.0
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 ¶
LoadScriptFile reads one local regular file as a script payload.
type PeerIdentity ¶ added in v0.15.0
type PeerIdentity struct {
Role string `json:"role"`
Address string `json:"address,omitempty"`
HostKeyFingerprint string `json:"host_key_fingerprint,omitempty"`
AuthMethod string `json:"auth_method,omitempty"`
User string `json:"user,omitempty"`
SSHPasswordKey string `json:"ssh_password_key,omitempty"`
SudoPasswordKey string `json:"sudo_password_key,omitempty"`
}
type Plan ¶ added in v0.15.0
type Plan struct {
SchemaVersion string `json:"schema_version"`
Semantics string `json:"semantics"`
Action string `json:"action"`
Targets []PlanTarget `json:"targets"`
Inputs map[string]string `json:"inputs"`
Risk Risk `json:"risk"`
Effects Effects `json:"effects"`
Bindable bool `json:"bindable"`
Unresolved []string `json:"unresolved,omitempty"`
PlanHash string `json:"plan_hash"`
}
Plan contains public semantic inputs only. Payloads and credentials are held separately by the caller and must not be reconstructed from this view.
func (Plan) CanonicalBytes ¶ added in v0.15.0
CanonicalBytes excludes display metadata and the digest itself. Go's JSON encoder sorts string map keys; target order is normalized by Seal.
func (Plan) CheckExpected ¶ added in v0.15.0
type PlanTarget ¶ added in v0.15.0
type PlanTarget struct {
Role string `json:"role"`
Alias string `json:"alias,omitempty"`
Address string `json:"address"`
Port string `json:"port"`
User string `json:"user"`
Bind string `json:"bind,omitempty"`
KeyFingerprint string `json:"key_fingerprint,omitempty"`
TrustSHA256 string `json:"trust_sha256,omitempty"`
SSHPasswordKey string `json:"ssh_password_key,omitempty"`
SudoKey string `json:"sudo_key,omitempty"`
}
type Policy ¶
type Policy struct {
FailureMode string `json:"failure_mode"`
MaxFailures int `json:"max_failures,omitempty"`
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"`
MaxFailures int `json:"max_failures,omitempty"`
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 {
Plan *Plan `json:"-"`
ExecutionID string `json:"-"`
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"`
KnownHostsData []byte `json:"-"`
ExpectedKeyFingerprint string `json:"-"`
Literal bool `json:"literal,omitempty"`
Bind string `json:"bind,omitempty"`
// Via is the named next hop from inventory or --via=. Empty means direct.
Via string `json:"via,omitempty"`
// Jumps is the resolved bastion chain, outermost first. Nested Jumps are empty.
Jumps []ResolvedTarget `json:"jumps,omitempty"`
}
ResolvedTarget is one frozen host from selector resolution.
func ResolveJumps ¶ added in v0.15.0
func ResolveJumps(hosts []HostRecord, target ResolvedTarget, viaOverride *string) (ResolvedTarget, error)
ResolveJumps walks named-host via pointers from target to the outermost bastion. viaOverride, when non-nil, replaces the target's inventory via (including an empty value that forces a direct connection).
Returned Jumps are outermost-first. Each hop must be a configured alias; literal addresses are rejected so secrets and host-key decisions stay named.
type Result ¶
type Result struct {
Metadata
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"`
PeerAddress string `json:"peer_address,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 {
Metadata
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 {
Metadata
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"`
PeerAddress string `json:"peer_address,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)