fix(update): refuse to initialize an install root instead of wiping it - #664
Merged
Conversation
`formae update` derived the orbital tree root from the running binary's location and, when that path carried no tree, offered to initialize one. orbital's Initialize is a force-init: it removes the root recursively before recreating it. A formae reached through a copy or symlink in a foreign prefix (a package manager's bin, /usr/local/bin, a build tree) resolved to that prefix, so confirming the prompt deleted an unrelated directory — and the update then reported success. update now refuses with the resolved path and the ways out; creating install roots stays with the installer, which is the only component that knows it owns the target. Root derivation also resolves symlinks first, so a shim on PATH resolves to the real install rather than making its own prefix the managed root.
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.
Summary
formae updateno longer initializes an orbital tree root. It refuses with the resolved path and the ways out; creating install roots stays with the installer, the only component that knows it owns the target directory.PATHresolves to the real install instead of making its own prefix the managed root.Why
The tree root was derived from the running binary's location (
dirname(dirname(os.Executable()))), and when that path carried no tree,updateprompted to initialize it.mgr.Initialize()is a force-init — orbital removes the root recursively before recreating it. So a formae reached through a copy or symlink in a foreign prefix (a package manager's bin directory,/usr/local/bin, a build tree) resolved to that prefix, and confirming the prompt deleted it. The update then installed into the fresh tree and reported success, so nothing signalled the loss.Two properties make it worse than a bad prompt:
os.Executable()on darwin returns the invoked path with symlinks intact, so any shim silently retargets the root; and root-owned prefixes cause orbital to re-exec under sudo first, so the delete can run elevated.Refusing is the only safe answer here —
updatecannot distinguish "user wants a new root" from "user is running the wrong binary", and one of those two readings is destructive. With symlink resolution in place, shims keep working, so the refusal only fires on genuinely rootless prefixes.refreshand theplugincommands already refused in this situation;updatewas the outlier.