Add cp, folder mv, get -r, and unlock/lock to remember the key

Filesystem basics: mv now moves folders as well as files, and like mv(1)
a NEW ending in / or naming an existing folder means into it. cp copies a
file, or a folder with -r, by writing new records that share the
original's objects, so it is instant and takes no space; rm already keeps
objects another record still uses. New records go first, so an
interrupted move leaves both names, never neither. get -r extracts a
folder, keeping its structure.

vault unlock [--for 5m] checks the passphrase and starts the binary again
as a hidden __agent process, handing it the suite ID and seed over a pipe.
The agent keeps them in mlocked memory, with core dumps off and (on Linux)
PR_SET_DUMPABLE cleared, serves them on a Unix socket in a 0700 per-user
directory whose owner is checked on every use, and wipes them and exits
at a hard deadline or on vault lock. Commands ask it first unless
VAULT_PASSPHRASE is set, and genkey stops any agent left for that path.

Guide, man pages (new vault-cp, vault-unlock, vault-lock), README and
screenshots updated; the guide's error table is split so it fits.
This commit is contained in:
Andy Dixon
2026-10-02 22:13:06 +01:00
parent 0d45ecea59
commit ec204f0ea2
31 changed files with 807 additions and 51 deletions
+17
View File
@@ -387,6 +387,23 @@ def main():
t.cmd("vault get nope 2>/dev/null; echo \"exit code: $?\"", P)
shoot("scripting", t)
# cp, folder mv, get -r
t = Term(box)
t.cmd("vault cp -r letters archive/2025", P)
t.cmd("vault mv ideas/notes.md archive/", P)
t.cmd("vault ls archive", P)
t.cmd("vault get -r archive -o restored/archive", P)
shoot("cp-mv", t)
# unlock: one passphrase, then commands stop asking until lock
t = Term(box)
t.cmd("vault unlock", P)
t.cmd("vault ls")
t.cmd("vault get archive/notes.md -o /tmp/notes.md")
t.cmd("vault lock")
t.moment("vault ls", "Enter passphrase:")
shoot("unlock", t)
# building, into a temporary OUT so an existing dist/ is left alone
rel = tempfile.mkdtemp(prefix="vault-release-")
targets = "linux/amd64 linux/arm darwin/arm64 windows/amd64"