staging

package
v1.8.1 Latest Latest
Warning

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

Go to latest
Published: Jul 11, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package staging provides staging functionality for AWS parameter and secret changes.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotStaged is returned when a parameter/secret is not staged.
	ErrNotStaged = errors.New("not staged")
	// ErrStateVersionTooNew is returned by UnmarshalJSON when the on-disk staging
	// state was written by a newer suve than this build can read. The caller must
	// upgrade suve; the state is left untouched rather than rewritten as an older
	// version.
	ErrStateVersionTooNew = errors.New("staging state was written by a newer suve; upgrade suve")
	// ErrStateVersionTooOld is returned by UnmarshalJSON when the state was
	// written by an older suve whose on-disk layout this build does not migrate.
	// The state decodes as empty (its records are dropped), but the error makes
	// that drop explicit so an importer can report it instead of silently
	// importing nothing. The working store treats it as a benign reset.
	ErrStateVersionTooOld = errors.New("staging state was written by an older suve and cannot be read; its records were dropped")
	// ErrDuplicateRecord is returned by UnmarshalJSON when a payload carries two
	// records for the same (name, namespace). Silently keeping the last one would
	// hide the ambiguity, so the state is rejected instead.
	ErrDuplicateRecord = errors.New("duplicate staged record")
)
View Source
var ErrServiceNotConfigured = errors.New("staging service not configured")

ErrServiceNotConfigured is returned by a ScopeResolver when the active scope does not name this service's backing resource (e.g. no Azure Key Vault while only App Configuration is configured). A single-service command treats it as a fatal usage error (with the resolver's descriptive message); a provider-wide command treats it as "skip this service" — an unconfigured service can hold no staged state, since staging is keyed by the resource name.

Functions

func CheckConflicts

func CheckConflicts(ctx context.Context, resolve ApplyStrategyResolver, entries map[EntryKey]Entry) map[EntryKey]struct{}

CheckConflicts checks if remote resources were modified after staging. Returns the set of EntryKeys that have conflicts.

Each entry is probed through the strategy resolved for its own namespace, so the probe carries the full EntryKey (name + namespace) and never collapses two same-named entries across namespaces onto one namespace's remote state. For namespace-agnostic providers the resolver returns the single strategy and the empty namespace, so behavior is unchanged.

For Create operations: conflicts if resource now exists (someone else created it). For Update/Delete operations with BaseModifiedAt: conflicts if the remote was modified after base.

func CheckEntryAndTagConflicts added in v1.8.1

func CheckEntryAndTagConflicts(
	ctx context.Context,
	resolve ApplyStrategyResolver,
	entries map[EntryKey]Entry,
	tags map[EntryKey]TagEntry,
) map[EntryKey]struct{}

CheckEntryAndTagConflicts checks both staged value changes and staged tag changes for conflicts and returns the merged set of conflicting EntryKeys.

It fetches each remote's last-modified time at most once, even when the same key carries both a value change and a tag change: the two probes previously double-fetched the same remote, wasting I/O and widening the window in which the two timestamps could disagree on second-granular providers. The value and tag comparisons now share that single fetch.

func CheckTagConflicts added in v1.8.0

func CheckTagConflicts(ctx context.Context, resolve ApplyStrategyResolver, tags map[EntryKey]TagEntry) map[EntryKey]struct{}

CheckTagConflicts checks if the remote resource behind each staged tag change was modified after the tags were fetched. Returns the set of EntryKeys that have conflicts.

It mirrors the Update/Delete path of CheckConflicts using the tag's own TagEntry.BaseModifiedAt: if the remote's last-modified time is after that base time, someone changed the resource since the tags were staged and the apply is a conflict rather than a silent overwrite. Each tag change is probed through the strategy resolved for its own namespace (App Configuration); other providers resolve the single strategy under the empty namespace.

A tag change with no BaseModifiedAt cannot be checked and is never a conflict. A remote that no longer exists (zero time) is skipped too — the tag apply will fail on its own.

Types

type ApplyStrategy

type ApplyStrategy interface {
	ServiceStrategy

	// Apply applies a staged entry operation to AWS.
	// Handles OperationCreate, OperationUpdate, and OperationDelete based on entry.Operation.
	Apply(ctx context.Context, name string, entry Entry) error

	// ApplyTags applies staged tag changes to AWS.
	ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

	// FetchLastModified returns the last modified time of the resource in AWS.
	// It returns a *ResourceNotFoundError when the resource does not exist, so
	// callers can distinguish "missing" from "exists but has no modification
	// time" (the latter returns a zero time with a nil error). Providers that
	// disable conflict detection may always return a zero time with a nil error.
	FetchLastModified(ctx context.Context, name string) (time.Time, error)
}

