diff --git a/schema/json/schema.json b/schema/json/schema.json index 6bc3dfb47..be4cb2e5f 100644 --- a/schema/json/schema.json +++ b/schema/json/schema.json @@ -40,6 +40,9 @@ "architecture": { "type": "string" }, + "authors": { + "type": "null" + }, "description": { "type": "string" }, @@ -48,31 +51,38 @@ }, "files": { "items": { - "properties": { - "checksum": { + "anyOf": [ + { "type": "string" }, - "ownerGid": { - "type": "string" - }, - "ownerUid": { - "type": "string" - }, - "path": { - "type": "string" - }, - "permissions": { - "type": "string" + { + "properties": { + "checksum": { + "type": "string" + }, + "ownerGid": { + "type": "string" + }, + "ownerUid": { + "type": "string" + }, + "path": { + "type": "string" + }, + "permissions": { + "type": "string" + } + }, + "required": [ + "checksum", + "ownerGid", + "ownerUid", + "path", + "permissions" + ], + "type": "object" } - }, - "required": [ - "checksum", - "ownerGid", - "ownerUid", - "path", - "permissions" - ], - "type": "object" + ] }, "type": "array" }, @@ -85,6 +95,12 @@ "license": { "type": "string" }, + "licenses": { + "items": { + "type": "string" + }, + "type": "array" + }, "maintainer": { "type": "string" }, diff --git a/syft/cataloger/cataloger.go b/syft/cataloger/cataloger.go index e366cea0e..85e0f77bc 100644 --- a/syft/cataloger/cataloger.go +++ b/syft/cataloger/cataloger.go @@ -8,13 +8,13 @@ package cataloger import ( "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/syft/syft/cataloger/apkdb" - "github.com/anchore/syft/syft/cataloger/bundler" "github.com/anchore/syft/syft/cataloger/deb" "github.com/anchore/syft/syft/cataloger/golang" "github.com/anchore/syft/syft/cataloger/java" "github.com/anchore/syft/syft/cataloger/javascript" "github.com/anchore/syft/syft/cataloger/python" "github.com/anchore/syft/syft/cataloger/rpmdb" + "github.com/anchore/syft/syft/cataloger/ruby" "github.com/anchore/syft/syft/pkg" "github.com/anchore/syft/syft/scope" ) @@ -36,7 +36,7 @@ type Cataloger interface { // ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages. func ImageCatalogers() []Cataloger { return []Cataloger{ - bundler.NewGemSpecCataloger(), + ruby.NewGemSpecCataloger(), python.NewPythonCataloger(), // TODO: split and replace me javascript.NewJavascriptCataloger(), // TODO: split and replace me deb.NewDpkgdbCataloger(), @@ -50,7 +50,7 @@ func ImageCatalogers() []Cataloger { // DirectoryCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations) func DirectoryCatalogers() []Cataloger { return []Cataloger{ - bundler.NewGemFileLockCataloger(), + ruby.NewGemFileLockCataloger(), python.NewPythonCataloger(), // TODO: split and replace me javascript.NewJavascriptCataloger(), // TODO: split and replace me deb.NewDpkgdbCataloger(), diff --git a/syft/cataloger/bundler/catalogers.go b/syft/cataloger/ruby/catalogers.go similarity index 98% rename from syft/cataloger/bundler/catalogers.go rename to syft/cataloger/ruby/catalogers.go index ae8554226..960cbf720 100644 --- a/syft/cataloger/bundler/catalogers.go +++ b/syft/cataloger/ruby/catalogers.go @@ -1,7 +1,7 @@ /* Package bundler provides a concrete Cataloger implementation for Ruby Gemfile.lock bundler files. */ -package bundler +package ruby import ( "github.com/anchore/syft/syft/cataloger/common" diff --git a/syft/cataloger/bundler/parse_gemfile_lock.go b/syft/cataloger/ruby/parse_gemfile_lock.go similarity index 98% rename from syft/cataloger/bundler/parse_gemfile_lock.go rename to syft/cataloger/ruby/parse_gemfile_lock.go index 28a45eb76..23a4a7756 100644 --- a/syft/cataloger/bundler/parse_gemfile_lock.go +++ b/syft/cataloger/ruby/parse_gemfile_lock.go @@ -1,4 +1,4 @@ -package bundler +package ruby import ( "bufio" diff --git a/syft/cataloger/bundler/parse_gemfile_lock_test.go b/syft/cataloger/ruby/parse_gemfile_lock_test.go similarity index 99% rename from syft/cataloger/bundler/parse_gemfile_lock_test.go rename to syft/cataloger/ruby/parse_gemfile_lock_test.go index bb0b254d0..4307c34fa 100644 --- a/syft/cataloger/bundler/parse_gemfile_lock_test.go +++ b/syft/cataloger/ruby/parse_gemfile_lock_test.go @@ -1,4 +1,4 @@ -package bundler +package ruby import ( "os" diff --git a/syft/cataloger/bundler/parse_gemspec.go b/syft/cataloger/ruby/parse_gemspec.go similarity index 77% rename from syft/cataloger/bundler/parse_gemspec.go rename to syft/cataloger/ruby/parse_gemspec.go index 11fa6c059..ad22dc9c8 100644 --- a/syft/cataloger/bundler/parse_gemspec.go +++ b/syft/cataloger/ruby/parse_gemspec.go @@ -1,11 +1,11 @@ -package bundler +package ruby import ( "bufio" + "encoding/json" "fmt" "io" "regexp" - "strconv" "strings" "github.com/mitchellh/mapstructure" @@ -48,6 +48,7 @@ var postProcessors = map[string]postProcessor{ } func processList(s string) []string { + // nolint:prealloc var results []string for _, item := range strings.Split(s, ",") { results = append(results, strings.Trim(item, "\" ")) @@ -106,47 +107,19 @@ func parseGemSpecEntries(_ string, reader io.Reader) ([]pkg.Package, error) { // renderUtf8 takes any string escaped string sub-sections from the ruby string and replaces those sections with the UTF8 runes. func renderUtf8(s string) string { - pattern := regexp.MustCompile(`\\u(?P[0-9A-F]{4,8})`) - fullReplacement := replaceAllStringSubmatchFunc(pattern, s, func(unicodeSection []string) string { - replacement := "" - if len(unicodeSection) == 1 { - return unicodeSection[0] - } - for idx, m := range unicodeSection { - if idx == 0 { - continue - } - value, err := strconv.ParseInt(m, 16, 64) - if err != nil { - // TODO: log? - panic(err) - //return unicodeSection[0] - } - replacement = strings.ReplaceAll(unicodeSection[0], "\\u"+m, string(rune(value))) + pattern := regexp.MustCompile(`\\u(?P[0-9A-F]{4})`) + fullReplacement := pattern.ReplaceAllStringFunc(s, func(unicodeSection string) string { + var replacement string + // note: the json parser already has support for interpreting hex-representations of unicode escaped strings as unicode runes. + // we can do this ourselves with strconv.Atoi, or leverage the existing json package. + if err := json.Unmarshal([]byte(`"`+unicodeSection+`"`), &replacement); err != nil { + return unicodeSection } return replacement }) return fullReplacement } -// replaceAllStringSubmatchFunc finds and replaces the given capture groups from the -func replaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string { - result := "" - lastIndex := 0 - - for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { - var groups []string - for i := 0; i < len(v); i += 2 { - groups = append(groups, str[v[i]:v[i+1]]) - } - - result += str[lastIndex:v[0]] + repl(groups) - lastIndex = v[1] - } - - return result + str[lastIndex:] -} - // matchCaptureGroups takes a regular expression and string and returns all of the named capture group results in a map. func matchCaptureGroups(regEx *regexp.Regexp, str string) map[string]string { match := regEx.FindStringSubmatch(str) diff --git a/syft/cataloger/bundler/parse_gemspec_test.go b/syft/cataloger/ruby/parse_gemspec_test.go similarity index 93% rename from syft/cataloger/bundler/parse_gemspec_test.go rename to syft/cataloger/ruby/parse_gemspec_test.go index 539372b53..2c0cae20c 100644 --- a/syft/cataloger/bundler/parse_gemspec_test.go +++ b/syft/cataloger/ruby/parse_gemspec_test.go @@ -1,4 +1,4 @@ -package bundler +package ruby import ( "os" @@ -19,7 +19,7 @@ func TestParseGemspec(t *testing.T) { Name: "bundler", Version: "2.1.4", Files: []string{"exe/bundle", "exe/bundler"}, - Authors: []string{"André Arko", "Samuel Giddins", "Colby Swandale", "Hiroshi Shibata", "David Rodréguez", "Grey Baker", "Stephanie Morillo", "Chris Morris", "James Wen", "Tim Moore", "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", "Yehuda Katz"}, + Authors: []string{"André Arko", "Samuel Giddins", "Colby Swandale", "Hiroshi Shibata", "David Rodríguez", "Grey Baker", "Stephanie Morillo", "Chris Morris", "James Wen", "Tim Moore", "André Medeiros", "Jessica Lynn Suttles", "Terence Lee", "Carl Lerche", "Yehuda Katz"}, Licenses: []string{"MIT"}, }, } diff --git a/syft/cataloger/bundler/test-fixtures/Gemfile.lock b/syft/cataloger/ruby/test-fixtures/Gemfile.lock similarity index 100% rename from syft/cataloger/bundler/test-fixtures/Gemfile.lock rename to syft/cataloger/ruby/test-fixtures/Gemfile.lock diff --git a/syft/cataloger/bundler/test-fixtures/bundler.gemspec b/syft/cataloger/ruby/test-fixtures/bundler.gemspec similarity index 100% rename from syft/cataloger/bundler/test-fixtures/bundler.gemspec rename to syft/cataloger/ruby/test-fixtures/bundler.gemspec diff --git a/syft/pkg/gem_metadata.go b/syft/pkg/gem_metadata.go index aa2edc310..26f5ae0f4 100644 --- a/syft/pkg/gem_metadata.go +++ b/syft/pkg/gem_metadata.go @@ -1,9 +1,9 @@ package pkg type GemMetadata struct { - Name string `mapstructure:"name" json:"name"` - Version string `mapstructure:"version" json:"version"` - Files []string `mapstructure:"files" json:"files"` + Name string `mapstructure:"name" json:"name"` + Version string `mapstructure:"version" json:"version"` + Files []string `mapstructure:"files" json:"files"` Authors []string `mapstructure:"authors" json:"authors"` Licenses []string `mapstructure:"licenses" json:"licenses"` }