From bf3e356540d33b90553da4df39dbb7823d68d6df Mon Sep 17 00:00:00 2001 From: t8y2 Date: Thu, 24 Sep 2026 17:57:12 +0800 Subject: [PATCH] fix(core): stop no-keyring builds creating the global fallback key --- .../dbx-core/src/persistence/secret_codec.rs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/dbx-core/src/persistence/secret_codec.rs b/crates/dbx-core/src/persistence/secret_codec.rs index 05bcf484e8..ac9283dd1d 100644 --- a/crates/dbx-core/src/persistence/secret_codec.rs +++ b/crates/dbx-core/src/persistence/secret_codec.rs @@ -6,7 +6,9 @@ //! Secret Service). `DBX_SECRET_KEY` and `DBX_SECRET_KEY_FILE` are supported //! for headless deployments. A per-user key file remains as a compatibility //! fallback for installations created before native credential storage was -//! enabled; the key is always outside the database and never enters a sync file. +//! enabled; on key-file-first platforms it may also be provisioned +//! automatically when no credential store is reachable. The key is always +//! outside the database and never enters a sync file. use aes_gcm::{ aead::{rand_core::RngCore, Aead, KeyInit, OsRng}, @@ -158,6 +160,17 @@ impl SecretCodec { if let Some(error) = compatibility_error { return Err(error); } + // Auto-provisioning the per-user fallback key is reserved for + // key-file platforms (Linux without a reachable Secret Service). On + // macOS and Windows the OS credential store is canonical: when the + // platform provider is absent (keyring feature compiled out, e.g. + // `--no-default-features` runs), writing a competing global key file + // next to real installations would strand them behind the wrong key, + // because this file outranks the keychain on every later launch. + // Test builds are exempt so unit tests keep working without the + // native backend; `default_key_path` sandboxes their key to the + // system temp directory in that case. + #[cfg(any(not(any(target_os = "macos", target_os = "windows")), test))] if allow_create { if let Some(path) = compatibility_path { let codec = create_key_file(&path, false)?; @@ -433,6 +446,12 @@ fn read_key_file_with_retry(path: &std::path::Path, reject_symlink: bool) -> Res } fn default_key_path() -> Option { + // Unit tests must never read or create the developer's real per-user key + // file; their auto-provisioned fallback lives in the system temp dir. + #[cfg(test)] + { + return Some(std::env::temp_dir().join("dbx-test-secret.key")); + } #[cfg(target_os = "macos")] if let Ok(home) = std::env::var("HOME") { return Some(std::path::PathBuf::from(home).join("Library/Application Support/dbx/secret.key"));