mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
Add PHP interpreter + extensions cataloger (#2585)
* Add PHP extensions binary classifiers Signed-off-by: Laurent Goderre <laurent.goderre@docker.com> * [wip] add php extensions cataloger Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix linting Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * find interpreters + extension Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * internalize binary cataloger utilities Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * default to linux/amd64 for test fixtures Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Laurent Goderre <laurent.goderre@docker.com> Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
0521ccaf5e
commit
a8e5b25632
@ -164,6 +164,7 @@ func DefaultPackageTaskFactories() Factories {
|
|||||||
},
|
},
|
||||||
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
|
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "linux", "kernel",
|
||||||
),
|
),
|
||||||
|
newSimplePackageTaskFactory(php.NewInterpreterCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, "binary", "php"),
|
||||||
newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages
|
newSimplePackageTaskFactory(sbomCataloger.NewCataloger, "sbom"), // note: not evidence of installed packages
|
||||||
newSimplePackageTaskFactory(bitnamiSbomCataloger.NewCataloger, "bitnami", pkgcataloging.InstalledTag, pkgcataloging.ImageTag),
|
newSimplePackageTaskFactory(bitnamiSbomCataloger.NewCataloger, "bitnami", pkgcataloging.InstalledTag, pkgcataloging.ImageTag),
|
||||||
newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"),
|
newSimplePackageTaskFactory(wordpress.NewWordpressPluginCataloger, pkgcataloging.DirectoryTag, pkgcataloging.ImageTag, "wordpress"),
|
||||||
|
|||||||
@ -13,12 +13,13 @@ import (
|
|||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const catalogerName = "binary-classifier-cataloger"
|
const catalogerName = "binary-classifier-cataloger"
|
||||||
|
|
||||||
type ClassifierCatalogerConfig struct {
|
type ClassifierCatalogerConfig struct {
|
||||||
Classifiers []Classifier `yaml:"classifiers" json:"classifiers" mapstructure:"classifiers"`
|
Classifiers []binutils.Classifier `yaml:"classifiers" json:"classifiers" mapstructure:"classifiers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultClassifierCatalogerConfig() ClassifierCatalogerConfig {
|
func DefaultClassifierCatalogerConfig() ClassifierCatalogerConfig {
|
||||||
@ -48,7 +49,7 @@ func (cfg ClassifierCatalogerConfig) MarshalJSON() ([]byte, error) {
|
|||||||
// related runtimes like Python, Go, Java, or Node. Some exceptions can be made for widely-used binaries such
|
// related runtimes like Python, Go, Java, or Node. Some exceptions can be made for widely-used binaries such
|
||||||
// as busybox.
|
// as busybox.
|
||||||
type cataloger struct {
|
type cataloger struct {
|
||||||
classifiers []Classifier
|
classifiers []binutils.Classifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns a string that uniquely describes the cataloger
|
// Name returns a string that uniquely describes the cataloger
|
||||||
@ -101,7 +102,7 @@ func mergePackages(target *pkg.Package, extra *pkg.Package) {
|
|||||||
target.Metadata = meta
|
target.Metadata = meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func catalog(resolver file.Resolver, cls Classifier) (packages []pkg.Package, err error) {
|
func catalog(resolver file.Resolver, cls binutils.Classifier) (packages []pkg.Package, err error) {
|
||||||
var errs error
|
var errs error
|
||||||
locations, err := resolver.FilesByGlob(cls.FileGlob)
|
locations, err := resolver.FilesByGlob(cls.FileGlob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -109,7 +110,7 @@ func catalog(resolver file.Resolver, cls Classifier) (packages []pkg.Package, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
pkgs, err := cls.EvidenceMatcher(cls, matcherContext{resolver: resolver, location: location})
|
pkgs, err := cls.EvidenceMatcher(cls, binutils.MatcherContext{Resolver: resolver, Location: location})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = unknown.Append(errs, location, err)
|
errs = unknown.Append(errs, location, err)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/binary/test-fixtures/manager/testutil"
|
"github.com/anchore/syft/syft/pkg/cataloger/binary/test-fixtures/manager/testutil"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
|
||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
"github.com/anchore/syft/syft/source/directorysource"
|
"github.com/anchore/syft/syft/source/directorysource"
|
||||||
"github.com/anchore/syft/syft/source/stereoscopesource"
|
"github.com/anchore/syft/syft/source/stereoscopesource"
|
||||||
@ -248,45 +249,6 @@ func Test_Cataloger_PositiveCases(t *testing.T) {
|
|||||||
Metadata: metadata("httpd-binary"),
|
Metadata: metadata("httpd-binary"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// TODO: find original binary...
|
|
||||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
|
||||||
logicalFixture: "php-cli/8.2.1/linux-amd64",
|
|
||||||
expected: pkg.Package{
|
|
||||||
Name: "php-cli",
|
|
||||||
Version: "8.2.1",
|
|
||||||
Type: "binary",
|
|
||||||
PURL: "pkg:generic/php-cli@8.2.1",
|
|
||||||
Locations: locations("php"),
|
|
||||||
Metadata: metadata("php-cli-binary"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// TODO: find original binary...
|
|
||||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
|
||||||
logicalFixture: "php-fpm/8.2.1/linux-amd64",
|
|
||||||
expected: pkg.Package{
|
|
||||||
Name: "php-fpm",
|
|
||||||
Version: "8.2.1",
|
|
||||||
Type: "binary",
|
|
||||||
PURL: "pkg:generic/php-fpm@8.2.1",
|
|
||||||
Locations: locations("php-fpm"),
|
|
||||||
Metadata: metadata("php-fpm-binary"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// TODO: find original binary...
|
|
||||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
|
||||||
logicalFixture: "php-apache/8.2.1/linux-amd64",
|
|
||||||
expected: pkg.Package{
|
|
||||||
Name: "libphp",
|
|
||||||
Version: "8.2.1",
|
|
||||||
Type: "binary",
|
|
||||||
PURL: "pkg:generic/php@8.2.1",
|
|
||||||
Locations: locations("libphp.so"),
|
|
||||||
Metadata: metadata("php-apache-binary"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// TODO: original binary is different than whats in config.yaml
|
// TODO: original binary is different than whats in config.yaml
|
||||||
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
// note: cannot find the original binary, using a custom snippet based on the original snippet in the repo
|
||||||
@ -1497,11 +1459,13 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
Locations: locations("foo"),
|
Locations: locations("foo"),
|
||||||
Metadata: metadata("foo-binary"),
|
Metadata: metadata("foo-binary"),
|
||||||
}
|
}
|
||||||
fooClassifier := Classifier{
|
fooClassifier := binutils.Classifier{
|
||||||
Class: "foo-binary",
|
Class: "foo-binary",
|
||||||
FileGlob: "**/foo",
|
FileGlob: "**/foo",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: binutils.FileContentsVersionMatcher(
|
||||||
`(?m)foobar\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)foobar\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
||||||
|
catalogerName,
|
||||||
|
),
|
||||||
Package: "foo",
|
Package: "foo",
|
||||||
PURL: mustPURL("pkg:generic/foo@version"),
|
PURL: mustPURL("pkg:generic/foo@version"),
|
||||||
CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"),
|
CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"),
|
||||||
@ -1516,7 +1480,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "empty-negative",
|
name: "empty-negative",
|
||||||
config: ClassifierCatalogerConfig{
|
config: ClassifierCatalogerConfig{
|
||||||
Classifiers: []Classifier{},
|
Classifiers: []binutils.Classifier{},
|
||||||
},
|
},
|
||||||
fixtureDir: "test-fixtures/custom/go-1.14",
|
fixtureDir: "test-fixtures/custom/go-1.14",
|
||||||
expected: nil,
|
expected: nil,
|
||||||
@ -1532,7 +1496,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "nodefault-negative",
|
name: "nodefault-negative",
|
||||||
config: ClassifierCatalogerConfig{
|
config: ClassifierCatalogerConfig{
|
||||||
Classifiers: []Classifier{fooClassifier},
|
Classifiers: []binutils.Classifier{fooClassifier},
|
||||||
},
|
},
|
||||||
fixtureDir: "test-fixtures/custom/go-1.14",
|
fixtureDir: "test-fixtures/custom/go-1.14",
|
||||||
expected: nil,
|
expected: nil,
|
||||||
@ -1541,7 +1505,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
name: "default-extended-positive",
|
name: "default-extended-positive",
|
||||||
config: ClassifierCatalogerConfig{
|
config: ClassifierCatalogerConfig{
|
||||||
Classifiers: append(
|
Classifiers: append(
|
||||||
append([]Classifier{}, defaultClassifers...),
|
append([]binutils.Classifier{}, defaultClassifers...),
|
||||||
fooClassifier,
|
fooClassifier,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1553,11 +1517,11 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
config: ClassifierCatalogerConfig{
|
config: ClassifierCatalogerConfig{
|
||||||
|
|
||||||
Classifiers: append(
|
Classifiers: append(
|
||||||
append([]Classifier{}, defaultClassifers...),
|
append([]binutils.Classifier{}, defaultClassifers...),
|
||||||
Classifier{
|
binutils.Classifier{
|
||||||
Class: "foo-binary",
|
Class: "foo-binary",
|
||||||
FileGlob: "**/foo",
|
FileGlob: "**/foo",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(`(?m)not there`),
|
EvidenceMatcher: binutils.FileContentsVersionMatcher(`(?m)not there`, catalogerName),
|
||||||
Package: "foo",
|
Package: "foo",
|
||||||
PURL: mustPURL("pkg:generic/foo@version"),
|
PURL: mustPURL("pkg:generic/foo@version"),
|
||||||
CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"),
|
CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"),
|
||||||
@ -1571,7 +1535,7 @@ func Test_Cataloger_CustomClassifiers(t *testing.T) {
|
|||||||
name: "default-cutsom-positive",
|
name: "default-cutsom-positive",
|
||||||
config: ClassifierCatalogerConfig{
|
config: ClassifierCatalogerConfig{
|
||||||
Classifiers: append(
|
Classifiers: append(
|
||||||
append([]Classifier{}, defaultClassifers...),
|
append([]binutils.Classifier{}, defaultClassifers...),
|
||||||
fooClassifier,
|
fooClassifier,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -1771,11 +1735,11 @@ func TestCatalogerConfig_MarshalJSON(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "only show names of classes",
|
name: "only show names of classes",
|
||||||
cfg: ClassifierCatalogerConfig{
|
cfg: ClassifierCatalogerConfig{
|
||||||
Classifiers: []Classifier{
|
Classifiers: []binutils.Classifier{
|
||||||
{
|
{
|
||||||
Class: "class",
|
Class: "class",
|
||||||
FileGlob: "glob",
|
FileGlob: "glob",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(".thing"),
|
EvidenceMatcher: binutils.FileContentsVersionMatcher(".thing", catalogerName),
|
||||||
Package: "pkg",
|
Package: "pkg",
|
||||||
PURL: packageurl.PackageURL{
|
PURL: packageurl.PackageURL{
|
||||||
Type: "type",
|
Type: "type",
|
||||||
|
|||||||
@ -1,22 +1,44 @@
|
|||||||
package binary
|
package binary
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
"github.com/anchore/syft/syft/cpe"
|
"github.com/anchore/syft/syft/cpe"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL]
|
||||||
|
var pythonVersionTemplate = `(?m)\x00(?P<version>{{ .version }}[-._a-zA-Z0-9]*)\x00`
|
||||||
|
|
||||||
//nolint:funlen
|
//nolint:funlen
|
||||||
func DefaultClassifiers() []Classifier {
|
func DefaultClassifiers() []binutils.Classifier {
|
||||||
return []Classifier{
|
m := binutils.ContextualEvidenceMatchers{CatalogerName: catalogerName}
|
||||||
|
|
||||||
|
var libpythonMatcher = m.FileNameTemplateVersionMatcher(
|
||||||
|
`(?:.*/|^)libpython(?P<version>[0-9]+(?:\.[0-9]+)+)[a-z]?\.so.*$`,
|
||||||
|
pythonVersionTemplate,
|
||||||
|
)
|
||||||
|
|
||||||
|
var rubyMatcher = m.FileContentsVersionMatcher(
|
||||||
|
// ruby 3.4.0dev (2024-09-15T01:06:11Z master 532af89e3b) [x86_64-linux]
|
||||||
|
// ruby 3.4.0preview1 (2024-05-16 master 9d69619623) [x86_64-linux]
|
||||||
|
// ruby 3.3.0rc1 (2023-12-11 master a49643340e) [x86_64-linux]
|
||||||
|
// 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<version>[0-9]+\.[0-9]+\.[0-9]+((p|preview|rc|dev)[0-9]*)?) `)
|
||||||
|
|
||||||
|
return []binutils.Classifier{
|
||||||
{
|
{
|
||||||
Class: "python-binary",
|
Class: "python-binary",
|
||||||
FileGlob: "**/python*",
|
FileGlob: "**/python*",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
// try to find version information from libpython shared libraries
|
// try to find version information from libpython shared libraries
|
||||||
sharedLibraryLookup(
|
binutils.SharedLibraryLookup(
|
||||||
`^libpython[0-9]+(?:\.[0-9]+)+[a-z]?\.so.*$`,
|
`^libpython[0-9]+(?:\.[0-9]+)+[a-z]?\.so.*$`,
|
||||||
libpythonMatcher),
|
libpythonMatcher),
|
||||||
// check for version information in the binary
|
// check for version information in the binary
|
||||||
fileNameTemplateVersionMatcher(
|
m.FileNameTemplateVersionMatcher(
|
||||||
`(?:.*/|^)python(?P<version>[0-9]+(?:\.[0-9]+)+)$`,
|
`(?:.*/|^)python(?P<version>[0-9]+(?:\.[0-9]+)+)$`,
|
||||||
pythonVersionTemplate),
|
pythonVersionTemplate),
|
||||||
),
|
),
|
||||||
@ -41,7 +63,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "pypy-binary-lib",
|
Class: "pypy-binary-lib",
|
||||||
FileGlob: "**/libpypy*.so*",
|
FileGlob: "**/libpypy*.so*",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\[PyPy (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)\[PyPy (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
Package: "pypy",
|
Package: "pypy",
|
||||||
PURL: mustPURL("pkg:generic/pypy@version"),
|
PURL: mustPURL("pkg:generic/pypy@version"),
|
||||||
@ -49,7 +71,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "go-binary",
|
Class: "go-binary",
|
||||||
FileGlob: "**/go",
|
FileGlob: "**/go",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)\x00`),
|
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?)\x00`),
|
||||||
Package: "go",
|
Package: "go",
|
||||||
PURL: mustPURL("pkg:generic/go@version"),
|
PURL: mustPURL("pkg:generic/go@version"),
|
||||||
@ -58,7 +80,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "julia-binary",
|
Class: "julia-binary",
|
||||||
FileGlob: "**/libjulia-internal.so",
|
FileGlob: "**/libjulia-internal.so",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)__init__\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00verify`),
|
`(?m)__init__\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00verify`),
|
||||||
Package: "julia",
|
Package: "julia",
|
||||||
PURL: mustPURL("pkg:generic/julia@version"),
|
PURL: mustPURL("pkg:generic/julia@version"),
|
||||||
@ -67,7 +89,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "helm",
|
Class: "helm",
|
||||||
FileGlob: "**/helm",
|
FileGlob: "**/helm",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`),
|
`(?m)\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`),
|
||||||
Package: "helm",
|
Package: "helm",
|
||||||
PURL: mustPURL("pkg:golang/helm.sh/helm@version"),
|
PURL: mustPURL("pkg:golang/helm.sh/helm@version"),
|
||||||
@ -76,13 +98,13 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "redis-binary",
|
Class: "redis-binary",
|
||||||
FileGlob: "**/redis-server",
|
FileGlob: "**/redis-server",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
// matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000"
|
// matches most recent versions of redis (~v7), e.g. "7.0.14buildkitsandbox-1702957741000000000"
|
||||||
FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`),
|
m.FileContentsVersionMatcher(`[^\d](?P<version>\d+.\d+\.\d+)buildkitsandbox-\d+`),
|
||||||
// matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000"
|
// matches against older versions of redis (~v3 - v6), e.g. "4.0.11841ce7054bd9-1542359302000000000"
|
||||||
FileContentsVersionMatcher(`[^\d](?P<version>[0-9]+\.[0-9]+\.[0-9]+)\w{12}-\d+`),
|
m.FileContentsVersionMatcher(`[^\d](?P<version>[0-9]+\.[0-9]+\.[0-9]+)\w{12}-\d+`),
|
||||||
// matches against older versions of redis (~v2), e.g. "Server started, Redis version 2.8.23"
|
// matches against older versions of redis (~v2), e.g. "Server started, Redis version 2.8.23"
|
||||||
FileContentsVersionMatcher(`Redis version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
m.FileContentsVersionMatcher(`Redis version (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
),
|
),
|
||||||
Package: "redis",
|
Package: "redis",
|
||||||
PURL: mustPURL("pkg:generic/redis@version"),
|
PURL: mustPURL("pkg:generic/redis@version"),
|
||||||
@ -94,13 +116,13 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "java-binary-openjdk",
|
Class: "java-binary-openjdk",
|
||||||
FileGlob: "**/java",
|
FileGlob: "**/java",
|
||||||
EvidenceMatcher: matchExcluding(
|
EvidenceMatcher: binutils.MatchExcluding(
|
||||||
evidenceMatchers(
|
binutils.EvidenceMatchers(
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
|
// [NUL]openjdk[NUL]java[NUL]0.0[NUL]11.0.17+8-LTS[NUL]
|
||||||
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
|
// [NUL]openjdk[NUL]java[NUL]1.8[NUL]1.8.0_352-b08[NUL]
|
||||||
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
|
`(?m)\x00openjdk\x00java\x00(?P<release>[0-9]+[.0-9]*)\x00(?P<version>[0-9]+[^\x00]+)\x00`),
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
|
// arm64 versions: [NUL]0.0[NUL][NUL][NUL][NUL][NUL]11.0.22+7[NUL][NUL][NUL][NUL][NUL][NUL][NUL]openjdk[NUL]java[NUL]
|
||||||
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
|
`(?m)\x00(?P<release>[0-9]+[.0-9]*)\x00+(?P<version>[0-9]+[^\x00]+)\x00+openjdk\x00java`),
|
||||||
),
|
),
|
||||||
@ -115,7 +137,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "java-binary-ibm",
|
Class: "java-binary-ibm",
|
||||||
FileGlob: "**/java",
|
FileGlob: "**/java",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]java[NUL]1.8[NUL][NUL][NUL][NUL]1.8.0-foreman_2022_09_22_15_30-b00[NUL]
|
// [NUL]java[NUL]1.8[NUL][NUL][NUL][NUL]1.8.0-foreman_2022_09_22_15_30-b00[NUL]
|
||||||
`(?m)\x00java\x00(?P<release>[0-9]+[.0-9]+)\x00{4}(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
|
`(?m)\x00java\x00(?P<release>[0-9]+[.0-9]+)\x00{4}(?P<version>[0-9]+[-._a-zA-Z0-9]+)\x00`),
|
||||||
Package: "java/jre",
|
Package: "java/jre",
|
||||||
@ -125,8 +147,8 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "java-binary-oracle",
|
Class: "java-binary-oracle",
|
||||||
FileGlob: "**/java",
|
FileGlob: "**/java",
|
||||||
EvidenceMatcher: matchExcluding(
|
EvidenceMatcher: binutils.MatchExcluding(
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// [NUL]19.0.1+10-21[NUL]
|
// [NUL]19.0.1+10-21[NUL]
|
||||||
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`),
|
`(?m)\x00(?P<version>[0-9]+[.0-9]+[+][-0-9]+)\x00`),
|
||||||
// don't match openjdk
|
// don't match openjdk
|
||||||
@ -139,7 +161,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "java-binary-graalvm",
|
Class: "java-binary-graalvm",
|
||||||
FileGlob: "**/java",
|
FileGlob: "**/java",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
|
`(?m)\x00(?P<version>[0-9]+[.0-9]+[.0-9]+\+[0-9]+-jvmci-[0-9]+[.0-9]+-b[0-9]+)\x00`),
|
||||||
Package: "java/graalvm",
|
Package: "java/graalvm",
|
||||||
PURL: mustPURL("pkg:generic/java/graalvm@version"),
|
PURL: mustPURL("pkg:generic/java/graalvm@version"),
|
||||||
@ -148,7 +170,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "java-binary-jdk",
|
Class: "java-binary-jdk",
|
||||||
FileGlob: "**/jdb",
|
FileGlob: "**/jdb",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
|
`(?m)\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\+[0-9]+)?([-._a-zA-Z0-9]+)?)\x00`),
|
||||||
Package: "java/jdk",
|
Package: "java/jdk",
|
||||||
PURL: mustPURL("pkg:generic/java/jdk@version"),
|
PURL: mustPURL("pkg:generic/java/jdk@version"),
|
||||||
@ -157,13 +179,13 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "nodejs-binary",
|
Class: "nodejs-binary",
|
||||||
FileGlob: "**/node",
|
FileGlob: "**/node",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
// [NUL]node v0.10.48[NUL]
|
// [NUL]node v0.10.48[NUL]
|
||||||
// [NUL]v0.12.18[NUL]
|
// [NUL]v0.12.18[NUL]
|
||||||
// [NUL]v4.9.1[NUL]
|
// [NUL]v4.9.1[NUL]
|
||||||
// node.js/v22.9.0
|
// node.js/v22.9.0
|
||||||
FileContentsVersionMatcher(`(?m)\x00(node )?v(?P<version>(0|4|5|6)\.[0-9]+\.[0-9]+)\x00`),
|
m.FileContentsVersionMatcher(`(?m)\x00(node )?v(?P<version>(0|4|5|6)\.[0-9]+\.[0-9]+)\x00`),
|
||||||
FileContentsVersionMatcher(`(?m)node\.js\/v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
m.FileContentsVersionMatcher(`(?m)node\.js\/v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
),
|
),
|
||||||
Package: "node",
|
Package: "node",
|
||||||
PURL: mustPURL("pkg:generic/node@version"),
|
PURL: mustPURL("pkg:generic/node@version"),
|
||||||
@ -172,7 +194,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "go-binary-hint",
|
Class: "go-binary-hint",
|
||||||
FileGlob: "**/VERSION*",
|
FileGlob: "**/VERSION*",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?(-[0-9a-f]{7})?)`),
|
`(?m)go(?P<version>[0-9]+\.[0-9]+(\.[0-9]+|beta[0-9]+|alpha[0-9]+|rc[0-9]+)?(-[0-9a-f]{7})?)`),
|
||||||
Package: "go",
|
Package: "go",
|
||||||
PURL: mustPURL("pkg:generic/go@version"),
|
PURL: mustPURL("pkg:generic/go@version"),
|
||||||
@ -181,7 +203,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "busybox-binary",
|
Class: "busybox-binary",
|
||||||
FileGlob: "**/busybox",
|
FileGlob: "**/busybox",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)BusyBox\s+v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)BusyBox\s+v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
Package: "busybox",
|
Package: "busybox",
|
||||||
PURL: mustPURL("pkg:generic/busybox@version"),
|
PURL: mustPURL("pkg:generic/busybox@version"),
|
||||||
@ -190,7 +212,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "util-linux-binary",
|
Class: "util-linux-binary",
|
||||||
FileGlob: "**/getopt",
|
FileGlob: "**/getopt",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00util-linux\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`),
|
`\x00util-linux\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`),
|
||||||
Package: "util-linux",
|
Package: "util-linux",
|
||||||
PURL: mustPURL("pkg:generic/util-linux@version"),
|
PURL: mustPURL("pkg:generic/util-linux@version"),
|
||||||
@ -199,10 +221,10 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "haproxy-binary",
|
Class: "haproxy-binary",
|
||||||
FileGlob: "**/haproxy",
|
FileGlob: "**/haproxy",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
FileContentsVersionMatcher(`(?m)version (?P<version>[0-9]+\.[0-9]+(\.|-dev|-rc)[0-9]+)(-[a-z0-9]{7})?, released 20`),
|
m.FileContentsVersionMatcher(`(?m)version (?P<version>[0-9]+\.[0-9]+(\.|-dev|-rc)[0-9]+)(-[a-z0-9]{7})?, released 20`),
|
||||||
FileContentsVersionMatcher(`(?m)HA-Proxy version (?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)`),
|
m.FileContentsVersionMatcher(`(?m)HA-Proxy version (?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)`),
|
||||||
FileContentsVersionMatcher(`(?m)(?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)-[0-9a-zA-Z]{7}.+HAProxy version`),
|
m.FileContentsVersionMatcher(`(?m)(?P<version>[0-9]+\.[0-9]+(\.|-dev)[0-9]+)-[0-9a-zA-Z]{7}.+HAProxy version`),
|
||||||
),
|
),
|
||||||
Package: "haproxy",
|
Package: "haproxy",
|
||||||
PURL: mustPURL("pkg:generic/haproxy@version"),
|
PURL: mustPURL("pkg:generic/haproxy@version"),
|
||||||
@ -211,44 +233,16 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "perl-binary",
|
Class: "perl-binary",
|
||||||
FileGlob: "**/perl",
|
FileGlob: "**/perl",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\/usr\/local\/lib\/perl\d\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)\/usr\/local\/lib\/perl\d\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
Package: "perl",
|
Package: "perl",
|
||||||
PURL: mustPURL("pkg:generic/perl@version"),
|
PURL: mustPURL("pkg:generic/perl@version"),
|
||||||
CPEs: singleCPE("cpe:2.3:a:perl:perl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
CPEs: singleCPE("cpe:2.3:a:perl:perl:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Class: "php-cli-binary",
|
|
||||||
FileGlob: "**/php*",
|
|
||||||
EvidenceMatcher: fileNameTemplateVersionMatcher(
|
|
||||||
`(.*/|^)php[0-9]*$`,
|
|
||||||
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
|
||||||
Package: "php-cli",
|
|
||||||
PURL: mustPURL("pkg:generic/php-cli@version"),
|
|
||||||
CPEs: singleCPE("cpe:2.3:a:php:php:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Class: "php-fpm-binary",
|
|
||||||
FileGlob: "**/php-fpm*",
|
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
|
||||||
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
|
||||||
Package: "php-fpm",
|
|
||||||
PURL: mustPURL("pkg:generic/php-fpm@version"),
|
|
||||||
CPEs: singleCPE("cpe:2.3:a:php:php:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Class: "php-apache-binary",
|
|
||||||
FileGlob: "**/libphp*.so",
|
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
|
||||||
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
|
||||||
Package: "libphp",
|
|
||||||
PURL: mustPURL("pkg:generic/php@version"),
|
|
||||||
CPEs: singleCPE("cpe:2.3:a:php:php:*:*:*:*:*:*:*:*", cpe.NVDDictionaryLookupSource),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Class: "php-composer-binary",
|
Class: "php-composer-binary",
|
||||||
FileGlob: "**/composer*",
|
FileGlob: "**/composer*",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)'pretty_version'\s*=>\s*'(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)'`),
|
`(?m)'pretty_version'\s*=>\s*'(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)'`),
|
||||||
Package: "composer",
|
Package: "composer",
|
||||||
PURL: mustPURL("pkg:generic/composer@version"),
|
PURL: mustPURL("pkg:generic/composer@version"),
|
||||||
@ -257,7 +251,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "httpd-binary",
|
Class: "httpd-binary",
|
||||||
FileGlob: "**/httpd",
|
FileGlob: "**/httpd",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)Apache\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)Apache\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
Package: "httpd",
|
Package: "httpd",
|
||||||
PURL: mustPURL("pkg:generic/httpd@version"),
|
PURL: mustPURL("pkg:generic/httpd@version"),
|
||||||
@ -266,7 +260,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "memcached-binary",
|
Class: "memcached-binary",
|
||||||
FileGlob: "**/memcached",
|
FileGlob: "**/memcached",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)memcached\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
`(?m)memcached\s(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`),
|
||||||
Package: "memcached",
|
Package: "memcached",
|
||||||
PURL: mustPURL("pkg:generic/memcached@version"),
|
PURL: mustPURL("pkg:generic/memcached@version"),
|
||||||
@ -275,7 +269,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "traefik-binary",
|
Class: "traefik-binary",
|
||||||
FileGlob: "**/traefik",
|
FileGlob: "**/traefik",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]v1.7.34[NUL]
|
// [NUL]v1.7.34[NUL]
|
||||||
// [NUL]2.9.6[NUL]
|
// [NUL]2.9.6[NUL]
|
||||||
// 3.0.4[NUL]
|
// 3.0.4[NUL]
|
||||||
@ -287,7 +281,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "arangodb-binary",
|
Class: "arangodb-binary",
|
||||||
FileGlob: "**/arangosh",
|
FileGlob: "**/arangosh",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?)\s\[linux\]`),
|
`(?m)\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?)\s\[linux\]`),
|
||||||
Package: "arangodb",
|
Package: "arangodb",
|
||||||
PURL: mustPURL("pkg:generic/arangodb@version"),
|
PURL: mustPURL("pkg:generic/arangodb@version"),
|
||||||
@ -296,7 +290,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "postgresql-binary",
|
Class: "postgresql-binary",
|
||||||
FileGlob: "**/postgres",
|
FileGlob: "**/postgres",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]PostgreSQL 15beta4
|
// [NUL]PostgreSQL 15beta4
|
||||||
// [NUL]PostgreSQL 15.1
|
// [NUL]PostgreSQL 15.1
|
||||||
// [NUL]PostgreSQL 9.6.24
|
// [NUL]PostgreSQL 9.6.24
|
||||||
@ -309,11 +303,11 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "mysql-binary",
|
Class: "mysql-binary",
|
||||||
FileGlob: "**/mysql",
|
FileGlob: "**/mysql",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
// shutdown[NUL]8.0.37[NUL][NUL][NUL][NUL][NUL]mysql_real_esc
|
// shutdown[NUL]8.0.37[NUL][NUL][NUL][NUL][NUL]mysql_real_esc
|
||||||
FileContentsVersionMatcher(`\x00(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)\x00+mysql`),
|
m.FileContentsVersionMatcher(`\x00(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)\x00+mysql`),
|
||||||
// /export/home/pb2/build/sb_0-26781090-1516292385.58/release/mysql-8.0.4-rc/mysys_ssl/my_default.cc
|
// /export/home/pb2/build/sb_0-26781090-1516292385.58/release/mysql-8.0.4-rc/mysys_ssl/my_default.cc
|
||||||
FileContentsVersionMatcher(`(?m).*/mysql-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
m.FileContentsVersionMatcher(`(?m).*/mysql-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
||||||
),
|
),
|
||||||
Package: "mysql",
|
Package: "mysql",
|
||||||
PURL: mustPURL("pkg:generic/mysql@version"),
|
PURL: mustPURL("pkg:generic/mysql@version"),
|
||||||
@ -322,7 +316,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "mysql-binary",
|
Class: "mysql-binary",
|
||||||
FileGlob: "**/mysql",
|
FileGlob: "**/mysql",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m).*/percona-server-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
`(?m).*/percona-server-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
||||||
Package: "percona-server",
|
Package: "percona-server",
|
||||||
PURL: mustPURL("pkg:generic/percona-server@version"),
|
PURL: mustPURL("pkg:generic/percona-server@version"),
|
||||||
@ -334,7 +328,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "mysql-binary",
|
Class: "mysql-binary",
|
||||||
FileGlob: "**/mysql",
|
FileGlob: "**/mysql",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m).*/Percona-XtraDB-Cluster-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
`(?m).*/Percona-XtraDB-Cluster-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
||||||
Package: "percona-xtradb-cluster",
|
Package: "percona-xtradb-cluster",
|
||||||
PURL: mustPURL("pkg:generic/percona-xtradb-cluster@version"),
|
PURL: mustPURL("pkg:generic/percona-xtradb-cluster@version"),
|
||||||
@ -347,7 +341,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "xtrabackup-binary",
|
Class: "xtrabackup-binary",
|
||||||
FileGlob: "**/xtrabackup",
|
FileGlob: "**/xtrabackup",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m).*/percona-xtrabackup-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
`(?m).*/percona-xtrabackup-(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)`),
|
||||||
Package: "percona-xtrabackup",
|
Package: "percona-xtrabackup",
|
||||||
PURL: mustPURL("pkg:generic/percona-xtrabackup@version"),
|
PURL: mustPURL("pkg:generic/percona-xtrabackup@version"),
|
||||||
@ -356,7 +350,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "mariadb-binary",
|
Class: "mariadb-binary",
|
||||||
FileGlob: "**/{mariadb,mysql}",
|
FileGlob: "**/{mariadb,mysql}",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// 10.6.15-MariaDB
|
// 10.6.15-MariaDB
|
||||||
`(?m)(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)-MariaDB`),
|
`(?m)(?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)?(alpha[0-9]|beta[0-9]|rc[0-9])?)-MariaDB`),
|
||||||
Package: "mariadb",
|
Package: "mariadb",
|
||||||
@ -366,7 +360,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "rust-standard-library-linux",
|
Class: "rust-standard-library-linux",
|
||||||
FileGlob: "**/libstd-????????????????.so",
|
FileGlob: "**/libstd-????????????????.so",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// clang LLVM (rustc version 1.48.0 (7eac88abb 2020-11-16))
|
// clang LLVM (rustc version 1.48.0 (7eac88abb 2020-11-16))
|
||||||
`(?m)(\x00)clang LLVM \(rustc version (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`),
|
`(?m)(\x00)clang LLVM \(rustc version (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`),
|
||||||
Package: "rust",
|
Package: "rust",
|
||||||
@ -376,7 +370,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "rust-standard-library-macos",
|
Class: "rust-standard-library-macos",
|
||||||
FileGlob: "**/libstd-????????????????.dylib",
|
FileGlob: "**/libstd-????????????????.dylib",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// c 1.48.0 (7eac88abb 2020-11-16)
|
// c 1.48.0 (7eac88abb 2020-11-16)
|
||||||
`(?m)c (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`),
|
`(?m)c (?P<version>[0-9]+(\.[0-9]+)?(\.[0-9]+)) \(\w+ \d{4}\-\d{2}\-\d{2}\)`),
|
||||||
Package: "rust",
|
Package: "rust",
|
||||||
@ -386,9 +380,9 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "ruby-binary",
|
Class: "ruby-binary",
|
||||||
FileGlob: "**/ruby",
|
FileGlob: "**/ruby",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
rubyMatcher,
|
rubyMatcher,
|
||||||
sharedLibraryLookup(
|
binutils.SharedLibraryLookup(
|
||||||
// try to find version information from libruby shared libraries
|
// try to find version information from libruby shared libraries
|
||||||
`^libruby\.so.*$`,
|
`^libruby\.so.*$`,
|
||||||
rubyMatcher),
|
rubyMatcher),
|
||||||
@ -400,12 +394,12 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "erlang-binary",
|
Class: "erlang-binary",
|
||||||
FileGlob: "**/erlexec",
|
FileGlob: "**/erlexec",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
||||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
@ -417,16 +411,16 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "erlang-alpine-binary",
|
Class: "erlang-alpine-binary",
|
||||||
FileGlob: "**/beam.smp",
|
FileGlob: "**/beam.smp",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
||||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// [NUL][NUL]26.1.2[NUL][NUL][NUL][NUL][NUL][NUL][NUL]NUL[NUL][NUL]Erlang/OTP
|
// [NUL][NUL]26.1.2[NUL][NUL][NUL][NUL][NUL][NUL][NUL]NUL[NUL][NUL]Erlang/OTP
|
||||||
`\x00+(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)\x00+Erlang/OTP`,
|
`\x00+(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)\x00+Erlang/OTP`,
|
||||||
),
|
),
|
||||||
@ -438,12 +432,12 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "erlang-library",
|
Class: "erlang-library",
|
||||||
FileGlob: "**/liberts_internal.a",
|
FileGlob: "**/liberts_internal.a",
|
||||||
EvidenceMatcher: evidenceMatchers(
|
EvidenceMatcher: binutils.EvidenceMatchers(
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
// <artificial>[NUL]/usr/src/otp_src_25.3.2.6/erts/
|
||||||
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/src/otp_src_(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
FileContentsVersionMatcher(
|
m.FileContentsVersionMatcher(
|
||||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||||
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
`(?m)/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+(\.[0-9]+){0,2}(-rc[0-9])?)/erts/`,
|
||||||
),
|
),
|
||||||
@ -455,7 +449,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "swipl-binary",
|
Class: "swipl-binary",
|
||||||
FileGlob: "**/swipl",
|
FileGlob: "**/swipl",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)swipl-(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\/`,
|
`(?m)swipl-(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\/`,
|
||||||
),
|
),
|
||||||
Package: "swipl",
|
Package: "swipl",
|
||||||
@ -465,7 +459,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "dart-binary",
|
Class: "dart-binary",
|
||||||
FileGlob: "**/dart",
|
FileGlob: "**/dart",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// MathAtan[NUL]2.12.4 (stable)
|
// MathAtan[NUL]2.12.4 (stable)
|
||||||
// "%s"[NUL]3.0.0 (stable)
|
// "%s"[NUL]3.0.0 (stable)
|
||||||
// Dart,GC"[NUL]3.5.2 (stable)
|
// Dart,GC"[NUL]3.5.2 (stable)
|
||||||
@ -479,7 +473,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "haskell-ghc-binary",
|
Class: "haskell-ghc-binary",
|
||||||
FileGlob: "**/ghc*",
|
FileGlob: "**/ghc*",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00GHC (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
`(?m)\x00GHC (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "haskell/ghc",
|
Package: "haskell/ghc",
|
||||||
@ -489,7 +483,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "haskell-cabal-binary",
|
Class: "haskell-cabal-binary",
|
||||||
FileGlob: "**/cabal",
|
FileGlob: "**/cabal",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)\x00Cabal-(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)-`,
|
`(?m)\x00Cabal-(?P<version>[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?)-`,
|
||||||
),
|
),
|
||||||
Package: "haskell/cabal",
|
Package: "haskell/cabal",
|
||||||
@ -499,7 +493,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "haskell-stack-binary",
|
Class: "haskell-stack-binary",
|
||||||
FileGlob: "**/stack",
|
FileGlob: "**/stack",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`(?m)Version\s*(?P<version>[0-9]+\.[0-9]+\.[0-9]+),\s*Git`,
|
`(?m)Version\s*(?P<version>[0-9]+\.[0-9]+\.[0-9]+),\s*Git`,
|
||||||
),
|
),
|
||||||
Package: "haskell/stack",
|
Package: "haskell/stack",
|
||||||
@ -509,7 +503,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "consul-binary",
|
Class: "consul-binary",
|
||||||
FileGlob: "**/consul",
|
FileGlob: "**/consul",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// NOTE: This is brittle and may not work for past or future versions
|
// NOTE: This is brittle and may not work for past or future versions
|
||||||
`CONSUL_VERSION: (?P<version>\d+\.\d+\.\d+)`,
|
`CONSUL_VERSION: (?P<version>\d+\.\d+\.\d+)`,
|
||||||
),
|
),
|
||||||
@ -520,7 +514,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "nginx-binary",
|
Class: "nginx-binary",
|
||||||
FileGlob: "**/nginx",
|
FileGlob: "**/nginx",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]nginx version: nginx/1.25.1 - fetches '1.25.1'
|
// [NUL]nginx version: nginx/1.25.1 - fetches '1.25.1'
|
||||||
// [NUL]nginx version: openresty/1.21.4.1 - fetches '1.21.4' as this is the nginx version part
|
// [NUL]nginx version: openresty/1.21.4.1 - fetches '1.21.4' as this is the nginx version part
|
||||||
`(?m)(\x00|\?)nginx version: [^\/]+\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(?:\+\d+)?(?:-\d+)?)`,
|
`(?m)(\x00|\?)nginx version: [^\/]+\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(?:\+\d+)?(?:-\d+)?)`,
|
||||||
@ -535,7 +529,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "bash-binary",
|
Class: "bash-binary",
|
||||||
FileGlob: "**/bash",
|
FileGlob: "**/bash",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// @(#)Bash version 5.2.15(1) release GNU
|
// @(#)Bash version 5.2.15(1) release GNU
|
||||||
// @(#)Bash version 5.2.0(1) alpha GNU
|
// @(#)Bash version 5.2.0(1) alpha GNU
|
||||||
// @(#)Bash version 5.2.0(1) beta GNU
|
// @(#)Bash version 5.2.0(1) beta GNU
|
||||||
@ -549,7 +543,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "openssl-binary",
|
Class: "openssl-binary",
|
||||||
FileGlob: "**/openssl",
|
FileGlob: "**/openssl",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]OpenSSL 3.1.4'
|
// [NUL]OpenSSL 3.1.4'
|
||||||
// [NUL]OpenSSL 1.1.1w'
|
// [NUL]OpenSSL 1.1.1w'
|
||||||
`\x00OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+([a-z]|-alpha[0-9]|-beta[0-9]|-rc[0-9])?)`,
|
`\x00OpenSSL (?P<version>[0-9]+\.[0-9]+\.[0-9]+([a-z]|-alpha[0-9]|-beta[0-9]|-rc[0-9])?)`,
|
||||||
@ -561,7 +555,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "gcc-binary",
|
Class: "gcc-binary",
|
||||||
FileGlob: "**/gcc",
|
FileGlob: "**/gcc",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// GCC: \(GNU\) 12.3.0'
|
// GCC: \(GNU\) 12.3.0'
|
||||||
`GCC: \(GNU\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
`GCC: \(GNU\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
||||||
),
|
),
|
||||||
@ -572,7 +566,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "fluent-bit-binary",
|
Class: "fluent-bit-binary",
|
||||||
FileGlob: "**/fluent-bit",
|
FileGlob: "**/fluent-bit",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]3.0.2[NUL]%sFluent Bit
|
// [NUL]3.0.2[NUL]%sFluent Bit
|
||||||
// [NUL]2.2.3[NUL]Fluent Bit
|
// [NUL]2.2.3[NUL]Fluent Bit
|
||||||
// [NUL]2.2.1[NUL][NUL][NUL]Fluent Bit
|
// [NUL]2.2.1[NUL][NUL][NUL]Fluent Bit
|
||||||
@ -587,7 +581,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "wordpress-cli-binary",
|
Class: "wordpress-cli-binary",
|
||||||
FileGlob: "**/wp",
|
FileGlob: "**/wp",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// wp-cli/wp-cli 2.9.0'
|
// wp-cli/wp-cli 2.9.0'
|
||||||
`(?m)wp-cli/wp-cli (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
`(?m)wp-cli/wp-cli (?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
||||||
),
|
),
|
||||||
@ -598,7 +592,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "curl-binary",
|
Class: "curl-binary",
|
||||||
FileGlob: "**/curl",
|
FileGlob: "**/curl",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`curl/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
`curl/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)`,
|
||||||
),
|
),
|
||||||
Package: "curl",
|
Package: "curl",
|
||||||
@ -608,7 +602,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "lighttpd-binary",
|
Class: "lighttpd-binary",
|
||||||
FileGlob: "**/lighttpd",
|
FileGlob: "**/lighttpd",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00lighttpd/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
`\x00lighttpd/(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "lighttpd",
|
Package: "lighttpd",
|
||||||
@ -618,7 +612,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "proftpd-binary",
|
Class: "proftpd-binary",
|
||||||
FileGlob: "**/proftpd",
|
FileGlob: "**/proftpd",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00ProFTPD Version (?P<version>[0-9]+\.[0-9]+\.[0-9]+[a-z]?)\x00`,
|
`\x00ProFTPD Version (?P<version>[0-9]+\.[0-9]+\.[0-9]+[a-z]?)\x00`,
|
||||||
),
|
),
|
||||||
Package: "proftpd",
|
Package: "proftpd",
|
||||||
@ -628,7 +622,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "zstd-binary",
|
Class: "zstd-binary",
|
||||||
FileGlob: "**/zstd",
|
FileGlob: "**/zstd",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
`\x00v(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "zstd",
|
Package: "zstd",
|
||||||
@ -638,7 +632,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "xz-binary",
|
Class: "xz-binary",
|
||||||
FileGlob: "**/xz",
|
FileGlob: "**/xz",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00xz \(XZ Utils\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
`\x00xz \(XZ Utils\) (?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "xz",
|
Package: "xz",
|
||||||
@ -648,7 +642,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "gzip-binary",
|
Class: "gzip-binary",
|
||||||
FileGlob: "**/gzip",
|
FileGlob: "**/gzip",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00(?P<version>[0-9]+\.[0-9]+)\x00`,
|
`\x00(?P<version>[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "gzip",
|
Package: "gzip",
|
||||||
@ -658,7 +652,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "sqlcipher-binary",
|
Class: "sqlcipher-binary",
|
||||||
FileGlob: "**/sqlcipher",
|
FileGlob: "**/sqlcipher",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`[^0-9]\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
`[^0-9]\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00`,
|
||||||
),
|
),
|
||||||
Package: "sqlcipher",
|
Package: "sqlcipher",
|
||||||
@ -668,7 +662,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "jq-binary",
|
Class: "jq-binary",
|
||||||
FileGlob: "**/jq",
|
FileGlob: "**/jq",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
`\x00(?P<version>[0-9]{1,3}\.[0-9]{1,3}(\.[0-9]+)?)\x00`,
|
`\x00(?P<version>[0-9]{1,3}\.[0-9]{1,3}(\.[0-9]+)?)\x00`,
|
||||||
),
|
),
|
||||||
Package: "jq",
|
Package: "jq",
|
||||||
@ -678,7 +672,7 @@ func DefaultClassifiers() []Classifier {
|
|||||||
{
|
{
|
||||||
Class: "chrome-binary",
|
Class: "chrome-binary",
|
||||||
FileGlob: "**/chrome",
|
FileGlob: "**/chrome",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
// [NUL]127.0.6533.119[NUL]Default
|
// [NUL]127.0.6533.119[NUL]Default
|
||||||
`\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\x00Default`,
|
`\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\x00Default`,
|
||||||
),
|
),
|
||||||
@ -689,18 +683,22 @@ func DefaultClassifiers() []Classifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// in both binaries and shared libraries, the version pattern is [NUL]3.11.2[NUL]
|
// singleCPE returns a []cpe.CPE with Source: Generated based on the cpe string or panics if the
|
||||||
var pythonVersionTemplate = `(?m)\x00(?P<version>{{ .version }}[-._a-zA-Z0-9]*)\x00`
|
// cpe string cannot be parsed into valid CPE Attributes
|
||||||
|
func singleCPE(cpeString string, source ...cpe.Source) []cpe.CPE {
|
||||||
|
src := cpe.GeneratedSource
|
||||||
|
if len(source) > 0 {
|
||||||
|
src = source[0]
|
||||||
|
}
|
||||||
|
return []cpe.CPE{
|
||||||
|
cpe.Must(cpeString, src),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var libpythonMatcher = fileNameTemplateVersionMatcher(
|
func mustPURL(purl string) packageurl.PackageURL {
|
||||||
`(?:.*/|^)libpython(?P<version>[0-9]+(?:\.[0-9]+)+)[a-z]?\.so.*$`,
|
p, err := packageurl.FromString(purl)
|
||||||
pythonVersionTemplate,
|
if err != nil {
|
||||||
)
|
panic(fmt.Sprintf("invalid PURL: %s", p))
|
||||||
|
}
|
||||||
var rubyMatcher = FileContentsVersionMatcher(
|
return p
|
||||||
// ruby 3.4.0dev (2024-09-15T01:06:11Z master 532af89e3b) [x86_64-linux]
|
}
|
||||||
// ruby 3.4.0preview1 (2024-05-16 master 9d69619623) [x86_64-linux]
|
|
||||||
// ruby 3.3.0rc1 (2023-12-11 master a49643340e) [x86_64-linux]
|
|
||||||
// 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<version>[0-9]+\.[0-9]+\.[0-9]+((p|preview|rc|dev)[0-9]*)?) `)
|
|
||||||
|
|||||||
18
syft/pkg/cataloger/binary/deprecated.go
Normal file
18
syft/pkg/cataloger/binary/deprecated.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package binary
|
||||||
|
|
||||||
|
import "github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
|
||||||
|
|
||||||
|
// Note: all generic utilities for catalogers have been moved to the internal/binutils package.
|
||||||
|
|
||||||
|
// Deprecated: This package is deprecated and will be removed in syft v2
|
||||||
|
type Classifier = binutils.Classifier
|
||||||
|
|
||||||
|
// Deprecated: This package is deprecated and will be removed in syft v2
|
||||||
|
type EvidenceMatcher = binutils.EvidenceMatcher
|
||||||
|
|
||||||
|
// Deprecated: This package is deprecated and will be removed in syft v2
|
||||||
|
func FileContentsVersionMatcher(
|
||||||
|
pattern string,
|
||||||
|
) EvidenceMatcher {
|
||||||
|
return binutils.FileContentsVersionMatcher(pattern, catalogerName)
|
||||||
|
}
|
||||||
@ -1,12 +0,0 @@
|
|||||||
name: php
|
|
||||||
offset: unknown
|
|
||||||
length: unknown
|
|
||||||
snippetSha256: d39ac8dadf5ba868455c487f1d0bb4c8bec64006fd7e5d76e3e27a26e47e637f
|
|
||||||
fileSha256: unknown
|
|
||||||
|
|
||||||
### byte snippet to follow ###
|
|
||||||
%s'
|
|
||||||
%s,%s
|
|
||||||
X-Powered-By: PHP/8.2.1
|
|
||||||
index pointer
|
|
||||||
PHP_VERSION
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
name: php-fpm
|
|
||||||
offset: unknown
|
|
||||||
length: unknown
|
|
||||||
snippetSha256: d39ac8dadf5ba868455c487f1d0bb4c8bec64006fd7e5d76e3e27a26e47e637f
|
|
||||||
fileSha256: unknown
|
|
||||||
|
|
||||||
### byte snippet to follow ###
|
|
||||||
%s'
|
|
||||||
%s,%s
|
|
||||||
X-Powered-By: PHP/8.2.1
|
|
||||||
index pointer
|
|
||||||
PHP_VERSION
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package binary
|
package binutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -34,7 +34,7 @@ type Classifier struct {
|
|||||||
// location. If the matcher returns a package, the file will be considered a candidate.
|
// location. If the matcher returns a package, the file will be considered a candidate.
|
||||||
EvidenceMatcher EvidenceMatcher `json:"-"`
|
EvidenceMatcher EvidenceMatcher `json:"-"`
|
||||||
|
|
||||||
// Information below is used to specify the Package information when returned
|
// The information below is used to specify the Package information when returned
|
||||||
|
|
||||||
// Package is the name to use for the package
|
// Package is the name to use for the package
|
||||||
Package string `json:"package"`
|
Package string `json:"package"`
|
||||||
@ -72,16 +72,16 @@ func (cfg Classifier) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EvidenceMatcher is a function called to catalog Packages that match some sort of evidence
|
// EvidenceMatcher is a function called to catalog Packages that match some sort of evidence
|
||||||
type EvidenceMatcher func(classifier Classifier, context matcherContext) ([]pkg.Package, error)
|
type EvidenceMatcher func(classifier Classifier, context MatcherContext) ([]pkg.Package, error)
|
||||||
|
|
||||||
type matcherContext struct {
|
type MatcherContext struct {
|
||||||
resolver file.Resolver
|
Resolver file.Resolver
|
||||||
location file.Location
|
Location file.Location
|
||||||
getReader func(resolver matcherContext) (unionreader.UnionReader, error)
|
GetReader func(resolver MatcherContext) (unionreader.UnionReader, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func evidenceMatchers(matchers ...EvidenceMatcher) EvidenceMatcher {
|
func EvidenceMatchers(matchers ...EvidenceMatcher) EvidenceMatcher {
|
||||||
return func(classifier Classifier, context matcherContext) ([]pkg.Package, error) {
|
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
|
||||||
for _, matcher := range matchers {
|
for _, matcher := range matchers {
|
||||||
match, err := matcher(classifier, context)
|
match, err := matcher(classifier, context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,14 +95,26 @@ func evidenceMatchers(matchers ...EvidenceMatcher) EvidenceMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate string) EvidenceMatcher {
|
type ContextualEvidenceMatchers struct {
|
||||||
|
CatalogerName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ContextualEvidenceMatchers) FileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate string) EvidenceMatcher {
|
||||||
|
return FileNameTemplateVersionMatcher(fileNamePattern, contentTemplate, c.CatalogerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ContextualEvidenceMatchers) FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
||||||
|
return FileContentsVersionMatcher(pattern, c.CatalogerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FileNameTemplateVersionMatcher(fileNamePattern, contentTemplate, catalogerName string) EvidenceMatcher {
|
||||||
pat := regexp.MustCompile(fileNamePattern)
|
pat := regexp.MustCompile(fileNamePattern)
|
||||||
return func(classifier Classifier, context matcherContext) ([]pkg.Package, error) {
|
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
|
||||||
if !pat.MatchString(context.location.RealPath) {
|
if !pat.MatchString(context.Location.RealPath) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
filepathNamedGroupValues := internal.MatchNamedCaptureGroups(pat, context.location.RealPath)
|
filepathNamedGroupValues := internal.MatchNamedCaptureGroups(pat, context.Location.RealPath)
|
||||||
|
|
||||||
// versions like 3.5 should not match any character, but explicit dot
|
// versions like 3.5 should not match any character, but explicit dot
|
||||||
for k, v := range filepathNamedGroupValues {
|
for k, v := range filepathNamedGroupValues {
|
||||||
@ -135,7 +147,7 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
|
|||||||
return nil, fmt.Errorf("unable to match version: %w", err)
|
return nil, fmt.Errorf("unable to match version: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := newClassifierPackage(classifier, context.location, matchMetadata)
|
p := NewClassifierPackage(classifier, context.Location, matchMetadata, catalogerName)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -144,9 +156,9 @@ func fileNameTemplateVersionMatcher(fileNamePattern string, contentTemplate stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
func FileContentsVersionMatcher(pattern, catalogerName string) EvidenceMatcher {
|
||||||
pat := regexp.MustCompile(pattern)
|
pat := regexp.MustCompile(pattern)
|
||||||
return func(classifier Classifier, context matcherContext) ([]pkg.Package, error) {
|
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
|
||||||
contents, err := getReader(context)
|
contents, err := getReader(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
||||||
@ -173,7 +185,7 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p := newClassifierPackage(classifier, context.location, matchMetadata)
|
p := NewClassifierPackage(classifier, context.Location, matchMetadata, catalogerName)
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -182,14 +194,14 @@ func FileContentsVersionMatcher(pattern string) EvidenceMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchExcluding tests the provided regular expressions against the file, and if matched, DOES NOT return
|
// MatchExcluding tests the provided regular expressions against the file, and if matched, DOES NOT return
|
||||||
// anything that the matcher would otherwise return
|
// anything that the matcher would otherwise return
|
||||||
func matchExcluding(matcher EvidenceMatcher, contentPatternsToExclude ...string) EvidenceMatcher {
|
func MatchExcluding(matcher EvidenceMatcher, contentPatternsToExclude ...string) EvidenceMatcher {
|
||||||
var nonMatchPatterns []*regexp.Regexp
|
var nonMatchPatterns []*regexp.Regexp
|
||||||
for _, p := range contentPatternsToExclude {
|
for _, p := range contentPatternsToExclude {
|
||||||
nonMatchPatterns = append(nonMatchPatterns, regexp.MustCompile(p))
|
nonMatchPatterns = append(nonMatchPatterns, regexp.MustCompile(p))
|
||||||
}
|
}
|
||||||
return func(classifier Classifier, context matcherContext) ([]pkg.Package, error) {
|
return func(classifier Classifier, context MatcherContext) ([]pkg.Package, error) {
|
||||||
contents, err := getReader(context)
|
contents, err := getReader(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
return nil, fmt.Errorf("unable to get read contents for file: %w", err)
|
||||||
@ -205,9 +217,9 @@ func matchExcluding(matcher EvidenceMatcher, contentPatternsToExclude ...string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher EvidenceMatcher) EvidenceMatcher {
|
func SharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher EvidenceMatcher) EvidenceMatcher {
|
||||||
pat := regexp.MustCompile(sharedLibraryPattern)
|
pat := regexp.MustCompile(sharedLibraryPattern)
|
||||||
return func(classifier Classifier, context matcherContext) (packages []pkg.Package, _ error) {
|
return func(classifier Classifier, context MatcherContext) (packages []pkg.Package, _ error) {
|
||||||
libs, err := sharedLibraries(context)
|
libs, err := sharedLibraries(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -217,24 +229,24 @@ func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher Evide
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
locations, err := context.resolver.FilesByGlob("**/" + lib)
|
locations, err := context.Resolver.FilesByGlob("**/" + lib)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, libraryLocation := range locations {
|
for _, libraryLocation := range locations {
|
||||||
newResolver := matcherContext{
|
newResolver := MatcherContext{
|
||||||
resolver: context.resolver,
|
Resolver: context.Resolver,
|
||||||
location: libraryLocation,
|
Location: libraryLocation,
|
||||||
getReader: context.getReader,
|
GetReader: context.GetReader,
|
||||||
}
|
}
|
||||||
newResolver.location = libraryLocation
|
newResolver.Location = libraryLocation
|
||||||
pkgs, err := sharedLibraryMatcher(classifier, newResolver)
|
pkgs, err := sharedLibraryMatcher(classifier, newResolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
// set the source binary as the first location
|
// set the source binary as the first location
|
||||||
locationSet := file.NewLocationSet(context.location)
|
locationSet := file.NewLocationSet(context.Location)
|
||||||
locationSet.Add(p.Locations.ToSlice()...)
|
locationSet.Add(p.Locations.ToSlice()...)
|
||||||
p.Locations = locationSet
|
p.Locations = locationSet
|
||||||
meta, _ := p.Metadata.(pkg.BinarySignature)
|
meta, _ := p.Metadata.(pkg.BinarySignature)
|
||||||
@ -242,7 +254,7 @@ func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher Evide
|
|||||||
Matches: append([]pkg.ClassifierMatch{
|
Matches: append([]pkg.ClassifierMatch{
|
||||||
{
|
{
|
||||||
Classifier: classifier.Class,
|
Classifier: classifier.Class,
|
||||||
Location: context.location,
|
Location: context.Location,
|
||||||
},
|
},
|
||||||
}, meta.Matches...),
|
}, meta.Matches...),
|
||||||
}
|
}
|
||||||
@ -254,19 +266,11 @@ func sharedLibraryLookup(sharedLibraryPattern string, sharedLibraryMatcher Evide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustPURL(purl string) packageurl.PackageURL {
|
func getReader(context MatcherContext) (unionreader.UnionReader, error) {
|
||||||
p, err := packageurl.FromString(purl)
|
if context.GetReader != nil {
|
||||||
if err != nil {
|
return context.GetReader(context)
|
||||||
panic(fmt.Sprintf("invalid PURL: %s", p))
|
|
||||||
}
|
}
|
||||||
return p
|
reader, err := context.Resolver.FileContentsByLocation(context.Location) //nolint:gocritic
|
||||||
}
|
|
||||||
|
|
||||||
func getReader(context matcherContext) (unionreader.UnionReader, error) {
|
|
||||||
if context.getReader != nil {
|
|
||||||
return context.getReader(context)
|
|
||||||
}
|
|
||||||
reader, err := context.resolver.FileContentsByLocation(context.location) //nolint:gocritic
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -274,32 +278,20 @@ func getReader(context matcherContext) (unionreader.UnionReader, error) {
|
|||||||
return unionreader.GetUnionReader(reader)
|
return unionreader.GetUnionReader(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// singleCPE returns a []cpe.CPE with Source: Generated based on the cpe string or panics if the
|
|
||||||
// cpe string cannot be parsed into valid CPE Attributes
|
|
||||||
func singleCPE(cpeString string, source ...cpe.Source) []cpe.CPE {
|
|
||||||
src := cpe.GeneratedSource
|
|
||||||
if len(source) > 0 {
|
|
||||||
src = source[0]
|
|
||||||
}
|
|
||||||
return []cpe.CPE{
|
|
||||||
cpe.Must(cpeString, src),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sharedLibraries returns a list of all shared libraries found within a binary, currently
|
// sharedLibraries returns a list of all shared libraries found within a binary, currently
|
||||||
// supporting: elf, macho, and windows pe
|
// supporting: elf, macho, and windows pe
|
||||||
func sharedLibraries(context matcherContext) ([]string, error) {
|
func sharedLibraries(context MatcherContext) ([]string, error) {
|
||||||
contents, err := getReader(context)
|
contents, err := getReader(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer internal.CloseAndLogError(contents, context.location.RealPath)
|
defer internal.CloseAndLogError(contents, context.Location.RealPath)
|
||||||
|
|
||||||
e, _ := elf.NewFile(contents)
|
e, _ := elf.NewFile(contents)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
symbols, err := e.ImportedLibraries()
|
symbols, err := e.ImportedLibraries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to read elf binary at: %s -- %s", context.location.RealPath, err)
|
log.Debugf("unable to read elf binary at: %s -- %s", context.Location.RealPath, err)
|
||||||
}
|
}
|
||||||
return symbols, nil
|
return symbols, nil
|
||||||
}
|
}
|
||||||
@ -311,7 +303,7 @@ func sharedLibraries(context matcherContext) ([]string, error) {
|
|||||||
if m != nil {
|
if m != nil {
|
||||||
symbols, err := m.ImportedLibraries()
|
symbols, err := m.ImportedLibraries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to read macho binary at: %s -- %s", context.location.RealPath, err)
|
log.Debugf("unable to read macho binary at: %s -- %s", context.Location.RealPath, err)
|
||||||
}
|
}
|
||||||
return symbols, nil
|
return symbols, nil
|
||||||
}
|
}
|
||||||
@ -323,7 +315,7 @@ func sharedLibraries(context matcherContext) ([]string, error) {
|
|||||||
if p != nil {
|
if p != nil {
|
||||||
symbols, err := p.ImportedLibraries()
|
symbols, err := p.ImportedLibraries()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("unable to read pe binary at: %s -- %s", context.location.RealPath, err)
|
log.Debugf("unable to read pe binary at: %s -- %s", context.Location.RealPath, err)
|
||||||
}
|
}
|
||||||
return symbols, nil
|
return symbols, nil
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package binary
|
package binutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
var emptyPURL = packageurl.PackageURL{}
|
var emptyPURL = packageurl.PackageURL{}
|
||||||
|
|
||||||
func newClassifierPackage(classifier Classifier, location file.Location, matchMetadata map[string]string) *pkg.Package {
|
func NewClassifierPackage(classifier Classifier, location file.Location, matchMetadata map[string]string, catalogerName string) *pkg.Package {
|
||||||
version, ok := matchMetadata["version"]
|
version, ok := matchMetadata["version"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package binary
|
package binutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -27,7 +27,7 @@ func Test_ClassifierCPEs(t *testing.T) {
|
|||||||
classifier: Classifier{
|
classifier: Classifier{
|
||||||
Package: "some-app",
|
Package: "some-app",
|
||||||
FileGlob: "**/version.txt",
|
FileGlob: "**/version.txt",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
|
||||||
CPEs: []cpe.CPE{},
|
CPEs: []cpe.CPE{},
|
||||||
},
|
},
|
||||||
cpes: nil,
|
cpes: nil,
|
||||||
@ -38,7 +38,7 @@ func Test_ClassifierCPEs(t *testing.T) {
|
|||||||
classifier: Classifier{
|
classifier: Classifier{
|
||||||
Package: "some-app",
|
Package: "some-app",
|
||||||
FileGlob: "**/version.txt",
|
FileGlob: "**/version.txt",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
|
||||||
CPEs: []cpe.CPE{
|
CPEs: []cpe.CPE{
|
||||||
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
||||||
},
|
},
|
||||||
@ -53,7 +53,7 @@ func Test_ClassifierCPEs(t *testing.T) {
|
|||||||
classifier: Classifier{
|
classifier: Classifier{
|
||||||
Package: "some-app",
|
Package: "some-app",
|
||||||
FileGlob: "**/version.txt",
|
FileGlob: "**/version.txt",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`),
|
EvidenceMatcher: FileContentsVersionMatcher(`(?m)my-verison:(?P<version>[0-9.]+)`, "cataloger-name"),
|
||||||
CPEs: []cpe.CPE{
|
CPEs: []cpe.CPE{
|
||||||
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
||||||
cpe.Must("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
cpe.Must("cpe:2.3:a:some:apps:*:*:*:*:*:*:*:*", cpe.GeneratedSource),
|
||||||
@ -70,7 +70,7 @@ func Test_ClassifierCPEs(t *testing.T) {
|
|||||||
classifier: Classifier{
|
classifier: Classifier{
|
||||||
Package: "some-app",
|
Package: "some-app",
|
||||||
FileGlob: "**/version-parts.txt",
|
FileGlob: "**/version-parts.txt",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(`(?m)\x00(?P<major>[0-9.]+)\x00(?P<minor>[0-9.]+)\x00(?P<patch>[0-9.]+)\x00`),
|
EvidenceMatcher: FileContentsVersionMatcher(`(?m)\x00(?P<major>[0-9.]+)\x00(?P<minor>[0-9.]+)\x00(?P<patch>[0-9.]+)\x00`, "cataloger-name"),
|
||||||
CPEs: []cpe.CPE{},
|
CPEs: []cpe.CPE{},
|
||||||
},
|
},
|
||||||
cpes: nil,
|
cpes: nil,
|
||||||
@ -84,7 +84,7 @@ func Test_ClassifierCPEs(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, ls, 1)
|
require.Len(t, ls, 1)
|
||||||
|
|
||||||
pkgs, err := test.classifier.EvidenceMatcher(test.classifier, matcherContext{resolver: resolver, location: ls[0]})
|
pkgs, err := test.classifier.EvidenceMatcher(test.classifier, MatcherContext{Resolver: resolver, Location: ls[0]})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Len(t, pkgs, 1)
|
require.Len(t, pkgs, 1)
|
||||||
@ -113,7 +113,7 @@ func TestClassifier_MarshalJSON(t *testing.T) {
|
|||||||
classifier: Classifier{
|
classifier: Classifier{
|
||||||
Class: "class",
|
Class: "class",
|
||||||
FileGlob: "glob",
|
FileGlob: "glob",
|
||||||
EvidenceMatcher: FileContentsVersionMatcher(".thing"),
|
EvidenceMatcher: FileContentsVersionMatcher(".thing", "cataloger-name"),
|
||||||
Package: "pkg",
|
Package: "pkg",
|
||||||
PURL: packageurl.PackageURL{
|
PURL: packageurl.PackageURL{
|
||||||
Type: "type",
|
Type: "type",
|
||||||
@ -165,12 +165,12 @@ func TestFileContentsVersionMatcher(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mockGetContent := func(context matcherContext) (unionreader.UnionReader, error) {
|
mockGetContent := func(context MatcherContext) (unionreader.UnionReader, error) {
|
||||||
return unionreader.GetUnionReader(io.NopCloser(bytes.NewBufferString(tt.data)))
|
return unionreader.GetUnionReader(io.NopCloser(bytes.NewBufferString(tt.data)))
|
||||||
}
|
}
|
||||||
fn := FileContentsVersionMatcher(tt.pattern)
|
fn := FileContentsVersionMatcher(tt.pattern, "cataloger-name")
|
||||||
p, err := fn(Classifier{}, matcherContext{
|
p, err := fn(Classifier{}, MatcherContext{
|
||||||
getReader: mockGetContent,
|
GetReader: mockGetContent,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
240
syft/pkg/cataloger/php/interpreter_cataloger.go
Normal file
240
syft/pkg/cataloger/php/interpreter_cataloger.go
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
package php
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/internal/unknown"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/cpe"
|
||||||
|
"github.com/anchore/syft/syft/file"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/binutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type interpreterCataloger struct {
|
||||||
|
name string
|
||||||
|
extensionsGlob string
|
||||||
|
interpreterClassifiers []binutils.Classifier
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInterpreterCataloger returns a new cataloger for PHP interpreters (php and php-fpm) as well as any installed C extensions.
|
||||||
|
func NewInterpreterCataloger() pkg.Cataloger { //nolint:funlen
|
||||||
|
name := "php-interpreter-cataloger"
|
||||||
|
m := binutils.ContextualEvidenceMatchers{CatalogerName: name}
|
||||||
|
return interpreterCataloger{
|
||||||
|
name: name,
|
||||||
|
// example matches:
|
||||||
|
// - as found in php-fpm docker library images: /usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so
|
||||||
|
// - as found in alpine images: /usr/lib/php83/modules/bcmath.so
|
||||||
|
extensionsGlob: "**/php*/**/*.so",
|
||||||
|
interpreterClassifiers: []binutils.Classifier{
|
||||||
|
{
|
||||||
|
Class: "php-cli-binary",
|
||||||
|
FileGlob: "**/php*",
|
||||||
|
EvidenceMatcher: m.FileNameTemplateVersionMatcher(
|
||||||
|
`(.*/|^)php[0-9]*$`,
|
||||||
|
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
||||||
|
Package: "php-cli",
|
||||||
|
PURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGeneric,
|
||||||
|
Name: "php-cli",
|
||||||
|
// the version will be filled in dynamically
|
||||||
|
},
|
||||||
|
CPEs: []cpe.CPE{
|
||||||
|
{
|
||||||
|
Attributes: cpe.Attributes{
|
||||||
|
Part: "a",
|
||||||
|
Vendor: "php",
|
||||||
|
Product: "php",
|
||||||
|
},
|
||||||
|
Source: cpe.NVDDictionaryLookupSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Class: "php-fpm-binary",
|
||||||
|
FileGlob: "**/php-fpm*",
|
||||||
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
|
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
||||||
|
Package: "php-fpm",
|
||||||
|
PURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGeneric,
|
||||||
|
Name: "php-fpm",
|
||||||
|
// the version will be filled in dynamically
|
||||||
|
},
|
||||||
|
CPEs: []cpe.CPE{
|
||||||
|
{
|
||||||
|
Attributes: cpe.Attributes{
|
||||||
|
Part: "a",
|
||||||
|
Vendor: "php",
|
||||||
|
Product: "php",
|
||||||
|
},
|
||||||
|
Source: cpe.NVDDictionaryLookupSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Class: "php-apache-binary",
|
||||||
|
FileGlob: "**/apache*/**/libphp*.so",
|
||||||
|
EvidenceMatcher: m.FileContentsVersionMatcher(
|
||||||
|
`(?m)X-Powered-By: PHP\/(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)`),
|
||||||
|
Package: "libphp",
|
||||||
|
PURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGeneric,
|
||||||
|
Name: "php",
|
||||||
|
// the version will be filled in dynamically
|
||||||
|
},
|
||||||
|
CPEs: []cpe.CPE{
|
||||||
|
{
|
||||||
|
Attributes: cpe.Attributes{
|
||||||
|
Part: "a",
|
||||||
|
Vendor: "php",
|
||||||
|
Product: "php",
|
||||||
|
},
|
||||||
|
Source: cpe.NVDDictionaryLookupSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) Name() string {
|
||||||
|
return p.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) Catalog(_ context.Context, resolver file.Resolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
interpreterPkgs, intErrs := p.catalogInterpreters(resolver)
|
||||||
|
extensionPkgs, extErrs := p.catalogExtensions(resolver)
|
||||||
|
|
||||||
|
// TODO: a future iteration of this cataloger could be to read all php.ini / php/conf.d/*.ini files and indicate which extensions are enabled
|
||||||
|
// and attempt to resolve the extension_dir. This can be tricky as it is a #define in the php source code and not always available
|
||||||
|
// in configuration. For the meantime we report all extensions present
|
||||||
|
|
||||||
|
// create a relationship for each interpreter package to the extensions
|
||||||
|
var relationships []artifact.Relationship
|
||||||
|
for _, interpreter := range interpreterPkgs {
|
||||||
|
for _, extension := range extensionPkgs {
|
||||||
|
relationships = append(relationships, artifact.Relationship{
|
||||||
|
From: extension,
|
||||||
|
To: interpreter,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var allPkgs []pkg.Package
|
||||||
|
allPkgs = append(allPkgs, interpreterPkgs...)
|
||||||
|
allPkgs = append(allPkgs, extensionPkgs...)
|
||||||
|
|
||||||
|
return allPkgs, relationships, unknown.Join(intErrs, extErrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) catalogInterpreters(resolver file.Resolver) ([]pkg.Package, error) {
|
||||||
|
var errs error
|
||||||
|
var packages []pkg.Package
|
||||||
|
for _, cls := range p.interpreterClassifiers {
|
||||||
|
locations, err := resolver.FilesByGlob(cls.FileGlob)
|
||||||
|
if err != nil {
|
||||||
|
// convert any file.Resolver path errors to unknowns with locations
|
||||||
|
errs = unknown.Join(errs, unknown.ProcessPathErrors(err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, location := range locations {
|
||||||
|
pkgs, err := cls.EvidenceMatcher(cls, binutils.MatcherContext{Resolver: resolver, Location: location})
|
||||||
|
if err != nil {
|
||||||
|
errs = unknown.Append(errs, location, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
packages = append(packages, pkgs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packages, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) catalogExtensions(resolver file.Resolver) ([]pkg.Package, error) {
|
||||||
|
locations, err := resolver.FilesByGlob(p.extensionsGlob)
|
||||||
|
if err != nil {
|
||||||
|
// convert any file.Resolver path errors to unknowns with locations
|
||||||
|
return nil, unknown.ProcessPathErrors(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var packages []pkg.Package
|
||||||
|
var errs error
|
||||||
|
for _, location := range locations {
|
||||||
|
pkgs, err := p.catalogExtension(resolver, location)
|
||||||
|
if err != nil {
|
||||||
|
errs = unknown.Append(errs, location, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
packages = append(packages, pkgs...)
|
||||||
|
}
|
||||||
|
return packages, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) catalogExtension(resolver file.Resolver, location file.Location) ([]pkg.Package, error) {
|
||||||
|
reader, err := resolver.FileContentsByLocation(location)
|
||||||
|
defer internal.CloseAndLogError(reader, location.RealPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, unknown.ProcessPathErrors(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
name, cls := p.getClassifier(location.RealPath)
|
||||||
|
if name == "" || cls == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgs, err := cls.EvidenceMatcher(*cls, binutils.MatcherContext{Resolver: resolver, Location: location})
|
||||||
|
if err != nil {
|
||||||
|
return nil, unknown.New(location, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p interpreterCataloger) getClassifier(realPath string) (string, *binutils.Classifier) {
|
||||||
|
if !strings.HasSuffix(realPath, ".so") {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
base := path.Base(realPath)
|
||||||
|
name := strings.TrimSuffix(base, ".so")
|
||||||
|
|
||||||
|
var match string
|
||||||
|
switch name {
|
||||||
|
case "mysqli":
|
||||||
|
match = `(mysqlnd|mysqli)?\s*\x00*(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00+API`
|
||||||
|
case "opcache":
|
||||||
|
match = `(?m)\x00+(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00+`
|
||||||
|
case "zip":
|
||||||
|
match = `\x00+(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00+Zip`
|
||||||
|
default:
|
||||||
|
match = fmt.Sprintf(`(?m)(\x00+%s)?\x00+(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00+API`, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return name, &binutils.Classifier{
|
||||||
|
Class: fmt.Sprintf("php-ext-%s-binary", name),
|
||||||
|
EvidenceMatcher: binutils.FileContentsVersionMatcher(match, p.name),
|
||||||
|
Package: name,
|
||||||
|
PURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeGeneric,
|
||||||
|
Name: name,
|
||||||
|
// the version will be filled in dynamically
|
||||||
|
},
|
||||||
|
CPEs: []cpe.CPE{
|
||||||
|
{
|
||||||
|
Attributes: cpe.Attributes{
|
||||||
|
Part: "a",
|
||||||
|
Vendor: fmt.Sprintf("php-%s", name),
|
||||||
|
Product: fmt.Sprintf("php-%s", name),
|
||||||
|
},
|
||||||
|
Source: cpe.GeneratedSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
149
syft/pkg/cataloger/php/interpreter_cataloger_test.go
Normal file
149
syft/pkg/cataloger/php/interpreter_cataloger_test.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package php
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_InterpreterCataloger(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fixture string
|
||||||
|
expectedPkgs []string
|
||||||
|
expectedRels []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "native installation with extensions",
|
||||||
|
fixture: "image-extensions",
|
||||||
|
expectedPkgs: []string{
|
||||||
|
// interpreters
|
||||||
|
"php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
|
||||||
|
// extensions
|
||||||
|
"bcmath @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so)",
|
||||||
|
"exif @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so)",
|
||||||
|
"ftp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so)",
|
||||||
|
"gd @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so)",
|
||||||
|
"gmp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so)",
|
||||||
|
"intl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so)",
|
||||||
|
"ldap @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so)",
|
||||||
|
"opcache @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so)",
|
||||||
|
"pcntl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so)",
|
||||||
|
"pdo_mysql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so)",
|
||||||
|
"pdo_pgsql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so)",
|
||||||
|
"sodium @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so)",
|
||||||
|
"sysvsem @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sysvsem.so)",
|
||||||
|
"zip @ 1.22.3 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/zip.so)",
|
||||||
|
},
|
||||||
|
expectedRels: []string{
|
||||||
|
"bcmath @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"bcmath @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"exif @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"exif @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"ftp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"ftp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"gd @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"gd @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"gmp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"gmp @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"intl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"intl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"ldap @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"ldap @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"opcache @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"opcache @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"pcntl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"pcntl @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"pdo_mysql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"pdo_mysql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"pdo_pgsql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"pdo_pgsql @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"sodium @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"sodium @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"sysvsem @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sysvsem.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"sysvsem @ 8.3.21 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sysvsem.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
"zip @ 1.22.3 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/zip.so) [dependency-of] php-cli @ 8.3.21 (/usr/local/bin/php)",
|
||||||
|
"zip @ 1.22.3 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/zip.so) [dependency-of] php-fpm @ 8.3.21 (/usr/local/sbin/php-fpm)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "apache installation with libphp and extensions",
|
||||||
|
fixture: "image-apache",
|
||||||
|
expectedPkgs: []string{
|
||||||
|
// interpreters
|
||||||
|
"libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
|
||||||
|
// extensions
|
||||||
|
"calendar @ 8.2.28 (/usr/lib/php/20220829/calendar.so)",
|
||||||
|
"ctype @ 8.2.28 (/usr/lib/php/20220829/ctype.so)",
|
||||||
|
"exif @ 8.2.28 (/usr/lib/php/20220829/exif.so)",
|
||||||
|
"ffi @ 8.2.28 (/usr/lib/php/20220829/ffi.so)",
|
||||||
|
"fileinfo @ 8.2.28 (/usr/lib/php/20220829/fileinfo.so)",
|
||||||
|
"ftp @ 8.2.28 (/usr/lib/php/20220829/ftp.so)",
|
||||||
|
"gettext @ 8.2.28 (/usr/lib/php/20220829/gettext.so)",
|
||||||
|
"iconv @ 8.2.28 (/usr/lib/php/20220829/iconv.so)",
|
||||||
|
"mysqli @ 8.2.28 (/usr/lib/php/20220829/mysqli.so)",
|
||||||
|
"opcache @ 8.2.28 (/usr/lib/php/20220829/opcache.so)",
|
||||||
|
"pdo @ 8.2.28 (/usr/lib/php/20220829/pdo.so)",
|
||||||
|
"pdo_mysql @ 8.2.28 (/usr/lib/php/20220829/pdo_mysql.so)",
|
||||||
|
"phar @ 8.2.28 (/usr/lib/php/20220829/phar.so)",
|
||||||
|
"posix @ 8.2.28 (/usr/lib/php/20220829/posix.so)",
|
||||||
|
"readline @ 8.2.28 (/usr/lib/php/20220829/readline.so)",
|
||||||
|
"shmop @ 8.2.28 (/usr/lib/php/20220829/shmop.so)",
|
||||||
|
"simplexml @ 8.2.28 (/usr/lib/php/20220829/simplexml.so)",
|
||||||
|
"sockets @ 8.2.28 (/usr/lib/php/20220829/sockets.so)",
|
||||||
|
"sysvmsg @ 8.2.28 (/usr/lib/php/20220829/sysvmsg.so)",
|
||||||
|
"sysvsem @ 8.2.28 (/usr/lib/php/20220829/sysvsem.so)",
|
||||||
|
"sysvshm @ 8.2.28 (/usr/lib/php/20220829/sysvshm.so)",
|
||||||
|
"tokenizer @ 8.2.28 (/usr/lib/php/20220829/tokenizer.so)",
|
||||||
|
"xml @ 8.2.28 (/usr/lib/php/20220829/xml.so)",
|
||||||
|
"xmlreader @ 8.2.28 (/usr/lib/php/20220829/xmlreader.so)",
|
||||||
|
"xmlwriter @ 8.2.28 (/usr/lib/php/20220829/xmlwriter.so)",
|
||||||
|
"xsl @ 8.2.28 (/usr/lib/php/20220829/xsl.so)",
|
||||||
|
},
|
||||||
|
expectedRels: []string{
|
||||||
|
"calendar @ 8.2.28 (/usr/lib/php/20220829/calendar.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"ctype @ 8.2.28 (/usr/lib/php/20220829/ctype.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"exif @ 8.2.28 (/usr/lib/php/20220829/exif.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"ffi @ 8.2.28 (/usr/lib/php/20220829/ffi.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"fileinfo @ 8.2.28 (/usr/lib/php/20220829/fileinfo.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"ftp @ 8.2.28 (/usr/lib/php/20220829/ftp.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"gettext @ 8.2.28 (/usr/lib/php/20220829/gettext.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"iconv @ 8.2.28 (/usr/lib/php/20220829/iconv.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"mysqli @ 8.2.28 (/usr/lib/php/20220829/mysqli.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"opcache @ 8.2.28 (/usr/lib/php/20220829/opcache.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"pdo @ 8.2.28 (/usr/lib/php/20220829/pdo.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"pdo_mysql @ 8.2.28 (/usr/lib/php/20220829/pdo_mysql.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"phar @ 8.2.28 (/usr/lib/php/20220829/phar.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"posix @ 8.2.28 (/usr/lib/php/20220829/posix.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"readline @ 8.2.28 (/usr/lib/php/20220829/readline.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"shmop @ 8.2.28 (/usr/lib/php/20220829/shmop.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"simplexml @ 8.2.28 (/usr/lib/php/20220829/simplexml.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"sockets @ 8.2.28 (/usr/lib/php/20220829/sockets.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"sysvmsg @ 8.2.28 (/usr/lib/php/20220829/sysvmsg.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"sysvsem @ 8.2.28 (/usr/lib/php/20220829/sysvsem.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"sysvshm @ 8.2.28 (/usr/lib/php/20220829/sysvshm.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"tokenizer @ 8.2.28 (/usr/lib/php/20220829/tokenizer.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"xml @ 8.2.28 (/usr/lib/php/20220829/xml.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"xmlreader @ 8.2.28 (/usr/lib/php/20220829/xmlreader.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"xmlwriter @ 8.2.28 (/usr/lib/php/20220829/xmlwriter.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
"xsl @ 8.2.28 (/usr/lib/php/20220829/xsl.so) [dependency-of] libphp @ 8.2.28 (/usr/lib/apache2/modules/libphp8.2.so)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
c := NewInterpreterCataloger()
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
WithImageResolver(t, tt.fixture).
|
||||||
|
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
|
||||||
|
//Expects(tt.expected, nil).
|
||||||
|
ExpectsPackageStrings(tt.expectedPkgs).
|
||||||
|
ExpectsRelationshipStrings(tt.expectedRels).
|
||||||
|
TestCataloger(t, c)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
11
syft/pkg/cataloger/php/test-fixtures/image-apache/Dockerfile
Normal file
11
syft/pkg/cataloger/php/test-fixtures/image-apache/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM --platform=linux/amd64 httpd:2.4.63-bookworm AS builder
|
||||||
|
|
||||||
|
RUN apt update -y && apt install -y libapache2-mod-php php8.2-memcache php8.2-memcache php8.2-xml php8.2-mysqli php8.2-opcache
|
||||||
|
|
||||||
|
FROM busybox:latest
|
||||||
|
|
||||||
|
# phplib.so
|
||||||
|
COPY --from=builder /usr/lib/apache2/ /usr/lib/apache2/
|
||||||
|
|
||||||
|
# php extensions
|
||||||
|
COPY --from=builder /usr/lib/php/ /usr/lib/php/
|
||||||
105
syft/pkg/cataloger/php/test-fixtures/image-extensions/Dockerfile
Normal file
105
syft/pkg/cataloger/php/test-fixtures/image-extensions/Dockerfile
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# source https://github.com/nextcloud/docker/blob/master/30/fpm-alpine/Dockerfile#L1
|
||||||
|
FROM --platform=linux/amd64 php:8.3-fpm-alpine3.21 AS builder
|
||||||
|
|
||||||
|
# entrypoint.sh and cron.sh dependencies
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apk add --no-cache \
|
||||||
|
imagemagick \
|
||||||
|
imagemagick-pdf \
|
||||||
|
imagemagick-jpeg \
|
||||||
|
imagemagick-raw \
|
||||||
|
imagemagick-tiff \
|
||||||
|
imagemagick-heic \
|
||||||
|
imagemagick-webp \
|
||||||
|
imagemagick-svg \
|
||||||
|
rsync \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
rm /var/spool/cron/crontabs/root; \
|
||||||
|
echo '*/5 * * * * php -f /var/www/html/cron.php' > /var/spool/cron/crontabs/www-data
|
||||||
|
|
||||||
|
# install the PHP extensions we need
|
||||||
|
# see https://docs.nextcloud.com/server/stable/admin_manual/installation/source_installation.html
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
apk add --no-cache --virtual .build-deps \
|
||||||
|
$PHPIZE_DEPS \
|
||||||
|
autoconf \
|
||||||
|
freetype-dev \
|
||||||
|
gmp-dev \
|
||||||
|
icu-dev \
|
||||||
|
imagemagick-dev \
|
||||||
|
libevent-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
libmcrypt-dev \
|
||||||
|
libmemcached-dev \
|
||||||
|
libpng-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libzip-dev \
|
||||||
|
openldap-dev \
|
||||||
|
pcre-dev \
|
||||||
|
postgresql-dev \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
docker-php-ext-configure ftp --with-openssl-dir=/usr; \
|
||||||
|
docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp; \
|
||||||
|
docker-php-ext-configure ldap; \
|
||||||
|
docker-php-ext-install -j "$(nproc)" \
|
||||||
|
bcmath \
|
||||||
|
exif \
|
||||||
|
ftp \
|
||||||
|
gd \
|
||||||
|
gmp \
|
||||||
|
intl \
|
||||||
|
ldap \
|
||||||
|
opcache \
|
||||||
|
pcntl \
|
||||||
|
pdo_mysql \
|
||||||
|
pdo_pgsql \
|
||||||
|
sysvsem \
|
||||||
|
zip \
|
||||||
|
; \
|
||||||
|
\
|
||||||
|
# pecl will claim success even if one install fails, so we need to perform each install separately
|
||||||
|
pecl install APCu-5.1.24; \
|
||||||
|
pecl install igbinary-3.2.16; \
|
||||||
|
pecl install imagick-3.8.0; \
|
||||||
|
pecl install memcached-3.3.0 \
|
||||||
|
--configureoptions 'enable-memcached-igbinary="yes"'; \
|
||||||
|
pecl install redis-6.2.0 \
|
||||||
|
--configureoptions 'enable-redis-igbinary="yes" enable-redis-zstd="yes" enable-redis-lz4="yes"'; \
|
||||||
|
\
|
||||||
|
docker-php-ext-enable \
|
||||||
|
apcu \
|
||||||
|
igbinary \
|
||||||
|
imagick \
|
||||||
|
memcached \
|
||||||
|
redis \
|
||||||
|
; \
|
||||||
|
rm -r /tmp/pear; \
|
||||||
|
\
|
||||||
|
runDeps="$( \
|
||||||
|
scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
|
||||||
|
| tr ',' '\n' \
|
||||||
|
| sort -u \
|
||||||
|
| awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
|
||||||
|
)"; \
|
||||||
|
apk add --no-network --virtual .nextcloud-phpext-rundeps $runDeps; \
|
||||||
|
apk del --no-network .build-deps
|
||||||
|
|
||||||
|
FROM busybox:latest
|
||||||
|
|
||||||
|
# interpreters + process manager
|
||||||
|
COPY --from=builder /usr/local/sbin/php-fpm /usr/local/sbin/php-fpm
|
||||||
|
COPY --from=builder /usr/local/bin/php /usr/local/bin/php
|
||||||
|
|
||||||
|
# extensions
|
||||||
|
COPY --from=builder /usr/local/lib/php/extensions /usr/local/lib/php/extensions
|
||||||
|
|
||||||
|
# configs
|
||||||
|
COPY --from=builder /usr/local/etc/php-fpm.conf /usr/local/etc/php-fpm.conf
|
||||||
|
COPY --from=builder /usr/local/etc/php/conf.d /usr/local/etc/php/conf.d
|
||||||
|
COPY --from=builder /usr/local/etc/php-fpm.d /usr/local/etc/php-fpm.d
|
||||||
|
COPY --from=builder /usr/local/etc/php-fpm.conf /usr/local/etc/php-fpm.conf
|
||||||
Loading…
x
Reference in New Issue
Block a user