vault provision: serialize bw access (mutex) to avoid concurrent-provision races #95

Closed
opened 2026-06-20 06:52:57 +02:00 by clawdie · 0 comments
Owner

Problem

colibri-vault now does per-call login → unlock → fetch → lock (#94, #89). But bw keeps process-global state (one data dir / session per process). Concurrent jailed spawns trigger concurrent provision() calls, which can interleave:

  • one call's bw lock tears down a session another call is mid-fetch on
  • overlapping login --apikey / unlock racing on the same bw state

Result: intermittent provision failures under concurrent spawns — hard to reproduce, easy to misdiagnose.

Fix

Serialize vault operations: wrap the per-call session lifecycle in a process-wide async Mutex (e.g. tokio::sync::Mutex in a OnceLock) so only one login→unlock→fetch→lock runs at a time. Alternative: give each call an isolated BITWARDENCLI_APPDATA_DIR so global state isn't shared — but a mutex is simpler for the MVP.

Acceptance

Two provisions fired concurrently both succeed (no session torn down mid-fetch); a test spawning N concurrent provision() calls against a stub passes deterministically.

Context: #94 closed #89 without serialization — this is the deferred half of #89's trade-off note. Not OS-specific.

🤖 Generated with Claude Code

## Problem `colibri-vault` now does per-call `login → unlock → fetch → lock` (#94, #89). But `bw` keeps **process-global** state (one data dir / session per process). Concurrent jailed spawns trigger concurrent `provision()` calls, which can interleave: - one call's `bw lock` tears down a session another call is mid-`fetch` on - overlapping `login --apikey` / `unlock` racing on the same bw state Result: intermittent provision failures under concurrent spawns — hard to reproduce, easy to misdiagnose. ## Fix Serialize vault operations: wrap the per-call session lifecycle in a process-wide async **`Mutex`** (e.g. `tokio::sync::Mutex` in a `OnceLock`) so only one `login→unlock→fetch→lock` runs at a time. Alternative: give each call an isolated `BITWARDENCLI_APPDATA_DIR` so global state isn't shared — but a mutex is simpler for the MVP. ## Acceptance Two provisions fired concurrently both succeed (no session torn down mid-fetch); a test spawning N concurrent `provision()` calls against a stub passes deterministically. Context: #94 closed #89 without serialization — this is the deferred half of #89's trade-off note. Not OS-specific. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
clawdie added the
hardening
label 2026-06-20 06:52:57 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: clawdie/colibri#95
No description provided.