ApplyStrategy defines service-specific apply operations.

type ApplyStrategyResolver added in v1.7.0

type ApplyStrategyResolver func(namespace string) (ApplyStrategy, error)

ApplyStrategyResolver resolves the ApplyStrategy for a given namespace. It mirrors the per-namespace resolution the apply path uses so a namespaced provider (Azure App Configuration) probes each entry against the remote state of its OWN namespace rather than the default one.

type AzureAppConfigParamStrategy added in v0.8.1

type AzureAppConfigParamStrategy struct {
	// contains filtered or unexported fields
}

AzureAppConfigParamStrategy implements the staging strategies for Azure App Configuration. App Configuration is UNVERSIONED, so:

  • Version specifiers (#VERSION, ~SHIFT, :LABEL) are rejected at parse time via azureappconfigversion.
  • Conflict detection is disabled (last-write-wins): FetchLastModified and the edit base time return zero, so apply never reports a modified-after conflict. Apply overwrites unconditionally.
  • Tag mutation is supported (azappconfig/v2 GET-merge-PUT + ETag): ApplyTags forwards TagEntry.Add/Remove to the store's Tag/Untag.

A nil store yields a parser-only strategy (ParseName/ParseSpec).

func NewAzureAppConfigParamStrategy added in v0.8.1

func NewAzureAppConfigParamStrategy(store provider.Store) *AzureAppConfigParamStrategy

NewAzureAppConfigParamStrategy creates an Azure App Configuration staging strategy over the given provider store. A nil store is allowed for parser-only use.

func (*AzureAppConfigParamStrategy) Apply added in v0.8.1

func (s *AzureAppConfigParamStrategy) Apply(ctx context.Context, name string, entry Entry) error

Apply applies a staged operation to Azure App Configuration.

func (*AzureAppConfigParamStrategy) ApplyTags added in v0.8.1

func (s *AzureAppConfigParamStrategy) ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

ApplyTags applies staged tag changes to App Configuration: TagEntry.Add via the store's Tag and TagEntry.Remove via Untag (each a GET-merge-PUT under the scope's namespace label). Additions are applied before removals.

func (*AzureAppConfigParamStrategy) FetchCurrent added in v0.8.1

func (s *AzureAppConfigParamStrategy) FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

FetchCurrent fetches the current value from App Configuration for diffing. App Configuration is unversioned, so the identifier is empty.

func (*AzureAppConfigParamStrategy) FetchCurrentTags added in v0.8.1

func (s *AzureAppConfigParamStrategy) FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)

FetchCurrentTags fetches the setting's current tags so stage diff can show the current value of a removed tag. A missing setting or a setting with no tags yields nil.

func (*AzureAppConfigParamStrategy) FetchCurrentValue added in v0.8.1

func (s *AzureAppConfigParamStrategy) FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)

FetchCurrentValue fetches the current value for editing. LastModified is left zero so the edit flow records no conflict base (last-write-wins).

func (*AzureAppConfigParamStrategy) FetchLastModified added in v0.8.1

func (s *AzureAppConfigParamStrategy) FetchLastModified(_ context.Context, _ string) (time.Time, error)

FetchLastModified returns a zero time with a nil error: App Configuration staging uses last-write-wins, so no modified-after conflict is ever reported. The nil error means the delete use case treats every setting as existing (never "not found"); apply is idempotent on a missing setting, so this is consistent with the last-write-wins model.

func (*AzureAppConfigParamStrategy) FetchVersion added in v0.8.1

func (s *AzureAppConfigParamStrategy) FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

FetchVersion fetches the current value. App Configuration is unversioned and the entire argument is the key, so this only ever resolves the current value.

func (*AzureAppConfigParamStrategy) HasDeleteOptions added in v0.8.1

func (s *AzureAppConfigParamStrategy) HasDeleteOptions() bool

HasDeleteOptions returns false: App Configuration has no delete options.

func (*AzureAppConfigParamStrategy) ItemName added in v0.8.1

func (s *AzureAppConfigParamStrategy) ItemName() string

ItemName returns the item name for messages.

func (*AzureAppConfigParamStrategy) ParseName added in v0.8.1

func (s *AzureAppConfigParamStrategy) ParseName(input string) (string, error)

ParseName parses and validates a name. App Configuration is unversioned, so the entire argument is the key (':' / '#' / '~' are legal key characters).

func (*AzureAppConfigParamStrategy) ParseSpec added in v0.8.1

