refactor(cli): Vault::after_manifest_change wrapper (Plan B Phase 4)
Adds the canonical post-mutation funnel: save_manifest_raw + groups.cache refresh in one method. Converts nine commands/*.rs mutation callsites from the manual save_manifest + refresh_groups_cache pair to a single vault.after_manifest_change(&manifest)?. save_manifest renamed to save_manifest_raw (pub(crate)) so future commands cannot accidentally bypass the cache refresh. Four of the nine sites (attach.rs add/detach, import.rs LastPass, trash.rs cmd_trash_empty's per-item save) previously skipped the cache refresh — the wrapper fixes them. refresh_groups_cache moves from main.rs to helpers.rs so the read-side warmup callers in get.rs/list.rs still reach it.
This commit is contained in:
@@ -69,7 +69,20 @@ impl UnlockedVault {
|
||||
Ok(decrypt_manifest(&bytes, &self.master_key)?)
|
||||
}
|
||||
|
||||
pub fn save_manifest(&self, manifest: &Manifest) -> Result<()> {
|
||||
/// Save the manifest and refresh the plaintext groups.cache. This is the
|
||||
/// canonical "I just mutated the manifest" funnel — every command that
|
||||
/// changes the manifest goes through this method, so cache freshness is
|
||||
/// a compile-time invariant rather than a discipline rule.
|
||||
pub fn after_manifest_change(&self, manifest: &Manifest) -> Result<()> {
|
||||
self.save_manifest_raw(manifest)?;
|
||||
crate::helpers::refresh_groups_cache(&self.root, manifest);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Encrypt the manifest and atomically write it. Most callers want
|
||||
/// `after_manifest_change` instead — this method skips the groups.cache
|
||||
/// refresh, leaving shell completion stale until the next mutation.
|
||||
pub(crate) fn save_manifest_raw(&self, manifest: &Manifest) -> Result<()> {
|
||||
let bytes = encrypt_manifest(manifest, &self.master_key)?;
|
||||
atomic_write(&self.manifest_path(), &bytes)
|
||||
}
|
||||
@@ -252,4 +265,21 @@ mod tests {
|
||||
assert_eq!(v["aead"], "xchacha20poly1305");
|
||||
assert_eq!(v["salt_path"], ".relicario/salt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn after_manifest_change_writes_manifest_and_groups_cache() {
|
||||
let dir = tempfile::TempDir::new().unwrap();
|
||||
let root = dir.path().to_path_buf();
|
||||
std::fs::create_dir_all(root.join(".relicario")).unwrap();
|
||||
std::fs::create_dir_all(root.join("items")).unwrap();
|
||||
let vault = UnlockedVault {
|
||||
root: root.clone(),
|
||||
master_key: Zeroizing::new([0u8; 32]),
|
||||
};
|
||||
let manifest = Manifest::new();
|
||||
|
||||
vault.after_manifest_change(&manifest).unwrap();
|
||||
assert!(root.join("manifest.enc").exists());
|
||||
assert!(root.join(".relicario/groups.cache").exists());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user