Skip to content

Commit

Permalink
port dart cataloger to new generic cataloger pattern (anchore#1285)
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 24, 2022
1 parent 525b259 commit 4ef0a7d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 96 deletions.
13 changes: 6 additions & 7 deletions syft/pkg/cataloger/dart/cataloger.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package dart

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

// NewPubspecLockCataloger returns a new Dartlang cataloger object base on pubspec lock files.
func NewPubspecLockCataloger() *common.GenericCataloger {
globParsers := map[string]common.ParserFn{
"**/pubspec.lock": parsePubspecLock,
}
const catalogerName = "dartlang-lock-cataloger"

return common.NewGenericCataloger(nil, globParsers, "dartlang-lock-cataloger")
// NewPubspecLockCataloger returns a new Dartlang cataloger object base on pubspec lock files.
func NewPubspecLockCataloger() *generic.Cataloger {
return generic.NewCataloger(catalogerName).
WithParserByGlobs(parsePubspecLock, "**/pubspec.lock")
}
56 changes: 56 additions & 0 deletions syft/pkg/cataloger/dart/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dart

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

func newPubspecLockPackage(name string, raw pubspecLockPackage, locations ...source.Location) pkg.Package {
metadata := pkg.DartPubMetadata{
Name: name,
Version: raw.Version,
HostedURL: raw.getHostedURL(),
VcsURL: raw.getVcsURL(),
}

p := pkg.Package{
Name: name,
Version: raw.Version,
Locations: source.NewLocationSet(locations...),
PURL: packageURL(metadata),
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Metadata: metadata,
}

p.SetID()

return p
}

func packageURL(m pkg.DartPubMetadata) string {
var qualifiers packageurl.Qualifiers

if m.HostedURL != "" {
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "hosted_url",
Value: m.HostedURL,
})
} else if m.VcsURL != "" { // Default to using Hosted if somehow both are provided
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "vcs_url",
Value: m.VcsURL,
})
}

return packageurl.NewPackageURL(
packageurl.TypePub,
"",
m.Name,
m.Version,
qualifiers,
"",
).ToString()
}
39 changes: 16 additions & 23 deletions syft/pkg/cataloger/dart/parse_pubspec_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ package dart

import (
"fmt"
"io"
"net/url"
"sort"

"gopkg.in/yaml.v2"

"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/common"
"github.com/anchore/syft/syft/pkg/cataloger/generic"
"github.com/anchore/syft/syft/source"
)

// integrity check
var _ common.ParserFn = parsePubspecLock
var _ generic.Parser = parsePubspecLock

const defaultPubRegistry string = "https://pub.dartlang.org"

Expand All @@ -38,8 +38,8 @@ type pubspecLockDescription struct {
ResolvedRef string `yaml:"resolved-ref" mapstructure:"resolved-ref"`
}

