Skip to content

Native credential backends

The keychain feature uses keyring-core directly. Implementations live in crates/identity/src/auth/keychain/; bootstrap::keychain supplies the shared adapter to server construction and the credential CLI. The existing identity singleton retains breadcrumb deduplication for vendor credential resolution. Each adapter owns its store rather than using keyring-core’s mutable process default. The first credential operation initializes the real store; startup that uses only environment/file/provider credentials needs no desktop agent. Initialization errors are cached and returned as KeychainError::Unavailable; restart after restoring the native service. No mock or sample store is selected in production. Operation errors remain errors, with fixed diagnostic categories instead of provider payloads or credential objects.

Verified on 2026-10-19; the Rust baseline remains 1.99.0. Registry dependencies are exact-pinned in the identity manifest.

Dependency Pin Selection/API
keyring-core =1.0.1 Store-owned CredentialStoreApi::build(service, user, None) and Entry get/set/delete; no global default or sample feature
dbus-secret-service-keyring-store =1.0.1 Linux Store::new(), crypto-rust and vendored; upstream connects using EncryptionType::Dh, never a plaintext session
apple-native-keyring-store =1.0.2 macOS keychain::Store::new(), keychain feature, preserving Keychain Services rather than switching to protected-data storage
windows-native-keyring-store =1.1.0 Windows Store::new(), default target-name mapping/persistence preserved; unused search feature disabled

The prior keyring = 4.2.0 v1 compatibility wrapper selected zbus-secret-service-keyring-store = 1.0.0 on Linux. The explicit keyutils feature in our former manifest did not change that selection. No migration from kernel keyutils storage is needed for credentials written by that wrapper.

The product lockfile drops keyring, both old Linux stores, secret-service, zbus, zbus_macros, zbus_names, zvariant, zvariant_derive, zvariant_utils, and dependencies used only by that chain. It adds dbus 0.9.12, dbus-secret-service 4.1.0, and libdbus-sys 0.2.7. Cargo also records optional OpenSSL packages due to the upstream optional vendoring feature; they are not activated by our crypto-rust selection (cargo tree -i openssl has no active path). This migration upgrades no unrelated existing package versions. All deny.toml duplicate exceptions are still matched and required by the remaining graph; none became obsolete. Advisory ignores remain empty.

Service names remain mcp-server-devtools.<kind>.<vendor>, and accounts remain the original principal string. A missing current entry falls back to mcp-server-atlassian.<kind>.<vendor>; an error does not. Writes update only the current namespace. Removal attempts both namespaces, returns NotFound only when neither exists, and propagates errors. Linux stores search all collections by the same service and username attributes with no target modifier. Existing ambiguity remains an error; the adapter does not arbitrarily choose or delete a credential when several items match.

Run the compatibility check on Linux with a GNOME keyring daemon and D-Bus tools:

Terminal window
scripts/ci/keychain-compatibility.sh

The script builds the former v1 writer in a temporary project outside the product graph, with keyring 4.2.0, keyring-core 1.0.0, zbus store 1.0.0, secret-service 5.1.0 and zbus 5.19.0. It uses a private session bus, a temporary home/config/data/runtime directory, and a synthetic unlock password. It writes 24 synthetic entries across two secret kinds, three vendors, current-only, legacy-only and both-namespace cases. The new identity adapter reads/deletes these, exercises new write/update/delete operations, and the old writer then confirms all 24 entries are gone. It never uses the user’s bus or personal keyring. GNOME_KEYRING_DAEMON can select an unpacked test daemon. The live Rust test is ignored by ordinary runs and requires the script’s isolation marker.

Ordinary tests cover keychain-disabled operations, a genuinely unavailable native backend in a child process (even with a global mock installed), namespace precedence/isolation, error propagation, diagnostic redaction and removal of the deprecated dependencies. Injected mock stores exist only in unit-test code.

vendored statically links libdbus, avoiding a runtime dependency on the host’s libdbus shared library and the old CI requirement for libsecret/libdbus headers. It requires a C compiler. It does not make a GNU/Linux executable wholly static; libc linkage still follows the selected Rust target. It also does not bundle a running D-Bus daemon or a Secret Service: desktop runtime prerequisites remain an available session bus, Secret Service and an unlocked collection. The existing musl/distroless image and system packages disable keychain, so neither libdbus nor an OS keyring agent enters those artifacts.

The locked libdbus-sys 0.2.7 bundles D-Bus 1.14.4 C sources. This adds native code/FFI and means operating-system library updates do not patch the bundled copy; monitor upstream C security fixes and rebuild the binary when updating. A clean RustSec gate is not a complete advisory audit of those embedded sources. The bundled library’s AFL-2.1 license option and source location are recorded in NOTICE, docs/licensing.md, and licenses/libdbus-COPYING.txt; the existing archive workflow includes these files. The Rust wrapper’s MIT/Apache metadata alone is not the C library’s license.

Validated on Linux on 2026-10-19 with Rust 1.99.0, the shared repository target, debug information disabled for dev/test and incremental compilation disabled:

  • Focused identity tests and Clippy with keychain enabled and disabled passed; root authentication and credential CLI tests passed (63 tests).
  • The isolated GNOME Secret Service compatibility script passed: all 24 old entries were read and deleted, the previous backend confirmed their removal, and new write/update/delete operations passed. A bus monitor restricted to OpenSession observed encrypted DH/AES session negotiation and no plain sessions. No personal credentials or desktop bus were used.
  • Workspace default and headless builds and Clippy (--all-targets -- -D warnings) passed. Default and Cedar workspace test suites passed; Cedar build and Clippy also passed. Formatting and cargo deny --locked check --deny warnings passed without advisory suppression or duplicate exceptions added.
  • The first default test run hit the console’s existing one-second expiry test; an additional serial run hit the response-cache principal-partitioning test. Both tests passed individually, and a subsequent normal full default suite passed. Neither test nor its implementation was changed for this migration.
  • The actual identity keychain adapter and contracts compiled for x86_64-apple-darwin, aarch64-apple-darwin and x86_64-pc-windows-msvc in a temporary harness using the product’s exact dependency versions. Full native product linking, macOS/Windows credential runtime tests and native installers remain unverified on this Linux host.
  • Debian/RPM package assembly and installation remain unverified: this host lacks the pinned package tools and the rootless systemd/Podman test runtime.
  • ELF inspection of the Linux live-test binary confirmed no shared libdbus or OpenSSL dependency. The bundled C library still requires separate upstream security monitoring as described above.
  • The repository Dockerfile built the keychain-disabled x86_64 musl release image successfully. In its distroless runtime, with networking disabled and a read-only root filesystem, --version reported 0.18.0 and a synthetic creds get returned the expected keychain-unavailable error. The extracted binary is a static PIE with no ELF interpreter. This was local validation; no image was published or deployed. The image’s live Vault round-trip was not exercised.

These repository gates use the keyring migration snapshot with async-compression 0.4.50. The concurrent upgrade to 0.4.51 is being validated separately by its owning task. Live Keycloak/Vault/SIEM, cloud-account and rootless systemd operations scenarios were not exercised by these ordinary workspace runs. Security review found no high-confidence introduced vulnerability; MCP01 and MCP04 controls and residual risks are recorded in the OWASP assessment, threat model and best-practices map.