Skip to content

chore(release): prepare release - #113

Merged
ifiokjr merged 1 commit into
mainfrom
monochange/release/release
Nov 3, 2026
Merged

ifiokjr merged 1 commit into
mainfrom
monochange/release/release

Conversation

@monochange

@monochange monochange Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Prepared release

  • command: release
  • group monosecret -> v0.5.0

Release notes

monosecret 0.5.0

Grouped release for monosecret.

Breaking

Sync upstream SecretSpec 0.21: resolver IPC, binary secrets

Owner: @ifiokjr · Review: PR #73

Merge cachix/secretspec from 5ea68378 (the recorded 0.21-era merge base) through upstream main @ b3a29191 (post-0.21 fixes), rebranded into the crates/monosecret, crates/monosecret_derive, crates/monosecret_ffi, and per-language monosecret_* SDK layout.

What breaks
  • Secret values are byte-native. Secrets::set now takes SecretBytes; text callers use set_text and deletions use prompt_and_set. Custom providers update get/set/get_many to SecretBytes; Provider::name returns &str and generator::generate returns bytes.
  • Cache entries use the v4 envelope preserving binary values. New entries are unreadable by 0.20 and earlier (they fall back to the provider); old entries remain readable.
  • Command-generated values include all stdout bytes including trailing newlines and spaces; trim in the command when unwanted. Empty or whitespace-only output is still rejected.
  • monosecret get no longer appends a newline when writing to a pipe or file; terminal output still ends in a newline. Piped monosecret set input remains trimmed text; use --from-file - to preserve exact bytes from stdin.
  • Building the C resolver client requires system yyjson via pkg-config/CMake; static consumers link -lyyjson.
