diff --git a/syft/pkg/cataloger/binary/cataloger_test.go b/syft/pkg/cataloger/binary/cataloger_test.go index 3270f5d2f35..f376ceed4cc 100644 --- a/syft/pkg/cataloger/binary/cataloger_test.go +++ b/syft/pkg/cataloger/binary/cataloger_test.go @@ -515,6 +515,52 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases(t *testing.T) { Metadata: metadata("rust-standard-library-linux"), }, }, + { + name: "positive-ruby-3.2.1", + fixtureDir: "test-fixtures/classifiers/dynamic/ruby-library-3.2.1", + expected: pkg.Package{ + Name: "ruby", + Version: "3.2.1", + Type: "binary", + PURL: "pkg:generic/ruby@3.2.1", + Locations: locations("ruby", "libruby.so.3.2.1"), + Metadata: pkg.BinaryMetadata{ + Matches: []pkg.ClassifierMatch{ + match("ruby-binary", "ruby"), + match("ruby-binary", "libruby.so.3.2.1"), + }, + }, + }, + }, + { + name: "positive-ruby-2.7.7", + fixtureDir: "test-fixtures/classifiers/dynamic/ruby-library-2.7.7", + expected: pkg.Package{ + Name: "ruby", + Version: "2.7.7p221", + Type: "binary", + PURL: "pkg:generic/ruby@2.7.7p221", + Locations: locations("ruby", "libruby.so.2.7.7"), + Metadata: pkg.BinaryMetadata{ + Matches: []pkg.ClassifierMatch{ + match("ruby-binary", "ruby"), + match("ruby-binary", "libruby.so.2.7.7"), + }, + }, + }, + }, + { + name: "positive-ruby-1.9.3p551", + fixtureDir: "test-fixtures/classifiers/positive/ruby-1.9.3p551", + expected: pkg.Package{ + Name: "ruby", + Version: "1.9.3p551", + Type: "binary", + PURL: "pkg:generic/ruby@1.9.3p551", + Locations: locations("ruby"), + Metadata: metadata("ruby-binary"), + }, + }, } for _, test := range tests { diff --git a/syft/pkg/cataloger/binary/default_classifiers.go b/syft/pkg/cataloger/binary/default_classifiers.go index 01c707eeb6f..9c3004ec612 100644 --- a/syft/pkg/cataloger/binary/default_classifiers.go +++ b/syft/pkg/cataloger/binary/default_classifiers.go @@ -220,6 +220,20 @@ var defaultClassifiers = []classifier{ PURL: mustPURL("pkg:generic/rust@version"), CPEs: singleCPE("cpe:2.3:a:rust-lang:rust:*:*:*:*:*:*:*:*"), }, + { + Class: "ruby-binary", + FileGlob: "**/ruby", + EvidenceMatcher: evidenceMatchers( + rubyMatcher, + sharedLibraryLookup( + // try to find version information from libruby shared libraries + `^libruby\.so.*$`, + rubyMatcher), + ), + Package: "ruby", + PURL: mustPURL("pkg:generic/ruby@version"), + CPEs: singleCPE("cpe:2.3:a:ruby-lang:ruby:*:*:*:*:*:*:*:*"), + }, } // in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL] @@ -229,3 +243,8 @@ var libpythonMatcher = fileNameTemplateVersionMatcher( `(?:.*/|^)libpython(?P[0-9]+(?:\.[0-9]+)+)\.so.*$`, pythonVersionTemplate, ) + +var rubyMatcher = fileContentsVersionMatcher( + // ruby 3.2.1 (2023-02-08 revision 31819e82c8) [x86_64-linux] + // ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5) [x86_64-linux] + `(?m)ruby (?P[0-9]\.[0-9]\.[0-9](p[0-9]+)?) `) diff --git a/syft/pkg/cataloger/binary/test-fixtures/Makefile b/syft/pkg/cataloger/binary/test-fixtures/Makefile index a23faaf887e..7cbbac3978a 100644 --- a/syft/pkg/cataloger/binary/test-fixtures/Makefile +++ b/syft/pkg/cataloger/binary/test-fixtures/Makefile @@ -2,7 +2,9 @@ all: \ classifiers/dynamic/python-binary-shared-lib-3.11 \ classifiers/dynamic/python-binary-shared-lib-redhat-3.9 \ - classifiers/dynamic/python-binary-with-version-3.9 + classifiers/dynamic/python-binary-with-version-3.9 \ + classifiers/dynamic/ruby-library-3.2.1 \ + classifiers/dynamic/ruby-library-2.7.7 classifiers/dynamic/python-binary-shared-lib-3.11: $(eval $@_image := "python:3.11-slim@sha256:0b106e1d2bf485c2a41474bc9cd5103e9eea4e179f40f10741b53b127059221e") @@ -28,6 +30,30 @@ classifiers/dynamic/python-binary-with-version-3.9: /usr/bin/python3.9 \ $@/python3.9 +classifiers/dynamic/ruby-library-3.2.1: + $(eval $@_image := "ruby:3.2.1-bullseye@sha256:b4a140656b0c5d26c0a80559b228b4d343f3fdbf56682fcbe88f6db1fa9afa6b") + ./get-image-file.sh $($@_image) \ + /usr/local/bin/ruby \ + $@/ruby + ./get-image-file.sh $($@_image) \ + /usr/local/lib/libruby.so.3.2.1 \ + $@/libruby.so.3.2.1 + ./get-image-file.sh $($@_image) \ + /usr/local/lib/libruby.so.3.2 \ + $@/libruby.so.3.2 + +classifiers/dynamic/ruby-library-2.7.7: + $(eval $@_image := "ruby:2.7.7-bullseye@sha256:055191740a063f33fef1f09423e5ed8f91143aae62a3772a90910118464c5120") + ./get-image-file.sh $($@_image) \ + /usr/local/bin/ruby \ + $@/ruby + ./get-image-file.sh $($@_image) \ + /usr/local/lib/libruby.so.2.7.7 \ + $@/libruby.so.2.7.7 + ./get-image-file.sh $($@_image) \ + /usr/local/lib/libruby.so.2.7 \ + $@/libruby.so.2.7 + .PHONY: clean clean: rm -rf classifiers/dynamic diff --git a/syft/pkg/cataloger/binary/test-fixtures/classifiers/positive/ruby-1.9.3p551/ruby b/syft/pkg/cataloger/binary/test-fixtures/classifiers/positive/ruby-1.9.3p551/ruby new file mode 100644 index 00000000000..c9edafcbce8 --- /dev/null +++ b/syft/pkg/cataloger/binary/test-fixtures/classifiers/positive/ruby-1.9.3p551/ruby @@ -0,0 +1,9 @@ +super from singleton method that is defined to multiple classes is not supported; this will be fixed in 1.9.3 or later +/usr/local/lib/ruby/site_ruby/1.9.1 +/usr/local/lib/ruby/site_ruby/1.9.1/x86_64-linux +/usr/local/lib/ruby/vendor_ruby/1.9.1 +/usr/local/lib/ruby/vendor_ruby/1.9.1/x86_64-linux +/usr/local/lib/ruby/1.9.1 +/usr/local/lib/ruby/1.9.1/x86_64-linux +ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux] +1.9.3