Documentation
¶
Overview ¶
Package inputsnapshot computes plan-time env-var fingerprints for the plan-stale diagnostic. Fingerprints are 16 hex chars (64 bits of preimage resistance); plan.json is treated as semi-sensitive and gitignored.
Index ¶
- Variables
- func Compute(varNames []string, lookup func(string) (string, bool)) map[string]string
- func ComputeDrift(planSnap, applySnap map[string]string) []interfaces.DriftEntry
- func FormatStaleError(drift []interfaces.DriftEntry) string
- func NewTolerantEnvProvider(planSnapshot map[string]string) func(name string) (string, bool)
- func OSEnvProvider(name string) (string, bool)
- func Snapshot(names []string, provider func(string) (string, bool)) map[string]string
- type StaleError
Constants ¶
This section is empty.
Variables ¶
var ErrEnvVarChanged = errors.New("env-var changed since plan")
ErrEnvVarChanged is the typed sentinel returned by the apply paths (cmd/wfctl/infra.go persisted-`--plan` path in W-1; wfctlhelpers.ApplyPlan in-process path in W-3a/T3.1.5) when an env var referenced at plan time has a different fingerprint at apply time. Callers match with errors.Is(err, ErrEnvVarChanged) to detect the plan-stale case programmatically. To avoid the sentinel's text appearing in user-facing output, callers SHOULD construct the user-visible error via NewStaleError(drift) — that returns a *StaleError whose Error() is exactly FormatStaleError(drift) and whose Unwrap() chain yields this sentinel for errors.Is.
Functions ¶
func Compute ¶
Compute returns a map of env-var name → 16-hex-char sha256 prefix of the value. Variables that aren't set (lookup returns ok=false) are omitted from the snapshot.
func ComputeDrift ¶
func ComputeDrift(planSnap, applySnap map[string]string) []interfaces.DriftEntry
ComputeDrift compares plan-time vs apply-time fingerprint snapshots and produces a drift report. Iterates over planSnap keys (no phantom InputNames field needed; map keys ARE the names). Honors the in-package preservedFingerprint sentinel from snapshot.go — keys whose applySnap value equals the sentinel are skipped (sub-action cleanup case).
Cross-function contract:
- Compute (snapshot.go) passes the sentinel through unhashed.
- NewTolerantEnvProvider (snapshot.go, sole sanctioned injector) returns the sentinel for plan-time-set apply-time-unset vars.
- ComputeDrift (this function) honors the sentinel by skipping the entry.
func FormatStaleError ¶
func FormatStaleError(drift []interfaces.DriftEntry) string
FormatStaleError renders a drift report into the canonical human-readable message used at every plan-stale call site (cmd/wfctl/infra.go persisted `--plan` path; wfctlhelpers.ApplyPlan in-process path in T3.1.5). Output:
plan stale: %d input(s) changed since plan KEY1: fingerprint planFP1 (plan) → applyFP1 (apply) KEY2: fingerprint planFP2 (plan) → applyFP2 (apply) hint: ensure all env vars referenced by your infra config are exported to both Plan and Apply steps
Drift entries are sorted by Name for deterministic output. An empty drift report yields the singular header line "plan stale: 0 input(s) changed since plan" with no trailing hint — callers should avoid invoking the formatter when no drift exists, but if they do the output stays minimal.
func NewTolerantEnvProvider ¶
NewTolerantEnvProvider returns an EnvProvider closure used by the in-process apply postcondition (T3.1.5). When a var was set at plan time (present in planSnapshot) but is now unset (sub-action cleanup), the closure returns the in-package preservedFingerprint sentinel so ComputeDrift suppresses the (false-positive) drift entry. For vars genuinely unset at both times, returns ("", false) → Compute drops the key from the resulting map.
This is the ONLY sanctioned way to inject the preservation sentinel. The sentinel constant is unexported, so external code cannot reference it by name; a determined caller could still return the literal string from a custom env-provider, but doing so is a deliberate discipline violation rather than a tooling bypass.
func OSEnvProvider ¶
OSEnvProvider is the canonical env-provider closure that reads from process env via os.LookupEnv. Used by start-of-apply InputSnapshot capture.
Types ¶
type StaleError ¶
type StaleError struct {
Drift []interfaces.DriftEntry
}
StaleError is the user-facing error returned by apply paths when env-var drift is detected. Its Error() is exactly FormatStaleError(drift) so the printed message is the canonical human diagnostic (no duplicated sentinel prefix); Unwrap() returns ErrEnvVarChanged so errors.Is works for programmatic detection.
func NewStaleError ¶
func NewStaleError(drift []interfaces.DriftEntry) *StaleError
NewStaleError constructs the canonical *StaleError for a non-empty drift report. Returns nil when drift is empty (caller should treat that as "no plan-stale condition" rather than wrapping a no-op error).
func (*StaleError) Error ¶
func (s *StaleError) Error() string
Error returns FormatStaleError(s.Drift) — the canonical human-readable per-key diagnostic with sorted entries and trailing hint.
func (*StaleError) Unwrap ¶
func (s *StaleError) Unwrap() error
Unwrap returns ErrEnvVarChanged so callers can use errors.Is(err, inputsnapshot.ErrEnvVarChanged) to detect the plan-stale case without coupling to the Error() text.