Secrets¶
Public API for the secrets subsystem, covering credential resolution across multiple providers such as kwargs, configuration files, keyring backends, and SOPS encrypted payloads.
Tip
For usage guide and examples, see Secrets.
Quick overview¶
resolve_secret(name)is the main entry point for resolving a secret by name.SecretResolverorchestrates credential resolution across multiple providers.sensitivedecorator marks functions whose return values should not be logged.Exceptions distinguish not-found (
SecretNotFoundError) from decryption failures (SecretDecryptionError).
Resolver¶
resolve_secret¶
- kstlib.secrets.resolve_secret(name: 'str', *, config: 'Mapping[str, Any] | None' = None, secrets: 'Mapping[str, Any] | None' = None, **request_kwargs: 'Any') 'SecretRecord' -> SecretRecord[source]
Resolve a secret by name using the global resolver cascade.
- Parameters:
name (str) – Identifier of the secret (
"smtp.password"for example).config (Mapping[str, Any] | None) – Optional configuration mapping describing providers. When not provided the function attempts to reuse the globally loaded config.
secrets (Mapping[str, Any] | None) – Optional mapping of secret overrides. These take precedence over all other providers (useful for testing).
request_kwargs (Any) – Additional keyword arguments forwarded to
SecretRequest. Supported keys arescope,required,defaultandmetadata.
- Returns:
A
SecretRecorddescribing the resolved secret and its provenance.- Raises:
SecretNotFoundError – If the secret is not found and required=True.
TypeError – If unsupported keyword arguments are provided.
- Return type:
SecretRecord
Example
>>> from kstlib.secrets.resolver import resolve_secret >>> # Override for testing >>> record = resolve_secret("api.key", secrets={"api.key": "test-value"}) >>> record.source <SecretSource.KWARGS: 'kwargs'>
get_secret_resolver¶
- kstlib.secrets.get_secret_resolver(config: 'Mapping[str, Any] | None' = None, *, secrets: 'Mapping[str, Any] | None' = None) 'SecretResolver' -> SecretResolver[source]
Build a resolver from configuration mapping.
When no explicit provider list is given, the default cascade is:
(KwargsProvider if secrets) -> EnvironmentProvider -> KeyringProvider -> (SOPSProvider if configured).- Parameters:
- Returns:
Configured
SecretResolverinstance.- Return type:
SecretResolver
Example
>>> from kstlib.secrets.resolver import get_secret_resolver >>> resolver = get_secret_resolver() # uses defaults >>> resolver.name 'default'
SecretResolver¶
- class kstlib.secrets.SecretResolver(providers, *, name=None)[source]
Bases:
objectResolve secrets by delegating to a sequence of providers.
The resolver iterates through providers in order until one returns a value. If no provider can resolve the secret and no default is given, a
SecretNotFoundErroris raised (whenrequired=True).Example
>>> from kstlib.secrets.resolver import SecretResolver >>> from kstlib.secrets.providers import get_provider >>> from kstlib.secrets.models import SecretRequest >>> resolver = SecretResolver([get_provider("environment")], name="app") >>> # resolver.resolve(SecretRequest(name="API_KEY"))
- __init__(self, providers: 'Sequence[SecretProvider]', *, name: 'str | None' = None) 'None' -> None[source]
Initialise the resolver with a provider cascade.
- Parameters:
providers (Sequence[SecretProvider]) – Ordered sequence of secret providers to query.
name (str | None) – Human-readable name for this resolver (used in error messages).
- property name: str
Return the resolver name.
- resolve(self, request: 'SecretRequest') 'SecretRecord' -> SecretRecord[source]
Resolve the secret using the configured provider cascade.
- Parameters:
request (SecretRequest) – The secret request to resolve.
- Returns:
A SecretRecord with the resolved value and metadata.
- Raises:
SecretNotFoundError – If the secret is not found and required=True.
- Return type:
SecretRecord
- async resolve_async(self, request: 'SecretRequest') 'SecretRecord' -> SecretRecord[source]
Async counterpart for
resolve.- Parameters:
request (SecretRequest) – The secret request to resolve.
- Returns:
A SecretRecord with the resolved value and metadata.
- Raises:
SecretNotFoundError – If the secret is not found and required=True.
- Return type:
SecretRecord
Models¶
SecretRecord¶
- class kstlib.secrets.SecretRecord(value, source, metadata=<factory>)[source]
Bases:
objectRepresents the value returned by the resolver.
- value
The secret itself.
- Type:
Any
- source
The origin of the secret.
- Type:
kstlib.secrets.models.SecretSource
- metadata
Provider specific metadata (e.g. timestamp, path, ttl).
- Type:
Mapping[str, Any]
- value: Any
- source: SecretSource
- __init__(self, value: 'Any', source: 'SecretSource', metadata: 'Mapping[str, Any]' = <factory>) None -> None
SecretRequest¶
- class kstlib.secrets.SecretRequest(name, scope=None, required=True, default=None, metadata=<factory>)[source]
Bases:
objectDescribes a secret lookup request.
- name
Identifier of the secret (e.g. “smtp.password”).
- Type:
- scope
Optional scope that providers can exploit for namespacing.
- Type:
str | None
- required
Whether the resolver must raise if the secret is missing.
- Type:
- default
Optional fallback value when the secret is not required.
- Type:
Any | None
- metadata
Arbitrary provider hints (e.g. keyring namespace).
- Type:
MutableMapping[str, Any]
- name: str
- required: bool
- metadata: MutableMapping[str, Any]
- __init__(self, name: 'str', scope: 'str | None' = None, required: 'bool' = True, default: 'Any | None' = None, metadata: 'MutableMapping[str, Any]' = <factory>) None -> None
SecretSource¶
- class kstlib.secrets.SecretSource(value)[source]
-
Enumerates the possible origins for a resolved secret.
- KWARGS = 'kwargs'
- ENVIRONMENT = 'environment'
- KEYRING = 'keyring'
- SOPS = 'sops'
- KMS = 'kms'
- DEFAULT = 'default'
- __format__(self, format_spec)
Returns format using actual value type unless __str__ has been overridden.
Sensitive Decorator¶
sensitive¶
- kstlib.secrets.sensitive(record: 'SecretRecord', *, providers: 'Sequence[CachePurgeProtocol] | None' = None) 'Iterator[Any]' -> Iterator[Any][source]
Temporarily expose a secret and scrub it afterwards.
The context manager yields the secret value so it can be used within the protected block. On exit it attempts to overwrite mutable buffers in place, clears provider caches when available, and replaces the value stored in the
SecretRecordwithNoneto break lingering references.Example
>>> from kstlib.secrets.models import SecretRecord, SecretSource >>> from kstlib.secrets.sensitive import sensitive >>> record = SecretRecord(value=bytearray(b"api-token"), source=SecretSource.SOPS) >>> with sensitive(record) as secret: ... secret[:3] = b"***" # handle the secret >>> record.value is None True
- Parameters:
record (SecretRecord) – Secret wrapped in a
SecretRecord.providers (Sequence[CachePurgeProtocol] | None) – Optional providers whose caches should be purged after use.
- Yields:
The decrypted secret value.
CachePurgeProtocol¶
Exceptions¶
SecretError¶
- class kstlib.secrets.SecretError[source]
Bases:
KstlibError,RuntimeErrorBase class for all secrets related errors.
SecretNotFoundError¶
- class kstlib.secrets.SecretNotFoundError[source]
Bases:
SecretErrorRaised when no provider can supply a requested secret.
SecretDecryptionError¶
- class kstlib.secrets.SecretDecryptionError[source]
Bases:
SecretErrorRaised when a secret payload cannot be decrypted.