func (s *AzureAppConfigParamStrategy) ParseSpec(input string) (name string, hasVersion bool, err error)

ParseSpec parses a name for reset. App Configuration is unversioned, so a version is never present; the entire argument is the key.

func (*AzureAppConfigParamStrategy) Service added in v0.8.1

func (s *AzureAppConfigParamStrategy) Service() Service

Service returns the service type.

func (*AzureAppConfigParamStrategy) ServiceName added in v0.8.1

func (s *AzureAppConfigParamStrategy) ServiceName() string

ServiceName returns the user-friendly service name.

type AzureKeyVaultSecretStrategy added in v0.8.1

type AzureKeyVaultSecretStrategy struct {
	// contains filtered or unexported fields
}

AzureKeyVaultSecretStrategy implements the staging strategies for Azure Key Vault secrets. Like the other strategies it is backed by a provider.Store and carries no cloud SDK dependency. Key Vault specifics:

  • Versions are opaque ids, parsed with azurekvversion (#ID, ~SHIFT); a staged "edit" applies as a new version via Put.
  • There are no force / recovery-window delete options (delete is a soft delete), so HasDeleteOptions reports false.
  • Tags are writable, so tag/untag staging is supported.
  • Conflict detection uses the secret's last-modified timestamp, like AWS.

A nil store yields a parser-only strategy (ParseName/ParseSpec).

func NewAzureKeyVaultSecretStrategy added in v0.8.1

func NewAzureKeyVaultSecretStrategy(store provider.Store) *AzureKeyVaultSecretStrategy

NewAzureKeyVaultSecretStrategy creates an Azure Key Vault staging strategy over the given provider store. A nil store is allowed for parser-only use.

func (*AzureKeyVaultSecretStrategy) Apply added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) Apply(ctx context.Context, name string, entry Entry) error

Apply applies a staged operation to Azure Key Vault.

func (*AzureKeyVaultSecretStrategy) ApplyTags added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

ApplyTags applies staged tag changes to the secret.

func (*AzureKeyVaultSecretStrategy) FetchCurrent added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

FetchCurrent fetches the current value from Key Vault for diffing.

func (*AzureKeyVaultSecretStrategy) FetchCurrentTags added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)

FetchCurrentTags fetches the current tags from Key Vault.

func (*AzureKeyVaultSecretStrategy) FetchCurrentValue added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)

FetchCurrentValue fetches the current value from Key Vault for editing.

func (*AzureKeyVaultSecretStrategy) FetchLastModified added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) FetchLastModified(ctx context.Context, name string) (time.Time, error)

FetchLastModified returns the last modified time of the secret. It returns a *ResourceNotFoundError when the secret does not exist, so callers can tell "missing" apart from "exists but has no modification time" (the latter returns a zero time with a nil error).

func (*AzureKeyVaultSecretStrategy) FetchVersion added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

FetchVersion fetches the value for a specific version.

func (*AzureKeyVaultSecretStrategy) HasDeleteOptions added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) HasDeleteOptions() bool

HasDeleteOptions returns false: Azure Key Vault has no force / recovery-window delete options in this abstraction.

func (*AzureKeyVaultSecretStrategy) ItemName added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) ItemName() string

ItemName returns the item name for messages.

func (*AzureKeyVaultSecretStrategy) ParseName added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) ParseName(input string) (string, error)

ParseName parses and validates a name for editing (no version specifier).

func (*AzureKeyVaultSecretStrategy) ParseSpec added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) ParseSpec(input string) (name string, hasVersion bool, err error)

ParseSpec parses a version spec string for reset.

func (*AzureKeyVaultSecretStrategy) Service added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) Service() Service

Service returns the service type.

func (*AzureKeyVaultSecretStrategy) ServiceName added in v0.8.1

func (s *AzureKeyVaultSecretStrategy) ServiceName() string

ServiceName returns the user-friendly service name.

type DeleteOptions

type DeleteOptions struct {
	// Force enables immediate permanent deletion without recovery window.
	Force bool `json:"force,omitempty"`
	// RecoveryWindow is the number of days before permanent deletion (7-30).
	// Only used when Force is false. 0 means default (30 days).
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	RecoveryWindow int `json:"recovery_window,omitempty"`
}

DeleteOptions holds options for Secrets Manager delete operations.

type DeleteStrategy added in v0.1.1

type DeleteStrategy interface {
	ServiceStrategy

	// FetchLastModified returns the last modified time of the resource in AWS.
	// Used for existence and conflict detection when applying delete operations.
	// It returns a *ResourceNotFoundError when the resource does not exist, so
	// callers can distinguish "missing" from "exists but has no modification
	// time" (the latter returns a zero time with a nil error).
	FetchLastModified(ctx context.Context, name string) (time.Time, error)
}

