Release Notes
Changed
- A provider URI may no longer carry a credential. A URI with a password
(scheme://user:secret@host) is rejected, and onepassword+token:// no
longer accepts the service account token in its userinfo
(onepassword+token://token@vault). A URI is committed to secretspec.toml,
echoed into shell history, and printed by CI, so a credential written there is
already disclosed and redacting it at the terminal cannot retract it. Keep the
scheme and supply the credential through a provider credential
(secretspec config provider login <alias>, or credentials = { ... } on the
alias) or the provider's environment variable; the errors name both. An
unparseable provider specification is now also redacted before it is reported.
secretspec get resolves through the same path as the SDK's resolve_named,
so a single-secret read makes exactly the decisions batch resolution makes. It
continues to read the whole profile regardless of an active scope, and audits
the coordinates it actually reached.
- 1Password field references now resolve in one batched CLI call, reducing
repeated unlocks and process startup when loading multiple secrets. If a
missing reference requires individual reads, those reads remain bounded and
concurrent.
- The Rust SDK's
ProviderAlias now provides leaf, credentials, and
credentials_mut helpers so callers can construct and inspect leaf or
inline-cached aliases without depending on their storage representation.
Added
- The Rust SDK can resolve a single secret with
Secrets::resolve_named, which
reads only that secret and the inputs it composes from. An unrelated missing
required secret no longer fails the call, and the result distinguishes an
undeclared name (including one the active scope hides) from a declared secret
with no value, reporting whether that value was required.
Secrets::with_default_reason sets a session reason only when none is already
in effect, so an embedding application can describe itself without discarding
the reason its own caller supplied through with_reason or
SECRETSPEC_REASON.
- Secrets can set
prompt = true to request a hidden value from the controlling
terminal when secretspec run finds no stored value. Writable providers save
the answer for later runs; the null provider keeps it invocation-only.
- Profiles can opt out of inheriting
[profiles.default] by setting
inherit = false in their profile defaults (0.19+), allowing standalone
secret sets alongside profiles that still share the default declarations.
- Passbolt provider (
passbolt://): store and read secrets in a
self-hosted Passbolt server through the community-maintained
go-passbolt-cli, with convention-based names, references to existing
resources, and credentials supplied by the CLI configuration or SecretSpec
provider environment variables.
- Provider aliases can define native
ref templates and secrets can override
coordinates per leaf alias with refs, so fallback providers and import
sources/destinations resolve independently. import --delete-source now
preflights the whole migration, verifies all writes before cleanup, and can
safely move between distinct entries in the same physical store.
- A
null provider lets non-sensitive, version-controlled environment values
use their manifest defaults and lets generated secrets stay ephemeral, with a
fresh value returned for each resolution and nothing written to provider
storage.
secretspec set and interactive secretspec check now preview the resolved
write destination before reading the value, including the exact file and
selector for SOPS.
- A
file provider stores each secret as one plaintext UTF-8 file beneath an
explicitly configured relative or absolute directory, with project/profile
isolation and support for existing file-mounted secrets through ref.item.
- Secrets can select values from stored JSON documents with RFC 6901 pointers
using extract. Extraction composes with provider-native references and
storage decoding; selected values are read-only so sibling document data is
never overwritten or deleted.
- Secrets can store values as standard Base64, URL-safe Base64, or hexadecimal
using encoding; writes encode logical text and reads decode stored values,
while as_path = true materializes arbitrary decoded bytes.
secretspec-ffi installs (via cargo cinstall) together with its C header
and a secretspec_ffi.pc, so consumers can link it — statically or
dynamically — without hand-written linker flags.
- The Haskell SDK's new
use-pkg-config cabal flag
(cabal build -f use-pkg-config) resolves an installed static or shared
library through pkg-config.
- The Ruby SDK's native extension accepts a new
--enable-pkg-config build
flag (gem install secretspec -- --enable-pkg-config) that resolves an
installed static or shared library through pkg-config.
- The Go SDK has a new
pkgconfig build tag (go build -tags pkgconfig) that
links an installed static or shared library, so it also works for a go get
dependency.
- The Haskell SDK declares the archive's macOS system frameworks
(SystemConfiguration, Security, CoreFoundation) in its cabal file, so
GHC passes them to every link on macOS.
- A single provider can now attach its cache directly to the same alias with
uri and cache, avoiding a second wrapper alias while retaining provider
credentials. Cached fallback routes remain available for multiple
authoritative providers.
Fixed
- Ruby gems for Apple silicon now use the generic
arm64-darwin platform
instead of including the build runner's Darwin version.
- Windows shared
secretspec-ffi installs now place the runtime DLL in the
documented PREFIX/lib runtime library directory.
import warns when a literal source uses convention naming but a provider
alias for the same storage container addresses active secrets differently
through a ref template or scoped refs. Import output also retains the
selected source alias, making alias-specific addressing visible without
changing literal-provider semantics.
(#312)
- The error for a coordinate a provider does not support now points at
refs.<alias> and alias ref templates as well as at removing the
coordinate, so a field written for one store no longer has to be dropped to
reach another store that organizes the secret differently.
(#266)
- The Proton Pass provider works with
pass-cli 2.2.4 and later, which removed
the pass-cli test subcommand the provider ran to check the session before
every read and write. The check now tries pass-cli info and falls back to
pass-cli test, so a single build works across pass-cli releases that
disagree about which check exists. A pass-cli with neither is reported as
incompatible with the SecretSpec release, instead of passing the CLI's usage
text through as the error.
(#279)
- SOPS write-target previews consistently use canonical physical paths on macOS
and Windows, matching the files used for writes.
- Passbolt now updates UUID-addressed resources outside a configured folder,
treats URI- and environment-selected forms of the same server as one import
destination, rejects malformed provider query parameters, and avoids
redundant resource listings during writes.
- Cache entries now store their absolute expiration time, allowing SecretSpec
to remove an expired entry whenever it encounters one, including at an
address previously used by another project or profile. Changing max_age
invalidates entries written under the previous policy. Fresh v2 entries remain
usable during migration, while foreign v2 entries remain untouched.
(#275)
run preserves non-UTF-8 environment values byte-for-byte when launching
child processes on Unix.
- Provider-scoped references now compare provider-defaulted coordinates before
destructive imports, apply scoped address overrides before comparing stores,
and recognize missing file destinations reached through symlinked parents.
They also invalidate caches for every coordinate change without display-format
collisions and retain the attempted native location in audit events when a
provider read fails. Same-store import validation handles Windows provider
paths without treating separators as TOML escapes.
- Profile overrides can switch between legacy
ref and provider-scoped refs
without retaining both inherited address models and failing validation.
- JSON extraction from file-backed documents now handles Windows store paths
without treating path separators as TOML escapes.
- SDK pkg-config setup now pins cargo-c's library and metadata install
directories, so Go, Ruby, and Haskell reliably discover
secretspec_ffi.pc across environments.
- The keyring provider no longer intermittently fails with a "No default store
has been set" error when resolving multiple secrets concurrently.
- The SOPS provider no longer substitutes a second time into a rendered path
segment, so a project or profile literally named {profile} or {project}
resolves to the file you configured instead of a different one.
- Invalid SOPS path templates are now rejected when loading serialized
provider configurations instead of being accepted without validation.
- The LastPass provider now reports its full item template rather than only the
first segment. A multi-segment template such as
lastpass://Shared/{project}/{profile}/{key} used to be reported as plain
lastpass, which reads back as the default secretspec/{project}/{profile}/{key}
template — a different folder — and lastpass://Work/TeamA/{key} read back as
the literal item Work, one item for every secret. Templates that differ
below their first segment are now distinguished, so repointing a cached route
at a new template invalidates its cached values instead of serving the old
ones until they expire. Single-segment templates are unaffected; cached
entries for a multi-segment template refetch once, silently, on first run.
- Provider fallback chains now reuse each provider and resolve independent
primary misses concurrently. Azure Key Vault providers also reuse their
client and serialize its initial challenge-based authentication, so chains
such as providers = ["keyring", "akv"] no longer fetch every fallback in
series or launch separate Azure CLI processes for the same resolution.
- Reusing a
Secrets instance now refreshes fallback providers for each
resolution, so provider-side caches observe rotated values and providers use
the latest reason supplied with with_reason.
Install secretspec 0.19.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/cachix/secretspec/releases/download/v0.19.0/secretspec-installer.sh | sh
Download secretspec 0.19.0