Releases: jdx/fnox
v1.24.0: GitHub OAuth lease backend
A focused release that adds a new github-oauth lease backend for minting short-lived, user-attributed GitHub tokens via OAuth device flow — without distributing an app private key.
Added
github-oauth lease backend (#464) -- @jdx
A new lease type that creates GitHub App user access tokens using the OAuth device flow and injects them as GITHUB_TOKEN (or a custom env var) for the duration of fnox exec. It is the recommended option for local development and user-attributed gh / GitHub API usage where you want a short-lived token tied to the signed-in user instead of a long-lived PAT in fnox.toml.
[leases.github]
type = "github-oauth"
client_id = "Iv1.yourgithubappclientid"
scope = "repo read:org workflow"
duration = "8h"fnox exec -- gh pr listOn first run, fnox prints a verification URL and user code, optionally opens the URL in your browser, and polls GitHub until you approve the device prompt. Subsequent runs reuse the cached token until it expires.
Highlights of the backend:
- Only the GitHub App client ID is required — no app private key and no client secret, so the lease config can be checked in and shared across a team. (The existing
github-appbackend remains the right choice for installation tokens in CI.) - OS keyring caching of access and refresh tokens, keyed by client id + scope + endpoints. Disable with
keyring_cache = falseto force the device flow on every lease. - Refresh token reuse when GitHub issues one — refreshes happen transparently; if the refresh fails, fnox falls back to a fresh device flow.
- Configurable env var via
env_var(e.g."GH_TOKEN") and configurableauth_base/api_basefor GitHub Enterprise Server. open_browsercontrols whether fnox tries to launch the verification URL automatically (usesopen/xdg-open/start).
The supported-backends table in the leases guide is updated, and the github-app docs now point local/user-attributed workflows at github-oauth. See the GitHub OAuth lease docs for the full reference.
Full Changelog: v1.23.1...v1.24.0
💚 Sponsor fnox
fnox is maintained by @jdx under en.dev — a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
v1.23.1: Alpine binaries and fnox-core crate
A small release that ships native musl binaries for Alpine users and splits the library half of fnox into its own fnox-core crate for downstream Rust consumers.
Added
musl Linux binaries (#452) -- @jdx
Releases now include x86_64-unknown-linux-musl and aarch64-unknown-linux-musl artifacts alongside the existing gnu builds. The previous glibc-linked binaries failed on Alpine with cannot execute: required file not found (missing libudev.so.1 and glibc-only symbols like __res_init) — even with gcompat installed. The musl builds are statically linked and run cleanly on alpine:3 and friends:
docker run --rm -v "$PWD:/work" alpine:3 sh -c \
'cd /work && tar xzf fnox-*-x86_64-unknown-linux-musl.tar.gz && ./fnox --version'Note: the fido2 provider is not compiled into musl builds (its ctap-hid-fido2 dependency doesn't build under musl). Alpine users needing hardware-key-style flows should use age, pass, or a cloud provider. The keychain provider compiles but, as on any headless Linux, requires a session bus at runtime.
Docs site favicons and web manifest (#448) -- @jdx
Adds a simplified vault-door favicon.svg plus favicon.ico, 16/32 PNGs, apple-touch-icon.png, Android Chrome icons, and a site.webmanifest for installable-PWA metadata.
Changed
fnox-core library crate (#458) -- @jdx
The repo is now a Cargo workspace, and the library half of fnox — every provider, the Provider trait, Config, SecretResolver, lease backends, settings, and the top-level Fnox API introduced in v1.22 — lives in a new fnox-core crate under crates/fnox-core/. The root fnox crate keeps the CLI-only pieces (commands, MCP server, TUI, shell integration, hook-env).
This is a pure refactor with no behavior change. Existing Rust consumers don't need to update imports: the binary crate's lib.rs re-exports every fnox-core module, so fnox::providers::*, fnox::config::*, fnox::Fnox, etc. continue to resolve. Projects that want a leaner dep tree can now depend on fnox-core directly instead.
Docs nav star badge (#447) -- @jdx
The GitHub link in the docs top-nav now reads ★ N instead of a bare number, and the count is actually populated on the live site — the deploy workflow now passes GITHUB_TOKEN to the VitePress build so stars.data.ts can hit the GitHub API at build time.
Full Changelog: v1.23.0...v1.23.1
💚 Sponsor fnox
fnox is maintained by @jdx under en.dev — a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
v1.23.0: Line selector for multiline secrets
A small, focused release that adds a line selector for picking a single line out of a multiline secret — most useful for the pass convention of storing the password on line 1 and metadata (username, URL, etc.) on subsequent lines.
Added
Line selector for multiline secrets (#446) -- @fgrosse
Secrets now accept a 1-indexed line field that returns just the Nth line of the resolved value. This matches the pass show <entry> --clip=N convention and lets you expose multiple fields from a single pass entry as separate secrets:
[providers.pass]
type = "password-store"
prefix = "fnox/"
[secrets]
# `pass show fnox/database` returns:
# <password>
# <username>
DB_PASSWORD = { provider = "pass", value = "database", line = 1 }
DB_USERNAME = { provider = "pass", value = "database", line = 2 }Details worth knowing:
lineis mutually exclusive withjson_path; using both on the same secret is an error.- Line splitting uses
str::lines(), so\r\nendings are handled cleanly and a single trailing newline doesn't shift indices. line = 0and out-of-range values produce clear error messages (e.g.`line = 5` is out of range; secret has 2 line(s)).- Post-processing applies uniformly to provider, default, and env-var sources.
fnox syncandfnox reencryptcache the raw provider value, not the post-processed view, so the selector stays a read-only projection.fnox setstill overwrites the entire entry —lineis read-only. Edit individual lines of an existing entry withpass edit <entry>.
See the password-store provider docs for a full walkthrough.
New Contributors
Full Changelog: v1.22.0...v1.23.0
💚 Sponsor fnox
fnox is maintained by @jdx under en.dev — a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
v1.22.0: Library API and a sticky-provider fix for `fnox set`
v1.22.0 introduces a top-level library API for embedding fnox in Rust applications, and fixes a sharp edge in fnox set that could turn an encrypted secret into plaintext.
Added
Top-level Fnox library API (#442) -- @bglusman
Downstream Rust consumers can now use fnox as a library in three lines instead of replicating the internals of GetCommand::run:
use fnox::Fnox;
let fnox = Fnox::discover()?; // walks up + merges parent + local + global config
let value = fnox.get("MY_KEY").await?;
let names = fnox.list()?;The new Fnox type lives in src/library.rs and is re-exported from the crate root. Highlights:
Fnox::discover()mirrors the binary's full config-discovery and merge chain viaConfig::load_smart, including theFNOX_PROFILEenv var.Fnox::open(path)loads an explicit config without the upward-search/merge behavior.Fnox::with_profile("staging")builder for non-default profiles.get()returnsFnoxError::SecretNotFoundwith a populated "Did you mean…" suggestion, matching the CLI's UX so callers don't need to recompute it.Fnoxis cheap to clone (Configis held behind anArc) and safe to hold across.await.
set() is intentionally not part of this first cut; it'll get its own design pass.
Fixed
fnox set no longer silently downgrades encrypted secrets to plaintext (#439) -- @rpendleton
When multiple providers were configured without a default_provider, running fnox set on an existing secret without --provider would write the new value as plaintext while leaving the original provider = "..." key in place. The next fnox get then failed trying to "decrypt" a value that was no longer encrypted.
fnox set now reuses the secret's existing provider before falling back to default_provider or plaintext, so updates stay encrypted and readable without having to pass --provider on every call:
fnox set --provider age MY_SECRET "original-value" # encrypted with age
fnox set MY_SECRET "new-value" # still encrypted with ageDeterministic provider ordering in the generated schema (#432) -- @jdx
Within-category provider ordering in build/generate_providers.rs was inheriting fs::read_dir order, which is OS- and filesystem-dependent. That non-determinism flowed into docs/public/schema.json and caused autofix.ci to keep reshuffling 100+ lines between runs. A secondary sort by provider name fixes the churn; running fnox schema twice now produces byte-identical output.
Mobile docs banner layout (#437) -- @jdx
At <=640px the announcement banner now switches to a column layout with the close button pinned to the top-right corner, instead of cramming the message and "Read more" link onto one squeezed line.
Changed
- Docs site nav now shows the current release version (read from
Cargo.tomlat build time) and a GitHub star count, matching the mise/aube docs (#443) -- @jdx - Added a dismissible cross-site announcement banner that fetches its config from
jdx.dev/banner.jsonand respects theexpiresfield (#434, #436) -- @jdx
New Contributors
Full Changelog: v1.21.0...v1.22.0
💚 Sponsor fnox
fnox is maintained by @jdx under en.dev — a small independent studio building developer tooling like mise, aube, hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors.
If fnox is handling secrets or config for you or your team, please consider sponsoring at en.dev. Sponsorships are what let fnox stay independent and the project keep moving.
v1.21.0: PowerShell integration and Windows fixes
v1.21.0 brings first-class PowerShell support for auto-loading secrets, plus two important fixes for Windows users.
Added
PowerShell integration (#421) -- @nbfritch
fnox now supports PowerShell (pwsh / powershell) alongside bash, zsh, fish, and Nushell for automatic secret loading. Add the following to your PowerShell profile to enable it:
(&fnox activate pwsh) | Out-String | Invoke-ExpressionThe integration hooks into the PowerShell prompt to run hook-env on each prompt, sets and unsets environment variables as you change directories, and prints the familiar fnox: +1 FOO / fnox: -1 FOO diff output. Tested on PowerShell 7.6 on macOS and Windows, as well as Windows PowerShell 5.1. See the Shell Integration guide for setup details.
Fixed
Windows: Nushell activation errors from backslashes in paths (#425) -- @john-trieu-nguyen
On Windows, fnox activate nu emitted paths with backslashes (e.g. C:\Users\john) inside Nushell double-quoted strings, which Nushell parses as escape sequences -- producing unrecognized escape after "\\" in string. Paths are now normalized to forward slashes so Nushell integration works out of the box on Windows.
Windows: Executable resolution for commands with extensions (#427) -- @john-trieu-nguyen
fnox exec -- npm install and similar commands previously failed on Windows because the Windows process API doesn't search PATHEXT the way a shell does, so npm (really npm.cmd) wouldn't be found. fnox exec, fnox edit, and the MCP server's exec tool now use which on Windows to resolve executables, matching shell behavior:
fnox exec -- npm install # now works on Windows
Changed
- Switched from an inlined
clap-sortmodule to the publishedclap-sortcrate (#409)
New Contributors
- @nbfritch made their first contribution in #421
- @john-trieu-nguyen made their first contribution in #425
Full Changelog: v1.20.0...v1.21.0
v1.20.0: Doppler Provider and Sync Fix for json_path
v1.20.0 adds a new Doppler secrets manager provider and fixes a bug where fnox sync would corrupt secrets that use json_path extraction.
Added
Doppler secrets manager provider (#376) -- @natefaerber
fnox now supports Doppler as a secrets provider. The provider uses the Doppler CLI under the hood and supports project/config scoping, service token authentication, and efficient batch fetching via --json.
[providers]
app-prod = { type = "doppler", project = "my-app", config = "prd" }
app-dev = { type = "doppler", project = "my-app", config = "dev" }
[secrets]
PROD_DB_URL = { provider = "app-prod", value = "DATABASE_URL" }
DEV_DB_URL = { provider = "app-dev", value = "DATABASE_URL" }All configuration fields (project, config, token) are optional -- when omitted, the provider falls back to the Doppler CLI's own defaults (from doppler setup or environment variables like DOPPLER_TOKEN). Authentication works via interactive login, service tokens in config, or the DOPPLER_TOKEN / FNOX_DOPPLER_TOKEN environment variables.
You can add a Doppler provider interactively with:
fnox provider add my-doppler dopplerSee the full Doppler provider documentation for setup instructions, CI/CD examples, and multi-environment patterns.
Fixed
fnox sync no longer corrupts secrets that use json_path (#371) -- @rpendleton
When syncing secrets that use json_path, the sync command was applying json_path extraction before caching the value. This meant the cached sync value contained only the extracted field (e.g. "admin") instead of the full raw secret (e.g. {"username":"admin","password":"secret123"}). On subsequent reads, json_path would be applied again to the already-extracted value, failing with "Failed to parse JSON secret".
The fix introduces SecretConfig::for_raw_resolve(), which strips post-processing fields (json_path, sync, default) before resolving. Both sync and reencrypt now use this method, ensuring raw provider values are always cached and future post-processing steps only need updating in one place.
New Contributors
- @natefaerber made their first contribution in #376
- @rpendleton made their first contribution in #371
Full Changelog: v1.19.0...v1.20.0
v1.19.0: Re-encrypt all the things
v1.19.0 adds a new fnox reencrypt command that makes it easy to re-encrypt all your secrets when encryption provider configuration changes -- for example, when adding or removing age recipients. This release also fixes a bug where fnox set -k would skip prompting for the secret value.
Added
fnox reencrypt subcommand (#365) -- @jdx
Previously, re-encrypting secrets after changing recipients required a tedious manual loop of fnox get and fnox set for each secret. The new fnox reencrypt command handles this in one step: it decrypts matching secrets and re-encrypts them with the current provider configuration, writing the updated ciphertext back to the correct source config file.
# Re-encrypt all age secrets
fnox reencrypt -p age
# Preview what would be re-encrypted
fnox reencrypt -p age --dry-run
# Re-encrypt specific keys
fnox reencrypt MY_SECRET OTHER_SECRET
# Filter by regex pattern
fnox reencrypt --filter "^DB_"
# Skip the confirmation prompt
fnox reencrypt -p age -fThe command correctly handles multi-line secrets, writes back to the original source file (including distinguishing root [secrets] from [profiles.X.secrets]), clears stale sync caches, and scrubs decrypted plaintext from the process environment after re-encryption. Only secrets backed by encryption-capable providers are eligible.
Fixed
fnox set -k now correctly prompts for the secret value (#367) -- @jdx
When using the -k / --key-name flag with fnox set, the command incorrectly treated it as a metadata-only operation and skipped prompting for the secret value. It also wrote the key name itself as the stored config value, bypassing the encryption provider entirely. Now -k works as expected: the secret value is read from stdin, a command-line argument, or an interactive prompt, and is properly encrypted and stored.
# These now work correctly
echo "my-secret" | fnox set -p age -k custom-key-name MY_SECRET
fnox set -p age -k custom-key-name MY_SECRET "my-secret"Full Changelog: v1.18.0...v1.19.0
v1.18.0: MCP Security Hardening and Sync Local File Output
v1.18.0 strengthens MCP server security with automatic output redaction and a secret allowlist, adds a --local-file option to fnox sync for keeping sync caches out of your committed config, and fixes auth prompt handling in batch providers. The YubiKey provider also no longer requires libusb to be installed just to start the binary.
Highlights
- MCP output redaction -- The
exectool now automatically replaces resolved secret values with[REDACTED]in stdout/stderr before returning output to the agent, closing a gap where agents could exfiltrate secrets via commands likeprintenv. - MCP secret allowlist -- A new
mcp.secretsconfig option restricts which secrets the MCP server exposes to AI agents, with dependency-aware warnings at startup. fnox sync --local-file-- Sync overrides can now be written tofnox.local.toml(gitignored) instead of the main config file, keeping your committed config clean.- YubiKey dynamic libusb loading -- The binary no longer hard-links libusb, so it starts normally on systems without libusb installed. Users get a clear error with install instructions only when they actually use the YubiKey provider.
Added
MCP exec output redaction (#357) -- @jdx
The MCP exec tool now scans stdout/stderr for resolved secret values and replaces them with [REDACTED] before returning output to the agent. This prevents agents from exfiltrating secrets via commands like printenv or echo $SECRET. Redaction uses Aho-Corasick leftmost-longest matching for correctness and is enabled by default. To disable (not recommended):
[mcp]
redact_output = falseMCP secret allowlist (#358) -- @jdx
A new mcp.secrets config option restricts which secrets the MCP server resolves and exposes. Unlisted secrets are never resolved (avoiding unnecessary auth prompts) and are invisible to both get_secret and exec. At startup, fnox warns if the allowlist contains unknown names or if an allowlisted secret depends on another secret not in the list.
[mcp]
secrets = ["GITHUB_TOKEN", "NPM_TOKEN"] # only these are available to the agentWhen omitted, all profile secrets are available (backward compatible).
fnox sync --local-file output target (#317) -- @florian-lackner365
fnox sync now accepts a --local-file flag that writes sync overrides to the local override file (fnox.local.toml or .fnox.local.toml) next to your config file, instead of modifying the main config. This keeps encrypted sync caches out of version control. The flag requires the config filename to be fnox.toml or .fnox.toml (other filenames are rejected) and conflicts with --global.
fnox sync -p age --local-file
# writes to fnox.local.toml (add to .gitignore)Fixed
Auth prompts now work in batch providers (#349) -- @johnpyp
When a batch provider (e.g. AWS KMS resolving multiple secrets at once) returned an auth error, the auth_command fallback was not triggered -- the secrets were silently skipped. Batch resolution now detects auth errors in the results, runs the configured auth command (e.g. aws sso login), and retries the batch.
Changed
YubiKey provider loads libusb dynamically (#348) -- @jdx
The yubico_manager crate has been replaced with a minimal reimplementation that loads libusb at runtime via libloading. Previously, libusb was linked at build time, which caused the binary to crash on startup (dyld errors on macOS) for users who did not have Homebrew libusb installed -- even if they never used the YubiKey provider. Now the binary starts normally on all systems, and users who try to use the YubiKey provider without libusb get a clear error with platform-specific install instructions.
New Contributors
- @florian-lackner365 made their first contribution in #317
- @johnpyp made their first contribution in #349
Full Changelog: v1.17.0...v1.18.0
v1.17.0: MCP Server, Cloudflare and GitHub App Leases, XDG Compliance
v1.17.0 introduces an MCP server for AI agent secret access, two new lease backends (Cloudflare and GitHub App), and the ability to resolve leased credentials from fnox get. It also brings XDG-compliant directory locations, improved signal handling in fnox exec, and several UX fixes across the TUI, FIDO2, and fnox set.
Highlights
- MCP server for AI agents --
fnox mcpstarts a session-scoped secret broker over stdio, letting AI agents like Claude Code access secrets without having them directly in the environment. - Cloudflare and GitHub App lease backends -- Create short-lived, scoped Cloudflare API tokens and GitHub App installation tokens with automatic expiry and revocation support.
fnox getresolves leases -- Requesting a key that a lease backend produces (e.g.fnox get AWS_ACCESS_KEY_ID) now resolves the lease automatically, with caching.- XDG-compliant directories -- Lease ledger storage now follows the XDG spec, moving from
~/.config/fnox/leases/to~/.local/state/fnox/leases/with automatic migration.
Added
MCP server for secret-gated AI agent access (#343) -- @jdx
The new fnox mcp command starts a Model Context Protocol server over stdio with two tools: get_secret (retrieve a secret by name) and exec (run a command with secrets injected as env vars). Secrets are batch-resolved on first access and cached in memory for the session. Tools can be selectively enabled via config:
[mcp]
tools = ["get_secret", "exec"] # default: both enabledConfigure in .claude/settings.json:
{
"mcpServers": {
"fnox": {
"command": "fnox",
"args": ["mcp"]
}
}
}Cloudflare API token lease backend (#335) -- @jdx
A new cloudflare lease backend creates short-lived, scoped Cloudflare API tokens. A parent token with API Tokens: Edit permission creates child tokens that automatically expire. Supports user-owned and account-owned tokens, explicit policies or parent-inherited policies, and configurable duration up to 24 hours.
[leases.cf]
type = "cloudflare"
account_id = "abc123def456"
duration = "1h"
[[leases.cf.policies]]
effect = "allow"
resources = { "com.cloudflare.api.account.{account_id}" = "*" }
[[leases.cf.policies.permission_groups]]
id = "c8fed203ed3043cba015a93ad1616f1f"
name = "Zone Read"GitHub App installation token lease backend (#342) -- @jdx
A new github-app lease backend creates short-lived GitHub installation access tokens (1 hour max, GitHub's hard limit). Supports scoping to specific permissions and repositories, GitHub Enterprise via api_base, and token revocation via the GitHub API.
[leases.github]
type = "github-app"
app_id = "12345"
installation_id = "67890"
private_key_file = "~/.config/fnox/github-app.pem"
[leases.github.permissions]
contents = "read"
pull_requests = "write"fnox get resolves leased credentials (#338) -- @jdx
fnox get now checks if the requested key is produced by a configured lease backend before falling back to provider secret resolution. For example, fnox get AWS_ACCESS_KEY_ID will resolve through the AWS STS lease backend (with caching) if one is configured.
fnox lease defaults to creating all leases (#337) -- @jdx
fnox lease create no longer requires a backend name -- omitting it (or passing --all) creates leases for all configured backends sequentially. Secrets are resolved once upfront and shared across backends. fnox lease with no subcommand also defaults to lease create --all.
FIDO2 PIN masking (#334) -- @jdx
FIDO2 PIN prompts now mask input with asterisks during typing, preventing shoulder-surfing.
Added -f as a short alias for --force on the init command, consistent with import and sync.
Fixed
XDG-compliant directory locations (#336) -- @jdx
Lease ledger files are now stored under ~/.local/state/fnox/leases/ (or $XDG_STATE_HOME/fnox/leases/), following the XDG Base Directory spec. Config resolution now honors $XDG_CONFIG_HOME. Existing ledger files are automatically migrated on first access. A new FNOX_STATE_DIR env var overrides the state directory.
fnox exec signal handling and silent exit (#339) -- @jdx
fnox exec now forwards SIGINT and SIGTERM to the child process so Ctrl-C and kill reach it properly. On subprocess failure, fnox exits silently with the child's exit code (128+signal for signal deaths) instead of printing a noisy error message. Temp files from as_file secrets are now properly cleaned up via Rust destructors.
fnox set writes to the correct config file (#331) -- @jdx
fnox set now writes to the lowest-priority existing config file in the current directory instead of always targeting fnox.toml. If only fnox.local.toml exists, secrets are written there. If a non-default profile is active and a profile-specific file exists (e.g. fnox.staging.toml), secrets are written there.
TUI skips interactive-auth providers (#333) -- @jdx
fnox tui now skips FIDO2 and YubiKey providers that require physical interaction, preventing display corruption from provider stderr output and input prompts. An error message directs users to fnox exec instead.
Removed duplicate FIDO2 touch prompt (#332) -- @jdx
Removed the redundant "Touch your FIDO2 key..." message -- the underlying library already prints its own touch prompt.
Breaking Changes
Lease ledger location moved -- Lease ledger files have moved from ~/.config/fnox/leases/ to ~/.local/state/fnox/leases/. Existing files are migrated automatically, but if you have scripts that reference the old path directly, update them to use ~/.local/state/fnox/leases/ or the FNOX_STATE_DIR env var.
fnox exec exit behavior changed -- fnox exec no longer prints an error message or returns a CommandExitFailed error when the subprocess fails. It exits silently with the child's exit code. If you were parsing fnox's error output to detect subprocess failures, check the exit code instead.
fnox lease create backend name is now optional -- Running fnox lease create without arguments now creates all configured leases instead of printing a usage error. Scripts that relied on the missing-argument error should be updated.
Full Changelog: v1.16.1...v1.17.0
v1.16.1: Encryption failures are now hard errors
This patch release fixes a security-relevant bug where fnox set silently stored secrets as plaintext when an encryption provider failed. It also adds custom endpoint support for all three AWS providers.
Fixed
fnox set now fails on encryption errors (#324) -- @jdx
Previously, fnox set caught encryption errors from any provider (age, AWS KMS, Azure KMS, GCP KMS, FIDO2, YubiKey) and silently fell back to storing the secret as plaintext. This meant a misconfigured or unreachable encryption provider would result in unencrypted secrets in your config file with only a warning in the logs.
Encryption failures are now hard errors -- fnox set will exit with a non-zero status and an error message instead of quietly storing plaintext.
Fixed Linux cross-compilation (#326) -- @jdx
Cross-compiled Linux builds (x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu) were failing due to a missing libudev-dev system dependency required by the hidapi crate. A Cross.toml configuration now ensures the dependency is installed in the cross-compilation Docker containers.
Added
Custom endpoint for AWS providers (#324) -- @jdx
The AWS KMS (aws-kms), Secrets Manager (aws-sm), and Parameter Store (aws-ps) providers now accept an optional endpoint field. This lets you point them at LocalStack, MinIO, or any other AWS-compatible API endpoint. Add it to your provider config like so:
[providers.kms]
type = "aws-kms"
key_id = "alias/my-key"
region = "us-east-1"
endpoint = "<your-custom-endpoint-url>"Breaking Changes
If you previously relied on fnox set silently falling back to plaintext when encryption failed, this behavior is removed. Encryption errors now cause the command to fail. Review any scripts or CI pipelines that call fnox set with encryption providers to ensure the provider is correctly configured and reachable.
Full Changelog: v1.16.0...v1.16.1