Skip to content

fix(drive,docs): refuse a repeat restore of an already-restored sheet - #1716

Merged
newhoggy merged 3 commits into
mainfrom
issue-1689-restore-duplicate-sheet
Sep 17, 2026
Merged

newhoggy merged 3 commits into
mainfrom
issue-1689-restore-duplicate-sheet

Conversation

@newhoggy

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • cargo build
  • cargo test --lib drive::lease:: (175 passed), cargo test --lib drive:: (1464 passed)
  • cargo clippy --all-targets -- -D warnings
  • Reviewed via /code-review high. Fixed the findings: broken intra-doc links to a renamed function (would have failed CI's Docs job), an over-claiming CLI message ("that restore's own lease" when the ledger can't actually guarantee which operation minted a live lease for the file — reworded), and a redundant HashSet rebuild in the pre-write recheck.
  • Also fixed a real, silent rebase conflict: onto latest main (carrying fix(drive): lease acquire spends the prompt and backup before the live-lease check; orphaned backups unreachable by prune #1690), a test's LeaseRecord struct literal was missing this branch's new restored_sheet_id field — no textual conflict markers, but a real compile error in test code that cargo build alone doesn't catch.

Re-running `drive lease restore` on a token whose deleted-sheet restore
had already succeeded silently copied the sheet in again, one "Copy of
..." per run, each costing a Touch ID prompt and a fresh Drive backup
copy. `spreadsheets.sheets.copyTo` assigns the destination a fresh
sheetId, so the backup sheet's own id stayed missing from the live
spreadsheet and the structural detection ADR-0080 §10 relies on kept
firing; the pre-write recheck compared against that same original id
rather than the one the previous restore created, so it passed too.

Live spreadsheet state alone cannot settle it. A restored sheet is
structurally indistinguishable from a live sheet that merely shares the
backup sheet's title -- an id absent from the backup, a matching title
-- and §10 deliberately restores *through* the latter rather than
refusing it. So the ledger row now records `restored_sheet_id`, the live
id each restore creates, and a repeat run is refused before the
authentication prompt and before the fresh backup copy, naming the sheet
and the still-live lease the earlier restore minted.

The guard keys on that id still being live rather than on `restored_at`
being set, so re-deleting the restored sheet and re-running legitimately
restores it again. The recheck immediately before the write applies the
same test, for a restore landing during the up-to-two-minute prompt
window. The Bytes restore path was already idempotent and is unchanged.
`restored_sheet_id` is additive, so ledgers written by earlier builds
keep loading.

Boxes InsertOutcome::AlreadyLeased's payload, which the new field pushed
over clippy's large_enum_variant threshold. Also corrects five
docs/drive.md examples that showed lease expiry timestamps as RFC3339
when the code prints chrono's Display form, and three verdicts missing
from docs/log.md's drive-lease-restore vocabulary.

Closes #1689
…1689

Intra-doc links still pointed at detect_deleted_sheet after its rename to
detect_sheet_restore, breaking `cargo doc --document-private-items` (the
CI Docs job's exact command). SheetAlreadyRestored's "that restore's own
lease is still live" message claimed a specific provenance that
live_lease_for can't actually guarantee — it returns any live lease for
the file, which could have been minted by an unrelated operation after
the original lease expired; reworded to not over-claim. Also avoids
rebuilding live.sheet_ids() twice in the pre-write recheck.
The rebase onto main (which now carries #1690's InsertsALiveLeaseDuringAuth
test helper) merged cleanly with no conflict markers, but silently left a
LeaseRecord struct literal missing the restored_sheet_id field this branch
added — a real compile error in test code only, since a non-test `cargo
build` never catches it.
@github-actions

Copy link
Copy Markdown

Coverage

Total: 97.27% ⚪ 0 pp vs main

Comparing 092d2f5..68aacee (merge-base → PR head)

File Before After Δ
src/drive/lease/restore.rs 99.19% 99.08% 🔴 -0.11 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 928-931 both guards this test helper against misuse; every call site below passes an acquire subcommand
src/cli/drive/lease.rs ignore 942-945 both guards this test helper against misuse; every call site below passes a prune subcommand
src/drive/lease/ledger.rs ignore 812-816 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 1137-1141 both every test using this double refuses before authenticating; a hit here is a regression, not a coverage gap

Patch coverage

Patch: 98.82% (417/422 new lines covered)

File Patch Uncovered new lines
src/cli/drive/lease.rs 100% (42/42)
src/cli/drive/sheets/write.rs 100% (1/1)
src/drive/content_edit.rs 100% (2/2)
src/drive/docs/write.rs 100% (1/1)
src/drive/lease/acquire.rs 100% (3/3)
src/drive/lease/check.rs 100% (1/1)
src/drive/lease/ledger.rs 100% (21/21)
src/drive/lease/prune.rs 100% (2/2)
src/drive/lease/restore.rs 98.54% (338/343) 783, 1621, 1680, 1758, 1845
src/drive/sheets/format.rs 100% (2/2)
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 (5)
  • src/drive/lease/restore.rs:783
  • src/drive/lease/restore.rs:1621
  • src/drive/lease/restore.rs:1680
  • src/drive/lease/restore.rs:1758
  • src/drive/lease/restore.rs:1845

📦 Full per-file coverage summary · run summary

@newhoggy
newhoggy merged commit 7312477 into main Sep 17, 2026
17 checks passed
@newhoggy
newhoggy deleted the issue-1689-restore-duplicate-sheet branch September 17, 2026 17:21
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): re-running lease restore on a restored sheet backup duplicates the sheet

1 participant