Skip to content

fix(drive,docs): refuse an already-leased file before backing up - #1715

Merged
newhoggy merged 2 commits into
mainfrom
issue-1690-acquire-live-lease-precheck
Sep 17, 2026
Merged

newhoggy merged 2 commits into
mainfrom
issue-1690-acquire-live-lease-precheck

Conversation

@newhoggy

Copy link
Copy Markdown
Contributor

Summary

Test plan

drive lease acquire's only live-lease check lived inside
insert_record, after the Touch ID prompt and the full backup - the
normal outcome of any second acquire on an already-leased file, not
just a rare race, and the orphaned backup was unreachable by drive
lease prune (#1678), which only ever iterates ledger rows.

Add a lock-free live_lease_for_file pre-check before authenticating
at all, refusing the common case for free. Leave the ledger lock
itself unheld across the prompt - it's a non-blocking, machine-wide
lock, so holding it across a 120s human prompt would fail every
other concurrent lease op - so insert_record's lock-held check
stays the sole authoritative gate for the pre-check's narrow
remaining race.

Reclaim the backup this attempt took on every exit but Acquired,
reusing prune's own clear_backup, as belt-and-braces for that race
and for the other outcomes that can still follow a real backup: a
post-backup metadata-fetch failure, a missing post-backup version,
or insert_record itself losing to a concurrently held lock. Warn
and audit a reclamation failure with a -backup-orphaned verdict
suffix naming the surviving backup's location, rather than
silently orphaning it.

Fixes #1690.
… migration

a_ledger_insert_failure_reclaims_the_backup_just_taken pre-created an empty
<ledger>.lock file to simulate a busy lock, which stopped working once
issue #1687 switched to flock(2): a bare file's existence holds nothing
under flock, only an actual lock does, so insert_record succeeded instead
of failing. Fixed by holding a real LedgerLock, matching restore.rs's own
already-correct pattern.

The same pre-existing-file pattern was used by six reports_a_lock_
acquisition_failure_as_failed tests across sheets/format, sheets/write,
sheets/validation, sheets/protection, sheets/structure and docs/write.
These route through check_and_lock_lease, which #1687 changed to *wait*
for a busy lock rather than hard-fail, so simply holding a real LedgerLock
here would make the tests block for the full lock-wait timeout instead of
failing fast. Fixed by creating a directory at the lock path instead: an
open() for write against it fails immediately with a genuine I/O error,
which acquire_waiting never retries.
@github-actions

Copy link
Copy Markdown

Coverage

Total: 97.27% ⚪ 0 pp vs main

Comparing 0fdc3c0..2c984d6 (merge-base → PR head)

File Before After Δ
src/drive/lease/acquire.rs 97.09% 96.71% 🔴 -0.37 pp
🔇 5 ignored region(s), 0 tolerated region(s)

ignore removes the lines from both reports; tolerate keeps them in the reported percentage but scores them against the baseline, so a cross-run flip cannot move a delta. Regions are read from each revision's own source.

File Kind Lines Rev Reason
src/cli/drive/lease.rs ignore 408-412 both a sheet restore's fresh backup is always a DriveCopy — restore.rs's own recheck refuses unless the target is still a spreadsheet, and acquire() only ever takes a Bytes backup of a non-native target; this arm exists solely for exhaustiveness over the shared LeaseBackup enum
src/cli/drive/lease.rs ignore 882-885 both guards this test helper against misuse; every call site below passes an acquire subcommand
src/cli/drive/lease.rs ignore 896-899 both guards this test helper against misuse; every call site below passes a prune subcommand
src/drive/lease/ledger.rs ignore 763-767 both mutate_locked refuses before ever calling the closure, so its body never runs — a hit here is a regression, not a coverage gap
src/drive/lease/restore.rs ignore 977-981 both every test using this double refuses before authenticating; a hit here is a regression, not a coverage gap

Patch coverage

Patch: 96.42% (323/335 new lines covered)

File Patch Uncovered new lines
src/drive/docs/write.rs 100% (1/1)
src/drive/lease/acquire.rs 96.21% (305/317) 253-259, 455, 1667-1668, 1763, 1824
src/drive/lease/ledger.rs 100% (9/9)
src/drive/lease/prune.rs 100% (2/2)
src/drive/lease/restore.rs 100% (1/1)
src/drive/sheets/format.rs 100% (1/1)
src/drive/sheets/protection.rs 100% (1/1)
src/drive/sheets/structure.rs 100% (1/1)
src/drive/sheets/validation.rs 100% (1/1)
src/drive/sheets/write.rs 100% (1/1)
Uncovered new lines (12)
  • src/drive/lease/acquire.rs:253
  • src/drive/lease/acquire.rs:254
  • src/drive/lease/acquire.rs:255
  • src/drive/lease/acquire.rs:256
  • src/drive/lease/acquire.rs:257
  • src/drive/lease/acquire.rs:258
  • src/drive/lease/acquire.rs:259
  • src/drive/lease/acquire.rs:455
  • src/drive/lease/acquire.rs:1667
  • src/drive/lease/acquire.rs:1668
  • src/drive/lease/acquire.rs:1763
  • src/drive/lease/acquire.rs:1824

📦 Full per-file coverage summary · run summary

@newhoggy
newhoggy merged commit 092d2f5 into main Sep 17, 2026
17 checks passed
@newhoggy
newhoggy deleted the issue-1690-acquire-live-lease-precheck branch September 17, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(drive): lease acquire spends the prompt and backup before the live-lease check; orphaned backups unreachable by prune

1 participant