Repository navigation
store: a plugin id that differs only in case is refused safely - #585
Merged
Merged
Conversation
Uninstall deletes plugins/<id> only when the filesystem lists a folder of exactly that name that no other entry shares an inode with; anything else (a case variant standing there, an alias, an unreadable listing, an id that is not a plain name) keeps the folder and drops only the card. On macOS this stopped a refused build's card from deleting an installed, unloaded plugin's folder. A refused store install or update becomes a failed job (Retry, or the update offer marked failed) instead of a row left started; plugins/ is read once per session for the clash check and again after an install or uninstall; the clash names come back borrowed, never truncated; and one card names every case variant of a folder. Part of #530 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the case-clash fix. Uninstall deletes plugins/<id> only when an entry of exactly that name exists and no other entry is the id in another case (store.folders.deletable, a new std-only file with unit tests); an exact-name symlink loses only the link. No inode rule: Zig fills Windows directory-entry inodes from a FileIndex NTFS leaves 0. The session cache is gone: each install, update, uninstall and load reads plugins/ fresh, the automatic update pass reads it once for the pass, and an unreadable listing refuses the install and keeps the folder. A refusal is built through buildJob with its reason, shown on the card with a Dismiss beside the plugin's own controls; startup groups case variants in one pass. Part of #530 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of fizzyedit/work#33
What changes
#560 landed a rule that refuses a plugin whose id matches another plugin's except for letter case. That code can lose data. This PR keeps the rule and fixes it, deciding every case by what the filesystem lists at the moment of the action, and taking the safe path whenever it can't tell.
main: an installed plugin inplugins/Graphlis not loaded, and a build ofgraphlis refused. Uninstalling the refused build from its card deletedplugins/graphl. On macOS and Windows that path isplugins/Graphl, so the installed plugin was deleted.uninstallPluginasksstore.folders.deletable(new std-onlyapp/store/plugin_folders.zig), which readsplugins/fresh. It deletes only when an entry named exactlyidexists and no other entry isidin another case. On a case-insensitive filesystem that second check is what protects the other plugin. It replacesApp.sameFolder.plugins/itself: install, update, uninstall, a live load.pass_foldersinapplyAllPendingUpdates).plugins/can't be read, the install, update or load is refused as a possible clash, and uninstall keeps the folder. Aplugins/that doesn't exist yet simply holds nothing.refusal), and builds the job throughbuildJobwith arefusedreason. That job is failed from the start and creates no folders.PluginManager.refuseCaseClashseam from the first round is gone; the store decides this itself.max_name_bytes. A message too long for its buffer is shown without the name, never cut short.SDK impact
App, the store and the loader are app-side, and the recorded fingerprint is unchanged.sdk/src/version.zig,sdk_versionuntouched, PR labelledsdksdk_version, lists thesdkPRs since the lastsdk-v*tagVerified
scripts/check-fmt.sh,zig build,test,test-integration,check-web,test-sdk-version,check-tests-reached,scripts/check-examples.sh).fizzy-plugin-folders-tests):..,a/band an unreadableplugins/all keep;.link;plugins/not made yet holds nothing.Textof the loadedtextis refused before it is opened, and its card shows failed;Textleaves a file inplugins/text;plugins/Graphlis found fresh by the clash check;graphlcard leavesplugins/Graphl/keep(the data-loss case onmain, reproduced here);plugins/solois still deleted by uninstall.check-web); there is noplugins/folder on the web.Follow-ups
🤖 Generated with Claude Code