From 56546a42a0a8c5e1675e37cd88a3535270cd54e8 Mon Sep 17 00:00:00 2001 From: Ahmetshbzz Date: Sat, 15 Aug 2026 14:33:19 +0200 Subject: [PATCH] fix: detect stdlib from the active Go toolchain Resolve GOROOT through the same go command used by package loading instead of relying on the tool build-time go/build default. This keeps standard-library detection correct when a prebuilt go-licenses binary scans a module with a newer downloaded toolchain. Use filepath.Rel against GOROOT/src to avoid path-prefix collisions and add regression coverage for mismatched build and active toolchain roots, prefix collisions, and the unsafe package special case. --- licenses/library.go | 31 +++++++++++++++++++++++-------- licenses/library_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/licenses/library.go b/licenses/library.go index fa59120f..d8ef5899 100644 --- a/licenses/library.go +++ b/licenses/library.go @@ -17,7 +17,7 @@ package licenses import ( "context" "fmt" - "go/build" + "os/exec" "path/filepath" "sort" "strings" @@ -83,6 +83,10 @@ func Libraries(ctx context.Context, classifier Classifier, includeTests bool, ig if err != nil { return nil, err } + goRoot, err := activeGoRoot(ctx) + if err != nil { + return nil, err + } vendoredSearch := []*Module{} for _, parentPkg := range rootPkgs { @@ -120,7 +124,7 @@ func Libraries(ctx context.Context, classifier Classifier, includeTests bool, ig pkgErrorOccurred = true return false } - if isStdLib(p) { + if isStdLib(p, goRoot) { // No license requirements for the Go standard library. return false } @@ -409,8 +413,20 @@ func (l *Library) Version() string { return "" } +func activeGoRoot(ctx context.Context) (string, error) { + output, err := exec.CommandContext(ctx, "go", "env", "GOROOT").Output() + if err != nil { + return "", fmt.Errorf("resolve active Go toolchain GOROOT: %w", err) + } + goRoot := strings.TrimSpace(string(output)) + if goRoot == "" || strings.ContainsAny(goRoot, "\r\n") || !filepath.IsAbs(goRoot) { + return "", fmt.Errorf("active Go toolchain returned invalid GOROOT %q", goRoot) + } + return filepath.Clean(goRoot), nil +} + // isStdLib returns true if this package is part of the Go standard library. -func isStdLib(pkg *packages.Package) bool { +func isStdLib(pkg *packages.Package, goRoot string) bool { if pkg.Name == "unsafe" { // Special case unsafe stdlib, because it does not contain go files. return true @@ -418,12 +434,11 @@ func isStdLib(pkg *packages.Package) bool { if len(pkg.GoFiles) == 0 { return false } - prefix := build.Default.GOROOT - sep := string(filepath.Separator) - if !strings.HasSuffix(prefix, sep) { - prefix += sep + relativePath, err := filepath.Rel(filepath.Join(goRoot, "src"), pkg.GoFiles[0]) + if err != nil || filepath.IsAbs(relativePath) || relativePath == ".." { + return false } - return strings.HasPrefix(pkg.GoFiles[0], prefix) + return !strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) } // isTestBinary returns true iff pkg is a test binary. diff --git a/licenses/library_test.go b/licenses/library_test.go index da00e8ce..6c411d1b 100644 --- a/licenses/library_test.go +++ b/licenses/library_test.go @@ -17,13 +17,42 @@ package licenses import ( "context" "os" + "path/filepath" "testing" "time" "github.com/google/go-cmp/cmp" "github.com/google/go-licenses/v2/internal/third_party/pkgsite/source" + "golang.org/x/tools/go/packages" ) +func TestIsStdLibUsesActiveToolchainRoot(t *testing.T) { + toolchainsRoot := t.TempDir() + activeRoot := filepath.Join(toolchainsRoot, "go1.26.6") + compiledRoot := filepath.Join(toolchainsRoot, "go1.26.5") + standardPackage := &packages.Package{ + Name: "fmt", + GoFiles: []string{filepath.Join(activeRoot, "src", "fmt", "print.go")}, + } + + if !isStdLib(standardPackage, activeRoot) { + t.Fatal("package from the active toolchain GOROOT was not identified as standard library") + } + if isStdLib(standardPackage, compiledRoot) { + t.Fatal("package was identified using the tool's compile-time GOROOT") + } + prefixCollision := &packages.Package{ + Name: "fmt", + GoFiles: []string{filepath.Join(activeRoot+"-other", "src", "fmt", "print.go")}, + } + if isStdLib(prefixCollision, activeRoot) { + t.Fatal("GOROOT path prefix collision was identified as standard library") + } + if !isStdLib(&packages.Package{Name: "unsafe"}, activeRoot) { + t.Fatal("unsafe package was not identified as standard library") + } +} + func TestLibraries(t *testing.T) { wd, err := os.Getwd() if err != nil {