mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
commit
1f272c2bda
13 changed files with 97 additions and 35 deletions
|
@ -68,5 +68,6 @@ func doRunCmd(cmd *cobra.Command, args []string) int {
|
|||
log.Errorf("could not format catalog results: %w", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
|
3
go.mod
3
go.mod
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f
|
||||
github.com/go-test/deep v1.0.6
|
||||
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.1
|
||||
|
@ -16,6 +17,6 @@ require (
|
|||
github.com/spf13/viper v1.7.0
|
||||
go.uber.org/zap v1.15.0
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 // indirect
|
||||
google.golang.org/protobuf v1.24.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
|
9
go.sum
9
go.sum
|
@ -210,6 +210,8 @@ github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
|
|||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
|
@ -628,8 +630,8 @@ google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84 h1:pSLkPbrjnPyLDYU
|
|||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200519141106-08726f379972 h1:6ydLqG65DIMNJf6p97WudGsmd1w3Ickm/LiZnBrREPI=
|
||||
google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 h1:JUs1uIDQ46c7iI0QuMPzAHqXaSmqKF0f9freFMk2ivs=
|
||||
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -650,6 +652,9 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
|||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
@ -18,7 +18,7 @@ func init() {
|
|||
controllerInstance.add(dpkg.NewAnalyzer())
|
||||
}
|
||||
|
||||
func Analyze(s scope.Scope) (pkg.Catalog, error) {
|
||||
func Analyze(s scope.Scope) (*pkg.Catalog, error) {
|
||||
return controllerInstance.analyze(s)
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ func (c *controller) add(a Analyzer) {
|
|||
c.analyzers = append(c.analyzers, a)
|
||||
}
|
||||
|
||||
func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
||||
func (c *controller) analyze(s scope.Scope) (*pkg.Catalog, error) {
|
||||
catalog := pkg.NewCatalog()
|
||||
fileSelection := make([]file.Reference, 0)
|
||||
|
||||
|
@ -44,7 +44,7 @@ func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
|||
// fetch contents for requested selection by analyzers
|
||||
contents, err := s.Image.MultipleFileContentsByRef(fileSelection...)
|
||||
if err != nil {
|
||||
return pkg.Catalog{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
|
@ -65,7 +65,7 @@ func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
|
|||
}
|
||||
|
||||
if errs != nil {
|
||||
return pkg.Catalog{}, errs
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
return catalog, nil
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
var endOfPackages = fmt.Errorf("no more packages to read")
|
||||
var errEndOfPackages = fmt.Errorf("no more packages to read")
|
||||
|
||||
func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
|
||||
buffedReader := bufio.NewReader(reader)
|
||||
|
@ -19,7 +19,7 @@ func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
|
|||
for {
|
||||
entry, err := parseEntry(buffedReader)
|
||||
if err != nil {
|
||||
if err == endOfPackages {
|
||||
if err == errEndOfPackages {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
|
@ -38,7 +38,7 @@ func parseEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err error) {
|
|||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return pkg.DpkgMetadata{}, endOfPackages
|
||||
return pkg.DpkgMetadata{}, errEndOfPackages
|
||||
}
|
||||
return pkg.DpkgMetadata{}, err
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ import (
|
|||
)
|
||||
|
||||
// TODO: add os detection results as return value
|
||||
func CatalogImage(img *image.Image, o scope.Option) (pkg.Catalog, error) {
|
||||
func CatalogImage(img *image.Image, o scope.Option) (*pkg.Catalog, error) {
|
||||
s, err := scope.NewScope(img, o)
|
||||
if err != nil {
|
||||
return pkg.Catalog{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: add OS detection here...
|
||||
|
|
|
@ -1,31 +1,75 @@
|
|||
package pkg
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anchore/imgbom/internal/log"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
// TODO: add reader methods (by type, id, fuzzy search, etc)
|
||||
|
||||
var nextPackageID int64
|
||||
|
||||
type Catalog struct {
|
||||
// TODO: catalog by package ID for potential indexing
|
||||
packages map[Type][]Package
|
||||
byID map[ID]*Package
|
||||
byType map[Type][]*Package
|
||||
byFile map[file.Reference][]*Package
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewCatalog() Catalog {
|
||||
return Catalog{
|
||||
packages: make(map[Type][]Package),
|
||||
func NewCatalog() *Catalog {
|
||||
return &Catalog{
|
||||
byID: make(map[ID]*Package),
|
||||
byType: make(map[Type][]*Package),
|
||||
byFile: make(map[file.Reference][]*Package),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Catalog) Package(id ID) *Package {
|
||||
return c.byID[id]
|
||||
}
|
||||
|
||||
func (c *Catalog) PackagesByFile(ref file.Reference) []*Package {
|
||||
return c.byFile[ref]
|
||||
}
|
||||
|
||||
func (c *Catalog) Add(p Package) {
|
||||
_, ok := c.packages[p.Type]
|
||||
if !ok {
|
||||
c.packages[p.Type] = make([]Package, 0)
|
||||
if p.id != 0 {
|
||||
log.Errorf("package already added to catalog: %s", p)
|
||||
return
|
||||
}
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
p.id = ID(nextPackageID)
|
||||
nextPackageID++
|
||||
|
||||
// store by package ID
|
||||
c.byID[p.id] = &p
|
||||
|
||||
// store by package type
|
||||
_, ok := c.byType[p.Type]
|
||||
if !ok {
|
||||
c.byType[p.Type] = make([]*Package, 0)
|
||||
}
|
||||
c.byType[p.Type] = append(c.byType[p.Type], &p)
|
||||
|
||||
// store by file references
|
||||
for _, s := range p.Source {
|
||||
_, ok := c.byFile[s]
|
||||
if !ok {
|
||||
c.byFile[s] = make([]*Package, 0)
|
||||
}
|
||||
c.byFile[s] = append(c.byFile[s], &p)
|
||||
}
|
||||
c.packages[p.Type] = append(c.packages[p.Type], p)
|
||||
}
|
||||
|
||||
func (c *Catalog) Enumerate(types ...Type) <-chan Package {
|
||||
channel := make(chan Package)
|
||||
func (c *Catalog) Enumerate(types ...Type) <-chan *Package {
|
||||
channel := make(chan *Package)
|
||||
go func() {
|
||||
defer close(channel)
|
||||
for ty, packages := range c.packages {
|
||||
for ty, packages := range c.byType {
|
||||
if len(types) != 0 {
|
||||
found := false
|
||||
typeCheck:
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package pkg
|
||||
|
||||
import "github.com/anchore/stereoscope/pkg/file"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// TODO: add package ID (random/incremental)
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
)
|
||||
|
||||
type ID int64
|
||||
|
||||
// TODO: add field to trace which analyzer detected this
|
||||
type Package struct {
|
||||
id ID
|
||||
Name string
|
||||
Version string
|
||||
Source []file.Reference
|
||||
|
@ -14,4 +19,10 @@ type Package struct {
|
|||
Metadata interface{}
|
||||
}
|
||||
|
||||
// TODO: stringer...
|
||||
func (p Package) ID() ID {
|
||||
return p.id
|
||||
}
|
||||
|
||||
func (p Package) String() string {
|
||||
return fmt.Sprintf("Pkg(type=%s, name=%s, version=%s)", p.Type, p.Name, p.Version)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ const (
|
|||
ApkPkg
|
||||
DebPkg
|
||||
JavaPkg
|
||||
NodePkg
|
||||
JavaScriptPkg
|
||||
PacmanPkg
|
||||
PythonPkg
|
||||
RpmPkg
|
||||
|
@ -19,7 +19,7 @@ var typeStr = []string{
|
|||
"apk",
|
||||
"deb",
|
||||
"java",
|
||||
"node",
|
||||
"javascript",
|
||||
"pacman",
|
||||
"python",
|
||||
"rpm",
|
||||
|
|
|
@ -49,7 +49,7 @@ type artifact struct {
|
|||
Metadata interface{} `json:"metadata"`
|
||||
}
|
||||
|
||||
func (pres *Presenter) Present(output io.Writer, img *stereoscopeImg.Image, catalog pkg.Catalog) error {
|
||||
func (pres *Presenter) Present(output io.Writer, img *stereoscopeImg.Image, catalog *pkg.Catalog) error {
|
||||
tags := make([]string, len(img.Metadata.Tags))
|
||||
for idx, tag := range img.Metadata.Tags {
|
||||
tags[idx] = tag.String()
|
||||
|
|
|
@ -16,7 +16,7 @@ var Options = []Option{
|
|||
JSONPresenter,
|
||||
}
|
||||
|
||||
type Option uint
|
||||
type Option int
|
||||
|
||||
func ParseOption(userStr string) Option {
|
||||
switch strings.ToLower(userStr) {
|
||||
|
@ -28,7 +28,7 @@ func ParseOption(userStr string) Option {
|
|||
}
|
||||
|
||||
func (o Option) String() string {
|
||||
if int(o) >= len(optionStr) {
|
||||
if int(o) >= len(optionStr) || o < 0 {
|
||||
return optionStr[0]
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
type Presenter interface {
|
||||
Present(io.Writer, *image.Image, pkg.Catalog) error
|
||||
Present(io.Writer, *image.Image, *pkg.Catalog) error
|
||||
}
|
||||
|
||||
func GetPresenter(option Option) Presenter {
|
||||
|
|
|
@ -8,7 +8,7 @@ const (
|
|||
AllLayersScope
|
||||
)
|
||||
|
||||
type Option uint
|
||||
type Option int
|
||||
|
||||
var optionStr = []string{
|
||||
"UnknownScope",
|
||||
|
@ -32,7 +32,7 @@ func ParseOption(userStr string) Option {
|
|||
}
|
||||
|
||||
func (o Option) String() string {
|
||||
if int(o) >= len(optionStr) {
|
||||
if int(o) >= len(optionStr) || o < 0 {
|
||||
return optionStr[0]
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue