Skip to content

Commit

Permalink
Add Basic Nix Cataloger
Browse files Browse the repository at this point in the history
  • Loading branch information
juliosueiras committed Jul 19, 2022
1 parent 571de36 commit 7bd7f31
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 0 deletions.
1 change: 1 addition & 0 deletions schema/json/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type artifactMetadataContainer struct {
Dart pkg.DartPubMetadata
Dotnet pkg.DotnetDepsMetadata
Portage pkg.PortageMetadata
Nix pkg.NixStoreMetadata
}

func main() {
Expand Down
9 changes: 9 additions & 0 deletions syft/file/classifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ var DefaultClassifiers = []Classifier{
`(?m)(?P<version>{{ .version }}\.[0-9]+[-_a-zA-Z0-9]*)`,
},
},
{
Class: "nix-store",
FilepathPatterns: []*regexp.Regexp{
regexp.MustCompile(`/nix/store/[^-]*-([^-]*)-(?P<version>.*)/$`),
},
EvidencePatternTemplates: []string{
`(?m)(?P<version>{{ .version }}\.[0-9]+[-_a-zA-Z0-9]*)`,
},
},
{
Class: "cpython-source",
FilepathPatterns: []*regexp.Regexp{
Expand Down
2 changes: 2 additions & 0 deletions syft/pkg/cataloger/cataloger.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/rpmdb"
"github.com/anchore/syft/syft/pkg/cataloger/ruby"
"github.com/anchore/syft/syft/pkg/cataloger/rust"
"github.com/anchore/syft/syft/pkg/cataloger/nixstore"
"github.com/anchore/syft/syft/pkg/cataloger/swift"
"github.com/anchore/syft/syft/source"
)
Expand Down Expand Up @@ -58,6 +59,7 @@ func ImageCatalogers(cfg Config) []Cataloger {
golang.NewGoModuleBinaryCataloger(),
dotnet.NewDotnetDepsCataloger(),
portage.NewPortageCataloger(),
nixstore.NewNixStoreCataloger(),
}, cfg.Catalogers)
}

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

import (
"fmt"

"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)

type Cataloger struct{}

func NewNixStoreCataloger() *Cataloger {
return &Cataloger{}
}

func (c *Cataloger) Name() string {
return "nix-store-cataloger"
}

func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
nixStoreFileMatches, err := resolver.FilesByGlob(pkg.NixStoreGlob)
if err != nil {
return nil, nil, fmt.Errorf("failed to find any nix store directory: %w", err)
}

var allPackages []pkg.Package
pkgMap := make(map[string]interface{})
for _, storeLocation := range nixStoreFileMatches {
name, version := extractNameAndVersion(storeLocation.VirtualPath)

if version != "" {
nixLookupPkg := pkgMap[fmt.Sprintf("%s-%s", name, version)]
if nixLookupPkg == nil {
nixPkg := pkg.NixStoreMetadata{
Source: name,
SourceVersion: version,
}

p := newNixStorePackage(nixPkg)
p.Name = name
p.Version = version
p.FoundBy = c.Name()
p.Locations = []source.Location{storeLocation}
p.SetID()

log.Debug(p)

pkgMap[fmt.Sprintf("%s-%s", name, version)] = p

} else {
nixLookupPkg := nixLookupPkg.(pkg.Package)
nixLookupPkg.Locations = append(nixLookupPkg.Locations, storeLocation)
pkgMap[fmt.Sprintf("%s-%s", name, version)] = nixLookupPkg
}
}
}

for _, p := range pkgMap {
allPackages = append(allPackages, p.(pkg.Package))
}
return allPackages, nil, nil
}
31 changes: 31 additions & 0 deletions syft/pkg/cataloger/nixstore/parse_nix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package nixstore

import (
"fmt"
"regexp"

"github.com/anchore/syft/internal"

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

var (
errEndOfPackages = fmt.Errorf("no more packages to read")
sourceRegexp = regexp.MustCompile(`/nix/store/[^-]*-(?P<name>[^-]*)-(?P<version>[^-/]*).*/`)
)

func newNixStorePackage(d pkg.NixStoreMetadata) pkg.Package {
return pkg.Package{
Name: d.Package,
Version: d.Version,
Type: pkg.NixStorePkg,
MetadataType: pkg.NixStoreMetadataType,
Metadata: d,
}
}

func extractNameAndVersion(source string) (string, string) {
// special handling for the Source field since it has formatted data
match := internal.MatchNamedCaptureGroups(sourceRegexp, source)
return match["name"], match["version"]
}
2 changes: 2 additions & 0 deletions syft/pkg/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
ApkMetadataType MetadataType = "ApkMetadata"
AlpmMetadataType MetadataType = "AlpmMetadata"
DpkgMetadataType MetadataType = "DpkgMetadata"
NixStoreMetadataType MetadataType = "NixStoreMetadata"
GemMetadataType MetadataType = "GemMetadata"
JavaMetadataType MetadataType = "JavaMetadata"
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
Expand All @@ -35,6 +36,7 @@ var AllMetadataTypes = []MetadataType{
ApkMetadataType,
AlpmMetadataType,
DpkgMetadataType,
NixStoreMetadataType,
GemMetadataType,
JavaMetadataType,
NpmPackageJSONMetadataType,
Expand Down
37 changes: 37 additions & 0 deletions syft/pkg/nix_store_metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package pkg

import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/distro"
)

const NixStoreGlob = "/nix/store/**"

type NixStoreMetadata struct {
Package string `mapstructure:"Package" json:"package"`
Architecture string `mapstructure:"A" json:"architecture"`
Source string `mapstructure:"Source" json:"source"`
Version string `mapstructure:"Version" json:"version"`
SourceVersion string `mapstructure:"SourceVersion" json:"sourceVersion"`
}

func (m NixStoreMetadata) PackageURL(d *distro.Distro) string {
if d == nil {
return ""
}
pURL := packageurl.NewPackageURL(
// TODO: replace with `packageurl.TypeDebian` upon merge of https://github.com/package-url/packageurl-go/pull/21
// TODO: or, since we're now using an Anchore fork of this module, we could do this sooner.
"nix",
d.Type.String(),
m.Package,
m.Version,
packageurl.Qualifiers{
{
Key: "arch",
Value: m.Architecture,
},
},
"")
return pURL.ToString()
}
4 changes: 4 additions & 0 deletions syft/pkg/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
JavaPkg Type = "java-archive"
JenkinsPluginPkg Type = "jenkins-plugin"
GoModulePkg Type = "go-module"
NixStorePkg Type = "nix-store"
RustPkg Type = "rust-crate"
KbPkg Type = "msrc-kb"
DartPubPkg Type = "dart-pub"
Expand All @@ -39,6 +40,7 @@ var AllPkgs = []Type{
NpmPkg,
PythonPkg,
PhpComposerPkg,
NixStorePkg,
JavaPkg,
JenkinsPluginPkg,
GoModulePkg,
Expand All @@ -63,6 +65,8 @@ func (t Type) PackageURLType() string {
return packageurl.TypeGem
case DebPkg:
return "deb"
case NixStorePkg:
return "nix"
case PythonPkg:
return packageurl.TypePyPi
case PhpComposerPkg:
Expand Down

0 comments on commit 7bd7f31

Please sign in to comment.