What is wrong:FileStorer.List and ListStream (internal/storage/file.go) walk with afero.Walk, which does not follow a symlink, so a symlinked metadata/ or blobs/ is listed as one non-directory key. Stat, Get and Put do follow it, so backups and restores keep working while every listing is empty.
How it was shown: after a backup, metadata/ was moved elsewhere and replaced by a symlink to it. snapshot list then warned "1 local snapshot record(s) not found in backup destination store", and prune --force printed "Removing stale local record ..." and "Deleted 1 blob(s)", leaving 0 blobs while both metadata files were still in place behind the link. With blobs/ symlinked instead, remote info --json gave total_blob_count: 0 beside referenced_blob_count: 1, and remote nuke --force printed "Backup destination store is now empty." with the blob still there.
Definition of done
A listing of a file:// destination reads through a symlinked directory the way Stat and Get do, or fails; it never reports a store it could not read as empty.
Tests cover a symlinked metadata/ and a symlinked blobs/, and check that prune deletes nothing in either case.
Model: opus-5-5
Found by the defect hunt in https://git.eeqj.de/sneak/vaultik/issues/288 (part 5).
**What is wrong:** `FileStorer.List` and `ListStream` (`internal/storage/file.go`) walk with `afero.Walk`, which does not follow a symlink, so a symlinked `metadata/` or `blobs/` is listed as one non-directory key. `Stat`, `Get` and `Put` do follow it, so backups and restores keep working while every listing is empty.
**How it was shown:** after a backup, `metadata/` was moved elsewhere and replaced by a symlink to it. `snapshot list` then warned "1 local snapshot record(s) not found in backup destination store", and `prune --force` printed "Removing stale local record ..." and "Deleted 1 blob(s)", leaving 0 blobs while both metadata files were still in place behind the link. With `blobs/` symlinked instead, `remote info --json` gave `total_blob_count: 0` beside `referenced_blob_count: 1`, and `remote nuke --force` printed "Backup destination store is now empty." with the blob still there.
**Definition of done**
- A listing of a `file://` destination reads through a symlinked directory the way `Stat` and `Get` do, or fails; it never reports a store it could not read as empty.
- Tests cover a symlinked `metadata/` and a symlinked `blobs/`, and check that `prune` deletes nothing in either case.
Model: opus-5-5
Implemented in #331: the file:// listings now read through a symlinked directory as Get and Stat do, and a link pointing back up the tree makes them fail. A symlinked metadata/ or blobs/ whose target is missing still lists as empty, as a missing directory does.
Model: opus-5-5
Implemented in https://git.eeqj.de/sneak/vaultik/pulls/331: the `file://` listings now read through a symlinked directory as `Get` and `Stat` do, and a link pointing back up the tree makes them fail. A symlinked `metadata/` or `blobs/` whose target is missing still lists as empty, as a missing directory does.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found by the defect hunt in #288 (part 5).
What is wrong:
FileStorer.ListandListStream(internal/storage/file.go) walk withafero.Walk, which does not follow a symlink, so a symlinkedmetadata/orblobs/is listed as one non-directory key.Stat,GetandPutdo follow it, so backups and restores keep working while every listing is empty.How it was shown: after a backup,
metadata/was moved elsewhere and replaced by a symlink to it.snapshot listthen warned "1 local snapshot record(s) not found in backup destination store", andprune --forceprinted "Removing stale local record ..." and "Deleted 1 blob(s)", leaving 0 blobs while both metadata files were still in place behind the link. Withblobs/symlinked instead,remote info --jsongavetotal_blob_count: 0besidereferenced_blob_count: 1, andremote nuke --forceprinted "Backup destination store is now empty." with the blob still there.Definition of done
file://destination reads through a symlinked directory the wayStatandGetdo, or fails; it never reports a store it could not read as empty.metadata/and a symlinkedblobs/, and check thatprunedeletes nothing in either case.Model: opus-5-5
Implemented in #331: the
file://listings now read through a symlinked directory asGetandStatdo, and a link pointing back up the tree makes them fail. A symlinkedmetadata/orblobs/whose target is missing still lists as empty, as a missing directory does.Model: opus-5-5