DeleteStrategy defines service-specific delete staging operations.

type DiffStrategy

type DiffStrategy interface {
	ServiceStrategy

	// FetchCurrent fetches the current value from AWS for diffing.
	FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

	// FetchCurrentTags fetches the current tags from AWS for showing in diff output.
	// Returns nil map if the resource doesn't exist or has no tags.
	FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)
}

DiffStrategy defines service-specific diff/fetch operations.

type EditFetchResult

type EditFetchResult struct {
	// Value is the current value in AWS.
	Value string
	// LastModified is the last modification time of the resource.
	// Used for conflict detection when applying staged changes.
	LastModified time.Time
}

EditFetchResult holds the result of fetching a value for editing.

type EditStrategy

type EditStrategy interface {
	Parser

	// FetchCurrentValue fetches the current value from AWS for editing.
	// Returns the value and last modified time for conflict detection.
	FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)
}

EditStrategy defines service-specific edit operations.

type Entry

type Entry struct {
	Operation   Operation `json:"operation"`
	Value       *string   `json:"value,omitempty"` // nil for delete, pointer to distinguish from empty string
	Description *string   `json:"description,omitempty"`
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	StagedAt time.Time `json:"staged_at"`
	// BaseModifiedAt records the AWS LastModified time when the value was fetched.
	// Used for conflict detection: if AWS was modified after this time, it's a conflict.
	// Only set for update/delete operations (nil for create since there's no base).
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	BaseModifiedAt *time.Time `json:"base_modified_at,omitempty"`
	// DeleteOptions holds Secrets Manager-specific delete options.
	// Only used when Operation is OperationDelete and service is Secrets Manager.
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	DeleteOptions *DeleteOptions `json:"delete_options,omitempty"`
}

Entry represents a single staged entity change (create/update/delete). Tags are managed separately in TagEntry.

type EntryKey added in v1.5.2

type EntryKey struct {
	Name      string
	Namespace string
}

EntryKey identifies a staged item — an entry or a tag change — by name and namespace. Namespace is the Azure App Configuration label axis; empty is the null/default namespace and the only value for every other provider. Carrying both in one value is what makes it impossible to address a staged item without its namespace: the store API and the in-memory state maps are keyed by EntryKey, so a namespaced App Configuration setting can never be silently resolved under the default namespace. The same name under two namespaces is two distinct items.

func SortedEntryKeys added in v1.5.2

func SortedEntryKeys[V any](m map[EntryKey]V) []EntryKey

SortedEntryKeys returns the keys of m sorted by (name, namespace) for deterministic iteration and output.

func (EntryKey) Label added in v1.7.0

func (k EntryKey) Label() string

Label renders the key for display, appending the namespace as a [badge] when present. The empty (default) namespace — the only value for AWS, Google Cloud and Key Vault — renders as the bare name, matching status/diff output.

type EntryPrinter

type EntryPrinter struct {
	Writer io.Writer
}

EntryPrinter prints staged entries to the given writer.

func (*EntryPrinter) PrintEntry

func (p *EntryPrinter) PrintEntry(key EntryKey, entry Entry, verbose, showDeleteOptions bool)

PrintEntry prints a single staged entry identified by key. If verbose is true, shows detailed information including timestamp and value. If showDeleteOptions is true, shows delete options (Force/RecoveryWindow) for delete operations.

type FetchResult

type FetchResult struct {
	// Value is the current value in AWS.
	Value string
	// Identifier is a display string for the version (e.g., "#3" for SSM Parameter Store, "#abc123" for Secrets Manager).
	Identifier string
}

FetchResult holds the result of fetching a value from AWS.

type FullStrategy

type FullStrategy interface {
	ApplyStrategy
	DiffStrategy
	EditStrategy
	ResetStrategy
}

FullStrategy combines all service-specific strategy interfaces. This enables unified stage commands that work with either SSM Parameter Store or Secrets Manager.

type GoogleCloudSecretStrategy added in v0.8.1

type GoogleCloudSecretStrategy struct {
	// contains filtered or unexported fields
}

