Three correctness issues found auditing the vault lifecycle and garbage-collection paths. Each is fixed in its own commit with a kernel-test regression guard.
1. Items stranded after an interrupted purge plus a returning owner's write.
The crypto-erased-item reaper keys on a missing pdv_subject_key row. An interrupted purge leaves items with the key gone; a returning owner's write re-creates the key (resolveForWrite), so the missing-key signal no longer fires and the leftover items, encrypted under the erased key and undecryptable, are never reaped. Fix: also reap items whose created predates their realm's current subject key (the key is always created before the first item, so an older item is a prior-vault leftover).
2. A declined store offer leaves its sealed file on disk.
The operator decline of a store offer links to GrantManager::denyRequest(), which deletes the request row but not the offer's pending sealed file, orphaning the ciphertext. The owner path, denyOffer(), already crypto-erases. Fix: denyRequest() crypto-erases the pending file when one is present.
3. An expired store offer can still be approved.
purgeExpiredOffers() drains a bounded batch per cron run, so an expired write-scope request can still be live when the owner approves it, materializing offered data past its deadline. Fix: approveOffer() re-checks isExpired() after the lock and reload, and refuses.
A merge request with three commits (one per fix) and kernel-test coverage is attached.
Issue fork pdv-3594027
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mably commentedComment #5
mably commented