func parsePubspecLock(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
var packages []*pkg.Package
func parsePubspecLock(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package

dec := yaml.NewDecoder(reader)

Expand All @@ -48,27 +48,20 @@ func parsePubspecLock(path string, reader io.Reader) ([]*pkg.Package, []artifact
return nil, nil, fmt.Errorf("failed to parse pubspec.lock file: %w", err)
}

for name, pubPkg := range p.Packages {
packages = append(packages, newPubspecLockPackage(name, pubPkg))
var names []string
for name := range p.Packages {
names = append(names, name)
}

return packages, nil, nil
}
// always ensure there is a stable ordering of packages
sort.Strings(names)

func newPubspecLockPackage(name string, p pubspecLockPackage) *pkg.Package {
return &pkg.Package{
Name: name,
Version: p.Version,
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Metadata: &pkg.DartPubMetadata{
Name: name,
Version: p.Version,
HostedURL: p.getHostedURL(),
VcsURL: p.getVcsURL(),
},
for _, name := range names {
pubPkg := p.Packages[name]
pkgs = append(pkgs, newPubspecLockPackage(name, pubPkg, reader.Location))
}

return pkgs, nil, nil
}

func (p *pubspecLockPackage) getVcsURL() string {
Expand Down
49 changes: 28 additions & 21 deletions syft/pkg/cataloger/dart/parse_pubspec_lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/go-test/deep"
"github.com/stretchr/testify/require"

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

func assertPackagesEqual(t *testing.T, actual []*pkg.Package, expected map[string]*pkg.Package) {
assert.Len(t, actual, len(expected))
}

func TestParsePubspecLock(t *testing.T) {
expected := map[string]*pkg.Package{
"ale": {
expected := []pkg.Package{
{
Name: "ale",
Version: "3.3.0",
PURL: "pkg:pub/[email protected]?hosted_url=pub.hosted.org",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Expand All @@ -27,9 +26,10 @@ func TestParsePubspecLock(t *testing.T) {
HostedURL: "pub.hosted.org",
},
},
"analyzer": {
{
Name: "analyzer",
Version: "0.40.7",
PURL: "pkg:pub/[email protected]",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Expand All @@ -38,9 +38,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "0.40.7",
},
},
"ansicolor": {
{
Name: "ansicolor",
Version: "1.1.1",
PURL: "pkg:pub/[email protected]",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Expand All @@ -49,9 +50,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "1.1.1",
},
},
"archive": {
{
Name: "archive",
Version: "2.0.13",
PURL: "pkg:pub/[email protected]",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Expand All @@ -60,9 +62,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "2.0.13",
},
},
"args": {
{
Name: "args",
Version: "1.6.0",
PURL: "pkg:pub/[email protected]",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Expand All @@ -71,29 +74,33 @@ func TestParsePubspecLock(t *testing.T) {
Version: "1.6.0",
},
},
"key_binder": {
{
Name: "key_binder",
Version: "1.11.20",
PURL: "pkg:pub/[email protected]?vcs_url=git%40github.com:Workiva/key_binder.git%403f7b3a6350e73c7dcac45301c0e18fbd42af02f7",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
Metadata: pkg.DartPubMetadata{
Name: "key_binder",
Version: "1.11.20",
VcsURL: "[email protected]:Workiva/key_binder.git#3f7b3a6350e73c7dcac45301c0e18fbd42af02f7",
VcsURL: "[email protected]:Workiva/key_binder.git@3f7b3a6350e73c7dcac45301c0e18fbd42af02f7",
},
},
}

fixture, err := os.Open("test-fixtures/pubspec.lock")
if err != nil {
t.Fatalf("failed to open fixture: %+v", err)
}
require.NoError(t, err)

actual, _, err := parsePubspecLock(fixture.Name(), fixture)
if err != nil {
t.Fatalf("failed to parse pubspec.lock: %+v", err)
}
// TODO: no relationships are under test yet
actual, _, err := parsePubspecLock(nil, nil, source.LocationReadCloser{
Location: source.NewLocation(fixture.Name()),
ReadCloser: fixture,
})
require.NoError(t, err)

assertPackagesEqual(t, actual, expected)
differences := deep.Equal(expected, actual)
if differences != nil {
t.Errorf("returned package list differed from expectation: %+v", differences)
}
}
30 changes: 0 additions & 30 deletions syft/pkg/dart_pub_metadata.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
package pkg

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

type DartPubMetadata struct {
Name string `mapstructure:"name" json:"name"`
Version string `mapstructure:"version" json:"version"`
HostedURL string `mapstructure:"hosted_url" json:"hosted_url,omitempty"`
VcsURL string `mapstructure:"vcs_url" json:"vcs_url,omitempty"`
}

func (m DartPubMetadata) PackageURL(_ *linux.Release) string {
var qualifiers packageurl.Qualifiers

if m.HostedURL != "" {
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "hosted_url",
Value: m.HostedURL,
})
} else if m.VcsURL != "" { // Default to using Hosted if somehow both are provided
qualifiers = append(qualifiers, packageurl.Qualifier{
Key: "vcs_url",
Value: m.VcsURL,
})
}

return packageurl.NewPackageURL(
packageurl.TypePub,
"",
m.Name,
m.Version,
qualifiers,
"",
).ToString()
}
16 changes: 1 addition & 15 deletions syft/pkg/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,6 @@ func TestPackageURL(t *testing.T) {
},
expected: "pkg:golang/[email protected]",
},
{
name: "pub",
pkg: Package{
Name: "bad-name",
Version: "0.1.0",
Type: DartPubPkg,
Metadata: DartPubMetadata{
Name: "name",
Version: "0.2.0",
HostedURL: "pub.hosted.org",
},
},
expected: "pkg:pub/[email protected]?hosted_url=pub.hosted.org",
},

{
name: "dotnet",
pkg: Package{
Expand Down Expand Up @@ -225,6 +210,7 @@ func TestPackageURL(t *testing.T) {
expectedTypes.Remove(string(AlpmPkg))
expectedTypes.Remove(string(ApkPkg))
expectedTypes.Remove(string(ConanPkg))
expectedTypes.Remove(string(DartPubPkg))

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down

0 comments on commit 4ef0a7d

Please sign in to comment.