Skip to content

Commit

Permalink
port golang cataloger to new generic cataloger pattern (#1289)
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <[email protected]>

Signed-off-by: Alex Goodman <[email protected]>
  • Loading branch information
wagoodman authored Oct 25, 2022
1 parent 52cb726 commit 6826d76
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 239 deletions.
61 changes: 0 additions & 61 deletions syft/pkg/cataloger/golang/binary_cataloger.go

This file was deleted.

21 changes: 21 additions & 0 deletions syft/pkg/cataloger/golang/cataloger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Package golang provides a concrete Cataloger implementation for go.mod files.
*/
package golang

import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)

// NewGoModFileCataloger returns a new Go module cataloger object.
func NewGoModFileCataloger() *generic.Cataloger {
return generic.NewCataloger("go-mod-file-cataloger").
WithParserByGlobs(parseGoModFile, "**/go.mod")
}

// NewGoModuleBinaryCataloger returns a new Golang cataloger object.
func NewGoModuleBinaryCataloger() *generic.Cataloger {
return generic.NewCataloger("go-module-binary-cataloger").
WithParserByMimeTypes(parseGoBinary, internal.ExecutableMIMETypeSet.List()...)
}
17 changes: 0 additions & 17 deletions syft/pkg/cataloger/golang/mod_cataloger.go

This file was deleted.

69 changes: 69 additions & 0 deletions syft/pkg/cataloger/golang/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package golang

import (
"regexp"
"runtime/debug"
"strings"

"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)

func newGoBinaryPackage(dep *debug.Module, mainModule, goVersion, architecture string, buildSettings map[string]string, locations ...source.Location) pkg.Package {
if dep.Replace != nil {
dep = dep.Replace
}

p := pkg.Package{
Name: dep.Path,
Version: dep.Version,
PURL: packageURL(dep.Path, dep.Version),
Language: pkg.Go,
Type: pkg.GoModulePkg,
Locations: source.NewLocationSet(locations...),
MetadataType: pkg.GolangBinMetadataType,
Metadata: pkg.GolangBinMetadata{
GoCompiledVersion: goVersion,
H1Digest: dep.Sum,
Architecture: architecture,
BuildSettings: buildSettings,
MainModule: mainModule,
},
}

p.SetID()

return p
}

func packageURL(moduleName, moduleVersion string) string {
// source: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#golang
// note: "The version is often empty when a commit is not specified and should be the commit in most cases when available."

re := regexp.MustCompile(`(/)[^/]*$`)
fields := re.Split(moduleName, -1)
if len(fields) == 0 {
return ""
}
namespace := fields[0]
name := strings.TrimPrefix(strings.TrimPrefix(moduleName, namespace), "/")

if name == "" {
// this is a "short" url (with no namespace)
name = namespace
namespace = ""
}

// The subpath is used to point to a subpath inside a package (e.g. pkg:golang/google.golang.org/genproto#googleapis/api/annotations)
subpath := "" // TODO: not implemented

return packageurl.NewPackageURL(
packageurl.TypeGolang,
namespace,
name,
moduleVersion,
nil,
subpath,
).ToString()
}
41 changes: 41 additions & 0 deletions syft/pkg/cataloger/golang/package_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package golang

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/anchore/syft/syft/pkg"
)

func Test_packageURL(t *testing.T) {

tests := []struct {
name string
pkg pkg.Package
expected string
}{
{
name: "gocase",
pkg: pkg.Package{
Name: "github.com/anchore/syft",
Version: "v0.1.0",
},
expected: "pkg:golang/github.com/anchore/[email protected]",
},
{
name: "golang short name",
pkg: pkg.Package{
Name: "go.opencensus.io",
Version: "v0.23.0",
},
expected: "pkg:golang/[email protected]",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.expected, packageURL(test.pkg.Name, test.pkg.Version))
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import (

"golang.org/x/mod/module"

"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/pkg/cataloger/golang/internal/xcoff"
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
"github.com/anchore/syft/syft/source"
)

Expand All @@ -34,9 +38,27 @@ var (

const devel = "(devel)"

// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
func parseGoBinary(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package

unionReader, err := unionreader.GetUnionReader(reader.ReadCloser)
if err != nil {
return nil, nil, err
}

mods, archs := scanFile(unionReader, reader.RealPath)
internal.CloseAndLogError(reader.ReadCloser, reader.RealPath)

for i, mod := range mods {
pkgs = append(pkgs, buildGoPkgInfo(reader.Location, mod, archs[i])...)
}
return pkgs, nil, nil
}

func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Location) pkg.Package {
gbs := getBuildSettings(mod.Settings)
main := newGoBinaryPackage(&mod.Main, mod.Main.Path, mod.GoVersion, arch, location, gbs)
main := newGoBinaryPackage(&mod.Main, mod.Main.Path, mod.GoVersion, arch, gbs, location)
if main.Version == devel {
if version, ok := gbs["vcs.revision"]; ok {
if timestamp, ok := gbs["vcs.time"]; ok {
Expand All @@ -50,39 +72,14 @@ func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Locati
version = module.PseudoVersion("", "", ts, version)
}
main.Version = version
main.PURL = packageURL(main.Name, main.Version)
main.SetID()
}
}

return main
}

func newGoBinaryPackage(dep *debug.Module, mainModule, goVersion, architecture string, location source.Location, buildSettings map[string]string) pkg.Package {
if dep.Replace != nil {
dep = dep.Replace
}

p := pkg.Package{
FoundBy: catalogerName,
Name: dep.Path,
Version: dep.Version,
Language: pkg.Go,
Type: pkg.GoModulePkg,
Locations: source.NewLocationSet(location),
MetadataType: pkg.GolangBinMetadataType,
Metadata: pkg.GolangBinMetadata{
GoCompiledVersion: goVersion,
H1Digest: dep.Sum,
Architecture: architecture,
BuildSettings: buildSettings,
MainModule: mainModule,
},
}

p.SetID()

return p
}

// getArchs finds a binary architecture by two ways:
// 1) reading build info from binaries compiled by go1.18+
// 2) reading file headers from binaries compiled by < go1.18
Expand Down Expand Up @@ -192,7 +189,7 @@ func buildGoPkgInfo(location source.Location, mod *debug.BuildInfo, arch string)
if dep == nil {
continue
}
p := newGoBinaryPackage(dep, mod.Main.Path, mod.GoVersion, arch, location, nil)
p := newGoBinaryPackage(dep, mod.Main.Path, mod.GoVersion, arch, nil, location)
if pkg.IsValid(&p) {
pkgs = append(pkgs, p)
}
Expand Down
Loading

0 comments on commit 6826d76

Please sign in to comment.