fix: identify earth binaries via Go build info, not magic strings - #920
kmannislands wants to merge 1 commit into
Conversation
IsEarthlyBinary guarded a destructive path: symlinkEarthlyToEarth removes the sibling "earth" file and replaces it with a symlink whenever this returns true, so a false positive deletes a user's file. The old check grepped the target's raw bytes for "docs.earthly.dev", "api.earthly.dev" and buildcontext.Earthfile. That was unsound. The first two strings appear nowhere else in the source tree - a real earth binary contained them only because this function's own literals were compiled into it, so it passed by accident. Worse, byte presence is weak evidence in the direction that matters: any file that happens to contain those substrings was treated as an earth binary and deleted. Replace it with a real identity check using debug/buildinfo, which reads the Go module metadata embedded in a binary without executing it. Accept the binary only when its main module path is github.com/EarthBuild/earthbuild or the legacy upstream github.com/earthly/earthly (genuine pre-fork earthly binaries are exactly the ones bootstrap wants to replace). Every error from ReadFile - not a Go binary, directory, truncated, unreadable - fails closed to false. Renamed to IsEarthBinary per the earth/EarthBuild naming convention and updated the sole call site. The buildcontext import is no longer needed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
|
||
| import ( | ||
| "bytes" | ||
| "debug/buildinfo" |
There was a problem hiding this comment.
is it a problem to import this in a production build? no idea.
Tested against real binaries — the old check was never functionalRan the old heuristic and the new one side by side against every earth/earthly binary available, including a genuine pre-fork upstream binary installed from Homebrew ( Both module paths resolve correctly, including the legacy The old check returns false on every real binaryNot just on EarthBuild builds — on genuine upstream earthly too:
That means So this PR is less "hardening" than "bug fix restoring a feature that never worked". The silver lining is that the deprecation symlink also never mis-fired destructively. Reviewer note: this reactivates a destructive pathOnce this merges, Worth confirming the intended behavior for an install where |
➖ Are we earthbuild yet?No change in "earthly" occurrences 📈 Overall Progress
Keep up the great work migrating from Earthly to Earthbuild! 🚀 💡 Tips for finding more occurrencesRun locally to see detailed breakdown: ./.github/scripts/count-earthly.shNote that the goal is not to reach 0. |
|
What issue are we trying to resolve? |
The problem
IsEarthlyBinaryis a safety guard in front of a destructive operation.symlinkEarthlyToEarth(cmd/earth/subcmd/bootstrap_cmds.go) runs when the binary is invoked asearthly, looks for a sibling file namedearth, and if the check passes it doesos.Remove(earthPath)before symlinking. A false positive deletes a user's file.The check grepped the target file's raw bytes for
docs.earthly.dev,api.earthly.devandEarthfile. That is unsound in the one direction that matters:The fix
Use
debug/buildinfo.ReadFile, which reads a Go binary's module metadata without executing it, and matchinfo.Main.Pathagainst the EarthBuild module path or the legacy upstreamgithub.com/earthly/earthly(pre-fork binaries are exactly the ones bootstrap wants to replace).Fails closed: any error — missing file, directory, truncated or non-Go file, permission denied — reports false. A false negative just skips the symlink.
Renamed to
IsEarthBinaryper theAGENTS.mdnaming convention; there was exactly one call site. Dropped the now-unusedbytesandbuildcontextimports. No new module dependencies.Behavior change worth noting
Binaries built outside module mode, or with build info stripped, now report false where the old grep might have returned true. That is the safe direction, but it means a very old pre-modules earthly binary will no longer be auto-replaced.
Tests
Table-driven, including the regression the old code got wrong — a non-Go file stuffed with the legacy magic strings must report false.
go build ./...,go test ./cmd/... ./buildkitd/...,gofmt -landgo vetall clean.🤖 Generated with Claude Code