max / synckit
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
- Claude-Session
- https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
1 file changed,
+34 insertions,
-5 deletions
| @@ -257,6 +257,32 @@ | |||
| 257 | 257 | // - Error variant construction | |
| 258 | 258 | // - No-op stub behavior (when keychain feature is disabled) | |
| 259 | 259 | ||
| 260 | + | /// Install `keyring_core`'s in-memory mock as the process-global default store, | |
| 261 | + | /// once. | |
| 262 | + | /// | |
| 263 | + | /// Every test in this file that calls `store_key`, `load_key` or `delete_key` | |
| 264 | + | /// goes through it first. Without it those calls reach the platform secret | |
| 265 | + | /// service: on a developer machine that means writing test keys into the login | |
| 266 | + | /// keyring, and on a headless host (astra, any CI box) the D-Bus call has | |
| 267 | + | /// nobody to answer it and the test hangs rather than failing. | |
| 268 | + | /// | |
| 269 | + | /// `Once`, because the default store is process-global and the harness runs | |
| 270 | + | /// these tests concurrently. | |
| 271 | + | #[cfg(all(test, feature = "keychain", not(target_os = "ios")))] | |
| 272 | + | fn install_mock_store() { | |
| 273 | + | static STORE: std::sync::Once = std::sync::Once::new(); | |
| 274 | + | STORE.call_once(|| { | |
| 275 | + | keyring_core::set_default_store( | |
| 276 | + | keyring_core::mock::Store::new().expect("the mock keychain store"), | |
| 277 | + | ); | |
| 278 | + | }); | |
| 279 | + | } | |
| 280 | + | ||
| 281 | + | /// Nothing to install: without `keychain` the three functions are no-op stubs, | |
| 282 | + | /// and on iOS `entry` installs the Protected Data store unconditionally. | |
| 283 | + | #[cfg(all(test, any(not(feature = "keychain"), target_os = "ios")))] | |
| 284 | + | fn install_mock_store() {} | |
| 285 | + | ||
| 260 | 286 | #[cfg(test)] | |
| 261 | 287 | mod keystore_tests { | |
| 262 | 288 | use super::*; | |
| @@ -437,8 +463,6 @@ | |||
| 437 | 463 | ||
| 438 | 464 | // ── No-op stub behavior ── | |
| 439 | 465 | // These tests verify the public API contract regardless of feature flags. | |
| 440 | - | // When keychain is enabled, they exercise the real keyring path (which may | |
| 441 | - | // succeed or fail depending on OS keychain availability in CI). | |
| 442 | 466 | // The important contract: the functions exist, accept the right types, | |
| 443 | 467 | // and return the right types. | |
| 444 | 468 | ||
| @@ -446,11 +470,16 @@ | |||
| 446 | 470 | fn public_api_types_compile() { | |
| 447 | 471 | // Compile-time check that the public API signatures are correct. | |
| 448 | 472 | // This catches accidental signature changes. | |
| 473 | + | // | |
| 474 | + | // The calls below are real: under `keychain` they would otherwise reach | |
| 475 | + | // the host's secret service, which writes a test key into a developer's | |
| 476 | + | // login keyring and, on a headless box with no service to answer, | |
| 477 | + | // blocks until the harness gives up. Install the in-memory mock first so | |
| 478 | + | // the shape is checked against a store that always answers. | |
| 479 | + | super::install_mock_store(); | |
| 449 | 480 | let (app_id, user_id) = test_ids(); | |
| 450 | 481 | let key = [0u8; 32]; | |
| 451 | 482 | ||
| 452 | - | // These may fail at runtime due to keychain unavailability, | |
| 453 | - | // but they must compile with the correct types. | |
| 454 | 483 | let _: Result<()> = store_key(app_id, user_id, &key); | |
| 455 | 484 | // load_key now hands back the key inside a ZeroizeOnDrop guard so no bare | |
| 456 | 485 | // [u8; 32] copy outlives the caller's move into the master-key slot. | |
| @@ -495,7 +524,7 @@ | |||
| 495 | 524 | ||
| 496 | 525 | #[test] | |
| 497 | 526 | fn keychain_behaviour_against_mock_store() { | |
| 498 | - | keyring_core::set_default_store(mock::Store::new().expect("mock store")); | |
| 527 | + | super::install_mock_store(); | |
| 499 | 528 | ||
| 500 | 529 | // ── Round trip ── | |
| 501 | 530 | let (app_id, user_id) = ids(1); |