// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package build import ( "internal/testenv" "runtime" "strings" "testing" ) // Prefixes for packages that can be vendored into the go repo. // The prefixes are component-wise; for example, "golang.org/x" // matches "golang.org/x/build" but not "golang.org/xyz". // // DO NOT ADD TO THIS LIST TO FIX BUILDS. // Vendoring a new package requires prior discussion. var allowedPackagePrefixes = []string{ "golang.org/x", "github.com/google/pprof", "github.com/ianlancetaylor/demangle", "rsc.io/markdown", } // Verify that the vendor directories contain only packages matching the list above. func TestVendorPackages(t *testing.T) { _, thisFile, _, _ := runtime.Caller(0) goBin := testenv.GoToolPath(t) listCmd := testenv.Command(t, goBin, "list", "std", "cmd") out, err := listCmd.Output() if err != nil { t.Fatal(err) } for _, fullPkg := range strings.Split(string(out), "\n") { pkg, found := strings.CutPrefix(fullPkg, "vendor/") if !found { _, pkg, found = strings.Cut(fullPkg, "/vendor/") if !found { continue } } if !isAllowed(pkg) { t.Errorf(` Package %q should not be vendored into this repo. After getting approval from the Go team, add it to allowedPackagePrefixes in %s.`, pkg, thisFile) } } } func isAllowed(pkg string) bool { for _, pre := range allowedPackagePrefixes { if pkg == pre || strings.HasPrefix(pkg, pre+"/") { return true } } return false } func TestIsAllowed(t *testing.T) { for _, test := range []struct { in string want bool }{ {"evil.com/bad", false}, {"golang.org/x/build", true}, {"rsc.io/markdown", true}, {"rsc.io/markdowntonabbey", false}, {"rsc.io/markdown/sub", true}, } { got := isAllowed(test.in) if got != test.want { t.Errorf("%q: got %t, want %t", test.in, got, test.want) } } }