GoogleCloudSecretStrategy implements the staging strategies for Google Cloud Secret Manager. Like the AWS strategies it is backed by a provider.Store and carries no cloud SDK dependency. It differs from the AWS SecretStrategy in three provider-specific ways:

  • Versions are immutable integers, parsed with gcloudversion (#N, ~SHIFT); a staged "edit" applies as a new version via Put.
  • There are no delete options (no force / recovery window), so HasDeleteOptions reports false and Delete ignores staged DeleteOptions.
  • There are no staging labels (:LABEL).

A nil store yields a parser-only strategy (ParseName/ParseSpec).

func NewGoogleCloudSecretStrategy added in v0.8.1

func NewGoogleCloudSecretStrategy(store provider.Store) *GoogleCloudSecretStrategy

NewGoogleCloudSecretStrategy creates a Google Cloud Secret Manager staging strategy over the given provider store. A nil store is allowed for parser-only use.

func (*GoogleCloudSecretStrategy) Apply added in v0.8.1

func (s *GoogleCloudSecretStrategy) Apply(ctx context.Context, name string, entry Entry) error

Apply applies a staged operation to Google Cloud Secret Manager.

func (*GoogleCloudSecretStrategy) ApplyTags added in v0.8.1

func (s *GoogleCloudSecretStrategy) ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

ApplyTags applies staged tag (label) changes to Google Cloud Secret Manager.

func (*GoogleCloudSecretStrategy) FetchCurrent added in v0.8.1

func (s *GoogleCloudSecretStrategy) FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

FetchCurrent fetches the current value from Secret Manager for diffing.

func (*GoogleCloudSecretStrategy) FetchCurrentTags added in v0.8.1

func (s *GoogleCloudSecretStrategy) FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)

FetchCurrentTags fetches the current labels from Secret Manager.

func (*GoogleCloudSecretStrategy) FetchCurrentValue added in v0.8.1

func (s *GoogleCloudSecretStrategy) FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)

FetchCurrentValue fetches the current value from Secret Manager for editing. Returns *ResourceNotFoundError if the secret doesn't exist.

func (*GoogleCloudSecretStrategy) FetchLastModified added in v0.8.1

func (s *GoogleCloudSecretStrategy) FetchLastModified(ctx context.Context, name string) (time.Time, error)

FetchLastModified returns the last modified time of the secret. It returns a *ResourceNotFoundError when the secret does not exist, so callers can tell "missing" apart from "exists but has no modification time" (the latter returns a zero time with a nil error).

func (*GoogleCloudSecretStrategy) FetchVersion added in v0.8.1

func (s *GoogleCloudSecretStrategy) FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

FetchVersion fetches the value for a specific version.

func (*GoogleCloudSecretStrategy) HasDeleteOptions added in v0.8.1

func (s *GoogleCloudSecretStrategy) HasDeleteOptions() bool

HasDeleteOptions returns false: Google Cloud Secret Manager has no force / recovery-window delete options.

func (*GoogleCloudSecretStrategy) ItemName added in v0.8.1

func (s *GoogleCloudSecretStrategy) ItemName() string

ItemName returns the item name for messages.

func (*GoogleCloudSecretStrategy) ParseName added in v0.8.1

func (s *GoogleCloudSecretStrategy) ParseName(input string) (string, error)

ParseName parses and validates a name for editing (no version specifier).

func (*GoogleCloudSecretStrategy) ParseSpec added in v0.8.1

func (s *GoogleCloudSecretStrategy) ParseSpec(input string) (name string, hasVersion bool, err error)

ParseSpec parses a version spec string for reset.

func (*GoogleCloudSecretStrategy) Service added in v0.8.1

func (s *GoogleCloudSecretStrategy) Service() Service

Service returns the service type.

func (*GoogleCloudSecretStrategy) ServiceName added in v0.8.1

func (s *GoogleCloudSecretStrategy) ServiceName() string

ServiceName returns the user-friendly service name.

type Operation

type Operation string

Operation represents the type of staged change.

const (
	// OperationCreate represents a create operation (new item).
	OperationCreate Operation = "create"
	// OperationUpdate represents an update operation (existing item).
	OperationUpdate Operation = "update"
	// OperationDelete represents a delete operation.
	OperationDelete Operation = "delete"
)

type ParamStrategy

type ParamStrategy struct {
	// contains filtered or unexported fields
}

ParamStrategy implements ServiceStrategy for SSM Parameter Store. It is backed by a provider.Store rather than an AWS SDK client, so it carries no cloud SDK dependency. A nil store yields a parser-only strategy (ParseName/ParseSpec).

func NewParamStrategy

func NewParamStrategy(store provider.Store) *ParamStrategy

NewParamStrategy creates a new SSM Parameter Store strategy over the given provider store. A nil store is allowed for parser-only use.

func (*ParamStrategy) Apply

func (s *ParamStrategy) Apply(ctx context.Context, name string, entry Entry) error

