Add snapshot files to list a snapshot's files without restoring it (closes #435) #457

Open
clawbot wants to merge 1 commits from issue-435-snapshot-files into next
pull from: issue-435-snapshot-files
Collaborator

Closes #435.

New command vaultik snapshot files <snapshot-id> [path] [--json]. It downloads and decrypts the snapshot database as restore does, then prints mode, size in bytes, modification time (UTC) and path for every file at or under the path, sorted by path. --json prints an array of path, size, mode, mtime.

  • Named files, not ls: ls is already the alias of snapshot list.
  • Needs the private key, like restore. Accepts the same identifiers as restore, remote keys included.
  • A path that matches nothing is an error, matching restore.
  • The table is silenced by --quiet, as the snapshot list table is; --json output is not.
  • mode is Go's file mode string (-rw-r--r--, drwxr-xr-x). Symlinks show as Lrwxrwxrwx, not ls's l.
  • The missing-key error no longer says "for restore", since this command and deep verify return it too.
  • Restore's close-and-remove of the decrypted database moved to closeSnapshotDB, which both commands use.
  • README: command list, description, locking, key variable and --quiet notes.

Judgement call: the whole file list is loaded into memory before printing, as restore already does.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/vaultik/issues/435. New command `vaultik snapshot files <snapshot-id> [path] [--json]`. It downloads and decrypts the snapshot database as restore does, then prints mode, size in bytes, modification time (UTC) and path for every file at or under the path, sorted by path. `--json` prints an array of `path`, `size`, `mode`, `mtime`. - Named `files`, not `ls`: `ls` is already the alias of `snapshot list`. - Needs the private key, like restore. Accepts the same identifiers as restore, remote keys included. - A path that matches nothing is an error, matching restore. - The table is silenced by `--quiet`, as the `snapshot list` table is; `--json` output is not. - `mode` is Go's file mode string (`-rw-r--r--`, `drwxr-xr-x`). Symlinks show as `Lrwxrwxrwx`, not `ls`'s `l`. - The missing-key error no longer says "for restore", since this command and deep verify return it too. - Restore's close-and-remove of the decrypted database moved to `closeSnapshotDB`, which both commands use. - README: command list, description, locking, key variable and `--quiet` notes. Judgement call: the whole file list is loaded into memory before printing, as restore already does. Model: opus-5-5
clawbot added the needs-review label 2026-11-13 19:48:48 +01:00
clawbot added 1 commit 2026-11-13 19:48:48 +01:00
`vaultik snapshot files <snapshot-id> [path] [--json]` downloads and
decrypts the snapshot database, as restore does, and prints mode, size,
modification time and path for every file at or under the path. A path
that matches nothing is an error. It needs the private key.

Named `files` because `ls` is already the alias of `snapshot list`.
The missing-key error no longer says "for restore", since this command
and deep verify return it too.

Model: opus-5-5
clawbot self-assigned this 2026-11-13 19:48:50 +01:00
Author
Collaborator

Verdict: FAIL
Head: 1e01457d5d

needs-rework

  1. internal/vaultik/snapshot_files.go, type SnapshotFile: internal/database/models.go already has a SnapshotFile, the row that links a snapshot to a file in the snapshot_files table. Two unrelated types with one name, one package importing the other, mislead a reader. Acceptable: a name that says it is one entry of the printed listing, such as ListedFile, in the code, tests and comments.

  2. internal/vaultik/snapshot_files.go, errPathNotInSnapshot: it sits one letter away from restore's errPathsNotInSnapshot in internal/vaultik/restore.go, for the same condition with a different message. Acceptable: return errPathsNotInSnapshot wrapped with the path, and drop the new sentinel.

  3. Two behaviours the change adds can break with the suite green:

    • Dropping cmd.AddCommand(newSnapshotFilesCommand()) from internal/cli/snapshot.go, or passing the wrong argument as the path, fails no test. Acceptable: files added to the expected snapshot subcommands in internal/cli/entry_test.go, and a test that runs snapshot files through the command with a snapshot ID and a path and sees only that path listed.
    • Removing the v.UI.Quiet() check in ListSnapshotFiles fails no test, though the README says --quiet silences the table. The other commands that say so have a quiet test (internal/vaultik/snapshot_list_quiet_test.go, internal/vaultik/verify_quiet_test.go). Acceptable: a test that, with the UI quiet, prints no table and still prints the --json document.
  4. internal/cli/app.go, comment on readOnly: it lists the read-only commands and leaves out snapshot files. Acceptable: add it.

  5. README.md, snapshot files section: the mode column and the --json mode field use Go's file-mode notation, which differs from ls -l beyond symlinks. A setuid file shows as urwxr-xr-x (ls: -rwsr-xr-x), a sticky directory as dtrwxrwxrwx, and a device starts with D. Nothing tells the user or a script this. Acceptable: the section says the mode is in Go's file-mode notation, and lists as bullets the leading letters that differ from ls -l.

  6. README.md, sentences the change edits that each chain a comma list where a bulleted list belongs, with the verb after the list; the first and third also run past 30 words:

    • "Read-only commands — info, snapshot list, snapshot files, snapshot verify, and remote info — do not take the lock and are never blocked, so they run even while a backup is in progress."
    • "This covers the version, info, remote info and snapshot verify reports, the snapshot list and snapshot files tables, config get values, and every --json document."
    • "--quiet silences the human reports and tables (version, info, remote info, snapshot verify, snapshot list, snapshot files) but never the machine-consumed config get value or the --json documents, which a script depends on."
    • Acceptable: each becomes a short lead sentence followed by the commands as a bulleted list.
  7. README.md opening, third sentence: "It requires no private keys, secrets, or credentials (other than those required to PUT to encrypted object storage, such as S3 API keys) stored on the backed-up system." It puts an exception in the opening and splits "requires no … credentials" from "stored on the backed-up system". Acceptable: the main rule first, as a short sentence ("The backed-up system never holds the private key."), then a separate sentence saying it needs only the public key and the credentials to write to storage.

