Summary
CLI advisory lock (src/cli/lock.ts) writes only a static sentinel. release() deletes any lock file regardless of owner. Two --force writers can both acquire; neither owns the lock exclusively.
Audit ID: Section 2 Med — Wave 2
Related: Kernel exclusive open lock (B4 issue)
Root cause
release() {
rmSync(lockPath, { force: true });
}
No pid/host/nonce in lock file; no verify on release.
Fix
- Lock file content:
libredb-lock\n<pid>\n<hostname>\n<random-nonce>\n
release() — read and verify nonce matches; only then delete.
--force — check prior lock holder liveness (pid signal 0 / stale detection) before dropOwnLock; refuse if alive holder unless explicit force semantics documented.
Align format with kernel-level lock (B4) if shared constant extracted.
Tests
- Acquire + release own lock → ok.
- Simulate foreign lock content → release must not delete (or force path only).
--force on stale pid → succeeds.
Acceptance criteria
Verification
Summary
CLI advisory lock (
src/cli/lock.ts) writes only a static sentinel.release()deletes any lock file regardless of owner. Two--forcewriters can both acquire; neither owns the lock exclusively.Audit ID: Section 2 Med — Wave 2
Related: Kernel exclusive open lock (B4 issue)
Root cause
No pid/host/nonce in lock file; no verify on release.
Fix
libredb-lock\n<pid>\n<hostname>\n<random-nonce>\nrelease()— read and verify nonce matches; only then delete.--force— check prior lock holder liveness (pid signal 0 / stale detection) beforedropOwnLock; refuse if alive holder unless explicit force semantics documented.Align format with kernel-level lock (B4) if shared constant extracted.
Tests
--forceon stale pid → succeeds.Acceptance criteria
--forcecannot leave two live writers thinking they hold lock.bun run gategreen.Verification