Apply applies a staged operation to SSM Parameter Store.

func (*ParamStrategy) ApplyTags added in v0.3.0

func (s *ParamStrategy) ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

ApplyTags applies staged tag changes to SSM Parameter Store.

func (*ParamStrategy) FetchCurrent

func (s *ParamStrategy) FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

FetchCurrent fetches the current value from SSM Parameter Store for diffing.

func (*ParamStrategy) FetchCurrentTags added in v0.7.3

func (s *ParamStrategy) FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)

FetchCurrentTags fetches the current tags from SSM Parameter Store.

func (*ParamStrategy) FetchCurrentValue

func (s *ParamStrategy) FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)

FetchCurrentValue fetches the current value from SSM Parameter Store for editing. Returns *ResourceNotFoundError if the parameter doesn't exist.

func (*ParamStrategy) FetchLastModified

func (s *ParamStrategy) FetchLastModified(ctx context.Context, name string) (time.Time, error)

FetchLastModified returns the last modified time of the parameter. It returns a *ResourceNotFoundError when the parameter does not exist, so callers can tell "missing" apart from "exists but has no modification time" (the latter returns a zero time with a nil error).

func (*ParamStrategy) FetchVersion

func (s *ParamStrategy) FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

FetchVersion fetches the value for a specific version.

func (*ParamStrategy) HasDeleteOptions

func (s *ParamStrategy) HasDeleteOptions() bool

HasDeleteOptions returns false as SSM Parameter Store doesn't have delete options.

func (*ParamStrategy) ItemName

func (s *ParamStrategy) ItemName() string

ItemName returns the item name for messages.

func (*ParamStrategy) ParseName

func (s *ParamStrategy) ParseName(input string) (string, error)

ParseName parses and validates a name for editing.

func (*ParamStrategy) ParseSpec

func (s *ParamStrategy) ParseSpec(input string) (name string, hasVersion bool, err error)

ParseSpec parses a version spec string for reset.

func (*ParamStrategy) Service

func (s *ParamStrategy) Service() Service

Service returns the service type.

func (*ParamStrategy) ServiceName

func (s *ParamStrategy) ServiceName() string

ServiceName returns the user-friendly service name.

type Parser

type Parser interface {
	ServiceStrategy

	// ParseName parses and validates a name, returning only the base name without version specifiers.
	// Returns an error if version specifiers are present.
	ParseName(input string) (string, error)

	// ParseSpec parses a version spec string.
	// Returns the base name and whether a version/shift was specified.
	ParseSpec(input string) (name string, hasVersion bool, err error)
}

Parser provides name/spec parsing without AWS access. Use this interface when only parsing is needed (e.g., status, add commands).

func AzureAppConfigParamParserFactory added in v0.8.1

func AzureAppConfigParamParserFactory() Parser

AzureAppConfigParamParserFactory yields a parser-only strategy.

func AzureKeyVaultSecretParserFactory added in v0.8.1

func AzureKeyVaultSecretParserFactory() Parser

AzureKeyVaultSecretParserFactory yields a parser-only strategy.

func GoogleCloudSecretParserFactory added in v0.8.1

func GoogleCloudSecretParserFactory() Parser

GoogleCloudSecretParserFactory creates a Parser without provider access, for operations that don't need Google Cloud access (e.g. status, parsing).

func ParamParserFactory

func ParamParserFactory() Parser

ParamParserFactory creates a Parser without provider access. Use this for operations that don't need AWS access (e.g., status, parsing).

func SecretParserFactory

func SecretParserFactory() Parser

SecretParserFactory creates a Parser without provider access. Use this for operations that don't need AWS access (e.g., status, parsing).

type ParserFactory

type ParserFactory func() Parser

ParserFactory creates a Parser without AWS client.

type ResetStrategy

type ResetStrategy interface {
	Parser

	// FetchVersion fetches the value for a specific version.
	// Returns the value and a version label for display.
	FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

	// FetchCurrentValue fetches the current value from AWS for auto-skip detection.
	// Uses same signature as EditStrategy for implementation reuse.
	FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)
}

ResetStrategy defines service-specific reset operations.

type ResolvedScope added in v0.8.1

type ResolvedScope struct {
	// Scope keys the on-disk staging state (see provider.Scope.Key).
	Scope provider.Scope
	// Target is a human-readable description of where changes will be applied.
	Target string
}

ResolvedScope is the outcome of resolving the active provider's staging scope: the provider.Scope used to key on-disk staging state, plus a human-readable Target line shown in apply/pop confirmation prompts (e.g. an AWS profile/account/region, or a Google Cloud project).

