Repository navigation
PE-9205: A manifest leaves out hidden folders and loses no file to a path collision - #2265
Conversation
… collision PE-9205 Two live bugs in ManifestDataBuilder, both reproduced with a test before the fix. Hidden folders were published. The builder filtered each file by its own hidden flag, but hiding a folder marks that folder alone, so a hidden folder's visible files went out at their real paths while the manifest form said hidden files are excluded. The builder now prunes hidden folders however deep, without changing FolderNode.getRecursiveFiles, which the pending-files check also uses. Path collisions dropped files. Spaces become underscores, so "my file.txt" and "my_file.txt" share a path, and the paths map kept one of them. Gateways decode a request's path before matching it against a manifest's keys (ar-io-node src/middleware/arns.ts:46), so a raw path is a valid key: on a collision every file takes its raw path, which leaves the underscored path with the file whose name it already was. A file that collides with nobody keeps the path it has always had, so no existing URL moves. Two files at exactly the same path are told apart by id, the earliest created keeping the plain path. Three smaller defects in the same function: - A hidden index.html became the index while being left out of the paths, so the manifest's root served nothing. The index is now chosen from the files being published. - When the index collided, it pointed at the other file's path. - A folder with nothing to publish threw an unexplained StateError. It now throws ManifestHasNoFilesException, through the same failure path. The form's claim now says hidden files and folders are left out, which is true. Each rule was broken on purpose and the suite rerun: all eight mutants compiled and each failed the test written for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017NRgRqqrM4sg2EeqbGJzff
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
|
Visit the preview URL for this PR (updated for commit e8cefe5): https://ardrive-web--pr2265-fix-manifest-hidden-w9slynkp.web.app (expires Wed, 21 Oct 2026 05:16:03 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: a224ebaee2f0939e7665e7630e7d3d6cd7d0f8b0 |
Two live bugs in
ManifestDataBuilder, which every manifest goes through, from Create Manifest and from AutoDeploy after an upload. Both were reproduced with a test before anything changed.Hidden folders were published
The builder filtered each file by its own hidden flag. Hiding a folder marks that folder alone, never its contents (
hide_bloc.dart:72), and the folder tree keeps hidden folders (foldersInFolderhas noisHiddenpredicate). So a hidden folder's visible files went out at their real paths, permanently, while the manifest form told the user hidden files are left out.The builder now prunes hidden folders however deep.
FolderNode.getRecursiveFilesis unchanged, because the pending-files check also uses it.Path collisions dropped files
Spaces become underscores, so
my file.txtandmy_file.txtarrive at the same path, and the paths map kept one of them with no error.Gateways decode a request's path before matching it against a manifest's keys (
ar-io-nodesrc/middleware/arns.ts:46, compared exactly atsrc/lib/encoding.ts:402), so a raw path with its spaces is a valid key. On a collision every file takes its raw path, which leaves the underscored path with the file whose name it already was. A file that collides with nobody keeps the path it has always had, so no existing URL moves on republish. Two files at exactly the same path are told apart by id, the earliest created keeping the plain path:dup.txtanddup~<8 chars of id>.txt.Keys are deliberately not percent-encoded. An earlier plan of mine said to encode them; checking the gateway showed that would break every key containing
#,?,%or a space.Three smaller defects in the same function
index.htmlbecame the index while being left out of the paths, so the manifest's root served nothing. The index is now chosen from the files being published.StateErrorfrom.first. It now throwsManifestHasNoFilesException, through the sameManifestCreationExceptionfailure path as before. Pruning hidden folders makes this case more reachable, which is why it is handled here.The form's line now reads "Hidden files and folders are not added to the manifest," which is true.
Verification
Ten new tests, plus the existing five unchanged: 15/15. With the two other test files that touch manifests, 47/47.
Each rule was broken on purpose and the file rerun. All eight mutants compiled, and each was caught by the test written for it:
index.htmlthe indexflutter analyzeacross the project: no issues.dart formaton the edited files only: no changes.Not in this PR
What the manifest flow shows when a folder has nothing to publish. It fails with the existing generic failure, which is no worse than today's behaviour for an empty folder; disabling the button with a reason is a separate change.
🤖 Generated with Claude Code
https://claude.ai/code/session_017NRgRqqrM4sg2EeqbGJzff
Summary by CodeRabbit
index.html, otherwise it uses the first publishable file.