feat(build): resolve garble from Go install paths

This commit is contained in:
Virgil 2026-04-01 20:32:39 +00:00
parent 48e5a6e859
commit d21867ef61
2 changed files with 131 additions and 0 deletions

View file

@ -3,6 +3,7 @@ package builders
import (
"context"
"os"
"runtime"
"strings"
@ -193,6 +194,8 @@ func (b *GoBuilder) resolveGarbleCli(paths ...string) (string, error) {
"/opt/homebrew/bin/garble",
}
paths = append(paths, garbleInstallPaths()...)
if home := core.Env("HOME"); home != "" {
paths = append(paths, ax.Join(home, "go", "bin", "garble"))
}
@ -206,6 +209,27 @@ func (b *GoBuilder) resolveGarbleCli(paths ...string) (string, error) {
return command, nil
}
// garbleInstallPaths returns the standard Go install locations for garble.
func garbleInstallPaths() []string {
var paths []string
if gobin := core.Env("GOBIN"); gobin != "" {
paths = append(paths, ax.Join(gobin, "garble"))
}
if gopath := core.Env("GOPATH"); gopath != "" {
for _, root := range strings.Split(gopath, string(os.PathListSeparator)) {
root = strings.TrimSpace(root)
if root == "" {
continue
}
paths = append(paths, ax.Join(root, "bin", "garble"))
}
}
return paths
}
// hasVersionLDFlag reports whether a version linker flag is already present.
func hasVersionLDFlag(ldflags []string) bool {
for _, flag := range ldflags {

View file

@ -100,6 +100,69 @@ exec go "$@"
require.NoError(t, err)
}
func setupFakeGoBinary(t *testing.T, binDir string) {
t.Helper()
goScript := `#!/bin/sh
set -eu
log_file="${GO_BUILD_LOG_FILE:-}"
if [ -n "$log_file" ]; then
printf '%s\n' "$@" > "$log_file"
fi
env_log_file="${GO_BUILD_ENV_LOG_FILE:-}"
if [ -n "$env_log_file" ]; then
env | sort > "$env_log_file"
fi
if [ "${GOARCH:-}" = "invalid_arch" ]; then
exit 1
fi
if [ -f main.go ] && grep -q "not valid go code" main.go; then
exit 1
fi
output=""
previous=""
for argument in "$@"; do
if [ "$previous" = "-o" ]; then
output="$argument"
break
fi
previous="$argument"
done
if [ -n "$output" ]; then
mkdir -p "$(dirname "$output")"
printf 'fake binary\n' > "$output"
chmod +x "$output"
fi
`
err := ax.WriteFile(ax.Join(binDir, "go"), []byte(goScript), 0o755)
require.NoError(t, err)
}
func setupFakeGarbleBinary(t *testing.T, binDir string) {
t.Helper()
garbleScript := `#!/bin/sh
set -eu
log_file="${GARBLE_LOG_FILE:-}"
if [ -n "$log_file" ]; then
printf '%s\n' "$@" > "$log_file"
fi
exec go "$@"
`
err := ax.WriteFile(ax.Join(binDir, "garble"), []byte(garbleScript), 0o755)
require.NoError(t, err)
}
func TestGo_GoBuilderName_Good(t *testing.T) {
builder := NewGoBuilder()
assert.Equal(t, "go", builder.Name())
@ -568,6 +631,50 @@ func TestGo_GoBuilderBuild_Good(t *testing.T) {
assert.Contains(t, args, ".")
})
t.Run("finds garble in GOBIN when it is not on PATH", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("garble test helper uses a shell script")
}
goDir := t.TempDir()
setupFakeGoBinary(t, goDir)
t.Setenv("PATH", goDir+string(os.PathListSeparator)+"/usr/bin"+string(os.PathListSeparator)+"/bin")
garbleDir := t.TempDir()
setupFakeGarbleBinary(t, garbleDir)
t.Setenv("GOBIN", garbleDir)
projectDir := setupGoTestProject(t)
outputDir := t.TempDir()
logDir := t.TempDir()
logPath := ax.Join(logDir, "garble-gobin.log")
t.Setenv("GARBLE_LOG_FILE", logPath)
builder := NewGoBuilder()
cfg := &build.Config{
FS: io.Local,
ProjectDir: projectDir,
OutputDir: outputDir,
Name: "obfuscated-gobin",
Obfuscate: true,
}
targets := []build.Target{{OS: runtime.GOOS, Arch: runtime.GOARCH}}
artifacts, err := builder.Build(context.Background(), cfg, targets)
require.NoError(t, err)
require.Len(t, artifacts, 1)
assert.FileExists(t, artifacts[0].Path)
content, err := ax.ReadFile(logPath)
require.NoError(t, err)
args := strings.Split(strings.TrimSpace(string(content)), "\n")
require.NotEmpty(t, args)
assert.Equal(t, "build", args[0])
assert.Contains(t, args, "-trimpath")
})
t.Run("builds the configured main package path", func(t *testing.T) {
projectDir := setupGoTestProject(t)
err := ax.MkdirAll(ax.Join(projectDir, "cmd", "myapp"), 0755)