refactor: extract providers and core types into fnox-core crate#458
refactor: extract providers and core types into fnox-core crate#458
Conversation
Convert the repo into a Cargo workspace and split fnox into two crates: - `fnox-core` (`crates/fnox-core/`) — provider implementations, config types, secret resolver, lease backends, settings, error types, and the `Fnox` library API. Reusable as a library by downstream consumers. - `fnox` (root) — CLI binary plus the CLI-shaped modules (commands, MCP server, TUI, hook-env, shell integration). Depends on `fnox-core` and re-exports its modules from `lib.rs` so existing `fnox::providers`, `fnox::config`, etc. paths keep working. Build infrastructure for provider and settings code generation, plus the `providers/*.toml` and `settings.toml` inputs, move to the core crate so their `OUT_DIR`-relative `include!` calls resolve correctly. Workspace dependencies are declared in the root `Cargo.toml`; both crates reference them with `workspace = true` to keep versions consistent. `cargo build`, `cargo test --workspace`, and `mise run lint` all pass.
…irectly Provider, config, secret-resolver, and lease crates moved to fnox-core in the previous commit; the binary doesn't import them directly anymore. Drop the duplicate workspace-dep listings from the root crate. Removed deps: aes-gcm, age, arc-swap, async-trait, dirs, fslock, futures, hex, jsonwebtoken, pluralizer, rand, reqwest, serde_spanned, sha2, shellexpand, strsim, terminal_size, thiserror, urlencoding, walkdir, xx, plus the linux-only dbus / openssl-sys (now declared in fnox-core where keyring lives). Workspace.dependencies in the root Cargo.toml stays as the full list so both crates can keep version-pinning consistent via workspace = true. cargo build, cargo test --workspace, and mise run lint all still pass.
Greptile SummaryThis PR is a pure structural refactor that extracts the reusable engine (providers, config, secret resolver, lease backends, settings) into a new Confidence Score: 5/5Safe to merge — pure refactor with no behavior changes; only P2 findings. All findings are P2 (test helper naming and a fragile but non-critical regression guard). No logic changes to production code paths. crates/fnox-core/src/library.rs — regression-guard test is a no-op in this repo. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
WS["Cargo Workspace (root Cargo.toml)"]
WS --> FNOX["fnox (binary crate)\nsrc/main.rs, src/lib.rs\ncommands/, mcp_server, tui/\nhook_env, shell/"]
WS --> CORE["fnox-core (library crate)\ncrates/fnox-core/\nproviders/, config, secret_resolver\nlease_backends, settings, library.rs"]
FNOX -->|"depends on path + version"| CORE
FNOX -->|"re-exports all fnox_core::* modules"| REEXPORT["fnox::providers, fnox::config, etc.\n(preserved paths)"]
CORE --> PROV["Provider trait + 20 provider impls"]
CORE --> CFG["Config / SecretResolver"]
CORE --> LEASE["Lease + LeaseBackends"]
CORE --> SETTINGS["Settings (ArcSwap)"]
CORE --> API["Fnox convenience API\n(Fnox::discover / open / get / list)"]
RELEASE["mise-tasks/release-plz"]
RELEASE -->|"1. cargo publish -p fnox-core"| CORE
RELEASE -->|"2. cargo publish -p fnox"| FNOX
Reviews (3): Last reviewed commit: "fix(ci): drop --workspace from cargo msr..." | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request refactors the project into a Cargo workspace by extracting the core provider logic, configuration types, and secret resolution into a new fnox-core crate. The root Cargo.toml has been updated to manage shared metadata and dependencies via workspace inheritance, and the main fnox binary now re-exports these core modules to maintain backward compatibility. The review feedback suggests further centralizing the package version within the workspace configuration and moving target-specific dependencies to the workspace level to ensure consistent version management across all crates.
| [workspace.package] | ||
| edition = "2024" | ||
| authors = ["@jdx"] | ||
| description = "A flexible secret management tool supporting multiple providers and encryption methods" | ||
| license = "MIT" | ||
| repository = "https://github.com/jdx/fnox" | ||
| readme = "README.md" | ||
| rust-version = "1.91.1" |
There was a problem hiding this comment.
To fully leverage the workspace and ensure version consistency as mentioned in the PR summary, consider centralizing the package version. You can add version = "1.23.0" to the [workspace.package] section and then use version.workspace = true in both the root [package] and crates/fnox-core/Cargo.toml.
| [workspace.package] | |
| edition = "2024" | |
| authors = ["@jdx"] | |
| description = "A flexible secret management tool supporting multiple providers and encryption methods" | |
| license = "MIT" | |
| repository = "https://github.com/jdx/fnox" | |
| readme = "README.md" | |
| rust-version = "1.91.1" | |
| [workspace.package] | |
| version = "1.23.0" | |
| edition = "2024" | |
| authors = ["@jdx"] | |
| license = "MIT" | |
| repository = "https://github.com/jdx/fnox" | |
| rust-version = "1.91.1" |
| openssl-sys = { version = "0.9", features = ["vendored"] } | ||
| [package] | ||
| name = "fnox" | ||
| version = "1.23.0" |
| @@ -0,0 +1,85 @@ | |||
| [package] | |||
| name = "fnox-core" | |||
| version = "1.23.0" | |||
| ctap-hid-fido2 = "3" | ||
|
|
||
| [target.'cfg(target_os = "linux")'.dependencies] | ||
| dbus = { version = "0.9", features = ["vendored"] } | ||
| openssl-sys = { version = "0.9", features = ["vendored"] } |
There was a problem hiding this comment.
The dependencies ctap-hid-fido2, dbus, and openssl-sys are defined with explicit versions here, which is inconsistent with the other dependencies using workspace = true. To centralize version management and follow the plan described in the PR summary, these should be moved to the [workspace.dependencies] section in the root Cargo.toml. You can then reference them here using workspace = true within the target-specific dependency blocks.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit afd8419. Configure here.
Four fixes from PR review: - crates/fnox-core/src/lib.rs: crate doc claimed `lease_backends` was binary-only; it actually lives in fnox-core. Move it out of the binary's module list in the doc comment. - crates/fnox-core/src/library.rs: drop broken intra-doc links to `[commands]` / `[commands::get::*]` / `[commands::set::*]` (those modules live in the binary, not fnox-core, so rustdoc couldn't resolve them) and qualify the `secret_resolver::resolve_secret` link with `crate::`. - Cargo.toml: hoist `version = "1.23.0"` into `[workspace.package]` and reference it from both `fnox` and `fnox-core` via `version.workspace = true`, matching how edition / authors / license / etc. are already inherited. - Cargo.toml + crates/fnox-core/Cargo.toml: move the platform-specific `ctap-hid-fido2`, `dbus`, and `openssl-sys` deps into `[workspace.dependencies]` and reference them with `workspace = true` from the target-cfg blocks, matching the rest of the workspace dependency layout. cargo build, cargo test --workspace, mise run lint, and cargo doc --no-deps all still pass; the broken intra-doc-link warnings the reviewer flagged are gone.
Real bug caught by Cursor Bugbot: the tracing env-filter
`format!("fnox={}", log_level)` only matches log targets from the binary
crate. After moving most modules into `fnox_core`, every `tracing::*` call
in providers, config, lease, http, etc. emits under `fnox_core::*` targets
and was silently dropped — `--verbose` no longer surfaced debug output and
warn-level operational messages were lost. Filter now covers both crates.
Audit of GitHub Actions workflows for the workspace move turned up
additional gaps that CI and the release pipeline weren't catching because
they only operated on the root crate:
- `.github/workflows/ci.yml`:
- `cargo test` was only running 8 binary-crate tests; the 147 fnox-core
tests were silently skipped. Switch to `cargo test --workspace`.
- `cargo clippy -- -D warnings` only linted the binary; switch to
`cargo clippy --workspace --all-targets -- -D warnings`.
- `cargo msrv verify` only checked the binary; switch to `--workspace`.
- `mise-tasks/release-plz`:
- `cargo set-version --package fnox` doesn't update `[workspace.package]`
and would fail against `version.workspace = true`. Switch to
`cargo set-version --workspace`, which bumps the inherited workspace
version (and the path-dep pin in fnox's Cargo.toml) automatically.
- `cargo publish -p fnox` would fail because fnox depends on fnox-core
via path + version, and fnox-core needs to be on crates.io first.
Publish fnox-core, then fnox.
- `crates/fnox-core/src/auth_prompt.rs` + `settings.rs`:
Three pre-existing `assert_eq!(x, false)` clippy warnings in test code
that the pre-refactor `cargo clippy -- -D warnings` never saw because it
only checked the binary. Replace with `assert!(!x)` so the now-stricter
workspace clippy check passes.
cargo build, cargo test --workspace, cargo clippy --workspace --all-targets
-- -D warnings, and mise run lint all pass.
cargo-msrv doesn't have a --workspace flag; the previous commit's change broke the msrv job with `error: unexpected argument '--workspace' found`. Revert to plain `cargo msrv verify`. The binary depends on fnox-core via path, so verifying the binary's MSRV transitively verifies fnox-core too.
### 🚜 Refactor - extract providers and core types into fnox-core crate by [@jdx](https://github.com/jdx) in [#458](#458) ### 📚 Documentation - prefix star count with ★ glyph and populate it on deploy by [@jdx](https://github.com/jdx) in [#447](#447) - add favicons and web app manifest by [@jdx](https://github.com/jdx) in [#448](#448) ### 🔍 Other Changes - **(docs)** remove shrill.en.dev analytics script by [@jdx](https://github.com/jdx) in [#457](#457) - **(release)** add musl Linux targets for Alpine compatibility by [@jdx](https://github.com/jdx) in [#452](#452) - add plausible analytics by [@jdx](https://github.com/jdx) in [#451](#451) - bump hk to 1.44.3 by [@jdx](https://github.com/jdx) in [#454](#454) ### 📦️ Dependency Updates - update autofix-ci/action action to v1.3.4 by [@renovate[bot]](https://github.com/renovate[bot]) in [#455](#455) - update apple-actions/import-codesign-certs action to v7 by [@renovate[bot]](https://github.com/renovate[bot]) in [#456](#456)

Summary
Splits fnox into a Cargo workspace with a reusable
fnox-corelibrary crate alongside the existing CLI binary. The library half of fnox (providers, config types, secret resolver, lease backends, settings) now lives incrates/fnox-core/and can be depended on by other Rust projects without pulling in the CLI surface (commands, MCP server, TUI, shell integration, hook-env machinery).This is a pure refactor — no behavior change. Public Rust paths (
fnox::providers::*,fnox::config::*,fnox::Fnox, etc.) continue to work via re-exports from the binary crate'slib.rs, so existing library consumers don't have to update imports.What moved to
fnox-coreproviders/(every provider implementation, theProvidertrait, the wizard metadata, the resolver)config.rs,secret_resolver.rs,auth_prompt.rslease.rs,lease_backends/,http.rssettings.rs,error.rs,env.rs,source_registry.rs,spanned.rs,suggest.rs,temp_file_secrets.rslibrary.rs(theFnoxconvenience API)build.rs+build/generate_*.rs,providers/*.toml,settings.toml(build inputs)What stays in the root
fnoxcratemain.rs,commands/,mcp_server.rs,tui/,hook_env.rs,shell/lib.rsthat re-exports everyfnox-coremodule so existing paths keep workingOther changes
src/main.rswas double-declaring every module viamodalongsidelib.rs'spub mod; cleaned up to be a thin shim that uses the library crate.Cargo.toml; both crates pull from them viaworkspace = trueto keep versions consistent.Cargo.tomlto only the deps the binary uses directly (a follow-up commit on top of the move).provider_add_types_match_provider_definitionsincommands/provider/mod.rs) needed itsCARGO_MANIFEST_DIR-relative path updated to point atcrates/fnox-core/providers.Test plan
cargo build --workspacecleancargo test --workspace— 147 tests infnox-core, 8 infnox, all passmise run lint— all hk checks (cargo-fmt, cargo-clippy-D warnings, prettier, actionlint, shfmt, shellcheck, pkl) passmise run test:bats— 602 pass, 17 keychain failures pre-existing macOS interactive-auth limitation, 7 lease tests skipped (LocalStack not running locally). Same baseline asmain../target/debug/fnox --versionandfnox provider listsmoke tests🤖 Generated with Claude Code
Note
Medium Risk
Moderate risk because it restructures the crate into a workspace and changes build/test/release plumbing; behavior should be unchanged but mis-wired deps, paths, or logging filters could break CI, publishing, or downstream imports.
Overview
Creates a Cargo workspace and extracts providers/config/secret-resolution/lease logic into a new
fnox-corelibrary crate, while the rootfnoxcrate becomes a CLI-focused binary that depends onfnox-coreand re-exports its public modules to preserve existingfnox::...import paths.Updates CI and release automation to operate on the workspace (workspace-wide
cargo test/clippy, MSRV verification note,release-plznow bumps workspace version and publishesfnox-corebeforefnox), adjusts a provider-definition test path for the movedproviders/*.toml, and expands the default tracing filter to includefnox_corelogs.Reviewed by Cursor Bugbot for commit 9d2ee78. Bugbot is set up for automated code reviews on this repo. Configure here.