port dart cataloger to new generic cataloger pattern (#1285)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2022-10-24 16:37:42 -04:00 committed by GitHub
parent eb8ebd9ffc
commit fbdde6d4f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 107 additions and 96 deletions

View File

@ -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")
}

View File

@ -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()
}

View File

@ -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"
@ -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)
@ -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)
for _, name := range names {
pubPkg := p.Packages[name]
pkgs = append(pkgs, newPubspecLockPackage(name, pubPkg, reader.Location))
}
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(),
},
}
return pkgs, nil, nil
}
func (p *pubspecLockPackage) getVcsURL() string {

View File

@ -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/ale@3.3.0?hosted_url=pub.hosted.org",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
@ -27,9 +26,10 @@ func TestParsePubspecLock(t *testing.T) {
HostedURL: "pub.hosted.org",
},
},
"analyzer": {
{
Name: "analyzer",
Version: "0.40.7",
PURL: "pkg:pub/analyzer@0.40.7",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
@ -38,9 +38,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "0.40.7",
},
},
"ansicolor": {
{
Name: "ansicolor",
Version: "1.1.1",
PURL: "pkg:pub/ansicolor@1.1.1",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
@ -49,9 +50,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "1.1.1",
},
},
"archive": {
{
Name: "archive",
Version: "2.0.13",
PURL: "pkg:pub/archive@2.0.13",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
@ -60,9 +62,10 @@ func TestParsePubspecLock(t *testing.T) {
Version: "2.0.13",
},
},
"args": {
{
Name: "args",
Version: "1.6.0",
PURL: "pkg:pub/args@1.6.0",
Language: pkg.Dart,
Type: pkg.DartPubPkg,
MetadataType: pkg.DartPubMetadataType,
@ -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/key_binder@1.11.20?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: "git@github.com:Workiva/key_binder.git#3f7b3a6350e73c7dcac45301c0e18fbd42af02f7",
VcsURL: "git@github.com: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)
}
}

View File

@ -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()
}

View File

@ -35,21 +35,6 @@ func TestPackageURL(t *testing.T) {
},
expected: "pkg:golang/go.opencensus.io@v0.23.0",
},
{
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/name@0.2.0?hosted_url=pub.hosted.org",
},
{
name: "dotnet",
pkg: Package{
@ -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) {