New providers
  • Doppler (doppler://PROJECT[/CONFIG]): read, write, delete, and discover with profile-selected configs and DOPPLER_TOKEN auth.
  • Tailscale Setec (setec://): read, write, delete, and discover through a tailnet-authenticated server, with binary values and version-pinned reads.
New features
  • monosecret serve resolver IPC: request single declared secrets from another process over a versioned stdio protocol, with leases, prompts, store/delete, expiry/revision metadata, and --read-only mode. Rust clients use the new monosecret-ipc crate (async and blocking, including SSH transports); C clients use libmonosecret-resolver.
  • External providers: trusted executables can serve the versioned provider protocol with credential negotiation, interaction references in audit logs, and per-endpoint scoped environments.
  • Project-wide [defaults].providers chains, editor JSON Schemas (monosecret schema --config project|global), OpenPGP/OpenSSH key generation, Bitwarden UUID targeting, and JVM inline specs.
Fixes
  • Bounded HTTP timeouts (10s connect, 60s request) across Vault, OpenBao, Infisical, Cloudflare, Scaleway, AAC, Doppler, and Setec.
  • macOS keyring no longer prompts on every run after an upgrade; reads preserve items and access settings.
  • KDBX 4.0 files upgrade to 4.1 on write preserving encryption/KDF settings.
  • Bitwarden batch reads use one vault listing with search fallback; pass/gopass/LastPass whitespace handling hardened; cache planning avoids provider reads and refuses self-overlapping caches.
  • Post-0.21 upstream fixes: C-resolver early-output registration, timing-independent regression checks, crate-internal test fixtures, flaky-test hardening, and Nix-sandbox ancestor-walk isolation.

Features

Chain the audit log so edits to history are detectable

Packages: 🟠 rust:monosecret

Owner: @ifiokjr · Review: PR #108

Every audit entry now records the SHA-256 digest of its own content and
the digest of the entry before it, and monosecret audit --verify walks
the log recomputing every digest: editing an entry, reordering entries,
or removing one from the middle leaves a break reported by line number.
A new process continues the chain of the log it opens, entries written
before the chain existed are tolerated as an unhashed prefix, and the
restart the size cap performs counts as a new chain start rather than a
break — deleting the tail or the whole file remains indistinguishable
from those, which the docs state plainly, as does the fact that an
unkeyed chain catches partial edits rather than a full rewrite by an
attacker with write access to the log.

Threads sharing a logger append one chain, size-cap restarts create a new genesis, and failed writes leave the chain at the last successful event. Digests use canonical JSON key ordering so builds with different JSON feature sets can verify each other's logs.

Sync upstream 0.21.1 and post-release work

Packages: 🟠 rust:monosecret, 🟢 rust:monosecret_rpc

Owner: @ifiokjr · Review: PR #100

Ports the upstream range accumulated since the 0.4.0 sync, keeping every
fork-specific fix and provider. The headline additions:

  • Credential generators and X.509 identities. New generation types —
    passphrases and BIP-39 mnemonics, WireGuard and JWK private keys, age
    identities, and self-signed x509_identity PKCS#12 archives — plus typed
    conversion targets (pkcs12, pkcs8_private_key, x509_certificate,
    x509_certificate_chain, x509_issuer_chain) with from/format/
    credentials declarations decoded through the new typed module.
  • Transient failure retries. Provider reads share a bounded exponential
    retry policy across HTTP, SDK, CLI, and external transports; unknown errors
    stay permanent and writes opt in only with a replay-safety guarantee.
    Per-provider hand-rolled retry (Doppler's rate-limit handling) folds into
    the shared policy.
  • Wire compatibility hardening. The RPC crate accepts additive version 1
    response/result members, bounds JSON integers to the 2^53-1 safe range in
    both directions, and the C resolver mirrors both rules for portable peers.
  • Profile-aware import. monosecret import --profile selects the profile
    both sides of an import resolve against.
  • Unknown-field warnings. Secret declarations ignore unknown fields with
    a warning instead of silently dropping them.
  • Public provider listing. monosecret::providers() exposes built-in
    provider metadata, including feature-gated entries with their enabling
    feature.

Also ports monosecret init's schema directive on generated manifests,
safer block_on for current-thread runtimes, ResolvedSecret Debug redaction
(already independently hardened in the fork, whose stronger path redaction is
kept), the fake-provider-CLI test harness that avoids ETXTBSY on Linux, and
removal of the dead root test crate.

Beyond the 50ff51e cutoff, the sync also lands the follow-up upstream
fixes: monosecret check no longer persists decrypted as_path temp
files it never prints (they now drop with the command — verified by
regression tests pinning get/export persistence), keepass moves to
0.13.21 to fix KDBX DeletionTime serialization, and Proton Pass refs
gain read-only field selection (values never travel through pass-cli
arguments, which would expose them in the process list).

Dependency advisories found by cargo audit are addressed where a fixed
release exists: rustls 0.23.46 (secret-exposing Debug impls, KEX
downgrade), rustls-webpki 0.103.16 (distrusted-intermediate acceptance),
and webpki-root-certs 1.0.11 (emSign distrust). The legacy rustls 0.21
chain pinned under the AWS SDK stack and the unfixed rsa Marvin
advisory remain and are tracked as accepted risk.

  • Add a small Rust client for native and Wasm hosts. The client feature with default-features = false provides zeroizing access to host-resolved UTF-8 values, or named environment entries injected by monosecret run on native targets. Its normal dependency graph is only secrecy and zeroize; native resolution, process launching, crypto generators, and providers belong to the runtime feature. Default CLI/provider builds still include that runtime. Consumers that previously disabled defaults for native resolution must now enable runtime explicitly.
    Packages: 🟠 rust:monosecret
    Owner: @ifiokjr · Review: PR #112

Fixes

Refuse caches that would store secrets in plaintext

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #109

A cached provider alias whose cache provider does not store values
encrypted at rest is now refused at planning time: the cache envelope
is the secret's value in base64, so a plaintext store would hold a
plaintext copy of every secret it serves. Providers declare encryption
in their registry metadata — keyring, age, sops, and every managed
secret store declare it; env, dotenv, file, and Kubernetes (whose etcd
keeps secrets base64-encoded unless the cluster turns on encryption)
deliberately do not — and an undeclared or external store is refused
rather than assumed safe. An alias that accepts the tradeoff says so
explicitly with cache.allow_plaintext = true (0.4.5+), and the error
names the encrypted providers that need no opt-in.

ejson timeout tests no longer fail on a loaded machine

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #76

The two tests that prove a hung or exited ejson CLI is stopped at its timeout
read the stub's descendant-PID file with unwrap, and a loaded runner could
kill the process group before the shell wrote it — so the suite failed with "No
such file or directory" on a machine that was busy with something else. They now
wait for the file with a bounded retry, which keeps the assertion (the stub must
record its descendant, and the descendant must be gone) while removing the race,
and the exit-path test's timeout is generous because what it checks is the cost
relative to the deadline rather than how fast the stub runs.

No runtime behavior changes: the provider's timeout handling is untouched.

Allow cold macOS SDK validation to finish

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #105

The macOS test job has a two-hour budget for environment setup, Rust and
Dart tests, and native language SDK builds and tests. This avoids cancelling
successful cold runs during Swift compilation. Linux keeps its existing
one-hour budget, and every test suite still runs.

Block core dumps and ptrace while the CLI holds secrets

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #107

The monosecret, git-credential-monosecret, and
docker-credential-monosecret binaries now disable core dumps on every
Unix and, on Linux, mark the process non-dumpable, so a same-user process
cannot read the resolver's memory or /proc/<pid>/environ during the
window secrets are loaded. Working on monosecret itself is still possible
by setting MONOSECRET_ALLOW_DUMPABLE=1. The library embedding path (FFI
and the language SDKs) deliberately does not change the dumpability of a
host application's process.

Free runner disk space before packaging

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #110

The packaging workflow now removes unused hosted-runner SDKs and Docker
images before installing its development environment. This avoids running
out of disk before the package validation steps can start.

depends_on cycles no longer overflow the stack

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #71 · Closed issues: #70

Forcing a provider that declares depends_on (e.g. monosecret run --provider op) applied the session-wide override to the bootstrap secret too,
so building the provider needed the provider: unbounded recursion ending in
thread 'main' has overflowed its stack with no error to report or retry
against. The same abort happened for genuine configuration cycles (a
depends_on secret routed back at its own provider directly or through
profile defaults).

Bootstrap secrets now resolve from their own declared routes — the
--provider flag, the builder override, and MONOSECRET_PROVIDER are ignored
while they resolve — so --provider op reads OP_SERVICE_ACCOUNT_TOKEN from
where it is configured and then queries 1Password. Re-entrant construction is
tracked per thread and fails with a provider dependency cycle: store -> TOKEN -> store error naming the chain, and config loading rejects the direct
form up front (monosecret check reports it before anything runs). Six
regression tests cover the flag, the environment variable, both config-cycle
spellings, and static validation.

  • Keep release preparation within runner disk space. Release preparation and tagging now free the hosted runner's unused SDK and image space before entering devenv. The full development environment otherwise exhausts the disk while building the musl toolchain, preventing the MonoChange bot from creating or refreshing its release PR.
    Packages: 🟢 rust:monosecret
    Owner: @ifiokjr · Review: PR #111

Harden secret handling and clear workspace clippy warnings

Packages: 🟢 rust:monosecret, 🟢 rust:monosecret_rpc

Owner: @ifiokjr · Review: PR #81

Env files and dotenv stores are written owner-only (0600) through staged,
fsynced, atomically renamed temporaries, and symlinked store paths are refused
rather than written through. HTTP redirect refusal moves into the shared
provider client builder, closing the gap for the Railway, Pulumi ESC, Vercel,
and Netlify providers that had none, and the redundant per-provider policies
are dropped. Debug renderings of resolved secrets no longer print value or
path for any payload type, and GitHub ::add-mask:: commands are
percent-encoded and split one per line so multi-line values cannot leak into
job logs. The keyring username lookup is cached per process. The conformance
runner is clippy-clean (indexing/slicing, pass-by-value, unnecessary wraps),
its package renamed to kebab-case monosecret-rpc-conformance to silence the
cargo manifest warning, and cargo clippy and cargo check now emit zero
warnings across the workspace.

Security hardening from the deep audit

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #101

Fixes every actionable finding from a second, line-by-line security audit
of the provider layer, secret lifecycle, CLI surface, C resolver, and
packaging:

  • bws: monosecret set against bws:// is now opt-in behind
    MONOSECRET_BWS_ALLOW_ARGV_VALUES=1. The bws CLI only accepts a secret
    value as a command-line argument, which exposes it in the process list;
    the same reasoning already made Proton Pass field refs read-only.
  • env/export integrity: monosecret env now refuses non-UTF-8 secrets
    with the as_path guidance instead of silently emitting lossy
    replacement characters that differ from what run injects; non-ASCII
    secret names are rejected at emission (bash cannot source them);
    env --output refuses symlinked paths, tightens a pre-existing loose
    file to 0600, and monosecret init refuses a symlinked monosecret.toml.
  • dotenv/age: parse errors now report position and kind only — the
    dependency's error Display prints the raw offending line, which in age's
    case is decrypted plaintext. dotenv and age stores refuse symlinked
    paths on read as well as write, and the age store writes atomically
    (staged 0600 + fsync + rename) instead of a world-readable in-place
    truncate.
  • file provider: entries are read with O_NOFOLLOW, closing the
    check-then-read window where a racing writer could swap an entry for a
    symlink.
  • vault/openbao: tls=false is refused for non-loopback hosts — the
    request token would cross the network in cleartext.
  • manifests: generate.length/generate.bytes are bounded
    (1..=4096) so a fat-fingered length errors instead of aborting the
    process on an uncatchable allocation failure; case-folded duplicate
    secret names are rejected because the Windows environment collapses
    them nondeterministically; init --from dotenv:// skips keys that are
    not valid secret names instead of writing a manifest that fails its own
    validation.
  • hygiene: value-bearing wire structs (Bitwarden items, Cloudflare and
    Setec payloads) print [REDACTED] in Debug; the shell export buffer is
    zeroized; ValidationErrors Debug no longer carries default values;
    the docker credential helper writes diagnostics to stderr per the
    helper protocol; monosecret run's env is unchanged.
  • C resolver: returned buffers are defensively NUL-terminated (an
    unterminated allocation let error strings overread adjacent heap);
    ss_set_error keeps truncated messages instead of dropping them; the
    server-advertised methods array is capped so the pairwise duplicate
    check cannot be driven quadratically by a hostile endpoint; prompt
    answers reject embedded NUL like every other string field; the header
    now documents that frees must be serialized with in-flight calls on the
    same client.
  • PHP FFI installer: a failed checksum-sidecar fetch now fails closed
    instead of installing the library unverified.
  • tempfile: the getrandom feature is restored so temp-file names
    reseed from OS entropy in minimal/FFI builds.

Gate every pull request on the dependency advisory database

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #104

CI now runs cargo deny against the whole workspace lockfile: RustSec
advisories, the license allow list in deny.toml, duplicate-version and
wildcard policy, and permitted registry sources. The first run surfaced
seventeen live advisories nobody had seen.

The AWS Secrets Manager and Parameter Store providers no longer pull the
end-of-life hyper 0.14 + rustls 0.21 TLS client, which carried four
unpatched certificate-verification and session-secret advisories; they use
the same rustls 0.23 + aws-lc stack as every other HTTP provider. Lockfile
updates clear the remaining fixable advisories in tokio, ctutils, and a
yanked yoke-derive and async-executor releases. The PHP extension uses
ext-php-rs 0.16 with ZIP 9 and zstd 0.14, removing the vulnerable archive
build dependencies and their advisory exceptions. Only the rsa and
crypto-bigint timing advisories during local key generation remain
ignored in deny.toml, with an exposure assessment and the condition that
retires each ignore.

Prepare runner disk space for every Ubuntu job

Packages: 🟢 rust:monosecret

Owner: @ifiokjr · Review: PR #108

Development-environment setup now frees unused Ubuntu runner SDKs and
Docker images by default. This gives documentation, lint, benchmark, and
feature-check jobs the same disk preparation as builds and coverage, so
installing the shared environment does not exhaust the runner's disk.
Other platforms are unaffected, and callers can still opt out explicitly.

Release completed IPC request slots before publishing responses

Packages: 🟢 rust:monosecret_rpc

Owner: @ifiokjr · Review: PR #104

Sequential resolver calls no longer intermittently return unavailable
after filling the negotiated request window. A completed handler keeps its
slot until the bounded writer takes its response, then releases the slot
before the client can read that response. Cleanup still observes whether
the response was written, and cancelled or timed-out handlers retain their
slots until they actually stop.

Documentation

Keep the README's provider count pinned to the registry

Packages: ⚪ rust:monosecret

Owner: @ifiokjr · Review: PR #103

The README claimed eleven storage backends while the provider registry
ships forty-one, and the repository layout omitted the eight non-Rust
language SDKs, the conformance suite, and the schema directory. The
README now states the real count and describes the real layout, a new
registry test fails whenever the advertised count drifts from the
registered providers, and the one-off agent session reports committed to
the repository root (context.md, PR-CHANGES.md, sync-report.txt)
are gone along with their ignore-list entries. mdt's machine-local index
cache is no longer tracked, so mdt check and dprint stop rewriting
each other's output.

Other

  • Avoid "Text file busy" in passbolt provider tests. The passbolt test fixture wrote its fake CLI script through a file handle that stayed open in this process. A subprocess forked by another test thread could inherit that handle, and running the script then failed with ETXTBSY. The fixture now writes a scratch file and renames it into place, the same approach the bws provider tests already use. Only test code changes.
    Packages: ⚪ rust:monosecret
    Owner: @ifiokjr · Review: PR #94

Benchmark the hot paths and gate pull requests on them

Packages: ⚪ rust:monosecret

Owner: @ifiokjr · Review: PR #105

A criterion suite now covers the paths every invocation pays for: parsing
and validating monosecret.toml, composing the manifest, building the
derive macro's intermediate representation, resolving a profile through
the env provider both directly and via resolve_json, encoding and
classifying cache envelopes, and rendering monosecret env output. The
perf CI job benchmarks the base commit and the change on one runner and
fails when a median is more than 25% slower with the difference outside
three standard errors, and it keeps the workspace dependency graph under
a budget so compile time and binary size cannot creep up one crate at a
time. The crate gains a hidden __bench feature that exposes thin,
tested wrappers over the crate-private cache codec for the benchmarks;
it is not a public API.

Changed files

  • CHANGELOG.md
  • Cargo.lock
  • Cargo.toml
  • Package.swift
  • crates/monosecret/CHANGELOG.md
  • crates/monosecret/Cargo.toml
  • crates/monosecret_derive/CHANGELOG.md
  • crates/monosecret_derive/Cargo.toml
  • crates/monosecret_ffi/Cargo.toml
  • crates/monosecret_rpc/Cargo.toml
  • dart/monosecret/CHANGELOG.md
  • dart/monosecret/lib/src/version.dart
  • dart/monosecret/pubspec.yaml
  • dart/monosecret_builder/CHANGELOG.md
  • dart/monosecret_builder/pubspec.yaml
  • dotnet/monosecret_dotnet/src/Monosecret/Monosecret.csproj
  • haskell/monosecret_hs/monosecret.cabal
  • npm/monosecret__cli/package.json
  • npm/monosecret__cli-darwin-arm64/package.json
  • npm/monosecret__cli-darwin-x64/package.json
  • npm/monosecret__cli-linux-arm64-gnu/package.json
  • npm/monosecret__cli-linux-arm64-musl/package.json
  • npm/monosecret__cli-linux-x64-gnu/package.json
  • npm/monosecret__cli-linux-x64-musl/package.json
  • npm/monosecret__cli-win32-arm64-msvc/package.json
  • npm/monosecret__cli-win32-x64-msvc/package.json
  • npm/monosecret__client/package.json
  • npm/monosecret__client-darwin-arm64/package.json
  • npm/monosecret__client-linux-arm64-gnu/package.json
  • npm/monosecret__client-linux-x64-gnu/package.json
  • npm/monosecret__client-win32-x64-msvc/package.json
  • npm/monosecret__skill/package.json
  • pnpm-lock.yaml
  • pubspec.yaml
  • python/monosecret_py/pyproject.toml
  • ruby/monosecret_rb/monosecret_rb.gemspec

@codecov-commenter

codecov-commenter commented Nov 2, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.44%. Comparing base (1085de0) to head (410f5eb).

❌ Your project status has failed because the head coverage (27.74%) is below the target coverage (95.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #113      +/-   ##
==========================================
- Coverage   87.46%   87.44%   -0.02%     
==========================================
  Files         127      127              
  Lines       73904    73904              
  Branches       49       49              
==========================================
- Hits        64640    64628      -12     
- Misses       9255     9267      +12     
  Partials        9        9              
Flag Coverage Δ
crate-monosecret 87.53% <ø> (-0.02%) ⬇️
crate-monosecret-derive 87.53% <ø> (-0.02%) ⬇️
dart 94.50% <ø> (ø)
dart-monosecret 89.33% <ø> (ø)
dart-monosecret-builder 100.00% <ø> (ø)
npm 27.74% <ø> (ø)
npm-monosecret-client 27.74% <ø> (ø)
rust 87.53% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@monochange
monochange Bot force-pushed the monochange/release/release branch 6 times, most recently from 315f884 to 3f5e9d4 Compare November 3, 2026 05:36
Prepare release.

- release targets: monosecret (0.5.0)
- released packages: @monosecret/cli, @monosecret/cli-darwin-arm64, @monosecret/cli-darwin-x64, @monosecret/cli-linux-arm64-gnu, @monosecret/cli-linux-arm64-musl, @monosecret/cli-linux-x64-gnu, @monosecret/cli-linux-x64-musl, @monosecret/cli-win32-arm64-msvc, @monosecret/cli-win32-x64-msvc, @monosecret/client, @monosecret/client-darwin-arm64, @monosecret/client-linux-arm64-gnu, @monosecret/client-linux-x64-gnu, @monosecret/client-win32-x64-msvc, @monosecret/skill, monosecret, monosecret_builder, monosecret_derive, monosecret_ffi, monosecret_rpc
- updated changelogs: CHANGELOG.md, crates/monosecret/CHANGELOG.md, crates/monosecret_derive/CHANGELOG.md, dart/monosecret/CHANGELOG.md, dart/monosecret_builder/CHANGELOG.md
- deleted changesets: .changeset/1790278083-monosecret.md, .changeset/audit-hash-chain.md, .changeset/cache-encrypted-at-rest.md, .changeset/ejson-timeout-tests.md, .changeset/macos-sdk-test-time-budget.md, .changeset/non-dumpable-process.md, .changeset/package-runner-disk-space.md, .changeset/passbolt-fake-cli-etxtbsy.md, .changeset/perf-regression-gate.md, .changeset/provider-depends-on-cycle.md, .changeset/readme-provider-count.md, .changeset/release-runner-disk-space.md, .changeset/rpc-completed-request-slots.md, .changeset/secret-hardening-clippy-cleanup.md, .changeset/security-audit-round-2.md, .changeset/supply-chain-gate.md, .changeset/sync-upstream-0-21-1.md, .changeset/ubuntu-setup-disk-space-default.md, .changeset/wasm-client.md
@monochange
monochange Bot force-pushed the monochange/release/release branch from 3f5e9d4 to 410f5eb Compare November 3, 2026 06:35
@ifiokjr
ifiokjr merged commit 74a7e18 into main Nov 3, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants