Implement rollback-safe tree mutations
This commit is contained in:
36
docs/tree-mutations.md
Normal file
36
docs/tree-mutations.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Tree mutations
|
||||
|
||||
`TreeMutator` owns the `pass rm`, `mv`, and `cp` filesystem semantics in
|
||||
`crates/storage`. Callers provide typed command requests, a confirmation
|
||||
decision, secret-key access when selective reencryption is needed, and a
|
||||
`TreeCommitter`; they never inspect or mutate the password-store tree.
|
||||
|
||||
Sources use the repository resolver. A trailing slash explicitly selects a
|
||||
directory, while a logical path occupied by both `name.gpg` and `name/` is
|
||||
otherwise rejected as ambiguous. An existing destination directory is a
|
||||
container, so the source basename is appended. A destination ending in a slash
|
||||
must already be a directory. Same-object transfers, moves into their own
|
||||
subtree, entry/directory type collisions, symlinks, and subtrees containing
|
||||
unknown auxiliary files are rejected before any write.
|
||||
|
||||
Entry overwrites require either `--force` or an affirmative confirmation.
|
||||
Directory removal requires the recursive flag. Whole-directory transfers copy
|
||||
their `.gpg-id` and optional `.gpg-id.sig` boundaries; an existing destination
|
||||
policy is rejected instead of partly merging policy trees. Entries whose
|
||||
effective destination recipients differ are decrypted and reencrypted with the
|
||||
embedded OpenPGP backend, while matching ciphertext is preserved byte for byte.
|
||||
|
||||
Every destination entry and policy is atomically and durably written before a
|
||||
move removes its source. The operation retains source and overwritten
|
||||
destination bytes until the commit callback succeeds. A filesystem or commit
|
||||
failure restores both sides and removes directories created by the failed
|
||||
transaction. Successful moves and removals then prune empty source directories.
|
||||
The commit callback must report failure only when it has not created a commit;
|
||||
it receives the compatible intent `Remove ... from store.`, `Rename ... to
|
||||
....`, or `Copy ... to ....`.
|
||||
|
||||
Compatibility tests materialize the shared upstream-format fixtures and cover
|
||||
entry and subtree mutations, recursive requirements, cancellation, forced
|
||||
overwrite, directory destinations, ambiguity, nested signed recipient
|
||||
boundaries, selective reencryption, source preservation, source cleanup, and
|
||||
exact-tree rollback after a simulated commit failure.
|
||||
Reference in New Issue
Block a user