Model: opus-5-5

Verdict: FAIL Head: 1e01457d5d4a5a7d9f8a9a36b8735d67df4134be `needs-rework` 1. `internal/vaultik/snapshot_files.go`, type `SnapshotFile`: `internal/database/models.go` already has a `SnapshotFile`, the row that links a snapshot to a file in the `snapshot_files` table. Two unrelated types with one name, one package importing the other, mislead a reader. Acceptable: a name that says it is one entry of the printed listing, such as `ListedFile`, in the code, tests and comments. 2. `internal/vaultik/snapshot_files.go`, `errPathNotInSnapshot`: it sits one letter away from restore's `errPathsNotInSnapshot` in `internal/vaultik/restore.go`, for the same condition with a different message. Acceptable: return `errPathsNotInSnapshot` wrapped with the path, and drop the new sentinel. 3. Two behaviours the change adds can break with the suite green: - Dropping `cmd.AddCommand(newSnapshotFilesCommand())` from `internal/cli/snapshot.go`, or passing the wrong argument as the path, fails no test. Acceptable: `files` added to the expected snapshot subcommands in `internal/cli/entry_test.go`, and a test that runs `snapshot files` through the command with a snapshot ID and a path and sees only that path listed. - Removing the `v.UI.Quiet()` check in `ListSnapshotFiles` fails no test, though the README says `--quiet` silences the table. The other commands that say so have a quiet test (`internal/vaultik/snapshot_list_quiet_test.go`, `internal/vaultik/verify_quiet_test.go`). Acceptable: a test that, with the UI quiet, prints no table and still prints the `--json` document. 4. `internal/cli/app.go`, comment on `readOnly`: it lists the read-only commands and leaves out `snapshot files`. Acceptable: add it. 5. `README.md`, `snapshot files` section: the `mode` column and the `--json` `mode` field use Go's file-mode notation, which differs from `ls -l` beyond symlinks. A setuid file shows as `urwxr-xr-x` (`ls`: `-rwsr-xr-x`), a sticky directory as `dtrwxrwxrwx`, and a device starts with `D`. Nothing tells the user or a script this. Acceptable: the section says the mode is in Go's file-mode notation, and lists as bullets the leading letters that differ from `ls -l`. 6. `README.md`, sentences the change edits that each chain a comma list where a bulleted list belongs, with the verb after the list; the first and third also run past 30 words: - "Read-only commands — `info`, `snapshot list`, `snapshot files`, `snapshot verify`, and `remote info` — do not take the lock and are never blocked, so they run even while a backup is in progress." - "This covers the `version`, `info`, `remote info` and `snapshot verify` reports, the `snapshot list` and `snapshot files` tables, `config get` values, and every `--json` document." - "`--quiet` silences the human reports and tables (`version`, `info`, `remote info`, `snapshot verify`, `snapshot list`, `snapshot files`) but never the machine-consumed `config get` value or the `--json` documents, which a script depends on." - Acceptable: each becomes a short lead sentence followed by the commands as a bulleted list. 7. `README.md` opening, third sentence: "It requires no private keys, secrets, or credentials (other than those required to PUT to encrypted object storage, such as S3 API keys) stored on the backed-up system." It puts an exception in the opening and splits "requires no … credentials" from "stored on the backed-up system". Acceptable: the main rule first, as a short sentence ("The backed-up system never holds the private key."), then a separate sentence saying it needs only the public key and the credentials to write to storage. Model: opus-5-5
Some checks are pending
check / check (push) Waiting to run
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-435-snapshot-files:issue-435-snapshot-files
git checkout issue-435-snapshot-files
Sign in to join this conversation.