diff --git a/syft/pkg/cataloger/binary/classifier_cataloger_test.go b/syft/pkg/cataloger/binary/classifier_cataloger_test.go index d66cd393e..f14628764 100644 --- a/syft/pkg/cataloger/binary/classifier_cataloger_test.go +++ b/syft/pkg/cataloger/binary/classifier_cataloger_test.go @@ -1754,6 +1754,25 @@ func Test_Cataloger_PositiveCases(t *testing.T) { }, }, }, + { + // release-candidate elixir image — pre-fix the matchers stripped the + // "-rc.1" suffix from the elixir-library result and missed the + // elixir-binary entirely (#4819). + logicalFixture: "elixir/1.12.0-rc.1/linux-amd64", + expected: pkg.Package{ + Name: "elixir", + Version: "1.12.0-rc.1", + Type: "binary", + PURL: "pkg:generic/elixir@1.12.0-rc.1", + Locations: locations("elixir", "lib/elixir/ebin/elixir.app"), + Metadata: pkg.BinarySignature{ + Matches: []pkg.ClassifierMatch{ + match("elixir-binary", "elixir"), + match("elixir-library", "lib/elixir/ebin/elixir.app"), + }, + }, + }, + }, { logicalFixture: "istio_pilot-discovery/1.29.0-alpha.0/linux-amd64", expected: pkg.Package{ diff --git a/syft/pkg/cataloger/binary/classifiers.go b/syft/pkg/cataloger/binary/classifiers.go index 56ae02545..2802b16a7 100644 --- a/syft/pkg/cataloger/binary/classifiers.go +++ b/syft/pkg/cataloger/binary/classifiers.go @@ -768,7 +768,9 @@ func DefaultClassifiers() []binutils.Classifier { Class: "elixir-binary", FileGlob: "**/elixir", EvidenceMatcher: m.FileContentsVersionMatcher( - `(?m)ELIXIR_VERSION=(?P[0-9]+\.[0-9]+\.[0-9]+)`), + // Capture optional pre-release suffix (-rc.1, -alpha.0, -beta.2, + // etc.) so release-candidate elixir images (#4819) match. + `(?m)ELIXIR_VERSION=(?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-z0-9]+(?:\.[0-9]+)?)?)`), Package: "elixir", PURL: mustPURL("pkg:generic/elixir@version"), CPEs: []cpe.CPE{ @@ -779,7 +781,8 @@ func DefaultClassifiers() []binutils.Classifier { Class: "elixir-library", FileGlob: "**/elixir/ebin/elixir.app", EvidenceMatcher: m.FileContentsVersionMatcher( - `(?m)\{vsn,"(?P[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9]+)?)"\}`), + // Same pre-release extension as elixir-binary above. + `(?m)\{vsn,"(?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-z0-9]+(?:\.[0-9]+)?)?)"\}`), Package: "elixir", PURL: mustPURL("pkg:generic/elixir@version"), CPEs: singleCPE("cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource), diff --git a/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/elixir b/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/elixir new file mode 100644 index 000000000..210b6b969 --- /dev/null +++ b/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/elixir @@ -0,0 +1,20 @@ +#!/bin/sh + +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: 2021 The Elixir Team +# SPDX-FileCopyrightText: 2012 Plataformatec + +set -e + +ELIXIR_VERSION=1.12.0-rc.1 + +if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then + cat <&2 +Usage: $(basename "$0") [options] [.exs file] [data] + +## General options + + -e "COMMAND" Evaluates the given command (*) + -h, --help Prints this message (standalone) + -r "FILE" Requires the given files/patterns (*) + -S SCRIPT Finds and executes the given script in \$PATH diff --git a/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/lib/elixir/ebin/elixir.app b/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/lib/elixir/ebin/elixir.app new file mode 100644 index 000000000..110eaf432 --- /dev/null +++ b/syft/pkg/cataloger/binary/testdata/classifiers/snippets/elixir/1.12.0-rc.1/linux-amd64/lib/elixir/ebin/elixir.app @@ -0,0 +1,19 @@ +{application,elixir, + [{description,"elixir"}, + {vsn,"1.12.0-rc.1"}, + {modules, + ['Elixir.Access','Elixir.Agent.Server','Elixir.Agent', + 'Elixir.Application','Elixir.ArgumentError', + elixir_overridable,elixir_parser,elixir_quote,elixir_rewrite, + elixir_sup,elixir_tokenizer,elixir_utils,iex]}, + {registered,[elixir_sup,elixir_config,elixir_code_server]}, + {applications,[kernel,stdlib,compiler]}, + {mod,{elixir,[]}}, + {env, + [{ansi_syntax_colors, + [{atom,cyan}, + {binary,default_color}, + {operator,default_color}]}, + {check_endianness,true}, + {dbg_callback,{'Elixir.Macro',dbg,[]}}, + {time_zone_database,'Elixir.Calendar.UTCOnlyTimeZoneDatabase'}]}]}.