Skip to main content

max / synckit

Stop the keystore tests from reaching the host's real secret service `public_api_types_compile` calls store_key, load_key and delete_key for real. Under the `keychain` feature that means the platform keyring: on a developer machine it writes a test key into the login keyring, and on a headless host there is nobody on the other end of the D-Bus call, so the test does not fail, it hangs. Measured on astra, where it is reported as "running for over 60 seconds" and takes the whole binary with it, which is enough to make a cargo-mutants run there time out rather than measure anything. Hoist the mock-store install the behavioural module already did into a shared `Once` and call it from both, so every test in the file runs against a store that always answers.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-08-31 22:34 UTC
Signed with PGP, not checked
Commit: 0bfe0948c08992ce182d3b560ba2e1cc0e0a3f6e
Parent: efe2b0f
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);