Documentation
¶
Overview ¶
Package interfaces defines shared interface types used across the workflow engine, handlers, and module packages. Placing these interfaces here breaks the direct handler→module concrete-type dependency and enables each package to be tested in isolation with mocks.
Index ¶
- Constants
- Variables
- func CanonicalKeys() []string
- func IaCCanonicalSchemaJSON() []byte
- func IsCanonicalKey(key string) bool
- func IsValidHookEvent(s string) bool
- func IsValidationError(err error) bool
- func ValidateProviderID(s string, format ProviderIDFormat) bool
- func ValidationErrorStatus(err error) int
- type ActionError
- type ActionOutcome
- type ActionStatus
- type AlertSpec
- type ApplyResult
- type ArtifactEntry
- type AutoscalingSpec
- type BootstrapResult
- type CORSSpec
- type DestroyResult
- type Diagnostic
- type DiffResult
- type DomainSpec
- type DriftClass
- type DriftConfigDetector
- type DriftEntry
- type DriftResult
- type EgressRule
- type EgressSpec
- type Enumerator
- type EnumeratorAll
- type EventEmitter
- type EventRecorder
- type FieldChange
- type GeneratorMetadata
- type HealthCheckSpec
- type HealthResult
- type HookEvent
- type HookPayload
- type IaCCapabilityDeclaration
- type IaCLockHandle
- type IaCPlan
- type IaCProvider
- type IaCStateStore
- type IngressRule
- type IngressSpec
- type InstallVerifyPayload
- type JobSpec
- type LogDestinationSpec
- type MaintenanceSpec
- type MetricsRecorder
- type MigrationDriver
- type MigrationOptions
- type MigrationProvider
- type MigrationRepairRequest
- type MigrationRepairResult
- type MigrationRequest
- type MigrationResult
- type MigrationSource
- type MigrationStatus
- type PipelineContext
- type PipelineExecutor
- type PipelineRunner
- type PipelineStep
- type PlanAction
- type PlanDiagnostic
- type PlanDiagnosticSeverity
- type PluginVersionInfo
- type PortSpec
- type PostArtifactsPublishPayload
- type PostBuildPayload
- type PostContainerBuildPayload
- type PostContainerPushPayload
- type PostTargetBuildPayload
- type PreArtifactsPublishPayload
- type PreBuildFailPayload
- type PreBuildPayload
- type PreContainerBuildPayload
- type PreContainerPushPayload
- type PreTargetBuildPayload
- type ProviderCredentialRevoker
- type ProviderIDFormat
- type ProviderIDValidator
- type ProviderMigrationRepairer
- type ProviderPlanner
- type ProviderSizing
- type ProviderValidator
- type Reconfigurable
- type ResourceAdoptionLocator
- type ResourceDriver
- type ResourceHints
- type ResourceOutput
- type ResourceRef
- type ResourceReplacer
- type ResourceSpec
- type ResourceState
- type ResourceStatus
- type RouteSpec
- type SchemaRegistrar
- type Selector
- type SidecarSpec
- type Size
- type SizingDefaults
- type StaticSiteSpec
- type StepRegistrar
- type StepRegistryProvider
- type StepResult
- type Tenant
- type TenantFilter
- type TenantPatch
- type TenantRegistry
- type TenantResolver
- type TenantSpec
- type TerminationSpec
- type Trigger
- type TriggerRegistrar
- type Troubleshooter
- type UpsertSupporter
- type ValidationError
- type WorkerSpec
- type WorkflowStoreProvider
- type WorkloadResourceSpec
Constants ¶
const ( KeyName = "name" KeyRegion = "region" KeyImage = "image" KeyHTTPPort = "http_port" KeyInternalPorts = "internal_ports" KeyProtocol = "protocol" KeyInstanceCount = "instance_count" KeySize = "size" KeyEnvVars = "env_vars" KeyEnvVarsSecret = "env_vars_secret" //nolint:gosec // G101 false positive: this is a config key name, not a credential KeyVPCRef = "vpc_ref" KeyAutoscaling = "autoscaling" KeyRoutes = "routes" KeyCORS = "cors" KeyDomains = "domains" KeyHealthCheck = "health_check" KeyLivenessCheck = "liveness_check" KeyIngress = "ingress" KeyEgress = "egress" KeyAlerts = "alerts" KeyLogDestinations = "log_destinations" KeyTermination = "termination" KeyMaintenance = "maintenance" KeyJobs = "jobs" KeyWorkers = "workers" KeyStaticSites = "static_sites" KeySidecars = "sidecars" KeyBuildCommand = "build_command" KeyRunCommand = "run_command" KeyDockerfilePath = "dockerfile_path" KeySourceDir = "source_dir" KeyProviderSpecific = "provider_specific" )
Canonical IaC config key constants. These are the standard field names used across all IaC providers to describe application resource configuration.
const ( MigrationRepairConfirmation = "FORCE_MIGRATION_METADATA" MigrationRepairStatusSucceeded = "succeeded" MigrationRepairStatusFailed = "failed" MigrationRepairStatusApprovalRequired = "approval_required" MigrationRepairStatusUnsupported = "unsupported" )
Variables ¶
var ( ErrResourceNotFound = errors.New("iac: resource not found") // 404/410 ErrResourceAlreadyExists = errors.New("iac: resource already exists") // 409 Conflict ErrRateLimited = errors.New("iac: rate limited") // 429 ErrTransient = errors.New("iac: transient error") // 502/503/504 ErrForbidden = errors.New("iac: forbidden") // 403 ErrValidation = errors.New("iac: validation error") // 400/422 // ErrImageNotInRegistry indicates that an image tag or digest referenced // by a desired ResourceSpec is not present in the registry. Drivers // SHOULD return this (wrapped) from Diff, Create, and Update when an // image-presence pre-flight fails. Callers can use errors.Is for typed // identification, but gRPC-bound callers should ALSO match the message // string "iac: image tag or digest not found in registry" for // cross-process robustness — structpb does not preserve sentinel // identity across the gRPC plugin boundary. The message string is // load-bearing; do not change it. ErrImageNotInRegistry = errors.New("iac: image tag or digest not found in registry") // ErrProviderMethodUnimplemented indicates that a remote IaC provider // plugin does not implement the optional method that was just dispatched. // Used by the wfctl gRPC proxy *remoteIaCProvider to translate // gRPC codes.Unimplemented (and equivalent string-matched plugin errors) // into a stable sentinel that dispatch sites can errors.Is on. // // Why this exists // ─────────────── // v0.27.0 added optional sub-interfaces (EnumeratorAll, Enumerator, etc.) // to interfaces.IaCProvider. Dispatch sites (infra_audit_keys.go, // infra_cleanup.go, infra_prune.go) iterate providers and use a // type-assertion `p.(interfaces.X)` as the "does this provider support X?" // gate. v0.27.1 bridged these methods on remoteIaCProvider so audit-keys // could reach plugins that DO implement them, but as a side effect every // gRPC-loaded provider now satisfies the optional interface — even ones // whose plugin process does not implement the underlying method. // // To preserve the iterate-and-skip semantics, dispatch sites now call the // method and check for ErrProviderMethodUnimplemented via errors.Is. A // match is treated identically to the pre-v0.27.1 negative type-assert: // log "skipped <provider>: does not implement <Interface>" and continue // iterating to the next provider. // // Plugins SHOULD return status.Error(codes.Unimplemented, "...") from // their InvokeMethod / InvokeMethodContext dispatcher when an optional // method is not supported. The proxy translates this to // ErrProviderMethodUnimplemented for callers. ErrProviderMethodUnimplemented = errors.New("iac: provider method unimplemented") )
Sentinel errors for common IaC resource operation response categories. Use errors.Is to identify them after wrapping.
var SizingMap = map[Size]SizingDefaults{
SizeXS: {CPU: "0.25", Memory: "512Mi", DBStorage: "10Gi", CacheMemory: "256Mi"},
SizeS: {CPU: "1", Memory: "2Gi", DBStorage: "50Gi", CacheMemory: "1Gi"},
SizeM: {CPU: "2", Memory: "4Gi", DBStorage: "100Gi", CacheMemory: "4Gi"},
SizeL: {CPU: "4", Memory: "16Gi", DBStorage: "500Gi", CacheMemory: "16Gi"},
SizeXL: {CPU: "8", Memory: "32Gi", DBStorage: "1Ti", CacheMemory: "64Gi"},
}
SizingMap defines the default resource allocations per size tier.
Functions ¶
func CanonicalKeys ¶ added in v0.18.0
func CanonicalKeys() []string
CanonicalKeys returns the full list of canonical IaC config key strings.
func IaCCanonicalSchemaJSON ¶ added in v0.18.0
func IaCCanonicalSchemaJSON() []byte
IaCCanonicalSchemaJSON returns the raw JSON Schema bytes.
func IsCanonicalKey ¶ added in v0.18.0
IsCanonicalKey returns true if key is a recognized canonical IaC config key.
func IsValidHookEvent ¶ added in v0.18.0
IsValidHookEvent returns true if s matches a known HookEvent constant.
func IsValidationError ¶ added in v0.3.60
IsValidationError reports whether err (or any error in its chain) is a *ValidationError.
func ValidateProviderID ¶ added in v0.18.11
func ValidateProviderID(s string, format ProviderIDFormat) bool
ValidateProviderID returns true when s is a valid provider ID for the given format. Unknown and unrecognized formats always return true (forward compat). Freeform requires a non-empty string. Specific formats delegate to their dedicated validators.
func ValidationErrorStatus ¶ added in v0.3.60
ValidationErrorStatus returns the HTTP status code from a ValidationError in the error chain. Returns 400 if the error has no status or is not a ValidationError.
Types ¶
type ActionError ¶ added in v0.3.52
type ActionError struct {
Resource string `json:"resource"`
Action string `json:"action"`
Error string `json:"error"`
}
ActionError captures a resource-level error during apply or destroy.
type ActionOutcome ¶ added in v0.54.0
type ActionOutcome struct {
ActionIndex uint32 `json:"action_index"`
Status ActionStatus `json:"status"`
Error string `json:"error,omitempty"`
}
ActionOutcome is the wfctl-side per-action surfacing for v2 hook dispatch. Engine populates one entry per PlanAction in ApplyResult.Actions; wfctl dispatches v2 hooks (Created / Deleted) by matching ActionIndex back to the planned action slice. Per workflow#699 the proto-side pb.ActionResult mirror was deleted — ActionOutcome is now the sole representation of per-action outcome.
type ActionStatus ¶ added in v0.54.0
type ActionStatus uint8
ActionStatus categorizes per-action outcomes for wfctl-side hook dispatch. Mirrors pb.ActionStatus (plugin/external/proto/iac.proto) for type-safe Go boundary use; constant tags 0-6 MUST stay in lockstep with the proto. Per workflow#640 Phase 2 + workflow#698 Phase 2.3 + ADR 0040 invariants 1-2.
Phase 2.3 reclassification: the engine now distinguishes pre-dispatch (Skipped), dispatch (Error/DeleteFailed), and post-hook (CompensationFailed) failures. Consumers that previously checked ActionStatusError alone for "action did not produce desired end-state" should now check {Error, DeleteFailed, CompensationFailed, Skipped}.
const ( // ActionStatusUnspecified is the zero-value. Engine-side population // in wfctlhelpers.ApplyPlanWithHooks must replace this before // returning; wfctl rejects ActionOutcome entries left at // Unspecified per ADR 0040 invariant 2. Per workflow#699 the // proto-side decode path (formerly applyResultFromPB) is gone — // the only producer is now the engine's per-action populate. ActionStatusUnspecified ActionStatus = iota ActionStatusSuccess ActionStatusError ActionStatusDeleteFailed // Phase 2.3 (workflow#698): ActionStatusCompensated // reserved-for-future-emission; engine v0.56.0 does NOT emit (no auto-compensation); plugins may emit if they implement own compensation ActionStatusCompensationFailed // post-driver-success hook failed; cloud-side work IS done; operator must verify state; manual compensation may be required ActionStatusSkipped // action never attempted at driver (ctx-cancel pre-dispatch, JIT-substitution-fail, driver-resolve-fail); cloud-side state unchanged )
type AlertSpec ¶ added in v0.18.0
type AlertSpec struct {
Rule string `json:"rule" yaml:"rule"`
Operator string `json:"operator" yaml:"operator"` // GREATER_THAN | LESS_THAN
Value float64 `json:"value" yaml:"value"`
Window string `json:"window" yaml:"window"` // e.g. "10m"
Disabled bool `json:"disabled" yaml:"disabled"`
}
AlertSpec defines an observable metric threshold alert.
type ApplyResult ¶ added in v0.3.52
type ApplyResult struct {
PlanID string `json:"plan_id"`
Resources []ResourceOutput `json:"resources"`
Errors []ActionError `json:"errors,omitempty"`
// InitialInputSnapshot captures env-var fingerprints at the start of apply.
// Populated by wfctlhelpers.ApplyPlan (T3.1) at apply entry by snapshotting
// every name listed in plan.InputSnapshot through inputsnapshot.OSEnvProvider.
// Used by the deferred postcondition (T3.1.5) to compute the drift report
// against the apply-time snapshot.
InitialInputSnapshot map[string]string `json:"initial_input_snapshot,omitempty"`
// InputDriftReport names env-vars whose fingerprint changed between plan
// and apply. Populated by the deferred postcondition in
// wfctlhelpers.ApplyPlan (T3.1.5) regardless of whether the apply
// itself succeeded or errored. Empty (or nil) means no drift detected.
// Entries are sorted by Name for deterministic comparison and stable
// diagnostic output; the sort guarantee is enforced by
// inputsnapshot.ComputeDrift (covered by
// TestComputeDrift_ResultIsSortedByName in
// iac/inputsnapshot/compute_drift_test.go).
InputDriftReport []DriftEntry `json:"input_drift_report,omitempty"`
// ReplaceIDMap propagates new ProviderIDs from Replace actions to
// dependent resources whose Apply runs later in the same plan.
// Populated by doReplace (T3.4); consumed by JIT substitution in W-5
// (T5.2/T5.3).
//
// Keyed by the *replaced* resource's Name (i.e., action.Resource.Name
// from the Replace PlanAction — the resource whose Delete-then-Create
// just produced a fresh ProviderID). The value is the new ProviderID
// returned from the post-Delete Create. Dependent resources reference
// the replaced resource by name in their config, so JIT substitution
// in W-5 translates "name → new ProviderID" via this map.
ReplaceIDMap map[string]string `json:"replace_id_map,omitempty"`
// Actions surfaces per-PlanAction outcomes for v2 hook dispatch in
// wfctl. Always populated (one entry per IaCPlan.Actions index) when
// an IaC plugin declares ComputePlanVersion="v2" in
// CapabilitiesResponse. Per ADR 0024 + ADR 0040, plugins NOT
// declaring v2 are permanently incompatible with workflow v0.54.0+;
// there is no compat shim. Per workflow#640 Phase 2 + ADR 0040
// invariants 1-2.
Actions []ActionOutcome `json:"actions,omitempty"`
}
ApplyResult summarises the outcome of applying a plan.
type ArtifactEntry ¶ added in v0.18.0
ArtifactEntry is a single published artifact with its URL.
type AutoscalingSpec ¶ added in v0.18.0
type AutoscalingSpec struct {
Min int `json:"min" yaml:"min"`
Max int `json:"max" yaml:"max"`
CPUPercent int `json:"cpu_percent" yaml:"cpu_percent"`
MemoryPercent int `json:"memory_percent" yaml:"memory_percent"`
}
AutoscalingSpec controls horizontal-pod / instance autoscaling.
type BootstrapResult ¶ added in v0.18.6
type BootstrapResult struct {
// Bucket is the name of the created or confirmed state bucket/container.
Bucket string `json:"bucket,omitempty"`
// Region is the region where the bucket resides.
Region string `json:"region,omitempty"`
// Endpoint is the S3-compatible API endpoint URL (if applicable).
Endpoint string `json:"endpoint,omitempty"`
// EnvVars is a map of environment variable names to values that should be
// exported for CI capture (e.g. WFCTL_STATE_BUCKET, SPACES_BUCKET).
EnvVars map[string]string `json:"env_vars,omitempty"`
}
BootstrapResult contains metadata returned by a successful BootstrapStateBackend call.
type CORSSpec ¶ added in v0.18.0
type CORSSpec struct {
AllowOrigins []string `json:"allow_origins,omitempty" yaml:"allow_origins,omitempty"`
AllowMethods []string `json:"allow_methods,omitempty" yaml:"allow_methods,omitempty"`
AllowHeaders []string `json:"allow_headers,omitempty" yaml:"allow_headers,omitempty"`
ExposeHeaders []string `json:"expose_headers,omitempty" yaml:"expose_headers,omitempty"`
AllowCredentials bool `json:"allow_credentials" yaml:"allow_credentials"`
MaxAge string `json:"max_age,omitempty" yaml:"max_age,omitempty"`
}
CORSSpec configures Cross-Origin Resource Sharing headers.
type DestroyResult ¶ added in v0.3.52
type DestroyResult struct {
Destroyed []string `json:"destroyed"`
Errors []ActionError `json:"errors,omitempty"`
}
DestroyResult summarises the outcome of a destroy operation.
type Diagnostic ¶ added in v0.18.10
type Diagnostic struct {
ID string `json:"id"` // provider-side identifier (e.g. deployment ID)
Phase string `json:"phase"` // terminal or current phase
Cause string `json:"cause"` // human-readable root cause or error summary
At time.Time `json:"at"` // when the event was created or last updated
Detail string `json:"detail,omitempty"` // optional verbose tail (log excerpt, stack)
}
Diagnostic is a single troubleshooting finding returned by a Troubleshooter. It describes a recent provider-side event (deployment, job run, etc.) with enough context to understand why a health check failed without visiting the provider's console.
type DiffResult ¶ added in v0.3.52
type DiffResult struct {
NeedsUpdate bool `json:"needs_update"`
NeedsReplace bool `json:"needs_replace"`
Changes []FieldChange `json:"changes"`
}
DiffResult summarises the differences between desired and actual resource state.
type DomainSpec ¶ added in v0.18.0
type DomainSpec struct {
Name string `json:"name" yaml:"name"`
Zone string `json:"zone,omitempty" yaml:"zone,omitempty"`
Type string `json:"type" yaml:"type"` // PRIMARY | ALIAS
Wildcard bool `json:"wildcard" yaml:"wildcard"`
}
DomainSpec describes a custom domain attached to a service.
type DriftClass ¶ added in v0.20.5
type DriftClass string
DriftClass classifies the type of drift detected between IaC state and actual cloud state. Used by wfctl infra drift output and wfctl infra apply --refresh recovery semantics.
const ( // DriftClassUnknown is the zero value; preserved for backwards compat // with consumers serialized before the Class field existed. DriftClassUnknown DriftClass = "" // DriftClassInSync — state and cloud agree. DriftClassInSync DriftClass = "in-sync" // DriftClassGhost — state has the resource; cloud Read returned // ErrResourceNotFound. Caller can prune via wfctl infra apply --refresh. DriftClassGhost DriftClass = "ghost" // DriftClassConfig — state and cloud both have the resource but configs // differ. Caller reconciles via wfctl infra apply (normal plan path). DriftClassConfig DriftClass = "config" )
type DriftConfigDetector ¶ added in v0.22.1
type DriftConfigDetector interface {
DetectDriftWithSpecs(ctx context.Context, resources []ResourceRef, specs map[string]ResourceSpec) ([]DriftResult, error)
}
DriftConfigDetector is an OPTIONAL interface a provider MAY implement to surface config-drift in addition to the existence-only Ghost / InSync / Unknown classifications produced by DetectDrift.
specs is the per-ref applied-config map sourced from state. Callers build it from ResourceState.AppliedConfig (wrapped into ResourceSpec); missing or empty entries instruct the provider to fall back to existence-only behavior for that ref. The map key is ref.Name (matches ResourceState.Name).
Callers MUST type-assert against this interface and fall back to IaCProvider.DetectDrift(refs) on the negative case. Providers that do not implement DriftConfigDetector continue to work unchanged.
Providers SHOULD only return DriftClassConfig when they have high confidence the applied entry represents user-supplied config (not adoption-shaped Outputs reflow); see ResourceState.AppliedConfigSource (iac_state.go) for the canonical discriminator.
type DriftEntry ¶ added in v0.21.0
type DriftEntry struct {
Name string `json:"name"`
PlanFingerprint string `json:"plan_fingerprint"`
ApplyFingerprint string `json:"apply_fingerprint"`
}
DriftEntry names a single env-var whose fingerprint changed between plan-time and apply-time. Used by both the persisted-`--plan` path (cmd/wfctl/infra.go, wired in T1.5) and the in-process apply path (wfctlhelpers.ApplyPlan, wired in T3.1.5 — both via inputsnapshot.FormatStaleError).
type DriftResult ¶ added in v0.3.52
type DriftResult struct {
Name string `json:"name"`
Type string `json:"type"`
Drifted bool `json:"drifted"`
Class DriftClass `json:"class,omitempty"` // additive; omitted when Unknown
Expected map[string]any `json:"expected,omitempty"`
Actual map[string]any `json:"actual,omitempty"`
Fields []string `json:"fields,omitempty"` // which fields drifted
}
DriftResult captures detected drift between declared and actual resource state.
type EgressRule ¶ added in v0.18.0
type EgressRule struct {
Destination string `json:"destination" yaml:"destination"`
Protocol string `json:"protocol" yaml:"protocol"`
Allow bool `json:"allow" yaml:"allow"`
}
EgressRule is a single outbound allow/deny entry.
type EgressSpec ¶ added in v0.18.0
type EgressSpec struct {
Bandwidth string `json:"bandwidth,omitempty" yaml:"bandwidth,omitempty"` // informational budget, e.g. "1Gbps"
Rules []EgressRule `json:"rules,omitempty" yaml:"rules,omitempty"`
}
EgressSpec controls outbound traffic policy.
type Enumerator ¶ added in v0.21.2
type Enumerator interface {
EnumerateByTag(ctx context.Context, tag string) ([]ResourceRef, error)
}
Enumerator is an OPTIONAL interface for providers that can list resources by tag across the cloud account. Used by `wfctl infra cleanup --tag <name>`. Providers without a tag-query API simply do not implement it; the cleanup subcommand skips them with a structured stdout log line so operators see the explicit skip rather than silent under-cleanup.
The contract is intentionally narrow: implementations MUST return refs that the same provider's ResourceDriver(type).Delete can act on. ProviderID is recommended (the cleanup command may use it for log correlation), but Name + Type are the load-bearing identifiers Delete needs.
Callers MUST type-assert against this interface and treat the negative case as a skip — providers may or may not implement Enumerator depending on whether their cloud API exposes a tag-query primitive. The implementation status of individual provider plugins is documented in docs/WFCTL.md `#### infra cleanup`, not here, so the API comment does not go stale every time a new plugin gains tag-query support.
type EnumeratorAll ¶ added in v0.26.0
type EnumeratorAll interface {
EnumerateAll(ctx context.Context, resourceType string) ([]*ResourceOutput, error)
}
EnumeratorAll is an OPTIONAL provider interface for resource types that don't support tagging (e.g. DO Spaces keys). Returns ALL resources of resourceType in the account regardless of tag, with full metadata (Outputs map populated) so callers can filter without re-reading.
Returns []*ResourceOutput rather than []ResourceRef because filtering (drift detection, prune) needs the metadata. Implementations should paginate transparently. Returning *ResourceOutput keeps the contract consistent with ResourceDriver.Read which also returns this shape.
Per ADR 0016. Used by `wfctl infra audit-keys` + `wfctl infra prune`.
type EventEmitter ¶
type EventEmitter interface {
EmitWorkflowStarted(ctx context.Context, workflowType, action string, data map[string]any)
EmitWorkflowCompleted(ctx context.Context, workflowType, action string, duration time.Duration, results map[string]any)
EmitWorkflowFailed(ctx context.Context, workflowType, action string, duration time.Duration, err error)
}
EventEmitter publishes workflow lifecycle events. *module.WorkflowEventEmitter satisfies this interface. All methods must be safe to call when no event bus is configured (no-ops).
type EventRecorder ¶
type EventRecorder interface {
RecordEvent(ctx context.Context, executionID string, eventType string, data map[string]any) error
}
EventRecorder records pipeline execution events for observability. *store.EventRecorderAdapter and any compatible recorder satisfy this interface.
type FieldChange ¶ added in v0.3.52
type FieldChange struct {
Path string `json:"path"`
Old any `json:"old"`
New any `json:"new"`
ForceNew bool `json:"force_new"` // change requires resource replacement
}
FieldChange describes a single field-level difference.
type GeneratorMetadata ¶ added in v0.51.2
type GeneratorMetadata struct {
WfctlVersion string `json:"wfctl_version"`
Plugins []PluginVersionInfo `json:"plugins,omitempty"`
}
GeneratorMetadata records the wfctl version and installed IaC plugin versions that were present when an IaC plan or state operation was produced. Storing this information makes it possible to reason about compatibility between recorded state and the current toolchain, and to identify upgrades that may be required when behavior has changed between versions.
Note: Plugins lists all IaC provider plugins installed in WFCTL_PLUGIN_DIR at generation time. In single-run invocations this is equivalent to the loaded set, but operators should be aware that extra installed-but-not-used plugins may appear.
type HealthCheckSpec ¶ added in v0.18.0
type HealthCheckSpec struct {
HTTPPath string `json:"http_path,omitempty" yaml:"http_path,omitempty"`
TCPPort int `json:"tcp_port,omitempty" yaml:"tcp_port,omitempty"`
Port int `json:"port,omitempty" yaml:"port,omitempty"`
InitialDelaySeconds int `json:"initial_delay_seconds" yaml:"initial_delay_seconds"`
PeriodSeconds int `json:"period_seconds" yaml:"period_seconds"`
TimeoutSeconds int `json:"timeout_seconds" yaml:"timeout_seconds"`
SuccessThreshold int `json:"success_threshold" yaml:"success_threshold"`
FailureThreshold int `json:"failure_threshold" yaml:"failure_threshold"`
}
HealthCheckSpec describes an HTTP or TCP health probe.
type HealthResult ¶ added in v0.3.52
type HealthResult struct {
Healthy bool `json:"healthy"`
Message string `json:"message,omitempty"`
}
HealthResult is the outcome of a health check for a resource.
type HookEvent ¶ added in v0.18.0
type HookEvent string
HookEvent is the string identifier for a build-pipeline hook event.
const ( // Build lifecycle events emitted by wfctl build. HookEventPreBuild HookEvent = "pre_build" HookEventPreTargetBuild HookEvent = "pre_target_build" HookEventPostTargetBuild HookEvent = "post_target_build" HookEventPreContainerBuild HookEvent = "pre_container_build" HookEventPostContainerBuild HookEvent = "post_container_build" HookEventPreContainerPush HookEvent = "pre_container_push" HookEventPostContainerPush HookEvent = "post_container_push" HookEventPreArtifactsPublish HookEvent = "pre_artifacts_publish" HookEventPostArtifactsPublish HookEvent = "post_artifacts_publish" HookEventPreBuildFail HookEvent = "pre_build_fail" HookEventPostBuild HookEvent = "post_build" // HookEventInstallVerify is emitted by wfctl plugin install after tarball // download and before extraction. The supply-chain plugin registers a handler // that verifies cosign signatures, SBOM presence, and OSV vulnerability policy. HookEventInstallVerify HookEvent = "install_verify" )
func AllHookEvents ¶ added in v0.18.0
func AllHookEvents() []HookEvent
AllHookEvents returns all defined hook event constants.
type HookPayload ¶ added in v0.18.0
type HookPayload struct {
Event HookEvent `json:"event"`
Plugin string `json:"plugin"`
BuildID string `json:"build_id"`
Timestamp int64 `json:"timestamp"`
Data map[string]any `json:"data,omitempty"`
}
HookPayload is the JSON envelope passed to a plugin hook handler on stdin. Plugins decode this and then further decode Data into the event-specific struct.
type IaCCapabilityDeclaration ¶ added in v0.3.53
type IaCCapabilityDeclaration struct {
ResourceType string `json:"resource_type"` // infra.database, infra.vpc, etc.
Tier int `json:"tier"` // 1=infra, 2=shared, 3=app
Operations []string `json:"operations"` // create, read, update, delete, scale
}
IaCCapabilityDeclaration describes a resource type supported by a provider.
type IaCLockHandle ¶ added in v0.3.53
IaCLockHandle is returned by IaCStateStore.Lock and is used to release the lock.
type IaCPlan ¶ added in v0.3.53
type IaCPlan struct {
ID string `json:"id"`
Actions []PlanAction `json:"actions"`
CreatedAt time.Time `json:"created_at"`
// DesiredHash is a SHA-256 hex digest of the canonical desired-state inputs
// (sorted ResourceSpecs) at the time the plan was generated. wfctl infra apply
// --plan compares this against the current config to detect stale plans.
DesiredHash string `json:"plan_hash,omitempty"`
// Include records the sorted resource names passed through
// `wfctl infra plan --include`. Empty means the plan covered the full
// desired set. wfctl infra apply --plan uses this to recompute DesiredHash
// against the same scope without requiring --include at apply time.
Include []string `json:"include,omitempty"`
// SchemaVersion is bumped when on-disk plan format changes (W-5 sets to 2 when JIT is required).
SchemaVersion int `json:"schema_version,omitempty"`
// InputSnapshot records env var names read during ${VAR} substitution at
// plan time, fingerprinting only those that were SET (16-hex-char sha256
// prefix of the value). Unset vars are omitted from the map; their absence
// at apply time is therefore not flagged as drift. Apply re-computes inputs
// and prints diagnostic on mismatch.
//
// Completeness caveat: the cmd/wfctl scanner that populates this map
// (cmd/wfctl/infra_inputsnapshot.go::collectInfraEnvVarRefs) currently
// walks each module's own Config but does not apply top-level
// environments[env].envVars defaults. Vars that originate solely from a
// top-level envVars default may therefore be absent from the snapshot;
// closing this gap is tracked as a follow-up to W-1.
InputSnapshot map[string]string `json:"input_snapshot,omitempty"`
// GeneratorMetadata records the wfctl version and installed IaC plugin
// versions present when this plan was produced. Populated when the plan
// is serialised to disk (wfctl infra plan -o). Consumers can inspect
// this to assess whether upgrades are needed before re-applying a stored
// plan.
GeneratorMetadata *GeneratorMetadata `json:"generator_metadata,omitempty"`
}
IaCPlan is the complete execution plan for a set of infrastructure changes.
type IaCProvider ¶ added in v0.3.52
type IaCProvider interface {
Name() string
Version() string
Initialize(ctx context.Context, config map[string]any) error
// Capabilities returns what resource types this provider supports.
Capabilities() []IaCCapabilityDeclaration
// Lifecycle
Plan(ctx context.Context, desired []ResourceSpec, current []ResourceState) (*IaCPlan, error)
// Apply was removed per workflow#699 (2026-05-17). v2 dispatch
// routes through wfctlhelpers.ApplyPlanWithHooks (ResourceDriver
// per-action + IaCProviderFinalizer.FinalizeApply post-loop). The
// load-time Capabilities-RPC gate in cmd/wfctl/deploy_providers.go
// rejects plugins whose CapabilitiesResponse.compute_plan_version
// is not "v2".
Destroy(ctx context.Context, resources []ResourceRef) (*DestroyResult, error)
// Observability
Status(ctx context.Context, resources []ResourceRef) ([]ResourceStatus, error)
DetectDrift(ctx context.Context, resources []ResourceRef) ([]DriftResult, error)
// Migration
Import(ctx context.Context, cloudID string, resourceType string) (*ResourceState, error)
// Sizing
ResolveSizing(resourceType string, size Size, hints *ResourceHints) (*ProviderSizing, error)
// Resource drivers for fine-grained CRUD
ResourceDriver(resourceType string) (ResourceDriver, error)
// SupportedCanonicalKeys returns the subset of canonical IaC config keys
// that this provider understands. Providers may return a subset; callers
// use this to warn on unrecognised fields before applying a plan.
// Built-in and stub providers return the full canonical key set.
SupportedCanonicalKeys() []string
// BootstrapStateBackend ensures the state backend resource (bucket/container)
// exists on this provider. It is idempotent: if the resource already exists,
// it returns the current metadata without error. cfg is the expanded
// iac.state module config (backend, bucket, region, credentials, etc.).
//
// Providers that do not manage a state backend should return (nil, nil).
// The caller prints each entry in result.EnvVars as `export KEY=VALUE` for
// CI capture and writes result.Bucket back to the on-disk config.
BootstrapStateBackend(ctx context.Context, cfg map[string]any) (*BootstrapResult, error)
Close() error
}
IaCProvider is the main interface that cloud provider plugins implement. Each provider (AWS, GCP, Azure, DO) implements this as a gRPC plugin.
type IaCStateStore ¶ added in v0.3.52
type IaCStateStore interface {
SaveResource(ctx context.Context, state ResourceState) error
GetResource(ctx context.Context, name string) (*ResourceState, error)
ListResources(ctx context.Context) ([]ResourceState, error)
DeleteResource(ctx context.Context, name string) error
SavePlan(ctx context.Context, plan IaCPlan) error
GetPlan(ctx context.Context, id string) (*IaCPlan, error)
Lock(ctx context.Context, resource string, ttl time.Duration) (IaCLockHandle, error)
Close() error
}
IaCStateStore provides persistent state tracking for managed resources.
type IngressRule ¶ added in v0.18.0
type IngressRule struct {
Match string `json:"match" yaml:"match"` // path prefix or header expression
Component string `json:"component" yaml:"component"` // target service/worker name
}
IngressRule maps an HTTP match to a backend component.
type IngressSpec ¶ added in v0.18.0
type IngressSpec struct {
LoadBalancer string `json:"load_balancer,omitempty" yaml:"load_balancer,omitempty"` // e.g. round_robin | least_connections
Rules []IngressRule `json:"rules,omitempty" yaml:"rules,omitempty"`
}
IngressSpec controls inbound traffic routing.
type InstallVerifyPayload ¶ added in v0.18.0
type InstallVerifyPayload struct {
TarballPath string `json:"tarball_path"`
ExpectedSignatureIdentity string `json:"expected_signature_identity,omitempty"`
ExpectedSBOMHash string `json:"expected_sbom_hash,omitempty"`
VulnPolicy string `json:"vuln_policy,omitempty"` // block-critical | warn | off
}
InstallVerifyPayload is the Data payload for HookEventInstallVerify. The supply-chain plugin handler verifies the tarball's cosign signature, SBOM presence, and OSV vulnerability scan per the declared policy.
type JobSpec ¶ added in v0.18.0
type JobSpec struct {
Name string `json:"name" yaml:"name"`
Kind string `json:"kind" yaml:"kind"`
Image string `json:"image,omitempty" yaml:"image,omitempty"`
RunCommand string `json:"run_command" yaml:"run_command"`
EnvVars map[string]string `json:"env_vars,omitempty" yaml:"env_vars,omitempty"`
EnvVarsSecret map[string]string `json:"env_vars_secret,omitempty" yaml:"env_vars_secret,omitempty"`
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"` // non-empty for SCHEDULED kind
Termination *TerminationSpec `json:"termination,omitempty" yaml:"termination,omitempty"`
Alerts []AlertSpec `json:"alerts,omitempty" yaml:"alerts,omitempty"`
LogDestinations []LogDestinationSpec `json:"log_destinations,omitempty" yaml:"log_destinations,omitempty"`
}
JobSpec describes a one-off or scheduled job workload. Kind is one of: PRE_DEPLOY, POST_DEPLOY, FAILED_DEPLOY, SCHEDULED.
type LogDestinationSpec ¶ added in v0.18.0
type LogDestinationSpec struct {
Name string `json:"name" yaml:"name"`
Endpoint string `json:"endpoint" yaml:"endpoint"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
TLS bool `json:"tls" yaml:"tls"`
}
LogDestinationSpec forwards logs to an external system.
type MaintenanceSpec ¶ added in v0.18.0
type MaintenanceSpec struct {
Window string `json:"window" yaml:"window"` // e.g. "Sun 03:00-05:00 UTC"
Enabled bool `json:"enabled" yaml:"enabled"`
}
MaintenanceSpec defines a recurring maintenance window.
type MetricsRecorder ¶
type MetricsRecorder interface {
RecordWorkflowExecution(workflowType, action, status string)
RecordWorkflowDuration(workflowType, action string, duration time.Duration)
}
MetricsRecorder records workflow execution metrics. *module.MetricsCollector satisfies this interface. All methods must be safe to call when no metrics backend is configured (no-ops).
type MigrationDriver ¶ added in v0.18.0
type MigrationDriver interface {
Name() string
Up(ctx context.Context, req MigrationRequest) (MigrationResult, error)
Down(ctx context.Context, req MigrationRequest) (MigrationResult, error)
Status(ctx context.Context, req MigrationRequest) (MigrationStatus, error)
Goto(ctx context.Context, req MigrationRequest, target string) (MigrationResult, error)
}
MigrationDriver is the interface that migration backend plugins implement. Implementations live in workflow-plugin-migrations (golang-migrate, goose, atlas).
type MigrationOptions ¶ added in v0.18.0
MigrationOptions controls migration behaviour.
type MigrationProvider ¶ added in v0.18.0
type MigrationProvider interface {
// ProvidesMigrations returns an fs.FS rooted at the migrations directory.
// The FS must contain SQL files named in the golang-migrate convention:
// <version>_<description>.up.sql and <version>_<description>.down.sql.
ProvidesMigrations() (fs.FS, error)
// MigrationsDependencies returns the names of other MigrationProvider
// modules whose migrations must be applied before this module's.
// For example, the authz module might return ["workflow.tenants"].
// Returning nil or an empty slice means no dependencies.
MigrationsDependencies() []string
}
MigrationProvider is optionally implemented by modules that embed their own SQL migration files (e.g., the tenants module, authz module).
The workflow-plugin-migrations runner walks all registered modules in the modular service registry, calls ProvidesMigrations on those that implement this interface, collects the returned filesystems, orders them by declared dependency, and applies them before the application's own migrations.
type MigrationRepairRequest ¶ added in v0.19.0
type MigrationRepairRequest struct {
AppResourceName string `json:"app_resource_name"`
DatabaseResourceName string `json:"database_resource_name"`
JobImage string `json:"job_image"`
SourceDir string `json:"source_dir"`
ExpectedDirtyVersion string `json:"expected_dirty_version"`
ForceVersion string `json:"force_version"`
ThenUp bool `json:"then_up"`
UpIfClean bool `json:"up_if_clean"`
ConfirmForce string `json:"confirm_force"`
Env map[string]string `json:"env,omitempty"`
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
}
func (MigrationRepairRequest) Validate ¶ added in v0.19.0
func (r MigrationRepairRequest) Validate() error
type MigrationRepairResult ¶ added in v0.19.0
type MigrationRepairResult struct {
ProviderJobID string `json:"provider_job_id,omitempty"`
Status string `json:"status"`
Applied []string `json:"applied,omitempty"`
Logs string `json:"logs,omitempty"`
Diagnostics []Diagnostic `json:"diagnostics,omitempty"`
}
type MigrationRequest ¶ added in v0.18.0
type MigrationRequest struct {
DSN string
Source MigrationSource
Options MigrationOptions
}
MigrationRequest holds all parameters needed to run a migration operation.
func (MigrationRequest) Validate ¶ added in v0.18.0
func (r MigrationRequest) Validate() error
Validate returns ErrValidation if required fields are missing.
type MigrationResult ¶ added in v0.18.0
MigrationResult is returned after a successful migration operation.
type MigrationSource ¶ added in v0.18.0
MigrationSource describes where migration files come from.
type MigrationStatus ¶ added in v0.18.0
MigrationStatus describes the current migration state of a database.
type PipelineContext ¶ added in v0.3.39
type PipelineContext struct {
// TriggerData is the original data from the trigger (immutable after creation).
TriggerData map[string]any
// StepOutputs maps step-name -> output from each completed step.
StepOutputs map[string]map[string]any
// Current is the merged state: trigger data + all step outputs.
// Steps read from Current and their output is merged back into it.
Current map[string]any
// Metadata holds execution metadata (pipeline name, trace ID, etc.)
Metadata map[string]any
// StrictTemplates causes template execution to return an error instead of
// the zero value when a template expression references a missing map key.
// When false (the default), missing keys resolve to the zero value with a
// warning logged via Logger. Enable via pipeline config: strict_templates: true.
StrictTemplates bool
// Logger is used to emit warnings when a template expression resolves a
// missing key to the zero value (non-strict mode). When nil, slog.Default()
// is used.
Logger *slog.Logger
}
PipelineContext carries data through a pipeline execution.
func NewPipelineContext ¶ added in v0.3.39
func NewPipelineContext(triggerData map[string]any, metadata map[string]any) *PipelineContext
NewPipelineContext creates a PipelineContext initialized with trigger data.
func (*PipelineContext) MergeStepOutput ¶ added in v0.3.39
func (pc *PipelineContext) MergeStepOutput(stepName string, output map[string]any)
MergeStepOutput records a step's output and merges it into Current.
type PipelineExecutor ¶ added in v0.3.51
type PipelineExecutor interface {
// ExecutePipeline runs a named pipeline synchronously and returns its
// structured output. Returns _pipeline_output if set by
// step.pipeline_output, otherwise the pipeline's merged Current state.
ExecutePipeline(ctx context.Context, name string, data map[string]any) (map[string]any, error)
}
PipelineExecutor provides direct pipeline invocation for Go callers (gRPC servers, tests, etc.) without HTTP serialization overhead. *workflow.StdEngine satisfies this interface.
type PipelineRunner ¶
type PipelineRunner interface {
// Run executes the pipeline with the given trigger data and returns the
// merged result map (equivalent to PipelineContext.Current).
Run(ctx context.Context, data map[string]any) (map[string]any, error)
// SetLogger sets the logger used for pipeline execution.
// Implementations should be idempotent: if a logger is already set,
// a subsequent call should be a no-op.
SetLogger(logger *slog.Logger)
// SetEventRecorder sets the recorder used for pipeline execution events.
// Implementations should be idempotent: if a recorder is already set,
// a subsequent call should be a no-op.
SetEventRecorder(recorder EventRecorder)
}
PipelineRunner is the interface satisfied by *module.Pipeline. It allows workflow handlers to execute pipelines without importing the concrete module types, enabling handler unit tests with mocks.
type PipelineStep ¶ added in v0.3.39
type PipelineStep interface {
// Name returns the step's unique name within the pipeline.
Name() string
// Execute runs the step with the pipeline context.
Execute(ctx context.Context, pc *PipelineContext) (*StepResult, error)
}
PipelineStep is a single composable unit of work in a pipeline.
type PlanAction ¶ added in v0.3.52
type PlanAction struct {
Action string `json:"action"` // create, update, replace, delete
Resource ResourceSpec `json:"resource"`
Current *ResourceState `json:"current,omitempty"`
Changes []FieldChange `json:"changes,omitempty"`
// ResolvedConfigHash is the SHA-256 of POST-substitution Resource.Config,
// computed via platform.ConfigHash. Encoded as lower-case hex (no
// "sha256:" prefix); empty string when the config map is empty
// (platform.ConfigHash short-circuit). The field uses `omitempty`, so the
// empty-string case is ABSENT from plan.json — consumers should treat
// "key missing" and "value == empty string" as the same condition.
//
// Currently populated by ComputePlan and persisted in plan.json so apply
// has the per-action hash available; the apply-time consumer that surfaces
// a per-resource diagnostic on mismatch is wired in a follow-up PR (W-3a/
// T3.1.5). Until then the field is observable via plan.json inspection but
// not yet enforced at apply.
ResolvedConfigHash string `json:"resolved_config_hash,omitempty"`
}
PlanAction is a single planned change within an IaCPlan.
type PlanDiagnostic ¶ added in v0.21.0
type PlanDiagnostic struct {
// Severity is Error|Warning|Info; see PlanDiagnosticSeverity.
Severity PlanDiagnosticSeverity `json:"severity"`
// Resource is the offending resource name; empty for plan-level findings.
Resource string `json:"resource,omitempty"`
// Field is a dotted/bracketed field path within Resource (e.g. "vpc_ref"
// or "tags[0].key"); empty for resource-level findings.
Field string `json:"field,omitempty"`
// Message is a human-readable description of the finding.
Message string `json:"message"`
}
PlanDiagnostic is a single finding emitted by a ProviderValidator implementation against an IaCPlan. PlanDiagnostics surface cross-resource constraints (e.g. a database referencing an unknown VPC) at plan time rather than at the provider's API call.
type PlanDiagnosticSeverity ¶ added in v0.21.0
type PlanDiagnosticSeverity int
PlanDiagnosticSeverity classifies the severity of a plan-validation PlanDiagnostic returned by a provider that implements ProviderValidator. Exit-code mapping for `wfctl infra align`:
- PlanDiagnosticError → always fails the run (regardless of --strict).
- PlanDiagnosticWarning → advisory by default; fails the run under --strict.
- PlanDiagnosticInfo → never affects the exit code (even under --strict).
Note: distinct from the unrelated Troubleshooter Diagnostic type (iac_resource_driver.go), which describes runtime/deploy events. The plan spec for T4.1 originally proposed `Diagnostic` for the plan-validation type; renamed to PlanDiagnostic to remain purely additive (W-4 contract) without disturbing existing Troubleshooter consumers.
const ( // PlanDiagnosticInfo is purely informational — surfaced to the user but // never fails an align run. PlanDiagnosticInfo PlanDiagnosticSeverity = iota // PlanDiagnosticWarning flags a likely-misconfiguration that does not // block apply but should be reviewed (advisory under --strict). PlanDiagnosticWarning // PlanDiagnosticError indicates a constraint violation that the provider // would reject at apply time. Fails an align run under --strict. PlanDiagnosticError )
type PluginVersionInfo ¶ added in v0.51.2
type PluginVersionInfo struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
}
PluginVersionInfo captures the name and version of an installed IaC provider plugin found in the plugin directory at the time an IaC plan or apply was run.
type PortSpec ¶ added in v0.18.0
type PortSpec struct {
Name string `json:"name" yaml:"name"`
Port int `json:"port" yaml:"port"`
Protocol string `json:"protocol" yaml:"protocol"` // http | tcp | udp
Public bool `json:"public" yaml:"public"`
}
PortSpec describes a named port exposed by a service or sidecar.
type PostArtifactsPublishPayload ¶ added in v0.18.0
type PostArtifactsPublishPayload struct {
Assets []ArtifactEntry `json:"assets"`
DurationMs int64 `json:"duration_ms"`
}
type PostBuildPayload ¶ added in v0.18.0
type PostBuildPayload struct {
Targets []string `json:"targets"`
Success bool `json:"success"`
DurationMs int64 `json:"duration_ms"`
}
PostBuildPayload is the final build summary.
type PostContainerBuildPayload ¶ added in v0.18.0
type PostContainerBuildPayload struct {
Target string `json:"target"`
ImageRef string `json:"image_ref"`
Digest string `json:"digest"`
DurationMs int64 `json:"duration_ms"`
}
PostContainerBuildPayload carries the built image digest.
type PostContainerPushPayload ¶ added in v0.18.0
type PostTargetBuildPayload ¶ added in v0.18.0
type PreArtifactsPublishPayload ¶ added in v0.18.0
type PreArtifactsPublishPayload struct {
Assets []string `json:"assets"`
}
PreArtifactsPublishPayload / PostArtifactsPublishPayload describe asset publishing.
type PreBuildFailPayload ¶ added in v0.18.0
type PreBuildFailPayload struct {
Error string `json:"error"`
Target string `json:"target,omitempty"`
}
PreBuildFailPayload carries the error that caused the build to fail.
type PreBuildPayload ¶ added in v0.18.0
type PreBuildPayload struct {
ConfigPath string `json:"config_path"`
Targets []string `json:"targets"`
}
PreBuildPayload is the Data payload for HookEventPreBuild.
type PreContainerBuildPayload ¶ added in v0.18.0
type PreContainerBuildPayload struct {
Target string `json:"target"`
DockerfilePath string `json:"dockerfile_path"`
ContextPath string `json:"context_path"`
Tags []string `json:"tags"`
}
PreContainerBuildPayload carries Dockerfile + context for a container build start.
type PreContainerPushPayload ¶ added in v0.18.0
type PreContainerPushPayload struct {
ImageRef string `json:"image_ref"`
Registries []string `json:"registries"`
}
PreContainerPushPayload / PostContainerPushPayload describe registry push.
type PreTargetBuildPayload ¶ added in v0.18.0
PreTargetBuildPayload / PostTargetBuildPayload carry per-target context.
type ProviderCredentialRevoker ¶ added in v0.22.5
type ProviderCredentialRevoker interface {
RevokeProviderCredential(ctx context.Context, source string, credentialID string) error
}
ProviderCredentialRevoker is an OPTIONAL interface a provider MAY implement to support revoking previously-issued provider_credential credentials. Used by `wfctl infra bootstrap --force-rotate <name>` to invalidate the OLD credential at the upstream provider AFTER the new one has been minted and stored (mint-new-then-revoke-old ordering; see ADR 0012).
source is the provider_credential source string (e.g. "digitalocean.spaces"). credentialID is the provider-specific identifier of the OLD credential (e.g. the access_key for DO Spaces — stored as <name>_access_key).
Callers MUST type-assert before calling and treat the negative case as a "log warning, not implemented" path — providers that do not implement this interface are valid; revocation just does not happen automatically.
Error contract:
- nil → successfully revoked (or credential was already absent)
- non-nil → revocation failed; caller logs warning + emits telemetry but MUST NOT roll back the newly-stored credential (the new key is valid)
type ProviderIDFormat ¶ added in v0.18.11
type ProviderIDFormat int
ProviderIDFormat identifies the shape of provider-specific resource identifiers so wfctl can validate them at the driver boundary without knowing provider-specific semantics.
The zero value IDFormatUnknown disables validation for backward compatibility — drivers that don't opt in get today's behavior.
const ( // IDFormatUnknown disables validation (zero value). IDFormatUnknown ProviderIDFormat = iota // IDFormatUUID is the canonical 36-character hyphenated UUID shape. IDFormatUUID // IDFormatDomainName is an RFC 1035 domain name. IDFormatDomainName // IDFormatARN is an AWS-style colon-separated ARN. IDFormatARN // IDFormatFreeform allows any non-empty string. IDFormatFreeform )
func (ProviderIDFormat) String ¶ added in v0.18.11
func (f ProviderIDFormat) String() string
String returns a stable identifier for logs and error messages.
type ProviderIDValidator ¶ added in v0.18.11
type ProviderIDValidator interface {
ProviderIDFormat() ProviderIDFormat
}
ProviderIDValidator is an optional interface ResourceDriver implementations may provide to declare the shape of their ProviderIDs. wfctl uses the declaration to validate ProviderIDs at two boundaries:
- Input: before Update/Delete, probe ref.ProviderID against the declared format. On mismatch, wfctl logs a warning but still calls the driver so its own heal logic (if any) can run.
- Output: after Apply, probe r.ProviderID before persisting to state. Mismatch for non-Unknown formats is a HARD failure — the driver has a bug and state must not be corrupted. Freeform accepts any non-empty ProviderID; Unknown disables output validation.
Drivers that do not implement this interface receive today's behavior: no validation, no warning, no failure.
type ProviderMigrationRepairer ¶ added in v0.19.0
type ProviderMigrationRepairer interface {
RepairDirtyMigration(ctx context.Context, req MigrationRepairRequest) (*MigrationRepairResult, error)
}
type ProviderPlanner ¶ added in v0.21.0
type ProviderPlanner interface {
PlanV2(ctx context.Context, desired []ResourceSpec, current []ResourceState) (IaCPlan, error)
}
ProviderPlanner is an optional interface for v2 plugins that need custom plan logic (replacing platform.ComputePlan's default driver.Diff dispatch).
Reserved as an extension hook for Tofu/Pulumi-style adapter plugins. Core wfctl's platform.ComputePlan + wfctlhelpers.ApplyPlan do NOT type-assert against this interface in v0.21.0 — adapter PRs that wish to use it will add the type-assertion at the dispatch site in their own design discussion.
Plugins implementing this interface are accepted by the loader; the implementation is not yet exercised by core code.
type ProviderSizing ¶ added in v0.3.52
type ProviderSizing struct {
InstanceType string `json:"instance_type"`
Specs map[string]any `json:"specs"`
}
ProviderSizing is the concrete sizing resolved by a provider for a resource type.
type ProviderValidator ¶ added in v0.21.0
type ProviderValidator interface {
ValidatePlan(plan *IaCPlan) []PlanDiagnostic
}
ProviderValidator is an OPTIONAL interface that an IaCProvider implementation MAY also satisfy to expose provider-side cross-resource constraint validation at plan time. Consumers (e.g. R-A10 in cmd/wfctl/infra_align*.go) use a type-assertion to discover whether a given provider implements ValidatePlan; providers that do not implement it continue to work unchanged.
ValidatePlan is read-only: it MUST NOT mutate plan and MUST NOT make remote calls. The returned slice may be nil (no diagnostics).
type Reconfigurable ¶ added in v0.2.20
type Reconfigurable interface {
// Reconfigure applies new configuration to a running module.
// The module should:
// 1. Validate the new config
// 2. Gracefully drain in-flight work
// 3. Apply the new configuration
// 4. Resume accepting new work
// Returns an error if the new config is invalid or cannot be applied.
Reconfigure(ctx context.Context, newConfig map[string]any) error
}
Reconfigurable is optionally implemented by modules that support runtime reconfiguration without requiring a full engine restart. When a config change affects only modules implementing this interface, the engine can perform a surgical update instead of a full stop/rebuild/start.
type ResourceAdoptionLocator ¶ added in v0.18.14
type ResourceAdoptionLocator interface {
AdoptionRef(spec ResourceSpec) (ResourceRef, bool, error)
}
ResourceAdoptionLocator is an optional interface ResourceDriver implementations may provide when a desired ResourceSpec can be resolved to a live provider resource before local state exists. wfctl infra apply uses this to adopt existing resources into state and then computes an update/delete plan from real current state instead of blindly creating duplicates.
type ResourceDriver ¶ added in v0.3.52
type ResourceDriver interface {
Create(ctx context.Context, spec ResourceSpec) (*ResourceOutput, error)
Read(ctx context.Context, ref ResourceRef) (*ResourceOutput, error)
Update(ctx context.Context, ref ResourceRef, spec ResourceSpec) (*ResourceOutput, error)
Delete(ctx context.Context, ref ResourceRef) error
Diff(ctx context.Context, desired ResourceSpec, current *ResourceOutput) (*DiffResult, error)
HealthCheck(ctx context.Context, ref ResourceRef) (*HealthResult, error)
Scale(ctx context.Context, ref ResourceRef, replicas int) (*ResourceOutput, error)
// SensitiveKeys returns output keys whose values should be masked in logs and plan output.
SensitiveKeys() []string
}
ResourceDriver handles CRUD for a single resource type within a provider.
type ResourceHints ¶ added in v0.3.52
type ResourceHints struct {
CPU string `json:"cpu,omitempty" yaml:"cpu,omitempty"`
Memory string `json:"memory,omitempty" yaml:"memory,omitempty"`
Storage string `json:"storage,omitempty" yaml:"storage,omitempty"`
}
ResourceHints are optional fine-grained overrides on top of the Size tier.
type ResourceOutput ¶ added in v0.3.52
type ResourceOutput struct {
Name string `json:"name"`
Type string `json:"type"`
ProviderID string `json:"provider_id"`
Outputs map[string]any `json:"outputs"` // IPs, endpoints, connection strings
Sensitive map[string]bool `json:"sensitive,omitempty"` // keys whose values are sensitive
Status string `json:"status"`
}
ResourceOutput is the concrete output of a provisioned or read resource.
type ResourceRef ¶ added in v0.3.52
type ResourceRef struct {
Name string `json:"name"`
Type string `json:"type"`
ProviderID string `json:"provider_id,omitempty"`
}
ResourceRef is a lightweight reference to an existing resource.
type ResourceReplacer ¶ added in v0.23.0
type ResourceReplacer interface {
Replace(ctx context.Context, oldRef ResourceRef, spec ResourceSpec) (*ResourceOutput, error)
}
ResourceReplacer is an optional interface ResourceDriver implementations may provide when a resource's Replace transition needs more than naive Delete-then-Create — typically because the resource owns single-attach dependents (e.g., a DO Droplet with Block Storage Volumes, an AWS EC2 instance with EBS Volumes, a GCP VM with persistent disks) that the cloud refuses to associate with a new parent until the old parent releases them.
wfctlhelpers.doReplace probes for this interface; on opt-in, the driver receives the OLD ref and the NEW spec and is responsible for the full transition. On non-opt-in, doReplace calls wfctlhelpers.DefaultReplace (the existing Delete-then-Create logic, exported for direct dispatch).
Drivers SHOULD NOT implement this interface unless the resource has orchestration needs the engine cannot satisfy generically — naive Delete-then-Create is correct for the majority of cloud resources and is the default for a reason (atomicity, error attribution).
A driver that opts in but wants engine-default behavior for a particular spec calls wfctlhelpers.DefaultReplace directly. The engine never inspects the returned error to decide between paths, so there is no sentinel-error round-trip.
Error attribution: drivers MUST wrap their sub-step errors with a recognizable prefix (e.g., "<resource-type> replace %q: detach volume %q: %w"). Non-conforming returns are wrapped by the engine with "replace: driver: " at the dispatch boundary so operator attribution is preserved at runtime regardless of per-plugin discipline.
type ResourceSpec ¶ added in v0.3.52
type ResourceSpec struct {
Name string `json:"name"`
Type string `json:"type"`
Config map[string]any `json:"config"`
Size Size `json:"size,omitempty"`
Hints *ResourceHints `json:"hints,omitempty"`
DependsOn []string `json:"depends_on,omitempty"`
}
ResourceSpec is the desired state declaration for a single resource.
type ResourceState ¶ added in v0.3.52
type ResourceState struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Provider string `json:"provider"`
ProviderRef string `json:"provider_ref,omitempty"`
ProviderID string `json:"provider_id"`
ConfigHash string `json:"config_hash"`
AppliedConfig map[string]any `json:"applied_config"`
// AppliedConfigSource records the provenance of AppliedConfig:
// - "apply": AppliedConfig came from a user-supplied ResourceSpec.Config
// (set by applyWithProviderAndStore / applyPrecomputedPlanWithStore).
// - "adoption": AppliedConfig was reflowed from live cloud Outputs
// (set by adoptExistingResources). Comparing such entries against
// a fresh Read produces false-positive config-drift; consumers MUST
// refuse to compute config-drift on adoption-shaped entries.
// - "" (empty): legacy state written before this field existed.
// Consumers MUST treat as "adoption" (conservative default).
AppliedConfigSource string `json:"applied_config_source,omitempty"`
Outputs map[string]any `json:"outputs"`
Dependencies []string `json:"dependencies"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastDriftCheck time.Time `json:"last_drift_check,omitempty"`
}
ResourceState is the persisted state record for a single managed resource.
type ResourceStatus ¶ added in v0.3.52
type ResourceStatus struct {
Name string `json:"name"`
Type string `json:"type"`
ProviderID string `json:"provider_id"`
Status string `json:"status"` // running, stopped, degraded, unknown
Outputs map[string]any `json:"outputs"`
}
ResourceStatus is the live status of a provisioned resource.
type RouteSpec ¶ added in v0.18.0
type RouteSpec struct {
Path string `json:"path" yaml:"path"`
PreservePathPrefix bool `json:"preserve_path_prefix" yaml:"preserve_path_prefix"`
}
RouteSpec maps an HTTP path prefix to this service.
type SchemaRegistrar ¶
type SchemaRegistrar interface {
// Name returns the module name (used for logging).
Name() string
// RegisterAdminSchemas registers all admin API request/response schemas
// onto this generator. Equivalent to calling module.RegisterAdminSchemas(gen).
RegisterAdminSchemas()
// ApplySchemas applies all previously registered component schemas and
// operation schema overrides to the current OpenAPI spec.
ApplySchemas()
}
SchemaRegistrar is implemented by any service that can register admin schemas into an OpenAPI specification and apply them. Using this interface in cmd/server allows the server to enrich the OpenAPI spec without holding a concrete *module.OpenAPIGenerator pointer.
*module.OpenAPIGenerator satisfies this interface.
type Selector ¶ added in v0.18.0
Selector extracts a tenant lookup key from an HTTP request. Match returns the key, whether the selector matched, and any error.
type SidecarSpec ¶ added in v0.18.0
type SidecarSpec struct {
Name string `json:"name" yaml:"name"`
Image string `json:"image,omitempty" yaml:"image,omitempty"`
RunCommand string `json:"run_command" yaml:"run_command"`
EnvVars map[string]string `json:"env_vars,omitempty" yaml:"env_vars,omitempty"`
EnvVarsSecret map[string]string `json:"env_vars_secret,omitempty" yaml:"env_vars_secret,omitempty"`
Ports []PortSpec `json:"ports,omitempty" yaml:"ports,omitempty"`
Resources *WorkloadResourceSpec `json:"resources,omitempty" yaml:"resources,omitempty"`
HealthCheck *HealthCheckSpec `json:"health_check,omitempty" yaml:"health_check,omitempty"`
}
SidecarSpec describes a companion container that shares the network with the main service (e.g. Tailscale, Envoy).
type SizingDefaults ¶ added in v0.3.52
type SizingDefaults struct {
CPU string `json:"cpu"`
Memory string `json:"memory"`
DBStorage string `json:"db_storage"`
CacheMemory string `json:"cache_memory"`
}
SizingDefaults holds the concrete resource values for a given size tier.
type StaticSiteSpec ¶ added in v0.18.0
type StaticSiteSpec struct {
Name string `json:"name" yaml:"name"`
BuildCommand string `json:"build_command" yaml:"build_command"`
OutputDir string `json:"output_dir" yaml:"output_dir"`
EnvVars map[string]string `json:"env_vars,omitempty" yaml:"env_vars,omitempty"`
Routes []RouteSpec `json:"routes,omitempty" yaml:"routes,omitempty"`
CORS *CORSSpec `json:"cors,omitempty" yaml:"cors,omitempty"`
Domains []DomainSpec `json:"domains,omitempty" yaml:"domains,omitempty"`
Alerts []AlertSpec `json:"alerts,omitempty" yaml:"alerts,omitempty"`
}
StaticSiteSpec describes a statically-built web front-end.
type StepRegistrar ¶ added in v0.3.39
type StepRegistrar interface {
StepRegistryProvider
// Create instantiates a PipelineStep of the given type.
// app must be a modular.Application; it is typed as any to avoid
// coupling this interfaces package to the modular dependency.
Create(stepType, name string, config map[string]any, app any) (PipelineStep, error)
}
StepRegistrar manages step type registration and creation. It embeds StepRegistryProvider for type enumeration and adds a Create method for instantiating steps. Register is intentionally omitted from this interface because factory signatures use modular.Application (a concrete type) which cannot be expressed here without creating an import cycle.
type StepRegistryProvider ¶
type StepRegistryProvider interface {
// Types returns all registered step type names.
Types() []string
}
StepRegistryProvider exposes the step types registered in a step registry. *module.StepRegistry satisfies this interface.
type StepResult ¶ added in v0.3.39
type StepResult struct {
// Output is the data produced by this step.
Output map[string]any
// NextStep overrides the default next step (for conditional routing).
// Empty string means continue to the next step in sequence.
NextStep string
// Stop indicates the pipeline should stop after this step (success).
Stop bool
// Skipped indicates the step was bypassed by a guard (skip_if or if).
// When true, the pipeline executor will not record this step in StepOutputs.
Skipped bool
}
StepResult is the output of a single pipeline step execution.
type Tenant ¶ added in v0.18.0
type Tenant struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
Domains []string `json:"domains,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
IsActive bool `json:"is_active"`
}
Tenant represents an identified tenant in a multi-tenant system.
type TenantFilter ¶ added in v0.18.0
type TenantFilter struct {
ActiveOnly bool `json:"active_only,omitempty"`
Domain string `json:"domain,omitempty"`
Slug string `json:"slug,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
}
TenantFilter constrains the results of TenantRegistry.List. All zero-value fields are treated as "no constraint".
type TenantPatch ¶ added in v0.18.0
type TenantPatch struct {
Name *string `json:"name,omitempty"`
Domains []string `json:"domains,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
}
TenantPatch is a partial update payload; nil pointer fields are left unchanged.
type TenantRegistry ¶ added in v0.18.0
type TenantRegistry interface {
// Ensure creates the tenant if it does not exist, or returns the existing one.
Ensure(spec TenantSpec) (Tenant, error)
// GetByID looks up a tenant by its opaque ID.
GetByID(id string) (Tenant, error)
// GetByDomain looks up a tenant by one of its associated domains.
GetByDomain(domain string) (Tenant, error)
// GetBySlug looks up a tenant by its unique URL slug.
GetBySlug(slug string) (Tenant, error)
// List returns tenants matching the filter (all tenants if filter is zero).
List(filter TenantFilter) ([]Tenant, error)
// Update applies a partial patch to an existing tenant.
Update(id string, patch TenantPatch) (Tenant, error)
// Disable soft-deletes a tenant (sets IsActive=false).
Disable(id string) error
}
TenantRegistry persists and retrieves Tenant records.
type TenantResolver ¶ added in v0.18.0
type TenantResolver interface {
// Resolve returns the Tenant associated with the request.
// Returns the zero Tenant and no error when no tenant is found.
Resolve(ctx context.Context, r *http.Request) (Tenant, error)
}
TenantResolver resolves the tenant for an inbound request. Implementations combine one or more Selectors with a lookup strategy.
type TenantSpec ¶ added in v0.18.0
type TenantSpec struct {
Name string `json:"name"`
Slug string `json:"slug"`
Domains []string `json:"domains,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
TenantSpec is the creation payload for a Tenant.
func (TenantSpec) Validate ¶ added in v0.18.0
func (s TenantSpec) Validate() error
Validate checks that TenantSpec has the required fields and that the slug is well-formed. Slug must be non-empty and all-lowercase; mixed-case slugs are rejected to ensure consistent URL routing and cache key derivation.
type TerminationSpec ¶ added in v0.18.0
type TerminationSpec struct {
DrainSeconds int `json:"drain_seconds" yaml:"drain_seconds"`
GracePeriodSeconds int `json:"grace_period_seconds" yaml:"grace_period_seconds"`
}
TerminationSpec controls drain / graceful-shutdown behaviour.
type Trigger ¶
type Trigger interface {
modular.Module
modular.Startable
modular.Stoppable
// Configure sets up the trigger from configuration.
Configure(app modular.Application, triggerConfig any) error
}
Trigger defines what can start a workflow execution. Moving this interface here breaks the engine→module import dependency while preserving backward compatibility via the type alias in the module package.
*module.HTTPTrigger, *module.ScheduleTrigger, and other concrete trigger implementations all satisfy this interface.
type TriggerRegistrar ¶
type TriggerRegistrar interface {
// RegisterTrigger adds a trigger to the registry.
RegisterTrigger(trigger Trigger)
}
TriggerRegistrar manages registered triggers. *module.TriggerRegistry satisfies this interface.
type Troubleshooter ¶ added in v0.18.10
type Troubleshooter interface {
Troubleshoot(ctx context.Context, ref ResourceRef, failureMsg string) ([]Diagnostic, error)
}
Troubleshooter is an optional interface that ResourceDrivers may implement. wfctl calls Troubleshoot automatically when a health-check poll times out or a deploy operation returns a generic error, surfacing provider-side context that would otherwise require visiting the provider's web console.
Implementations should return the N most recent relevant events (deployments, job runs, etc.) in reverse-chronological order. Returning an error is non-fatal — wfctl logs it and continues with the original failure message.
type UpsertSupporter ¶ added in v0.21.0
type UpsertSupporter interface {
SupportsUpsert() bool
}
UpsertSupporter is an optional interface implemented by ResourceDrivers that support locating an existing resource by name alone (empty ProviderID) in their Read method. wfctlhelpers.ApplyPlan uses this hook to recover from Create that returns ErrResourceAlreadyExists: when the driver opts in via SupportsUpsert()==true, ApplyPlan calls Read with a name-only ResourceRef to obtain the existing ProviderID, then calls Update to bring the resource to the desired state — net effect of an idempotent upsert without requiring drivers to implement upsert natively.
Drivers that do not implement this interface (or return false) yield the original ErrResourceAlreadyExists unchanged — ApplyPlan does NOT silently swallow the conflict. Implementations should return true only when their Read can locate a resource by Name + Type without a ProviderID; returning true while requiring a non-empty ProviderID in Read defeats the recovery path.
type ValidationError ¶ added in v0.3.60
type ValidationError struct {
Message string
Status int // HTTP status code to use (e.g., 400, 422)
Field string // optional: which field was invalid
Code string // optional: machine-readable error code for clients
}
ValidationError indicates a step failed due to invalid user input, not an infrastructure error. HTTP handlers map this to a 4xx status code instead of the default 500 Internal Server Error.
func NewValidationError ¶ added in v0.3.60
func NewValidationError(msg string, status int) *ValidationError
NewValidationError creates a ValidationError with the given message and HTTP status code. Use status 400 for bad input, 422 for unprocessable entity, etc.
func (*ValidationError) Error ¶ added in v0.3.60
func (e *ValidationError) Error() string
type WorkerSpec ¶ added in v0.18.0
type WorkerSpec struct {
Name string `json:"name" yaml:"name"`
Image string `json:"image,omitempty" yaml:"image,omitempty"`
RunCommand string `json:"run_command" yaml:"run_command"`
EnvVars map[string]string `json:"env_vars,omitempty" yaml:"env_vars,omitempty"`
EnvVarsSecret map[string]string `json:"env_vars_secret,omitempty" yaml:"env_vars_secret,omitempty"`
InstanceCount int `json:"instance_count" yaml:"instance_count"`
Size string `json:"size,omitempty" yaml:"size,omitempty"`
Autoscaling *AutoscalingSpec `json:"autoscaling,omitempty" yaml:"autoscaling,omitempty"`
HealthCheck *HealthCheckSpec `json:"health_check,omitempty" yaml:"health_check,omitempty"`
Resources *WorkloadResourceSpec `json:"resources,omitempty" yaml:"resources,omitempty"`
Termination *TerminationSpec `json:"termination,omitempty" yaml:"termination,omitempty"`
Alerts []AlertSpec `json:"alerts,omitempty" yaml:"alerts,omitempty"`
LogDestinations []LogDestinationSpec `json:"log_destinations,omitempty" yaml:"log_destinations,omitempty"`
}
WorkerSpec describes a long-running background worker workload.
type WorkflowStoreProvider ¶
type WorkflowStoreProvider interface {
// Name returns the module name (used for logging).
Name() string
// WorkflowStore returns the underlying workflow data store as an opaque
// value. The caller is responsible for asserting the concrete type
// (typically *module.V1Store) when further operations are required.
WorkflowStore() any
}
WorkflowStoreProvider is implemented by any service that exposes a workflow data store. Using this interface in cmd/server decouples the server startup code from the concrete *module.WorkflowRegistry type.
*module.WorkflowRegistry satisfies this interface.
type WorkloadResourceSpec ¶ added in v0.18.0
type WorkloadResourceSpec struct {
CPUMillis int `json:"cpu_millis" yaml:"cpu_millis"` // 1000 = 1 vCPU
MemoryMiB int `json:"memory_mib" yaml:"memory_mib"`
CPULimit int `json:"cpu_limit" yaml:"cpu_limit"`
MemoryLimit int `json:"memory_limit" yaml:"memory_limit"`
}
WorkloadResourceSpec declares CPU and memory resource requests/limits for a workload. Named distinctly from interfaces.ResourceSpec which is used for IaC infrastructure resources.
Source Files
¶
- build_hooks.go
- events.go
- iac_canonical_keys.go
- iac_canonical_schema.go
- iac_canonical_types.go
- iac_provider.go
- iac_resource_driver.go
- iac_sizing.go
- iac_state.go
- idformat.go
- migration_driver.go
- migration_repair.go
- pipeline.go
- pipeline_executor.go
- provides_migrations.go
- reconfigurable.go
- registry.go
- tenant_registry.go
- tenant_resolver.go
- trigger.go