secrets

package
v0.84.3 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 28 Imported by: 3

Documentation

Overview

Package secrets provides secret storage backends (Provider), secret:// reference resolution (Resolver), and two complementary redaction utilities.

Two redaction categories — pick the right one

The package offers two DISTINCT ways to scrub secret material, addressing two different threat shapes. They are NOT interchangeable:

  • KEY-name masking — MaskSensitiveOutputs (masking.go). Given a structured outputs map (e.g. a step's key/value results) and a set of sensitive KEY names ("password", "token", "connection_string", ...), it replaces the VALUES of those keys with "(sensitive)". It never scans free text and never needs to know the secret's value — only its key. Use it for structured maps whose key set is known and trusted.

  • VALUE scanning — Redactor (redactor.go). Given an arbitrary blob of free text (a log line, a chat message, an LLM prompt body) and a set of previously-seen secret VALUES, it replaces every substring equal to a known value with "[REDACTED:label]". It does not care about KEY names in the text; it matches purely on value. Use it when the secret may appear anywhere in free text and only its value is known.

A typical engine integration arms a Redactor from a Provider (List+Get) at startup and on hot-swap, then runs Redact over every message/transcript body before it leaves the process. Structured step outputs flow through MaskSensitiveOutputs instead.

Redactor graceful-degrade contract

Redactor.LoadFromProvider is designed to be wired BEFORE its backing provider is reachable. If the provider's List call fails (read-only-without-list, not-yet-started, temporarily unavailable) LoadFromProvider returns nil and leaves the existing known-value set UNTOUCHED — it never panics and never empties the redactor on a List error. This lets a caller register a Redactor at construction time and re-arm it once the provider comes online (lazy resolve + hot-swap) without risking a window where the redactor is empty.

AddValue is the additive path: it merges a single value into the set without disturbing the rest. LoadFromProvider is the bulk/full-replace path: it swaps the entire set from the provider's current state. The two compose — callers may seed a few values via AddValue and then refresh from a provider.

Index

Constants

View Source
const SecretPrefix = "secret://"

SecretPrefix is the URI scheme used in config values to reference secrets.

Variables

View Source
var (
	ErrNotFound     = errors.New("secrets: secret not found")
	ErrUnsupported  = errors.New("secrets: operation not supported")
	ErrInvalidKey   = errors.New("secrets: invalid key")
	ErrProviderInit = errors.New("secrets: provider initialization failed")
)

Common errors.

Functions

func DefaultSensitiveKeys added in v0.9.4

func DefaultSensitiveKeys() []string

DefaultSensitiveKeys returns the default set of output keys considered sensitive.

func GenerateSecret added in v0.9.4

func GenerateSecret(ctx context.Context, genType string, config map[string]any) (string, error)

GenerateSecret produces a secret value based on genType and config. Supported types: "random_hex", "random_base64", "random_alphanumeric", "provider_credential". For "provider_credential", the returned string is a JSON-encoded map.

func MaskSensitiveOutputs added in v0.9.4

func MaskSensitiveOutputs(outputs map[string]any, sensitiveKeys []string) map[string]any

MaskSensitiveOutputs returns a copy of outputs with sensitive values replaced by "(sensitive)". sensitiveKeys is the merged set of keys to mask.

func MergeSensitiveKeys added in v0.9.4

func MergeSensitiveKeys(driverKeys []string) []string

MergeSensitiveKeys combines driver-specific keys with the defaults, deduplicating.

Types

type AWSConfig

type AWSConfig struct {
	Region          string `json:"region" yaml:"region"`
	AccessKeyID     string `json:"accessKeyId,omitempty" yaml:"accessKeyId,omitempty"`
	SecretAccessKey string `json:"secretAccessKey,omitempty" yaml:"secretAccessKey,omitempty"`
}

AWSConfig holds configuration for AWS Secrets Manager.

type AWSSecretsManagerProvider

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

AWSSecretsManagerProvider reads secrets from AWS Secrets Manager using the HTTP API with AWS Signature V4 signing. No external AWS SDK is required.

func NewAWSSecretsManagerProvider

func NewAWSSecretsManagerProvider(cfg AWSConfig) (*AWSSecretsManagerProvider, error)

NewAWSSecretsManagerProvider creates a new AWS Secrets Manager provider. If AccessKeyID/SecretAccessKey are empty, it falls back to the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

func NewAWSSecretsManagerProviderWithClient

func NewAWSSecretsManagerProviderWithClient(cfg AWSConfig, client HTTPClient) *AWSSecretsManagerProvider

NewAWSSecretsManagerProviderWithClient creates an AWS provider with a custom HTTP client (for testing).

func (*AWSSecretsManagerProvider) CheckAccess added in v0.67.0

func (p *AWSSecretsManagerProvider) CheckAccess(ctx context.Context) error

CheckAccess implements AccessChecker. It performs a lightweight check by attempting to list secrets. Errors never contain credential material.

func (*AWSSecretsManagerProvider) Config

Config returns the provider's AWS configuration.

func (*AWSSecretsManagerProvider) Delete

func (*AWSSecretsManagerProvider) Get

func (*AWSSecretsManagerProvider) List

List returns the names of all secrets using the ListSecrets API with pagination.

func (*AWSSecretsManagerProvider) Name

func (*AWSSecretsManagerProvider) SecretTarget added in v0.75.9

func (p *AWSSecretsManagerProvider) SecretTarget() ProviderTarget

SecretTarget describes the AWS Secrets Manager region namespace.

func (*AWSSecretsManagerProvider) Set

func (*AWSSecretsManagerProvider) StatAll added in v0.67.0

StatAll implements MetadataProvider on a best-effort basis. It lists secret names from AWS Secrets Manager and returns them with Exists=true and zero UpdatedAt (LastChangedDate is not fetched to avoid N+1 API calls). Returns ErrUnsupported when listing is not available.

type AccessChecker added in v0.67.0

type AccessChecker interface {
	CheckAccess(ctx context.Context) error
}

AccessChecker is optional: verify the store is reachable + usable for setup. CheckAccess MUST NOT leak credential material in its error.

type DevVaultConfig

type DevVaultConfig struct {
	// RootToken is the root token for the dev server. Default: "dev-root-token".
	RootToken string
	// ListenAddr is the address to listen on. Default: "127.0.0.1:0" (random port).
	ListenAddr string
	// MountPath is the KV v2 mount path. Default: "secret".
	MountPath string
}

DevVaultConfig holds configuration for a managed Vault dev server.

type DevVaultProvider

type DevVaultProvider struct {
	*VaultProvider
	// contains filtered or unexported fields
}

DevVaultProvider manages a Vault dev server subprocess and provides a real VaultProvider connected to it. This is useful for local development and integration testing without requiring an external Vault server.

func NewDevVaultProvider

func NewDevVaultProvider(cfg DevVaultConfig) (*DevVaultProvider, error)

NewDevVaultProvider starts a Vault dev server and returns a provider connected to it. It finds the vault binary on PATH, starts it with -dev mode, waits for readiness, and returns a fully functional VaultProvider.

The caller must call Close() to stop the subprocess.

Returns an error if the vault binary is not found or the server fails to start.

func (*DevVaultProvider) Addr

func (p *DevVaultProvider) Addr() string

Addr returns the listen address of the dev server.

func (*DevVaultProvider) Close

func (p *DevVaultProvider) Close() error

Close stops the Vault dev server subprocess and cleans up.

type EnvProvider

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

EnvProvider reads secrets from environment variables. Keys are converted to uppercase with dots replaced by underscores. For example, "database.password" becomes "DATABASE_PASSWORD".

func NewEnvProvider

func NewEnvProvider(prefix string) *EnvProvider

NewEnvProvider creates a new environment variable secret provider. If prefix is non-empty, it is prepended to all key lookups (e.g., prefix "APP_" + key "db_pass" -> "APP_DB_PASS").

func (*EnvProvider) CheckAccess added in v0.67.0

func (p *EnvProvider) CheckAccess(_ context.Context) error

CheckAccess implements AccessChecker. For EnvProvider, access is always available.

func (*EnvProvider) Delete

func (p *EnvProvider) Delete(_ context.Context, key string) error

func (*EnvProvider) Get

func (p *EnvProvider) Get(_ context.Context, key string) (string, error)

func (*EnvProvider) List

func (p *EnvProvider) List(_ context.Context) ([]string, error)

func (*EnvProvider) Name

func (p *EnvProvider) Name() string

func (*EnvProvider) SecretTarget added in v0.75.9

func (p *EnvProvider) SecretTarget() ProviderTarget

SecretTarget describes the current process environment namespace.

func (*EnvProvider) Set

func (p *EnvProvider) Set(_ context.Context, key, value string) error

func (*EnvProvider) StatAll added in v0.67.0

func (p *EnvProvider) StatAll(_ context.Context) ([]SecretMeta, error)

StatAll implements MetadataProvider. It lists env vars that match the prefix (same logic as List) and returns SecretMeta with Exists=true and zero UpdatedAt (env vars have no last-modified timestamp).

type EnvironmentManager added in v0.77.0

type EnvironmentManager interface {
	ListEnvironments(ctx context.Context) ([]ProviderEnvironment, error)
	ValidateEnvironment(ctx context.Context, name string) (ProviderEnvironment, error)
	EnsureEnvironment(ctx context.Context, name string) (ProviderEnvironment, error)
}

EnvironmentManager is optional: providers implement it when they can inspect and create environment-like namespaces used by scoped secrets.

ValidateEnvironment must return an error wrapping ErrNotFound when the named environment is absent, and an error wrapping ErrInvalidKey when name is empty or invalid for the provider. EnsureEnvironment must be idempotent: it returns existing environment metadata when present, creates the environment when it is absent, and returns provider metadata for the resulting environment.

type FileProvider

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

FileProvider reads secrets from files in a directory. Each file name is the secret key, and the file content is the value. This is compatible with Kubernetes secret volume mounts.

func NewFileProvider

func NewFileProvider(dir string) *FileProvider

NewFileProvider creates a file-based secret provider rooted at dir.

func (*FileProvider) CheckAccess added in v0.67.0

func (p *FileProvider) CheckAccess(_ context.Context) error

CheckAccess implements AccessChecker. It verifies the directory exists and is writable by attempting to create (then remove) a probe file.

func (*FileProvider) Delete

func (p *FileProvider) Delete(_ context.Context, key string) error

func (*FileProvider) Get

func (p *FileProvider) Get(_ context.Context, key string) (string, error)

func (*FileProvider) List

func (p *FileProvider) List(_ context.Context) ([]string, error)

func (*FileProvider) Name

func (p *FileProvider) Name() string

func (*FileProvider) SecretTarget added in v0.75.9

func (p *FileProvider) SecretTarget() ProviderTarget

SecretTarget describes the directory-backed file secret namespace.

func (*FileProvider) Set

func (p *FileProvider) Set(_ context.Context, key, value string) error

func (*FileProvider) StatAll added in v0.67.0

func (p *FileProvider) StatAll(_ context.Context) ([]SecretMeta, error)

StatAll implements MetadataProvider. It returns SecretMeta for every file in the directory, using the file's modification time as UpdatedAt.

type GitHubOrgVisibility added in v0.60.7

type GitHubOrgVisibility string

GitHubOrgVisibility controls who can pull an org-scoped secret. Mirrors GitHub's API field; one of "all", "selected", "private".

const (
	OrgVisibilityAll      GitHubOrgVisibility = "all"
	OrgVisibilitySelected GitHubOrgVisibility = "selected"
	OrgVisibilityPrivate  GitHubOrgVisibility = "private"
)

type GitHubSecretScope added in v0.60.7

type GitHubSecretScope string

GitHubSecretScope selects which GitHub secret namespace a provider writes to. Default zero value = repo (backwards-compat).

GitHubScopeRepo → /repos/{owner}/{repo}/actions/secrets/...
GitHubScopeEnv  → /repos/{owner}/{repo}/environments/{env}/secrets/...
GitHubScopeOrg  → /orgs/{org}/actions/secrets/...
const (
	GitHubScopeRepo GitHubSecretScope = "repo"
	GitHubScopeEnv  GitHubSecretScope = "env"
	GitHubScopeOrg  GitHubSecretScope = "org"
)

type GitHubSecretsProvider added in v0.9.4

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

GitHubSecretsProvider manages GitHub Actions secrets at repo, env, or org scope. Secrets are write-only on GitHub, so Get() returns ErrUnsupported.

func NewGitHubOrgSecretsProvider added in v0.60.7

func NewGitHubOrgSecretsProvider(org string, tokenEnvVar string, visibility GitHubOrgVisibility, selectedRepoIDs []int64) (*GitHubSecretsProvider, error)

NewGitHubOrgSecretsProvider creates an org-scoped provider. visibility is one of OrgVisibilityAll / Selected / Private. selectedRepoIDs is required iff visibility=Selected.

Requires the token to have admin:org scope.

func NewGitHubSecretsProvider added in v0.9.4

func NewGitHubSecretsProvider(repo string, tokenEnvVar string) (*GitHubSecretsProvider, error)

NewGitHubSecretsProvider creates a repo-scoped provider for the given "owner/repo". tokenEnvVar is the name of the environment variable holding the GitHub token. Backwards-compatible — sets scope=repo.

func (*GitHubSecretsProvider) CheckAccess added in v0.67.0

func (p *GitHubSecretsProvider) CheckAccess(ctx context.Context) error

CheckAccess implements AccessChecker. It verifies the configured credentials have at least read access by fetching the public key. Errors never contain credential material.

func (*GitHubSecretsProvider) CheckVariable added in v0.80.0

func (p *GitHubSecretsProvider) CheckVariable(ctx context.Context, key string) (VariableMeta, error)

CheckVariable reports whether a GitHub Actions variable exists without returning its value.

func (*GitHubSecretsProvider) Delete added in v0.9.4

func (p *GitHubSecretsProvider) Delete(ctx context.Context, key string) error

Delete removes a GitHub Actions secret.

func (*GitHubSecretsProvider) DeleteVariable added in v0.80.0

func (p *GitHubSecretsProvider) DeleteVariable(ctx context.Context, key string) error

DeleteVariable removes a GitHub Actions variable.

func (*GitHubSecretsProvider) EnsureEnvironment added in v0.77.0

func (p *GitHubSecretsProvider) EnsureEnvironment(ctx context.Context, name string) (ProviderEnvironment, error)

EnsureEnvironment creates the GitHub Actions environment when it is missing.

func (*GitHubSecretsProvider) Environment added in v0.57.5

func (p *GitHubSecretsProvider) Environment() string

Environment returns the configured GitHub Actions environment scope.

func (*GitHubSecretsProvider) Get added in v0.9.4

Get always returns ErrUnsupported because GitHub secrets are write-only.

func (*GitHubSecretsProvider) List added in v0.9.4

func (p *GitHubSecretsProvider) List(ctx context.Context) ([]string, error)

List returns the names of all GitHub Actions secrets for the repo.

func (*GitHubSecretsProvider) ListEnvironments added in v0.77.0

func (p *GitHubSecretsProvider) ListEnvironments(ctx context.Context) ([]ProviderEnvironment, error)

ListEnvironments returns the GitHub Actions environments defined for the configured repository.

func (*GitHubSecretsProvider) ListVariables added in v0.80.0

func (p *GitHubSecretsProvider) ListVariables(ctx context.Context) ([]VariableMeta, error)

ListVariables returns metadata for GitHub Actions variables in the configured repo, environment, or organization scope. Returned values are redacted.

func (*GitHubSecretsProvider) Name added in v0.9.4

func (p *GitHubSecretsProvider) Name() string

func (*GitHubSecretsProvider) Scope added in v0.60.7

Scope reports the current scope.

func (*GitHubSecretsProvider) SecretTarget added in v0.75.9

func (p *GitHubSecretsProvider) SecretTarget() ProviderTarget

SecretTarget describes the GitHub Actions secret namespace represented by this provider: repository, environment, or organization.

func (*GitHubSecretsProvider) Set added in v0.9.4

func (p *GitHubSecretsProvider) Set(ctx context.Context, key, value string) error

Set encrypts value with the repo's public key and stores it as a secret.

func (*GitHubSecretsProvider) SetEnvironment added in v0.57.5

func (p *GitHubSecretsProvider) SetEnvironment(environment string)

SetEnvironment scopes subsequent operations to a GitHub Actions environment. Empty scope means repository-level secrets. Calling SetEnvironment with a non-empty value flips scope to env.

func (*GitHubSecretsProvider) SetVariable added in v0.80.0

func (p *GitHubSecretsProvider) SetVariable(ctx context.Context, key, value string) error

SetVariable creates or updates a GitHub Actions variable in the configured repo, environment, or organization scope.

func (*GitHubSecretsProvider) StatAll added in v0.67.0

func (p *GitHubSecretsProvider) StatAll(ctx context.Context) ([]SecretMeta, error)

StatAll implements MetadataProvider. It returns presence + timestamp for every secret visible to the configured token. UpdatedAt is the updated_at field from GitHub, falling back to created_at when updated_at is zero.

func (*GitHubSecretsProvider) ValidateEnvironment added in v0.77.0

func (p *GitHubSecretsProvider) ValidateEnvironment(ctx context.Context, name string) (ProviderEnvironment, error)

ValidateEnvironment verifies that a GitHub Actions environment exists for the configured repository.

type HTTPClient

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

HTTPClient is an interface for HTTP requests (allows testing). Used by the AWS Secrets Manager provider.

type KeychainProvider added in v0.11.0

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

KeychainProvider implements Provider using the OS credential store (macOS Keychain, Linux Secret Service, Windows Credential Manager).

All keys are namespaced under a single "service" string so multiple workflow services on the same machine don't collide.

On Linux, requires a running Secret Service implementation (libsecret, gnome-keyring, or KWallet). Headless servers without one should use FileProvider or VaultProvider instead.

KeychainProvider is safe for concurrent use. mu guards all access to trackedKeys.

func NewKeychainProvider added in v0.11.0

func NewKeychainProvider(service string) (*KeychainProvider, error)

NewKeychainProvider returns a provider namespaced to the given service name. Service must not be empty — an empty service stores secrets in a shared namespace where they can collide across applications.

func (*KeychainProvider) Delete added in v0.11.0

func (p *KeychainProvider) Delete(ctx context.Context, key string) error

Delete removes the secret stored under key from the OS keychain.

func (*KeychainProvider) Get added in v0.11.0

func (p *KeychainProvider) Get(ctx context.Context, key string) (string, error)

Get retrieves the secret stored under the given key from the OS keychain.

func (*KeychainProvider) List added in v0.11.0

func (p *KeychainProvider) List(ctx context.Context) ([]string, error)

List returns all keys that have been set during the lifetime of this provider instance.

func (*KeychainProvider) Name added in v0.11.0

func (p *KeychainProvider) Name() string

Name returns the provider identifier "keychain".

func (*KeychainProvider) SecretTarget added in v0.75.9

func (p *KeychainProvider) SecretTarget() ProviderTarget

SecretTarget describes the OS keychain service namespace.

func (*KeychainProvider) Set added in v0.11.0

func (p *KeychainProvider) Set(ctx context.Context, key, value string) error

Set stores the given value under key in the OS keychain.

type MetadataProvider added in v0.67.0

type MetadataProvider interface {
	Provider
	StatAll(ctx context.Context) ([]SecretMeta, error)
}

MetadataProvider is optional: stores that can report which keys exist and when they changed.

type MultiResolver

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

MultiResolver resolves secret references in configuration values using multiple providers identified by URI scheme. It is backward-compatible: bare ${VAR_NAME} references (without a scheme) default to env resolution.

func NewMultiResolver

func NewMultiResolver() *MultiResolver

NewMultiResolver creates a new MultiResolver. An EnvProvider is registered by default under the "env" scheme.

func (*MultiResolver) Expand

func (m *MultiResolver) Expand(ctx context.Context, input string) (string, error)

Expand replaces all ${...} patterns in input with resolved values.

Supported formats:

  • ${vault:secret/path#field} — uses "vault" provider with key "secret/path#field"
  • ${aws-sm:secret-name} — uses "aws-sm" provider with key "secret-name"
  • ${env:VAR_NAME} — uses "env" provider with key "VAR_NAME"
  • ${VAR_NAME} — backward-compatible, uses "env" provider (os.LookupEnv via EnvProvider)

func (*MultiResolver) Provider

func (m *MultiResolver) Provider(scheme string) Provider

Provider returns the provider for a given scheme, or nil if not found.

func (*MultiResolver) Register

func (m *MultiResolver) Register(scheme string, provider Provider)

Register adds or replaces a provider for a given scheme.

func (*MultiResolver) Schemes

func (m *MultiResolver) Schemes() []string

Schemes returns the list of registered provider schemes.

func (*MultiResolver) Unregister

func (m *MultiResolver) Unregister(scheme string)

Unregister removes a provider for the given scheme.

type Provider

type Provider interface {
	// Name returns the provider identifier.
	Name() string
	// Get retrieves a secret value by key.
	Get(ctx context.Context, key string) (string, error)
	// Set stores a secret. Returns ErrUnsupported if read-only.
	Set(ctx context.Context, key, value string) error
	// Delete removes a secret. Returns ErrUnsupported if read-only.
	Delete(ctx context.Context, key string) error
	// List returns all available secret keys. Returns ErrUnsupported if not supported.
	List(ctx context.Context) ([]string, error)
}

Provider defines the interface for secret storage backends.

type ProviderEnvironment added in v0.77.0

type ProviderEnvironment struct {
	Provider string
	Name     string
	Label    string
	Exists   bool
	Source   string
}

ProviderEnvironment describes a provider-owned environment or namespace used as a secret target. It is intentionally metadata-only and must never include secret values or credential material.

type ProviderTarget added in v0.75.9

type ProviderTarget struct {
	Provider string
	Scope    string
	Subject  string
	Label    string
}

ProviderTarget describes the concrete provider namespace a Provider instance reads or writes. It is intentionally value-only and must not include secret values or credential material.

func DescribeTarget added in v0.75.9

func DescribeTarget(provider Provider) ProviderTarget

DescribeTarget returns a safe provider-owned target description. Providers that do not implement TargetDescriber fall back to their Name.

type Redactor added in v0.84.0

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

Redactor is a concurrency-safe, free-text VALUE scanner that replaces any occurrence of a known secret value inside an arbitrary string with the token "[REDACTED:label]". It is the engine's shared utility for scrubbing secret material out of human-facing text (logs, transcripts, agent messages, LLM prompts) where the secret's KEY is not known ahead of time — only its VALUE.

VALUE-scan (Redactor) vs KEY-mask (MaskSensitiveOutputs)

The secrets package provides two DISTINCT redaction categories; do not conflate them:

  • MaskSensitiveOutputs (masking.go) is a KEY-name mask: given a structured outputs map, it replaces the VALUES of a fixed set of sensitive KEYS ("password", "token", ...) with the literal "(sensitive)". It does not scan free text and does not need to know the secret value.

  • Redactor (this type) is a VALUE scan: given an arbitrary blob of text, it finds substrings equal to a previously-seen secret VALUE and replaces them. It does not care about KEY names in the text; it matches on value.

Use MaskSensitiveOutputs for structured key/value maps whose key set is known. Use Redactor when the secret may appear anywhere in free text (chat messages, log lines, prompt bodies) and only its value is known.

Graceful-degrade contract

LoadFromProvider degrades gracefully: if the provider's List call fails (for example because the provider is read-only-without-list, unavailable, or not yet started) LoadFromProvider returns nil and leaves the existing known-value set untouched rather than panicking or emptying the redactor. This lets a caller wire a Redactor before its backing provider is reachable and re-arm it once the provider comes online. A nil Redactor is also safe to call: NewRedactor is not required for zero-value usage, but the helper makes the intent explicit and pre-allocates the map.

func NewRedactor added in v0.84.0

func NewRedactor() *Redactor

NewRedactor returns a ready-to-use Redactor with an empty known-value set. The returned value is safe for concurrent use immediately.

func (*Redactor) AddValue added in v0.84.0

func (r *Redactor) AddValue(label, value string)

AddValue registers a single secret value under the given label and merges it additively into the existing known-value set. Subsequent calls to Redact will replace every occurrence of value with "[REDACTED:label]".

If value is the empty string the call is a no-op: empty values cannot be meaningfully scanned for as substrings and would over-match.

AddValue is concurrency-safe and may be called concurrently with Redact and LoadFromProvider.

func (*Redactor) LoadFromProvider added in v0.84.0

func (r *Redactor) LoadFromProvider(ctx context.Context, p Provider) error

LoadFromProvider performs a FULL-REPLACE of the known-value set from a secrets.Provider: it enumerates the provider's keys via List, resolves each via Get, builds a fresh map off-lock, then swaps it in under a single write lock. Any value previously added via AddValue that is not present in the provider is dropped.

LoadFromProvider degrades gracefully (see the graceful-degrade contract on Redactor): if List returns an error the call returns nil and leaves the existing known-value set untouched — it does NOT panic and does NOT empty the redactor. Individual Get errors for a key skip that key but do not fail the whole load. Empty-string values from the provider are skipped.

A nil Redactor is tolerated: LoadFromProvider is a no-op.

func (*Redactor) Redact added in v0.84.0

func (r *Redactor) Redact(text string) string

Redact returns text with every occurrence of each known secret value replaced by "[REDACTED:label]". The scan is a plain substring match (not a regexp): it is safe to use on untrusted input but callers should not rely on it for canonicalization — only for scrubbing.

Redact is concurrency-safe and may be called concurrently with AddValue and LoadFromProvider. A nil Redactor returns the input text unchanged.

Values are applied longest-first so a shorter secret that is a substring of a longer one cannot shadow it (which would leave the longer value partially unredacted). The known set is snapshotted under the read lock, then the substring scan runs lock-free over the snapshot, giving deterministic output independent of map iteration order.

func (*Redactor) RedactMessage added in v0.84.0

func (r *Redactor) RedactMessage(content string) (string, bool)

RedactMessage redacts content and reports whether any substitution occurred. It is the convenience wrapper for callers (e.g. message pipelines) that want to know whether a message was altered without diffing the strings. A nil Redactor returns (content, false).

type Resolver

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

Resolver resolves secret:// references in configuration values.

func NewResolver

func NewResolver(provider Provider) *Resolver

NewResolver creates a resolver backed by the given provider.

func (*Resolver) Provider

func (r *Resolver) Provider() Provider

Provider returns the underlying provider.

func (*Resolver) Resolve

func (r *Resolver) Resolve(ctx context.Context, value string) (string, error)

Resolve replaces a value containing a secret:// reference with the actual secret. If the value does not start with SecretPrefix, it is returned as-is.

func (*Resolver) ResolveMap

func (r *Resolver) ResolveMap(ctx context.Context, m map[string]any) (map[string]any, error)

ResolveMap resolves all secret:// references in a string map.

type Result added in v0.72.0

type Result struct {
	Reachable bool
	Reason    string
}

Result holds the outcome of a Reachability check.

Reachable is true when the secrets provider can be reached from the given execution environment. Reason is empty when Reachable is true, and contains a human-readable (non-credential-leaking) explanation when Reachable is false.

func Reachability added in v0.72.0

func Reachability(ctx context.Context, p Provider, execEnv string) Result

Reachability determines whether the secrets referenced by a plan can be read from the given execution environment (execEnv). It is designed to be fail-safe: when the answer is uncertain and the exec-env is remote, it returns unreachable rather than failing open.

ctx bounds any backend probe (AccessChecker.CheckAccess). Callers MUST pass a deadline-bearing context (e.g. the pipeline/route ctx) so a slow or unreachable remote backend cannot hang the pre-flight (vault default ~60s, aws ~10s) past the request deadline.

Classification uses a concrete type-switch rather than Name() string-matching. Name() is a config-assigned identifier that operators may override; the concrete type is the authoritative signal for capability detection.

Rules (in order):

  1. *EnvProvider, *FileProvider, *KeychainProvider — host-local backends. Reachable ONLY when execEnv is local ("" | "local" | "local-docker"). For a REMOTE exec-env these are fail-safe UNREACHABLE: under the agent-side-resolution model (ADR 0017), a remote exec-env resolves secrets with the remote agent's OWN provider, so the engine cannot vouch that the engine-host's env vars / files / OS keychain exist on the remote runner (e.g. a macOS keychain entry is not present on a remote Linux runner). This is intentionally conservative: it is the safe default until the agent-probe hardening filed in ADR 0017 lands.

  2. *GitHubSecretsProvider — short-circuited to unreachable BEFORE any AccessChecker call. GitHub secrets are write-only: Get() returns ErrUnsupported and values are only injected at CI-job startup. No exec-env can read them at runtime. CheckAccess on the GitHub provider would succeed (it probes the public key endpoint, not Get), so probing it would give a false "reachable" verdict.

  3. All other providers that implement AccessChecker — call CheckAccess(ctx). Reachable iff CheckAccess returns nil.

  4. Providers that do NOT implement AccessChecker + remote execEnv — fail-safe unreachable ("reachability unknown for remote exec-env; assuming unreachable"). We never fail open for an unknown/unclassified backend in a remote context.

  5. Providers that do NOT implement AccessChecker + local execEnv — treat as reachable (local operation; the runtime will surface access errors if any).

type RotationProvider added in v0.3.3

type RotationProvider interface {
	Provider
	// Rotate generates a new secret value and stores it, returning the new value.
	Rotate(ctx context.Context, key string) (string, error)
	// GetPrevious retrieves the previous version of a rotated secret (for grace periods).
	GetPrevious(ctx context.Context, key string) (string, error)
}

RotationProvider extends Provider with key rotation capabilities.

type SecretMeta added in v0.67.0

type SecretMeta struct {
	Name      string
	Exists    bool
	UpdatedAt time.Time // zero when the store doesn't expose it
}

SecretMeta is presence + freshness for one key. Never carries a value.

type TargetDescriber added in v0.75.9

type TargetDescriber interface {
	SecretTarget() ProviderTarget
}

TargetDescriber is optional: providers implement it when they can describe their concrete namespace, such as GitHub repo/env/org or AWS region.

type VariableMeta added in v0.80.0

type VariableMeta struct {
	Name      string
	Value     string
	Exists    bool
	UpdatedAt time.Time
}

VariableMeta is presence + freshness for one non-secret configuration variable. Value is intentionally optional and callers should usually leave it empty in status displays; provider variables are not credentials, but they can still carry operational details that do not belong in logs.

type VariableProvider added in v0.80.0

type VariableProvider interface {
	Name() string
	SetVariable(ctx context.Context, key, value string) error
	DeleteVariable(ctx context.Context, key string) error
	ListVariables(ctx context.Context) ([]VariableMeta, error)
	CheckVariable(ctx context.Context, key string) (VariableMeta, error)
}

VariableProvider is the provider-side analog to Provider for non-sensitive setup values such as GitHub Actions variables. It must not be used for credential material; sensitive plugin requirements belong in Provider.

type VaultConfig

type VaultConfig struct {
	Address   string `json:"address" yaml:"address"`
	Token     string `json:"token" yaml:"token"`
	MountPath string `json:"mount_path" yaml:"mount_path"`
	Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}

VaultConfig holds configuration for HashiCorp Vault.

type VaultProvider

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

VaultProvider implements a HashiCorp Vault secret provider using the official vault/api client library. It supports KV v2 operations: Get, Set, Delete, and List.

func NewVaultProvider

func NewVaultProvider(cfg VaultConfig) (*VaultProvider, error)

NewVaultProvider creates a new Vault provider using the official vault/api client. It validates the config, creates an api.Client, sets the token and namespace.

func NewVaultProviderFromClient

func NewVaultProviderFromClient(client *vault.Client, cfg VaultConfig) *VaultProvider

NewVaultProviderFromClient creates a VaultProvider from an existing vault/api client. This is useful for testing or when you need custom client configuration.

func NewVaultProviderHTTP deprecated

func NewVaultProviderHTTP(cfg VaultConfig) (*VaultProvider, error)

NewVaultProviderHTTP is a deprecated alias for NewVaultProvider. It exists for backward compatibility.

Deprecated: Use NewVaultProvider instead.

func (*VaultProvider) CheckAccess added in v0.67.0

func (p *VaultProvider) CheckAccess(ctx context.Context) error

CheckAccess implements AccessChecker. It performs a lightweight check by attempting to list the mount's metadata root. The returned error never wraps the raw vault error, which may carry the address or secret path.

func (*VaultProvider) Client

func (p *VaultProvider) Client() *vault.Client

Client returns the underlying vault/api client for advanced use.

func (*VaultProvider) Config

func (p *VaultProvider) Config() VaultConfig

Config returns the provider's Vault configuration.

func (*VaultProvider) Delete

func (p *VaultProvider) Delete(ctx context.Context, key string) error

Delete removes a secret from Vault KV v2.

func (*VaultProvider) Get

func (p *VaultProvider) Get(ctx context.Context, key string) (string, error)

Get retrieves a secret value from Vault KV v2. The key can be in the format "path" or "path#field". If #field is specified, returns that specific field from the secret data. Otherwise, returns the entire data as JSON.

func (*VaultProvider) GetPrevious added in v0.3.3

func (p *VaultProvider) GetPrevious(ctx context.Context, key string) (string, error)

GetPrevious retrieves version N-1 of the secret at the given key from Vault KV v2. It reads the current version metadata to determine N, then fetches version N-1. Returns ErrNotFound if the secret has only one version or does not exist.

func (*VaultProvider) List

func (p *VaultProvider) List(ctx context.Context) ([]string, error)

List returns all secret keys under the mount path. It uses the Vault logical LIST operation on the metadata path.

func (*VaultProvider) Name

func (p *VaultProvider) Name() string

func (*VaultProvider) Rotate added in v0.3.3

func (p *VaultProvider) Rotate(ctx context.Context, key string) (string, error)

Rotate generates a new random 32-byte hex-encoded secret and stores it at the given key, creating a new version in Vault KV v2. It returns the newly generated value.

func (*VaultProvider) SecretTarget added in v0.75.9

func (p *VaultProvider) SecretTarget() ProviderTarget

SecretTarget describes the Vault KV namespace used by this provider.

func (*VaultProvider) Set

func (p *VaultProvider) Set(ctx context.Context, key, value string) error

Set stores a secret value in Vault KV v2. The value is stored as {"value": val} in the secret data map.

func (*VaultProvider) StatAll added in v0.67.0

func (p *VaultProvider) StatAll(ctx context.Context) ([]SecretMeta, error)

StatAll implements MetadataProvider on a best-effort basis. If the Vault client is wired and the mount is reachable, it returns entries from the KV v2 metadata list. Otherwise it returns ErrUnsupported so callers can fall back.

Jump to

Keyboard shortcuts

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