github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/golang/stdlib_package.go (about) 1 package golang 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/anchore/syft/internal" 9 "github.com/anchore/syft/syft/artifact" 10 "github.com/anchore/syft/syft/cpe" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 ) 14 15 func stdlibProcessor(ctx context.Context, _ file.Resolver, pkgs []pkg.Package, relationships []artifact.Relationship, err error) ([]pkg.Package, []artifact.Relationship, error) { 16 compilerPkgs, newRelationships := stdlibPackageAndRelationships(ctx, pkgs) 17 return append(pkgs, compilerPkgs...), append(relationships, newRelationships...), err 18 } 19 20 func stdlibPackageAndRelationships(ctx context.Context, pkgs []pkg.Package) ([]pkg.Package, []artifact.Relationship) { 21 var goCompilerPkgs []pkg.Package 22 var relationships []artifact.Relationship 23 totalLocations := file.NewLocationSet() 24 for _, goPkg := range pkgs { 25 mValue, ok := goPkg.Metadata.(pkg.GolangBinaryBuildinfoEntry) 26 if !ok { 27 continue 28 } 29 30 // go binary packages should only contain a single location 31 for _, location := range goPkg.Locations.ToSlice() { 32 if totalLocations.Contains(location) { 33 continue 34 } 35 36 stdLibPkg := newGoStdLib(ctx, mValue.GoCompiledVersion, goPkg.Locations) 37 if stdLibPkg == nil { 38 continue 39 } 40 goCompilerPkgs = append(goCompilerPkgs, *stdLibPkg) 41 totalLocations.Add(location) 42 43 relationships = append(relationships, artifact.Relationship{ 44 From: *stdLibPkg, 45 To: goPkg, 46 Type: artifact.DependencyOfRelationship, 47 }) 48 } 49 } 50 return goCompilerPkgs, relationships 51 } 52 53 func newGoStdLib(ctx context.Context, version string, location file.LocationSet) *pkg.Package { 54 stdlibCpe, err := generateStdlibCpe(version) 55 if err != nil { 56 return nil 57 } 58 goCompilerPkg := &pkg.Package{ 59 Name: "stdlib", 60 Version: version, 61 PURL: packageURL("stdlib", strings.TrimPrefix(version, "go")), 62 CPEs: []cpe.CPE{stdlibCpe}, 63 Locations: location, 64 Licenses: pkg.NewLicenseSet(pkg.NewLicenseWithContext(ctx, "BSD-3-Clause")), 65 Language: pkg.Go, 66 Type: pkg.GoModulePkg, 67 Metadata: pkg.GolangBinaryBuildinfoEntry{ 68 GoCompiledVersion: version, 69 }, 70 } 71 goCompilerPkg.SetID() 72 73 return goCompilerPkg 74 } 75 76 func generateStdlibCpe(version string) (stdlibCpe cpe.CPE, err error) { 77 // GoCompiledVersion when pulled from a binary is prefixed by go 78 version = strings.TrimPrefix(version, "go") 79 80 // we also need to trim starting from the first +<metadata> to 81 // correctly extract potential rc candidate information for cpe generation 82 // ex: 2.0.0-rc.1+build.123 -> 2.0.0-rc.1; if no + is found then + is returned 83 after, _, found := strings.Cut("+", version) 84 if found { 85 version = after 86 } 87 88 // extracting <version> and <candidate> 89 // https://regex101.com/r/985GsI/1 90 captureGroups := internal.MatchNamedCaptureGroups(versionCandidateGroups, version) 91 vr, ok := captureGroups["version"] 92 if !ok || vr == "" { 93 return stdlibCpe, fmt.Errorf("could not match candidate version for: %s", version) 94 } 95 96 cpeString := fmt.Sprintf("cpe:2.3:a:golang:go:%s:-:*:*:*:*:*:*", captureGroups["version"]) 97 if candidate, ok := captureGroups["candidate"]; ok && candidate != "" { 98 cpeString = fmt.Sprintf("cpe:2.3:a:golang:go:%s:%s:*:*:*:*:*:*", vr, candidate) 99 } 100 101 return cpe.New(cpeString, cpe.GeneratedSource) 102 }