type ResourceNotFoundError added in v0.4.8

type ResourceNotFoundError struct {
	Err error
}

ResourceNotFoundError indicates a resource was not found in AWS.

func (*ResourceNotFoundError) Error added in v0.4.8

func (e *ResourceNotFoundError) Error() string

func (*ResourceNotFoundError) Unwrap added in v0.4.8

func (e *ResourceNotFoundError) Unwrap() error

type ScopeResolver added in v0.8.1

type ScopeResolver func(ctx context.Context) (ResolvedScope, error)

ScopeResolver resolves the active provider's staging scope. AWS resolves it from the STS caller identity; Google Cloud from the configured project. It may perform network calls (e.g. STS GetCallerIdentity), so it is only invoked by staging commands, never by read/write commands.

type SecretStrategy

type SecretStrategy struct {
	// contains filtered or unexported fields
}

SecretStrategy implements ServiceStrategy for Secrets Manager. It is backed by a provider.Store rather than an AWS SDK client, so it carries no cloud SDK dependency of its own. A nil store yields a parser-only strategy.

func NewSecretStrategy

func NewSecretStrategy(store provider.Store) *SecretStrategy

NewSecretStrategy creates a new Secrets Manager strategy over the given provider store. A nil store is allowed for parser-only use.

func (*SecretStrategy) Apply

func (s *SecretStrategy) Apply(ctx context.Context, name string, entry Entry) error

Apply applies a staged operation to Secrets Manager.

func (*SecretStrategy) ApplyTags added in v0.3.0

func (s *SecretStrategy) ApplyTags(ctx context.Context, name string, tagEntry TagEntry) error

ApplyTags applies staged tag changes to Secrets Manager.

func (*SecretStrategy) FetchCurrent

func (s *SecretStrategy) FetchCurrent(ctx context.Context, name string) (*FetchResult, error)

FetchCurrent fetches the current value from Secrets Manager for diffing.

func (*SecretStrategy) FetchCurrentTags added in v0.7.3

func (s *SecretStrategy) FetchCurrentTags(ctx context.Context, name string) (map[string]string, error)

FetchCurrentTags fetches the current tags from Secrets Manager.

func (*SecretStrategy) FetchCurrentValue

func (s *SecretStrategy) FetchCurrentValue(ctx context.Context, name string) (*EditFetchResult, error)

FetchCurrentValue fetches the current value from Secrets Manager for editing. Returns *ResourceNotFoundError if the secret doesn't exist.

func (*SecretStrategy) FetchLastModified

func (s *SecretStrategy) FetchLastModified(ctx context.Context, name string) (time.Time, error)

FetchLastModified returns the last modified time of the secret. It returns a *ResourceNotFoundError when the secret does not exist, so callers can tell "missing" apart from "exists but has no modification time" (the latter returns a zero time with a nil error).

func (*SecretStrategy) FetchVersion

func (s *SecretStrategy) FetchVersion(ctx context.Context, input string) (value string, versionLabel string, err error)

FetchVersion fetches the value for a specific version.

func (*SecretStrategy) HasDeleteOptions

func (s *SecretStrategy) HasDeleteOptions() bool

HasDeleteOptions returns true as Secrets Manager has delete options.

func (*SecretStrategy) ItemName

func (s *SecretStrategy) ItemName() string

ItemName returns the item name for messages.

func (*SecretStrategy) ParseName

func (s *SecretStrategy) ParseName(input string) (string, error)

ParseName parses and validates a name for editing.

func (*SecretStrategy) ParseSpec

func (s *SecretStrategy) ParseSpec(input string) (name string, hasVersion bool, err error)

ParseSpec parses a version spec string for reset.

func (*SecretStrategy) Service

func (s *SecretStrategy) Service() Service

Service returns the service type.

func (*SecretStrategy) ServiceName

func (s *SecretStrategy) ServiceName() string

ServiceName returns the user-friendly service name.

type Service

type Service string

Service represents which AWS service the staged change belongs to.

const (
	// ServiceParam represents AWS Systems Manager Parameter Store.
	ServiceParam Service = "param"
	// ServiceSecret represents AWS Secrets Manager.
	ServiceSecret Service = "secret"
)

func KindToService added in v0.8.0

func KindToService(k provider.Kind) Service

KindToService maps a provider Kind to the equivalent staging Service.

func SupportedServices added in v0.8.0

func SupportedServices(scope provider.Scope) []Service

SupportedServices returns the staging Services supported by the given scope, in the scope's stable kind order. This is the registry-driven iteration source that replaces hardcoded {ServiceParam, ServiceSecret} loops.

