mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
wip: wip
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
This commit is contained in:
parent
7934696463
commit
029b948d73
6 changed files with 169 additions and 1 deletions
2
go.mod
2
go.mod
|
@ -232,7 +232,7 @@ require (
|
|||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/term v0.24.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/tools v0.25.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1153,6 +1153,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -84,6 +84,12 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
|
|||
},
|
||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Go, Golang, "gomod",
|
||||
),
|
||||
newPackageTaskFactory(
|
||||
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
|
||||
return golang.NewGoLibraryCataloger(cfg.PackagesConfig.Golang)
|
||||
},
|
||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Go, Golang, "gomod",
|
||||
),
|
||||
newSimplePackageTaskFactory(java.NewGradleLockfileCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, Java, "gradle"),
|
||||
newPackageTaskFactory(
|
||||
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
|
||||
|
|
|
@ -16,6 +16,7 @@ var versionCandidateGroups = regexp.MustCompile(`(?P<version>\d+(\.\d+)?(\.\d+)?
|
|||
const (
|
||||
modFileCatalogerName = "go-module-file-cataloger"
|
||||
binaryCatalogerName = "go-module-binary-cataloger"
|
||||
libraryCatalogerName = "go-module-library-cataloger"
|
||||
)
|
||||
|
||||
// NewGoModuleFileCataloger returns a new cataloger object that searches within go.mod files.
|
||||
|
@ -33,3 +34,8 @@ func NewGoModuleBinaryCataloger(opts CatalogerConfig) pkg.Cataloger {
|
|||
).
|
||||
WithProcessors(stdlibProcessor)
|
||||
}
|
||||
|
||||
func NewGoLibraryCataloger(opts CatalogerConfig) pkg.Cataloger {
|
||||
return generic.NewCataloger(libraryCatalogerName).
|
||||
WithParserByGlobs(newGoLibraryCataloger().parseGoModFile, "**/go.mod")
|
||||
}
|
||||
|
|
153
syft/pkg/cataloger/golang/parse_go_libraries.go
Normal file
153
syft/pkg/cataloger/golang/parse_go_libraries.go
Normal file
|
@ -0,0 +1,153 @@
|
|||
package golang
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
"golang.org/x/mod/modfile"
|
||||
"io"
|
||||
)
|
||||
|
||||
type goLibraryCataloger struct{}
|
||||
|
||||
func newGoLibraryCataloger() *goLibraryCataloger {
|
||||
return &goLibraryCataloger{}
|
||||
}
|
||||
|
||||
func (c *goLibraryCataloger) parseGoModFile(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
contents, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read go module: %w", err)
|
||||
}
|
||||
|
||||
modPath := modfile.ModulePath(contents)
|
||||
pkgInfo, err := libraries(ctx, modPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to determine package info: %w", err)
|
||||
}
|
||||
pkgInfoNoOp(pkgInfo)
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func pkgInfoNoOp(info []pkgInfo) []*pkg.Package {
|
||||
return []*pkg.Package{}
|
||||
}
|
||||
|
||||
// These are the steps we take to find libraries:
|
||||
// 1. we list all modules and all packages
|
||||
// 2. for each package, we find a list of candidates
|
||||
// 3. we deduplicate all candidates
|
||||
// 4. for each candidate, we classify if the candidate is a license file
|
||||
// 5. for each package, we select the first candidates that is a license
|
||||
// file & add the package to a list of packages for that license file
|
||||
// 6. we return an array of libraries (which are the license files, the
|
||||
// found licenses in that file, all the packages that had that file as
|
||||
// its first candidate and the module in which those packages live)
|
||||
func libraries(ctx context.Context, modPath string) ([]pkgInfo, error) {
|
||||
cfg := &packages.Config{
|
||||
Context: ctx,
|
||||
Mode: packages.NeedImports | packages.NeedDeps | packages.NeedFiles | packages.NeedName | packages.NeedModule,
|
||||
Tests: true, // TODO: should we inject this to be configurable
|
||||
}
|
||||
|
||||
rootPkgs, err := packages.Load(cfg, modPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vendoredSearch := []*Module{}
|
||||
for _, parentPkg := range rootPkgs {
|
||||
if parentPkg.Module == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
module := newModule(parentPkg.Module)
|
||||
if module.Dir == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
vendoredSearch = append(vendoredSearch, module)
|
||||
}
|
||||
|
||||
allPackages := []pkgInfo{}
|
||||
{
|
||||
pkgErrorOccurred := false
|
||||
packages.Visit(rootPkgs, func(p *packages.Package) bool {
|
||||
if len(p.Errors) > 0 {
|
||||
pkgErrorOccurred = true
|
||||
return false
|
||||
}
|
||||
if len(p.OtherFiles) > 0 {
|
||||
// log.Warningf("%q contains non-Go code that can't be inspected for further dependencies:\n%s", p.PkgPath, strings.Join(p.OtherFiles, "\n"))
|
||||
}
|
||||
|
||||
var pkgDir string
|
||||
switch {
|
||||
case len(p.GoFiles) > 0:
|
||||
pkgDir = filepath.Dir(p.GoFiles[0])
|
||||
case len(p.CompiledGoFiles) > 0:
|
||||
pkgDir = filepath.Dir(p.CompiledGoFiles[0])
|
||||
case len(p.OtherFiles) > 0:
|
||||
pkgDir = filepath.Dir(p.OtherFiles[0])
|
||||
default:
|
||||
// This package is empty - nothing to do.
|
||||
return true
|
||||
}
|
||||
|
||||
module := newModule(p.Module)
|
||||
allPackages = append(allPackages, pkgInfo{
|
||||
pkgPath: p.PkgPath,
|
||||
modulePath: module.Path,
|
||||
pkgDir: pkgDir,
|
||||
moduleDir: module.Dir,
|
||||
})
|
||||
return true
|
||||
}, nil)
|
||||
if pkgErrorOccurred {
|
||||
return nil, fmt.Errorf("failed to parse go modules")
|
||||
}
|
||||
}
|
||||
return allPackages, nil
|
||||
}
|
||||
|
||||
func newModule(mod *packages.Module) *Module {
|
||||
tmp := *mod
|
||||
if tmp.Replace != nil {
|
||||
tmp = *tmp.Replace
|
||||
}
|
||||
|
||||
// The +incompatible suffix does not affect module version.
|
||||
// ref: https://golang.org/ref/mod#incompatible-versions
|
||||
tmp.Version = strings.TrimSuffix(tmp.Version, "+incompatible")
|
||||
return &Module{
|
||||
Path: tmp.Path,
|
||||
Version: tmp.Version,
|
||||
Dir: tmp.Dir,
|
||||
}
|
||||
}
|
||||
|
||||
type Module struct {
|
||||
Path string
|
||||
Version string
|
||||
Dir string
|
||||
}
|
||||
|
||||
type pkgInfo struct {
|
||||
// pkgPath is the import path of the package.
|
||||
pkgPath string
|
||||
// modulePath is the module path of the package.
|
||||
modulePath string
|
||||
|
||||
// pkgDir is the directory containing the package's source code.
|
||||
pkgDir string
|
||||
// moduleDir is the directory containing the module's source code.
|
||||
moduleDir string
|
||||
}
|
1
syft/pkg/cataloger/golang/parse_go_libraries_test.go
Normal file
1
syft/pkg/cataloger/golang/parse_go_libraries_test.go
Normal file
|
@ -0,0 +1 @@
|
|||
package golang
|
Loading…
Reference in a new issue