mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
port ruby cataloger to new generic cataloger pattern (#1322)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
3048382bbd
commit
41464bbd7f
@ -4,23 +4,17 @@ Package ruby bundler provides a concrete Cataloger implementation for Ruby Gemfi
|
|||||||
package ruby
|
package ruby
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/common"
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewGemFileLockCataloger returns a new Bundler cataloger object tailored for parsing index-oriented files (e.g. Gemfile.lock).
|
// NewGemFileLockCataloger returns a new Bundler cataloger object tailored for parsing index-oriented files (e.g. Gemfile.lock).
|
||||||
func NewGemFileLockCataloger() *common.GenericCataloger {
|
func NewGemFileLockCataloger() *generic.Cataloger {
|
||||||
globParsers := map[string]common.ParserFn{
|
return generic.NewCataloger("ruby-gemfile-cataloger").
|
||||||
"**/Gemfile.lock": parseGemFileLockEntries,
|
WithParserByGlobs(parseGemFileLockEntries, "**/Gemfile.lock")
|
||||||
}
|
|
||||||
|
|
||||||
return common.NewGenericCataloger(nil, globParsers, "ruby-gemfile-cataloger")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGemSpecCataloger returns a new Bundler cataloger object tailored for detecting installations of gems (e.g. Gemspec).
|
// NewGemSpecCataloger returns a new Bundler cataloger object tailored for detecting installations of gems (e.g. Gemspec).
|
||||||
func NewGemSpecCataloger() *common.GenericCataloger {
|
func NewGemSpecCataloger() *generic.Cataloger {
|
||||||
globParsers := map[string]common.ParserFn{
|
return generic.NewCataloger("ruby-gemspec-cataloger").
|
||||||
"**/specifications/**/*.gemspec": parseGemSpecEntries,
|
WithParserByGlobs(parseGemSpecEntries, "**/specifications/**/*.gemspec")
|
||||||
}
|
|
||||||
|
|
||||||
return common.NewGenericCataloger(nil, globParsers, "ruby-gemspec-cataloger")
|
|
||||||
}
|
}
|
||||||
|
|||||||
53
syft/pkg/cataloger/ruby/package.go
Normal file
53
syft/pkg/cataloger/ruby/package.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package ruby
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newGemfileLockPackage(name, version string, locations ...source.Location) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: name,
|
||||||
|
Version: version,
|
||||||
|
PURL: packageURL(name, version),
|
||||||
|
Locations: source.NewLocationSet(locations...),
|
||||||
|
Language: pkg.Ruby,
|
||||||
|
Type: pkg.GemPkg,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGemspecPackage(m pkg.GemMetadata, locations ...source.Location) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: m.Name,
|
||||||
|
Version: m.Version,
|
||||||
|
Locations: source.NewLocationSet(locations...),
|
||||||
|
PURL: packageURL(m.Name, m.Version),
|
||||||
|
Licenses: m.Licenses,
|
||||||
|
Language: pkg.Ruby,
|
||||||
|
Type: pkg.GemPkg,
|
||||||
|
MetadataType: pkg.GemMetadataType,
|
||||||
|
Metadata: m,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func packageURL(name, version string) string {
|
||||||
|
var qualifiers packageurl.Qualifiers
|
||||||
|
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeGem,
|
||||||
|
"",
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
qualifiers,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
31
syft/pkg/cataloger/ruby/package_test.go
Normal file
31
syft/pkg/cataloger/ruby/package_test.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package ruby
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_packageURL(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "p",
|
||||||
|
version: "v",
|
||||||
|
expected: "pkg:gem/p@v",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%s@%s", test.name, test.version), func(t *testing.T) {
|
||||||
|
actual := packageURL(test.name, test.version)
|
||||||
|
if diff := cmp.Diff(test.expected, actual); diff != "" {
|
||||||
|
t.Errorf("unexpected packageURL (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,23 +2,22 @@ package ruby
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"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 _ generic.Parser = parseGemFileLockEntries
|
||||||
var _ common.ParserFn = parseGemFileLockEntries
|
|
||||||
|
|
||||||
var sectionsOfInterest = internal.NewStringSet("GEM")
|
var sectionsOfInterest = internal.NewStringSet("GEM")
|
||||||
|
|
||||||
// parseGemFileLockEntries is a parser function for Gemfile.lock contents, returning all Gems discovered.
|
// parseGemFileLockEntries is a parser function for Gemfile.lock contents, returning all Gems discovered.
|
||||||
func parseGemFileLockEntries(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
func parseGemFileLockEntries(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
pkgs := make([]*pkg.Package, 0)
|
var pkgs []pkg.Package
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
var currentSection string
|
var currentSection string
|
||||||
@ -41,12 +40,13 @@ func parseGemFileLockEntries(_ string, reader io.Reader) ([]*pkg.Package, []arti
|
|||||||
if len(candidate) != 2 {
|
if len(candidate) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pkgs = append(pkgs, &pkg.Package{
|
pkgs = append(pkgs,
|
||||||
Name: candidate[0],
|
newGemfileLockPackage(
|
||||||
Version: strings.Trim(candidate[1], "()"),
|
candidate[0],
|
||||||
Language: pkg.Ruby,
|
strings.Trim(candidate[1], "()"),
|
||||||
Type: pkg.GemPkg,
|
reader.Location,
|
||||||
})
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
|
|||||||
@ -1,102 +1,69 @@
|
|||||||
package ruby
|
package ruby
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseGemfileLockEntries(t *testing.T) {
|
func TestParseGemfileLockEntries(t *testing.T) {
|
||||||
|
fixture := "test-fixtures/Gemfile.lock"
|
||||||
var expectedGems = map[string]string{
|
locations := source.NewLocationSet(source.NewLocation(fixture))
|
||||||
"actionmailer": "4.1.1",
|
var expectedPkgs = []pkg.Package{
|
||||||
"actionpack": "4.1.1",
|
{Name: "actionmailer", Version: "4.1.1", PURL: "pkg:gem/actionmailer@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"actionview": "4.1.1",
|
{Name: "actionpack", Version: "4.1.1", PURL: "pkg:gem/actionpack@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"activemodel": "4.1.1",
|
{Name: "actionview", Version: "4.1.1", PURL: "pkg:gem/actionview@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"activerecord": "4.1.1",
|
{Name: "activemodel", Version: "4.1.1", PURL: "pkg:gem/activemodel@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"activesupport": "4.1.1",
|
{Name: "activerecord", Version: "4.1.1", PURL: "pkg:gem/activerecord@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"arel": "5.0.1.20140414130214",
|
{Name: "activesupport", Version: "4.1.1", PURL: "pkg:gem/activesupport@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"bootstrap-sass": "3.1.1.1",
|
{Name: "arel", Version: "5.0.1.20140414130214", PURL: "pkg:gem/arel@5.0.1.20140414130214", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"builder": "3.2.2",
|
{Name: "bootstrap-sass", Version: "3.1.1.1", PURL: "pkg:gem/bootstrap-sass@3.1.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"coffee-rails": "4.0.1",
|
{Name: "builder", Version: "3.2.2", PURL: "pkg:gem/builder@3.2.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"coffee-script": "2.2.0",
|
{Name: "coffee-rails", Version: "4.0.1", PURL: "pkg:gem/coffee-rails@4.0.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"coffee-script-source": "1.7.0",
|
{Name: "coffee-script", Version: "2.2.0", PURL: "pkg:gem/coffee-script@2.2.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"erubis": "2.7.0",
|
{Name: "coffee-script-source", Version: "1.7.0", PURL: "pkg:gem/coffee-script-source@1.7.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"execjs": "2.0.2",
|
{Name: "erubis", Version: "2.7.0", PURL: "pkg:gem/erubis@2.7.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"hike": "1.2.3",
|
{Name: "execjs", Version: "2.0.2", PURL: "pkg:gem/execjs@2.0.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"i18n": "0.6.9",
|
{Name: "hike", Version: "1.2.3", PURL: "pkg:gem/hike@1.2.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"jbuilder": "2.0.7",
|
{Name: "i18n", Version: "0.6.9", PURL: "pkg:gem/i18n@0.6.9", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"jquery-rails": "3.1.0",
|
{Name: "jbuilder", Version: "2.0.7", PURL: "pkg:gem/jbuilder@2.0.7", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"json": "1.8.1",
|
{Name: "jquery-rails", Version: "3.1.0", PURL: "pkg:gem/jquery-rails@3.1.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"kgio": "2.9.2",
|
{Name: "json", Version: "1.8.1", PURL: "pkg:gem/json@1.8.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"libv8": "3.16.14.3",
|
{Name: "kgio", Version: "2.9.2", PURL: "pkg:gem/kgio@2.9.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"mail": "2.5.4",
|
{Name: "libv8", Version: "3.16.14.3", PURL: "pkg:gem/libv8@3.16.14.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"mime-types": "1.25.1",
|
{Name: "mail", Version: "2.5.4", PURL: "pkg:gem/mail@2.5.4", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"minitest": "5.3.4",
|
{Name: "mime-types", Version: "1.25.1", PURL: "pkg:gem/mime-types@1.25.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"multi_json": "1.10.1",
|
{Name: "minitest", Version: "5.3.4", PURL: "pkg:gem/minitest@5.3.4", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"mysql2": "0.3.16",
|
{Name: "multi_json", Version: "1.10.1", PURL: "pkg:gem/multi_json@1.10.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"polyglot": "0.3.4",
|
{Name: "mysql2", Version: "0.3.16", PURL: "pkg:gem/mysql2@0.3.16", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"rack": "1.5.2",
|
{Name: "polyglot", Version: "0.3.4", PURL: "pkg:gem/polyglot@0.3.4", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"rack-test": "0.6.2",
|
{Name: "rack", Version: "1.5.2", PURL: "pkg:gem/rack@1.5.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"rails": "4.1.1",
|
{Name: "rack-test", Version: "0.6.2", PURL: "pkg:gem/rack-test@0.6.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"railties": "4.1.1",
|
{Name: "rails", Version: "4.1.1", PURL: "pkg:gem/rails@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"raindrops": "0.13.0",
|
{Name: "railties", Version: "4.1.1", PURL: "pkg:gem/railties@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"rake": "10.3.2",
|
{Name: "raindrops", Version: "0.13.0", PURL: "pkg:gem/raindrops@0.13.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"rdoc": "4.1.1",
|
{Name: "rake", Version: "10.3.2", PURL: "pkg:gem/rake@10.3.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"ref": "1.0.5",
|
{Name: "rdoc", Version: "4.1.1", PURL: "pkg:gem/rdoc@4.1.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sass": "3.2.19",
|
{Name: "ref", Version: "1.0.5", PURL: "pkg:gem/ref@1.0.5", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sass-rails": "4.0.3",
|
{Name: "sass", Version: "3.2.19", PURL: "pkg:gem/sass@3.2.19", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sdoc": "0.4.0",
|
{Name: "sass-rails", Version: "4.0.3", PURL: "pkg:gem/sass-rails@4.0.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"spring": "1.1.3",
|
{Name: "sdoc", Version: "0.4.0", PURL: "pkg:gem/sdoc@0.4.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sprockets": "2.11.0",
|
{Name: "spring", Version: "1.1.3", PURL: "pkg:gem/spring@1.1.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sprockets-rails": "2.1.3",
|
{Name: "sprockets", Version: "2.11.0", PURL: "pkg:gem/sprockets@2.11.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"sqlite3": "1.3.9",
|
{Name: "sprockets-rails", Version: "2.1.3", PURL: "pkg:gem/sprockets-rails@2.1.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"therubyracer": "0.12.1",
|
{Name: "sqlite3", Version: "1.3.9", PURL: "pkg:gem/sqlite3@1.3.9", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"thor": "0.19.1",
|
{Name: "therubyracer", Version: "0.12.1", PURL: "pkg:gem/therubyracer@0.12.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"thread_safe": "0.3.3",
|
{Name: "thor", Version: "0.19.1", PURL: "pkg:gem/thor@0.19.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"tilt": "1.4.1",
|
{Name: "thread_safe", Version: "0.3.3", PURL: "pkg:gem/thread_safe@0.3.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"treetop": "1.4.15",
|
{Name: "tilt", Version: "1.4.1", PURL: "pkg:gem/tilt@1.4.1", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"turbolinks": "2.2.2",
|
{Name: "treetop", Version: "1.4.15", PURL: "pkg:gem/treetop@1.4.15", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"tzinfo": "1.2.0",
|
{Name: "turbolinks", Version: "2.2.2", PURL: "pkg:gem/turbolinks@2.2.2", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"uglifier": "2.5.0",
|
{Name: "tzinfo", Version: "1.2.0", PURL: "pkg:gem/tzinfo@1.2.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
"unicorn": "4.8.3",
|
{Name: "uglifier", Version: "2.5.0", PURL: "pkg:gem/uglifier@2.5.0", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
|
{Name: "unicorn", Version: "4.8.3", PURL: "pkg:gem/unicorn@4.8.3", Locations: locations, Language: pkg.Ruby, Type: pkg.GemPkg},
|
||||||
}
|
}
|
||||||
|
|
||||||
fixture, err := os.Open("test-fixtures/Gemfile.lock")
|
pkgtest.TestFileParser(t, fixture, parseGemFileLockEntries, expectedPkgs, nil)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: no relationships are under test yet
|
|
||||||
actual, _, err := parseGemFileLockEntries(fixture.Name(), fixture)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to parse gemfile lock: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(actual) != len(expectedGems) {
|
|
||||||
for _, a := range actual {
|
|
||||||
t.Log(" ", a)
|
|
||||||
}
|
|
||||||
t.Fatalf("unexpected package count: %d!=%d", len(actual), len(expectedGems))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, a := range actual {
|
|
||||||
expectedVersion, ok := expectedGems[a.Name]
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("unexpected package found: %s", a.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if expectedVersion != a.Version {
|
|
||||||
t.Errorf("unexpected package version (pkg=%s): %s", a.Name, a.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Language != pkg.Ruby {
|
|
||||||
t.Errorf("bad language (pkg=%+v): %+v", a.Name, a.Language)
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Type != pkg.GemPkg {
|
|
||||||
t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -13,11 +12,11 @@ import (
|
|||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"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 _ generic.Parser = parseGemFileLockEntries
|
||||||
var _ common.ParserFn = parseGemFileLockEntries
|
|
||||||
|
|
||||||
type postProcessor func(string) []string
|
type postProcessor func(string) []string
|
||||||
|
|
||||||
@ -36,14 +35,14 @@ var patterns = map[string]*regexp.Regexp{
|
|||||||
"homepage": regexp.MustCompile(`.*\.homepage\s*=\s*["']{1}(?P<homepage>.*)["']{1} *`),
|
"homepage": regexp.MustCompile(`.*\.homepage\s*=\s*["']{1}(?P<homepage>.*)["']{1} *`),
|
||||||
|
|
||||||
// match example: files = ["exe/bundle".freeze, "exe/bundler".freeze] ---> "exe/bundle".freeze, "exe/bundler".freeze
|
// match example: files = ["exe/bundle".freeze, "exe/bundler".freeze] ---> "exe/bundle".freeze, "exe/bundler".freeze
|
||||||
"files": regexp.MustCompile(`.*\.files\s*=\s*\[(?P<files>.*)\] *`),
|
"files": regexp.MustCompile(`.*\.files\s*=\s*\[(?P<files>.*)] *`),
|
||||||
|
|
||||||
// match example: authors = ["Andr\u00E9 Arko".freeze, "Samuel Giddins".freeze, "Colby Swandale".freeze,
|
// match example: authors = ["Andr\u00E9 Arko".freeze, "Samuel Giddins".freeze, "Colby Swandale".freeze,
|
||||||
// "Hiroshi Shibata".freeze, "David Rodr\u00EDguez".freeze, "Grey Baker".freeze...]
|
// "Hiroshi Shibata".freeze, "David Rodr\u00EDguez".freeze, "Grey Baker".freeze...]
|
||||||
"authors": regexp.MustCompile(`.*\.authors\s*=\s*\[(?P<authors>.*)\] *`),
|
"authors": regexp.MustCompile(`.*\.authors\s*=\s*\[(?P<authors>.*)] *`),
|
||||||
|
|
||||||
// match example: licenses = ["MIT".freeze] ----> "MIT".freeze
|
// match example: licenses = ["MIT".freeze] ----> "MIT".freeze
|
||||||
"licenses": regexp.MustCompile(`.*\.licenses\s*=\s*\[(?P<licenses>.*)\] *`),
|
"licenses": regexp.MustCompile(`.*\.licenses\s*=\s*\[(?P<licenses>.*)] *`),
|
||||||
}
|
}
|
||||||
|
|
||||||
var postProcessors = map[string]postProcessor{
|
var postProcessors = map[string]postProcessor{
|
||||||
@ -60,8 +59,8 @@ func processList(s string) []string {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGemSpecEntries(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
func parseGemSpecEntries(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
var pkgs []*pkg.Package
|
var pkgs []pkg.Package
|
||||||
var fields = make(map[string]interface{})
|
var fields = make(map[string]interface{})
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
@ -79,8 +78,8 @@ func parseGemSpecEntries(_ string, reader io.Reader) ([]*pkg.Package, []artifact
|
|||||||
for field, pattern := range patterns {
|
for field, pattern := range patterns {
|
||||||
matchMap := internal.MatchNamedCaptureGroups(pattern, sanitizedLine)
|
matchMap := internal.MatchNamedCaptureGroups(pattern, sanitizedLine)
|
||||||
if value := matchMap[field]; value != "" {
|
if value := matchMap[field]; value != "" {
|
||||||
if postProcessor := postProcessors[field]; postProcessor != nil {
|
if pp := postProcessors[field]; pp != nil {
|
||||||
fields[field] = postProcessor(value)
|
fields[field] = pp(value)
|
||||||
} else {
|
} else {
|
||||||
fields[field] = value
|
fields[field] = value
|
||||||
}
|
}
|
||||||
@ -96,15 +95,7 @@ func parseGemSpecEntries(_ string, reader io.Reader) ([]*pkg.Package, []artifact
|
|||||||
return nil, nil, fmt.Errorf("unable to decode gem metadata: %w", err)
|
return nil, nil, fmt.Errorf("unable to decode gem metadata: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgs = append(pkgs, &pkg.Package{
|
pkgs = append(pkgs, newGemspecPackage(metadata, reader.Location))
|
||||||
Name: metadata.Name,
|
|
||||||
Version: metadata.Version,
|
|
||||||
Licenses: metadata.Licenses,
|
|
||||||
Language: pkg.Ruby,
|
|
||||||
Type: pkg.GemPkg,
|
|
||||||
MetadataType: pkg.GemMetadataType,
|
|
||||||
Metadata: metadata,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkgs, nil, nil
|
return pkgs, nil, nil
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
package ruby
|
package ruby
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-test/deep"
|
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseGemspec(t *testing.T) {
|
func TestParseGemspec(t *testing.T) {
|
||||||
|
fixture := "test-fixtures/bundler.gemspec"
|
||||||
|
|
||||||
|
locations := source.NewLocationSet(source.NewLocation(fixture))
|
||||||
|
|
||||||
var expectedPkg = pkg.Package{
|
var expectedPkg = pkg.Package{
|
||||||
Name: "bundler",
|
Name: "bundler",
|
||||||
Version: "2.1.4",
|
Version: "2.1.4",
|
||||||
|
PURL: "pkg:gem/bundler@2.1.4",
|
||||||
|
Locations: locations,
|
||||||
Type: pkg.GemPkg,
|
Type: pkg.GemPkg,
|
||||||
Licenses: []string{"MIT"},
|
Licenses: []string{"MIT"},
|
||||||
Language: pkg.Ruby,
|
Language: pkg.Ruby,
|
||||||
@ -27,25 +32,5 @@ func TestParseGemspec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fixture, err := os.Open("test-fixtures/bundler.gemspec")
|
pkgtest.TestFileParser(t, fixture, parseGemSpecEntries, []pkg.Package{expectedPkg}, nil)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: no relationships are under test yet
|
|
||||||
actual, _, err := parseGemSpecEntries(fixture.Name(), fixture)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to parse gemspec: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(actual) != 1 {
|
|
||||||
for _, a := range actual {
|
|
||||||
t.Log(" ", a)
|
|
||||||
}
|
|
||||||
t.Fatalf("unexpected package count: %d!=1", len(actual))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range deep.Equal(actual[0], &expectedPkg) {
|
|
||||||
t.Errorf("diff: %+v", d)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,24 +17,6 @@ func TestPackageURL(t *testing.T) {
|
|||||||
distro *linux.Release
|
distro *linux.Release
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
name: "gem",
|
|
||||||
pkg: Package{
|
|
||||||
Name: "name",
|
|
||||||
Version: "v0.1.0",
|
|
||||||
Type: GemPkg,
|
|
||||||
},
|
|
||||||
expected: "pkg:gem/name@v0.1.0",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "npm",
|
|
||||||
pkg: Package{
|
|
||||||
Name: "name",
|
|
||||||
Version: "v0.1.0",
|
|
||||||
Type: NpmPkg,
|
|
||||||
},
|
|
||||||
expected: "pkg:npm/name@v0.1.0",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "cargo",
|
name: "cargo",
|
||||||
pkg: Package{
|
pkg: Package{
|
||||||
@ -109,6 +91,8 @@ func TestPackageURL(t *testing.T) {
|
|||||||
expectedTypes.Remove(string(PhpComposerPkg))
|
expectedTypes.Remove(string(PhpComposerPkg))
|
||||||
expectedTypes.Remove(string(PythonPkg))
|
expectedTypes.Remove(string(PythonPkg))
|
||||||
expectedTypes.Remove(string(RpmPkg))
|
expectedTypes.Remove(string(RpmPkg))
|
||||||
|
expectedTypes.Remove(string(GemPkg))
|
||||||
|
expectedTypes.Remove(string(NpmPkg))
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user