type ServiceStrategy

type ServiceStrategy interface {
	// Service returns the service type (ServiceParam or ServiceSecret).
	Service() Service

	// ServiceName returns the user-friendly service name (e.g., "SSM Parameter Store", "Secrets Manager").
	ServiceName() string

	// ItemName returns the item name for messages (e.g., "parameter", "secret").
	ItemName() string

	// HasDeleteOptions returns true if delete options should be displayed.
	HasDeleteOptions() bool
}

ServiceStrategy defines the common interface for service-specific operations. This enables Strategy Pattern to consolidate duplicate code across SSM Parameter Store and Secrets Manager commands.

type State

type State struct {
	Version int
	Entries map[Service]map[EntryKey]Entry
	Tags    map[Service]map[EntryKey]TagEntry
}

State represents the entire staging state (v3). Entries and Tags are keyed by EntryKey (name + namespace) and managed separately for cleaner separation of concerns. On disk each item is a structured record carrying its name and namespace explicitly; see MarshalJSON / UnmarshalJSON.

func NewEmptyState added in v0.7.0

func NewEmptyState() *State

NewEmptyState creates a new empty state with initialized maps.

func (*State) EntryCount added in v0.7.0

func (s *State) EntryCount() int

EntryCount returns the total number of entries in the state.

func (*State) ExtractService added in v0.7.0

func (s *State) ExtractService(service Service) *State

ExtractService returns a new state containing only entries for the specified service. If service is empty, returns a clone of the entire state.

func (*State) IsEmpty added in v0.7.0

func (s *State) IsEmpty() bool

IsEmpty checks if a state has no entries and no tags.

func (*State) MarshalJSON added in v1.5.2

func (s *State) MarshalJSON() ([]byte, error)

MarshalJSON writes the state as structured (name, namespace) records, sorted for deterministic output.

func (*State) Merge added in v0.7.0

func (s *State) Merge(other *State)

Merge merges another state into this state. The other state takes precedence for conflicting entries.

func (*State) RemoveService added in v0.7.0

func (s *State) RemoveService(service Service)

RemoveService removes all entries for the specified service from this state. If service is empty, clears all entries.

func (*State) TagCount added in v0.7.0

func (s *State) TagCount() int

TagCount returns the total number of tag entries in the state.

func (*State) TotalCount added in v0.7.0

func (s *State) TotalCount() int

TotalCount returns the total number of entries and tags in the state.

func (*State) UnmarshalJSON added in v1.5.2

func (s *State) UnmarshalJSON(data []byte) error

UnmarshalJSON reads a v3 (structured-record) state. Pre-v3 layouts (NUL-composite string map keys) are intentionally NOT migrated: they are treated as empty (see stateVersion) so a format bump never crashes commands — stale local working state is dropped rather than converted.

type StrategyFactory

type StrategyFactory func(ctx context.Context) (FullStrategy, error)

StrategyFactory creates a FullStrategy for a given context. Used to defer AWS client initialization until command execution.

type TagEntry added in v0.3.0

type TagEntry struct {
	Add    map[string]string   `json:"add,omitempty"`    // Tags to add or update
	Remove maputil.Set[string] `json:"remove,omitempty"` // Tag keys to remove
	// StagedAt records when the tag change was staged.
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	StagedAt time.Time `json:"staged_at"`
	// BaseModifiedAt records the AWS LastModified time when tags were fetched.
	// Used for conflict detection.
	//nolint:tagliatelle // JSON uses snake_case for consistency with file storage format
	BaseModifiedAt *time.Time `json:"base_modified_at,omitempty"`
}

TagEntry represents staged tag changes for an entity. Managed separately from Entry for cleaner separation of concerns.

Directories

Path Synopsis
Package cli provides shared runners and command builders for stage commands.
Package cli provides shared runners and command builders for stage commands.
Package store provides storage interfaces and implementations for staging.
Package store provides storage interfaces and implementations for staging.
file
Package file provides file-based staging storage.
Package file provides file-based staging storage.
file/internal/crypt
Package crypt provides encryption for staging files.
Package crypt provides encryption for staging files.
file/internal/keyprovider
Package keyprovider resolves the AES-256 data key used to encrypt the working staging state files (param.json/secret.json).
Package keyprovider resolves the AES-256 data key used to encrypt the working staging state files (param.json/secret.json).
testutil
Package testutil provides test utilities for staging package.
Package testutil provides test utilities for staging package.
Package transition implements state machine logic for staging operations.
Package transition implements state machine logic for staging operations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL