package binary import ( "context" "errors" "flag" "fmt" "io" "slices" "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/anchore/packageurl-go" "github.com/anchore/stereoscope/pkg/imagetest" "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/binary/internal/manager/testutil" "github.com/anchore/syft/syft/pkg/cataloger/internal/binutils" "github.com/anchore/syft/syft/source" "github.com/anchore/syft/syft/source/directorysource" "github.com/anchore/syft/syft/source/stereoscopesource" ) var mustUseOriginalBinaries = flag.Bool("must-use-original-binaries", false, "force the use of binaries for testing (instead of snippets)") func Test_Cataloger_PositiveCases(t *testing.T) { tests := []struct { name string // logicalFixture is the logical path to the full binary or snippet. This is relative to the testdata/classifiers/snippets // or testdata/classifiers/bin directory . Snippets are searched for first, and if not found, then existing binaries are // used. If no binary or snippet is found the test will fail. If '-must-use-original-binaries' is used the only // full binaries are tested (no snippets), and if no binary is found the test will be skipped. logicalFixture string expected pkg.Package expectedPackages []pkg.Package }{ { logicalFixture: "arangodb/3.11.8/linux-amd64", expected: pkg.Package{ Name: "arangodb", Version: "3.11.8", Type: "binary", PURL: "pkg:generic/arangodb@3.11.8", Locations: locations("arangosh"), Metadata: metadata("arangodb-binary"), }, }, { logicalFixture: "arangodb/3.12.0-2/linux-amd64", expected: pkg.Package{ Name: "arangodb", Version: "3.12.0-2", Type: "binary", PURL: "pkg:generic/arangodb@3.12.0-2", Locations: locations("arangosh"), Metadata: metadata("arangodb-binary"), }, }, { logicalFixture: "arangodb/3.12.5/linux-amd64", expected: pkg.Package{ Name: "arangodb", Version: "3.12.5", Type: "binary", PURL: "pkg:generic/arangodb@3.12.5", Locations: locations("arangosh"), Metadata: metadata("arangodb-binary"), }, }, { logicalFixture: "arangodb/3.12.5-2/linux-amd64", expected: pkg.Package{ Name: "arangodb", Version: "3.12.5-2", Type: "binary", PURL: "pkg:generic/arangodb@3.12.5-2", Locations: locations("arangosh"), Metadata: metadata("arangodb-binary"), }, }, { logicalFixture: "postgres/15beta4/linux-amd64", expected: pkg.Package{ Name: "postgresql", Version: "15beta4", Type: "binary", PURL: "pkg:generic/postgresql@15beta4", Locations: locations("postgres"), Metadata: metadata("postgresql-binary"), }, }, { logicalFixture: "postgres/15.1/linux-amd64", expected: pkg.Package{ Name: "postgresql", Version: "15.1", Type: "binary", PURL: "pkg:generic/postgresql@15.1", Locations: locations("postgres"), Metadata: metadata("postgresql-binary"), }, }, { logicalFixture: "postgres/9.6.24/linux-amd64", expected: pkg.Package{ Name: "postgresql", Version: "9.6.24", Type: "binary", PURL: "pkg:generic/postgresql@9.6.24", Locations: locations("postgres"), Metadata: metadata("postgresql-binary"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "postgres/9.5alpha1/linux-amd64", expected: pkg.Package{ Name: "postgresql", Version: "9.5alpha1", Type: "binary", PURL: "pkg:generic/postgresql@9.5alpha1", Locations: locations("postgres"), Metadata: metadata("postgresql-binary"), }, }, { logicalFixture: "mysql/8.0.34/linux-amd64", expected: pkg.Package{ Name: "mysql", Version: "8.0.34", Type: "binary", PURL: "pkg:generic/mysql@8.0.34", Locations: locations("mysql"), Metadata: metadata("mysql-binary"), }, }, { logicalFixture: "mysql/8.0.37/linux-amd64", expected: pkg.Package{ Name: "mysql", Version: "8.0.37", Type: "binary", PURL: "pkg:generic/mysql@8.0.37", Locations: locations("mysql"), Metadata: metadata("mysql-binary"), }, }, { logicalFixture: "percona-server/8.0.35/linux-amd64", expected: pkg.Package{ Name: "percona-server", Version: "8.0.35", Type: "binary", PURL: "pkg:generic/percona-server@8.0.35", Locations: locations("mysql"), Metadata: metadata("mysql-binary"), }, }, { logicalFixture: "percona-xtradb-cluster/8.0.34/linux-amd64", expected: pkg.Package{ Name: "percona-xtradb-cluster", Version: "8.0.34", Type: "binary", PURL: "pkg:generic/percona-xtradb-cluster@8.0.34", Locations: locations("mysql"), Metadata: metadata("mysql-binary"), }, }, { logicalFixture: "percona-xtrabackup/8.0.35/linux-amd64", expected: pkg.Package{ Name: "percona-xtrabackup", Version: "8.0.35", Type: "binary", PURL: "pkg:generic/percona-xtrabackup@8.0.35", Locations: locations("xtrabackup"), Metadata: metadata("xtrabackup-binary"), }, }, { logicalFixture: "mysql/5.6.51/linux-amd64", expected: pkg.Package{ Name: "mysql", Version: "5.6.51", Type: "binary", PURL: "pkg:generic/mysql@5.6.51", Locations: locations("mysql"), Metadata: metadata("mysql-binary"), }, }, { logicalFixture: "mariadb/10.6.15/linux-amd64", expected: pkg.Package{ Name: "mariadb", Version: "10.6.15", Type: "binary", PURL: "pkg:generic/mariadb@10.6.15", Locations: locations("mariadb"), Metadata: metadata("mariadb-binary"), }, }, { // RHEL / MariaDB.org tarball builds do not embed the "-MariaDB" marker; the version is only // present in the build path (e.g. mariadb-11.8.5-2-redhat-x86_64). The release suffix ("-2") // must not leak into the version. Regression for anchore/grype#3452. logicalFixture: "mariadb/11.8.5/linux-amd64", expected: pkg.Package{ Name: "mariadb", Version: "11.8.5", Type: "binary", PURL: "pkg:generic/mariadb@11.8.5", Locations: locations("mariadb"), Metadata: metadata("mariadb-binary"), }, }, { logicalFixture: "mysqld/9.7.0/linux-amd64", expected: pkg.Package{ Name: "mysql-server", Version: "9.7.0", Type: "binary", PURL: "pkg:generic/mysql-server@9.7.0", Locations: locations("mysqld"), Metadata: metadata("mysqld-mysql-server-binary"), }, }, { logicalFixture: "mysql-cluster/9.7.0/linux-amd64", expected: pkg.Package{ Name: "mysql-cluster", Version: "9.7.0", Type: "binary", PURL: "pkg:generic/mysql-cluster@9.7.0", Locations: locations("mysqld"), Metadata: metadata("mysqld-mysql-cluster-binary"), }, }, { logicalFixture: "mysql-cluster/7.6.17/linux-amd64", expectedPackages: []pkg.Package{ { Name: "mysql-server", Version: "5.7.33", Type: "binary", PURL: "pkg:generic/mysql-server@5.7.33", Locations: locations("mysqld"), Metadata: metadata("mysqld-mysql-cluster-legacy-binary"), }, { Name: "mysql-cluster", Version: "7.6.17", Type: "binary", PURL: "pkg:generic/mysql-cluster@7.6.17", Locations: locations("mysqld"), Metadata: metadata("mysqld-mysql-cluster-legacy-binary"), }, }, }, { logicalFixture: "ndbd/9.7.0/linux-amd64", expected: pkg.Package{ Name: "mysql-cluster", Version: "9.7.0", Type: "binary", PURL: "pkg:generic/mysql-cluster@9.7.0", Locations: locations("ndbd"), Metadata: metadata("ndbd-binary"), }, }, { logicalFixture: "ndbmtd/9.7.0/linux-amd64", expected: pkg.Package{ Name: "mysql-cluster", Version: "9.7.0", Type: "binary", PURL: "pkg:generic/mysql-cluster@9.7.0", Locations: locations("ndbmtd"), Metadata: metadata("ndbmtd-binary"), }, }, { logicalFixture: "ndb_mgmd/9.7.0/linux-amd64", expected: pkg.Package{ Name: "mysql-cluster", Version: "9.7.0", Type: "binary", PURL: "pkg:generic/mysql-cluster@9.7.0", Locations: locations("ndb_mgmd"), Metadata: metadata("ndb_mgmd-binary"), }, }, { logicalFixture: "mongodb/8.0.17/linux-amd64", expected: pkg.Package{ Name: "mongodb", Version: "8.0.17", Type: "binary", PURL: "pkg:generic/mongodb@8.0.17", Locations: locations("mongod"), Metadata: metadata("mongodb-binary"), }, }, { logicalFixture: "mongodb/7.0.28/linux-amd64", expected: pkg.Package{ Name: "mongodb", Version: "7.0.28", Type: "binary", PURL: "pkg:generic/mongodb@7.0.28", Locations: locations("mongod"), Metadata: metadata("mongodb-binary"), }, }, { logicalFixture: "mongodb/6.0.27/linux-amd64", expected: pkg.Package{ Name: "mongodb", Version: "6.0.27", Type: "binary", PURL: "pkg:generic/mongodb@6.0.27", Locations: locations("mongod"), Metadata: metadata("mongodb-binary"), }, }, { logicalFixture: "mongodb/5.0.32/linux-amd64", expected: pkg.Package{ Name: "mongodb", Version: "5.0.32", Type: "binary", PURL: "pkg:generic/mongodb@5.0.32", Locations: locations("mongod"), Metadata: metadata("mongodb-binary"), }, }, { logicalFixture: "mongodb/4.4.30/linux-amd64", expected: pkg.Package{ Name: "mongodb", Version: "4.4.30", Type: "binary", PURL: "pkg:generic/mongodb@4.4.30", Locations: locations("mongod"), Metadata: metadata("mongodb-binary"), }, }, { logicalFixture: "traefik/1.7.34/linux-amd64", expected: pkg.Package{ Name: "traefik", Version: "1.7.34", Type: "binary", PURL: "pkg:generic/traefik@1.7.34", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "traefik/2.9.6/linux-amd64", expected: pkg.Package{ Name: "traefik", Version: "2.9.6", Type: "binary", PURL: "pkg:generic/traefik@2.9.6", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "traefik/2.10.7/linux-amd64", expected: pkg.Package{ Name: "traefik", Version: "2.10.7", Type: "binary", PURL: "pkg:generic/traefik@2.10.7", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "traefik/3.0.4/linux-riscv64", expected: pkg.Package{ Name: "traefik", Version: "3.0.4", Type: "binary", PURL: "pkg:generic/traefik@3.0.4", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "traefik/3.6.5/linux-amd64", expected: pkg.Package{ Name: "traefik", Version: "3.6.5", Type: "binary", PURL: "pkg:generic/traefik@3.6.5", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { // regression test: big-endian architectures (e.g. s390x) previously matched an unrelated // single-NUL-terminated numeric string elsewhere in the binary instead of the real version logicalFixture: "traefik/3.6.8/linux-s390x", expected: pkg.Package{ Name: "traefik", Version: "3.6.8", Type: "binary", PURL: "pkg:generic/traefik@3.6.8", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "traefik/2.11.1/linux-arm", expected: pkg.Package{ Name: "traefik", Version: "2.11.1", Type: "binary", PURL: "pkg:generic/traefik@2.11.1", Locations: locations("traefik"), Metadata: metadata("traefik-binary"), }, }, { logicalFixture: "memcached/1.6.18/linux-amd64", expected: pkg.Package{ Name: "memcached", Version: "1.6.18", Type: "binary", PURL: "pkg:generic/memcached@1.6.18", Locations: locations("memcached"), Metadata: metadata("memcached-binary"), }, }, { logicalFixture: "httpd/2.4.54/linux-amd64", expected: pkg.Package{ Name: "httpd", Version: "2.4.54", Type: "binary", PURL: "pkg:generic/httpd@2.4.54", Locations: locations("httpd"), Metadata: metadata("httpd-binary"), }, }, { // 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 logicalFixture: "perl/5.12.5/linux-amd64", expected: pkg.Package{ Name: "perl", Version: "5.12.5", Type: "cpan", PURL: "pkg:cpan/perl@5.12.5", Locations: locations("perl"), Metadata: metadata("perl-binary"), }, }, { // 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 logicalFixture: "perl/5.20.0/linux-amd64", expected: pkg.Package{ Name: "perl", Version: "5.20.0", Type: "cpan", PURL: "pkg:cpan/perl@5.20.0", Locations: locations("perl"), Metadata: metadata("perl-binary"), }, }, { // 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 logicalFixture: "perl/5.37.8/linux-amd64", expected: pkg.Package{ Name: "perl", Version: "5.37.8", Type: "cpan", PURL: "pkg:cpan/perl@5.37.8", Locations: locations("perl"), Metadata: metadata("perl-binary"), }, }, { logicalFixture: "haproxy/1.5.14/linux-amd64", expected: pkg.Package{ Name: "haproxy", Version: "1.5.14", Type: "binary", PURL: "pkg:generic/haproxy@1.5.14", Locations: locations("haproxy"), Metadata: metadata("haproxy-binary"), }, }, { logicalFixture: "haproxy/1.8.22/linux-amd64", expected: pkg.Package{ Name: "haproxy", Version: "1.8.22", Type: "binary", PURL: "pkg:generic/haproxy@1.8.22", Locations: locations("haproxy"), Metadata: metadata("haproxy-binary"), }, }, { logicalFixture: "haproxy/2.0.0/linux-amd64", expected: pkg.Package{ Name: "haproxy", Version: "2.0.0", Type: "binary", PURL: "pkg:generic/haproxy@2.0.0", Locations: locations("haproxy"), Metadata: metadata("haproxy-binary"), }, }, { logicalFixture: "haproxy/2.7.3/linux-amd64", expected: pkg.Package{ Name: "haproxy", Version: "2.7.3", Type: "binary", PURL: "pkg:generic/haproxy@2.7.3", Locations: locations("haproxy"), Metadata: metadata("haproxy-binary"), }, }, { logicalFixture: "haproxy/3.1-dev0/linux-amd64", expected: pkg.Package{ Name: "haproxy", Version: "3.1-dev0", Type: "binary", PURL: "pkg:generic/haproxy@3.1-dev0", Locations: locations("haproxy"), Metadata: metadata("haproxy-binary"), }, }, { logicalFixture: "helm/4.1.4/linux-s390x", expected: pkg.Package{ Name: "helm", Version: "4.1.4", Type: "binary", PURL: "pkg:golang/helm.sh/helm@4.1.4", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/3.15.2/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "3.15.2", Type: "binary", PURL: "pkg:golang/helm.sh/helm@3.15.2", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/3.12.0/linux-s390x", expected: pkg.Package{ Name: "helm", Version: "3.12.0", Type: "binary", PURL: "pkg:golang/helm.sh/helm@3.12.0", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/3.11.1/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "3.11.1", Type: "binary", PURL: "pkg:golang/helm.sh/helm@3.11.1", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/3.0.0-alpha.1/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "3.0.0-alpha.1", Type: "binary", PURL: "pkg:golang/helm.sh/helm@3.0.0-alpha.1", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/2.17.0-rc.1/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "2.17.0-rc.1", Type: "binary", PURL: "pkg:golang/helm.sh/helm@2.17.0-rc.1", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/2.0.0-beta.2/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "2.0.0-beta.2", Type: "binary", PURL: "pkg:golang/helm.sh/helm@2.0.0-beta.2", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { logicalFixture: "helm/3.10.3/linux-amd64", expected: pkg.Package{ Name: "helm", Version: "3.10.3", Type: "binary", PURL: "pkg:golang/helm.sh/helm@3.10.3", Locations: locations("helm"), Metadata: metadata("helm"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "redis-server/2.8.23/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "2.8.23", Type: "binary", PURL: "pkg:generic/redis@2.8.23", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "redis-server/4.0.11/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "4.0.11", Type: "binary", PURL: "pkg:generic/redis@4.0.11", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "redis-server/5.0.0/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "5.0.0", Type: "binary", PURL: "pkg:generic/redis@5.0.0", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "redis-server/6.0.16/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "6.0.16", Type: "binary", PURL: "pkg:generic/redis@6.0.16", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "redis-server/7.0.0/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "7.0.0", Type: "binary", PURL: "pkg:generic/redis@7.0.0", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "redis-server/7.0.14/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "7.0.14", Type: "binary", PURL: "pkg:generic/redis@7.0.14", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "redis-server/7.2.3/linux-amd64", expected: pkg.Package{ Name: "redis", Version: "7.2.3", Type: "binary", PURL: "pkg:generic/redis@7.2.3", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "redis-server/7.2.3/linux-arm64", expected: pkg.Package{ Name: "redis", Version: "7.2.3", Type: "binary", PURL: "pkg:generic/redis@7.2.3", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "redis-server/7.2.5/linux-386", expected: pkg.Package{ Name: "redis", Version: "7.2.5", Type: "binary", PURL: "pkg:generic/redis@7.2.5", Locations: locations("redis-server"), Metadata: metadata("redis-binary"), }, }, { logicalFixture: "valkey-server/9.0.0/linux-amd64", expected: pkg.Package{ Name: "valkey", Version: "9.0.0", Type: "binary", PURL: "pkg:generic/valkey@9.0.0", Locations: locations("valkey-server"), Metadata: metadata("valkey-binary"), }, }, { // no python binary, but we find libpython, which is surfaced as primary evidence logicalFixture: "python-shared-lib/3.7.4/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.7.4", PURL: "pkg:generic/python@3.7.4", Locations: locations("libpython3.7m.so.1.0"), Metadata: metadata("python-binary-lib"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "python-slim-shared-libs/3.11/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.11.2", PURL: "pkg:generic/python@3.11.2", Locations: locations("python3.11", "libpython3.11.so.1.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.11"), match("python-binary", "libpython3.11.so.1.0"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "python-rhel-shared-libs/3.9/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.9.13", PURL: "pkg:generic/python@3.9.13", Locations: locations("python3.9", "libpython3.9.so.1.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.9"), match("python-binary", "libpython3.9.so.1.0"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "python3.9/3.9.16/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.9.2", PURL: "pkg:generic/python@3.9.2", Locations: locations("python3.9"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.9"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "python-alpine-shared-libs/3.4/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.4.10", PURL: "pkg:generic/python@3.4.10", Locations: locations("python3.4", "libpython3.4m.so.1.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("python-binary", "python3.4"), match("python-binary", "libpython3.4m.so.1.0"), }, }, }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "python-with-incorrect-match/3.5.3/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.5.3", PURL: "pkg:generic/python@3.5.3", Locations: locations("python3.5"), Metadata: metadata("python-binary"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "python/3.6.3/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.6.3", PURL: "pkg:generic/python@3.6.3", Locations: locations("python3.6"), Metadata: metadata("python-binary"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "python-duplicates/3.8.16/linux-amd64", expected: pkg.Package{ Name: "python", Version: "3.8.16", Type: "binary", PURL: "pkg:generic/python@3.8.16", Locations: locations("dir/python3.8", "python3.8", "libpython3.8.so"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("python-binary", "dir/python3.8"), match("python-binary", "python3.8"), match("python-binary-lib", "libpython3.8.so"), }, }, }, }, { logicalFixture: "pypy-shared-lib/7.3.14/linux-amd64", expected: pkg.Package{ Name: "pypy", Version: "7.3.14", PURL: "pkg:generic/pypy@7.3.14", Locations: locations("libpypy3.9-c.so"), Metadata: metadata("pypy-binary-lib"), }, }, { logicalFixture: "go/1.21.3/linux-amd64", expected: pkg.Package{ Name: "go", Version: "1.21.3", PURL: "pkg:generic/go@1.21.3", Locations: locations("go"), Metadata: metadata("go-binary"), }, }, { logicalFixture: "node/0.10.48/linux-amd64", expected: pkg.Package{ Name: "node", Version: "0.10.48", PURL: "pkg:generic/node@0.10.48", Locations: locations("node"), Metadata: metadata("nodejs-binary"), }, }, { logicalFixture: "node/0.12.18/linux-amd64", expected: pkg.Package{ Name: "node", Version: "0.12.18", PURL: "pkg:generic/node@0.12.18", Locations: locations("node"), Metadata: metadata("nodejs-binary"), }, }, { logicalFixture: "node/4.9.1/linux-amd64", expected: pkg.Package{ Name: "node", Version: "4.9.1", PURL: "pkg:generic/node@4.9.1", Locations: locations("node"), Metadata: metadata("nodejs-binary"), }, }, { logicalFixture: "node/19.2.0/linux-amd64", expected: pkg.Package{ Name: "node", Version: "19.2.0", PURL: "pkg:generic/node@19.2.0", Locations: locations("node"), Metadata: metadata("nodejs-binary"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "go-version-hint/1.15-dev/any", expected: pkg.Package{ Name: "go", Version: "1.15", PURL: "pkg:generic/go@1.15", Locations: locations("bin/go", "VERSION"), Metadata: metadata("go-binary"), }, }, { logicalFixture: "go-version-hint/1.15/any", expected: pkg.Package{ Name: "go", Version: "1.15", PURL: "pkg:generic/go@1.15", Locations: locations("bin/go", "VERSION"), Metadata: metadata("go-binary"), }, }, { logicalFixture: "go-version-hint/1.15w/any", expected: pkg.Package{ Name: "go", Version: "1.15", PURL: "pkg:generic/go@1.15", Locations: locations("bin/go.exe", "VERSION"), Metadata: metadata("go-binary"), }, }, { logicalFixture: "go-version-hint/1.21/any", expected: pkg.Package{ Name: "go", Version: "1.21", PURL: "pkg:generic/go@1.21", Locations: locations("go", "VERSION"), Metadata: metadata("go-binary"), }, }, { // note: this is for compatability with dev version of golang tip image, which resolves the issue #3681 logicalFixture: "go-version-hint/1.25/any", expected: pkg.Package{ Name: "go", Version: "1.25-d524e1e", PURL: "pkg:generic/go@1.25-d524e1e", Locations: locations("bin/go", "VERSION.cache"), Metadata: metadata("go-binary"), }, }, { logicalFixture: "go-version-hint/1.25w/any", expected: pkg.Package{ Name: "go", Version: "1.25-d524e1e", PURL: "pkg:generic/go@1.25-d524e1e", Locations: locations("go.exe", "VERSION"), Metadata: metadata("go-binary"), }, }, { // note: this is testing BUSYBOX which is typically through a link to "[" (in this case a symlink but in // practice this is often a hard link). logicalFixture: `busybox/1.36.1/linux-amd64`, expected: pkg.Package{ Name: "busybox", Version: "1.36.1", PURL: "pkg:generic/busybox@1.36.1", Locations: locations("["), // note: busybox is a link to [ Metadata: metadata("busybox-binary", "[", "busybox"), }, }, { logicalFixture: `util-linux/2.37.4/linux-amd64`, expected: pkg.Package{ Name: "util-linux", Version: "2.37.4", PURL: "pkg:generic/util-linux@2.37.4", Locations: locations("getopt"), Metadata: metadata("util-linux-binary"), }, }, { logicalFixture: "java-jre-openjdk/1.8.0_352-b08/linux-amd64", expected: pkg.Package{ Name: "openjdk", Version: "1.8.0_352-b08", Type: "binary", PURL: "pkg:generic/oracle/openjdk@1.8.0_352-b08", Locations: locations("java"), Metadata: metadata("java-binary-openjdk-with-update", "java"), }, }, { logicalFixture: "java-jre-openjdk/11.0.17/linux-amd64", expected: pkg.Package{ Name: "openjdk", Version: "11.0.17+8-LTS", Type: "binary", PURL: "pkg:generic/oracle/openjdk@11.0.17%2B8-LTS", Locations: locations("java"), Metadata: metadata("java-binary-openjdk", "java"), }, }, { logicalFixture: "java-jre-openjdk-eclipse/11.0.22/linux-amd64", expected: pkg.Package{ Name: "openjdk", Version: "11.0.22+7", Type: "binary", PURL: "pkg:generic/oracle/openjdk@11.0.22%2B7", Locations: locations("java"), Metadata: metadata("java-binary-openjdk", "java"), }, }, { logicalFixture: "java-jre-openjdk-arm64-eclipse/11.0.22/linux-arm64", expected: pkg.Package{ Name: "openjdk", Version: "11.0.22+7", Type: "binary", PURL: "pkg:generic/oracle/openjdk@11.0.22%2B7", Locations: locations("java"), Metadata: metadata("java-binary-openjdk", "java"), }, }, { logicalFixture: "java-graal-openjdk/17.0.3+7-jvmci-22.1-b06/linux-amd64", expected: pkg.Package{ Name: "graalvm", Version: "17.0.3+7-jvmci-22.1-b06", Type: "binary", PURL: "pkg:generic/oracle/graalvm@17.0.3%2B7-jvmci-22.1-b06", Locations: locations("java"), Metadata: metadata("java-binary-graalvm", "java"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "java-jre-oracle/19.0.1/linux-amd64", expected: pkg.Package{ Name: "jre", Version: "19.0.1+10-21", Type: "binary", PURL: "pkg:generic/oracle/jre@19.0.1%2B10-21", Locations: locations("java"), Metadata: metadata("java-binary-oracle", "java"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "java-jre-oracle/19.0.1/darwin", expected: pkg.Package{ Name: "jre", Version: "19.0.1+10-21", Type: "binary", PURL: "pkg:generic/oracle/jre@19.0.1%2B10-21", Locations: locations("java"), Metadata: metadata("java-binary-oracle", "java"), }, }, { logicalFixture: "java-jdk-openjdk/21.0.2+13-LTS/linux-amd64", expected: pkg.Package{ Name: "openjdk", Version: "21.0.2+13-LTS", Type: "binary", PURL: "pkg:generic/oracle/openjdk@21.0.2%2B13-LTS", Locations: locations("jdb"), Metadata: metadata("java-binary-openjdk-fallthrough", "jdb"), }, }, { logicalFixture: "rust-libstd/1.50.0/linux-amd64", expected: pkg.Package{ Name: "rust", Version: "1.50.0", Type: "binary", PURL: "pkg:generic/rust@1.50.0", Locations: locations("libstd-6f77337c1826707d.so"), Metadata: metadata("rust-standard-library-linux"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "rust-libstd/1.50.0/darwin", expected: pkg.Package{ Name: "rust", Version: "1.50.0", Type: "binary", PURL: "pkg:generic/rust@1.50.0", Locations: locations("libstd-f6f9eec1635e636a.dylib"), Metadata: metadata("rust-standard-library-macos"), }, }, { // TODO: find original binary... // note: cannot find the original binary, using a custom snippet based on the original snippet in the repo logicalFixture: "rust-libstd/1.67.1/darwin", expected: pkg.Package{ Name: "rust", Version: "1.67.1", Type: "binary", PURL: "pkg:generic/rust@1.67.1", Locations: locations("libstd-16f2b65e77054c42.dylib"), Metadata: metadata("rust-standard-library-macos"), }, }, { logicalFixture: "rust-libstd-musl/1.67.1/linux-amd64", expected: pkg.Package{ Name: "rust", Version: "1.67.1", Type: "binary", PURL: "pkg:generic/rust@1.67.1", Locations: locations("libstd-86aefecbddda356d.so"), Metadata: metadata("rust-standard-library-linux"), }, }, { logicalFixture: "rust-libstd/1.67.1/linux-amd64", expected: pkg.Package{ Name: "rust", Version: "1.67.1", Type: "binary", PURL: "pkg:generic/rust@1.67.1", Locations: locations("libstd-c6192dd4c4d410ac.so"), Metadata: metadata("rust-standard-library-linux"), }, }, { // note: dynamic (non-snippet) test case name: "positive-ruby-3.2.1", logicalFixture: "ruby-bullseye-shared-libs/3.2.1/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "3.2.1", Type: "binary", PURL: "pkg:generic/ruby@3.2.1", Locations: locations("ruby", "libruby.so.3.2.1"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.3.2.1"), }, }, }, }, { // note: dynamic (non-snippet) test case name: "positive-ruby-3.4.0-dev", logicalFixture: "ruby-shared-libs/3.4.0-dev/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "3.4.0dev", Type: "binary", PURL: "pkg:generic/ruby@3.4.0dev", Locations: locations("ruby", "libruby.so.3.4.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.3.4.0"), }, }, }, }, { // note: dynamic (non-snippet) test case name: "positive-ruby-3.4.0-preview1", logicalFixture: "ruby-shared-libs/3.4.0-preview1/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "3.4.0preview1", Type: "binary", PURL: "pkg:generic/ruby@3.4.0preview1", Locations: locations("ruby", "libruby.so.3.4.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.3.4.0"), }, }, }, }, { // note: dynamic (non-snippet) test case name: "positive-ruby-3.3.0-rc1", logicalFixture: "ruby-shared-libs/3.3.0-rc1/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "3.3.0rc1", Type: "binary", PURL: "pkg:generic/ruby@3.3.0rc1", Locations: locations("ruby", "libruby.so.3.3.0"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.3.3.0"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "ruby-bullseye-shared-libs/2.7.7/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "2.7.7p221", Type: "binary", PURL: "pkg:generic/ruby@2.7.7p221", Locations: locations("ruby", "libruby.so.2.7.7"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.2.7.7"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "ruby-shared-libs/2.6.10/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "2.6.10p210", Type: "binary", PURL: "pkg:generic/ruby@2.6.10p210", Locations: locations("ruby", "libruby.so.2.6.10"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("ruby-binary", "ruby"), match("ruby-binary", "libruby.so.2.6.10"), }, }, }, }, { logicalFixture: "ruby/1.9.3p551/linux-amd64", expected: pkg.Package{ Name: "ruby", Version: "1.9.3p551", Type: "binary", PURL: "pkg:generic/ruby@1.9.3p551", Locations: locations("ruby"), Metadata: metadata("ruby-binary"), }, }, { logicalFixture: "consul/1.15.2/linux-amd64", expected: pkg.Package{ Name: "consul", Version: "1.15.2", Type: "binary", PURL: "pkg:golang/github.com/hashicorp/consul@1.15.2", Locations: locations("consul"), Metadata: metadata("consul-binary"), }, }, { logicalFixture: "consul/1.12.9/linux-amd64", expected: pkg.Package{ Name: "consul", Version: "1.12.9", Type: "binary", PURL: "pkg:golang/github.com/hashicorp/consul@1.12.9", Locations: locations("consul"), Metadata: metadata("consul-binary"), }, }, { logicalFixture: "consul/1.7.14/linux-amd64", expected: pkg.Package{ Name: "consul", Version: "1.7.14", Type: "binary", PURL: "pkg:golang/github.com/hashicorp/consul@1.7.14", Locations: locations("consul"), Metadata: metadata("consul-binary"), }, }, { logicalFixture: "vault/1.21.0-rc1/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.21.0-rc1", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.21.0-rc1", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.20.2/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.20.2", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.20.2", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.19.4/linux-arm64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.19.4", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.19.4", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.14.10/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.14.10", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.14.10", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.14.3/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.14.3", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.14.3", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.13.13/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.13.13", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.13.13", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "vault/1.11.6/linux-amd64", expected: pkg.Package{ Name: "github.com/hashicorp/vault", Version: "1.11.6", Type: "golang", PURL: "pkg:golang/github.com/hashicorp/vault@1.11.6", Locations: locations("vault"), Metadata: metadata("hashicorp-vault-binary"), }, }, { logicalFixture: "erlang/25.3.2.6/linux-amd64", expected: pkg.Package{ Name: "erlang", Version: "25.3.2.6", Type: "binary", PURL: "pkg:generic/erlang@25.3.2.6", Locations: locations("erlexec"), Metadata: metadata("erlang-binary"), }, }, { logicalFixture: "erlang/26.2.0.0/linux-amd64", expected: pkg.Package{ Name: "erlang", Version: "26.2", Type: "binary", PURL: "pkg:generic/erlang@26.2", Locations: locations("erlexec"), Metadata: metadata("erlang-binary"), }, }, { logicalFixture: "erlang/26.2.4/linux-amd64", expected: pkg.Package{ Name: "erlang", Version: "26.2.4", Type: "binary", PURL: "pkg:generic/erlang@26.2.4", Locations: locations("liberts_internal.a"), Metadata: metadata("erlang-library"), }, }, { logicalFixture: "erlang/27.0/linux-amd64", expected: pkg.Package{ Name: "erlang", Version: "27.0", Type: "binary", PURL: "pkg:generic/erlang@27.0", Locations: locations("beam.smp"), Metadata: metadata("erlang-alpine-binary"), }, }, { logicalFixture: "erlang/26.1.2/linux-arm64", expected: pkg.Package{ Name: "erlang", Version: "26.1.2", Type: "binary", PURL: "pkg:generic/erlang@26.1.2", Locations: locations("beam.smp"), Metadata: metadata("erlang-alpine-binary"), }, }, { logicalFixture: "erlang/17.5.6.9/linux-amd64", expected: pkg.Package{ Name: "erlang", Version: "17.5.6.9", Type: "binary", PURL: "pkg:generic/erlang@17.5.6.9", Locations: locations("beam.smp"), Metadata: metadata("erlang-alpine-binary"), }, }, { logicalFixture: "swipl/9.3.8/linux-amd64", expected: pkg.Package{ Name: "swipl", Version: "9.3.8", Type: "binary", PURL: "pkg:generic/swipl@9.3.8", Locations: locations("swipl"), Metadata: metadata("swipl-binary"), }, }, { logicalFixture: "dart/2.12.4/linux-amd64", expected: pkg.Package{ Name: "dart", Version: "2.12.4", Type: "binary", PURL: "pkg:generic/dart@2.12.4", Locations: locations("dart"), Metadata: metadata("dart-binary"), }, }, { logicalFixture: "dart/3.0.0/linux-arm", expected: pkg.Package{ Name: "dart", Version: "3.0.0", Type: "binary", PURL: "pkg:generic/dart@3.0.0", Locations: locations("dart"), Metadata: metadata("dart-binary"), }, }, { logicalFixture: "dart/3.5.2/linux-amd64", expected: pkg.Package{ Name: "dart", Version: "3.5.2", Type: "binary", PURL: "pkg:generic/dart@3.5.2", Locations: locations("dart"), Metadata: metadata("dart-binary"), }, }, { logicalFixture: "dart/3.6.0-216.1.beta/linux-amd64", expected: pkg.Package{ Name: "dart", Version: "3.6.0-216.1.beta", Type: "binary", PURL: "pkg:generic/dart@3.6.0-216.1.beta", Locations: locations("dart"), Metadata: metadata("dart-binary"), }, }, { logicalFixture: "deno/1.10.3/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.10.3", Type: "binary", PURL: "pkg:generic/deno@1.10.3", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.11.3/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.11.3", Type: "binary", PURL: "pkg:generic/deno@1.11.3", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.11.4/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.11.4", Type: "binary", PURL: "pkg:generic/deno@1.11.4", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.16.4/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.16.4", Type: "binary", PURL: "pkg:generic/deno@1.16.4", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.28.3/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.28.3", Type: "binary", PURL: "pkg:generic/deno@1.28.3", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.29.4/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.29.4", Type: "binary", PURL: "pkg:generic/deno@1.29.4", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/1.41.0/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "1.41.0", Type: "binary", PURL: "pkg:generic/deno@1.41.0", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/2.0.0/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "2.0.0", Type: "binary", PURL: "pkg:generic/deno@2.0.0", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/2.6.3/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "2.6.3", Type: "binary", PURL: "pkg:generic/deno@2.6.3", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "deno/2.9.2/linux-amd64", expected: pkg.Package{ Name: "deno", Version: "2.9.2", Type: "binary", PURL: "pkg:generic/deno@2.9.2", Locations: locations("deno"), Metadata: metadata("deno-binary"), }, }, { logicalFixture: "bun/0.5.9/linux-amd64", expected: pkg.Package{ Name: "bun", Version: "0.5.9", Type: "binary", PURL: "pkg:generic/bun@0.5.9", Locations: locations("bun"), Metadata: metadata("bun-binary"), }, }, { logicalFixture: "bun/1.0.0/linux-amd64", expected: pkg.Package{ Name: "bun", Version: "1.0.0", Type: "binary", PURL: "pkg:generic/bun@1.0.0", Locations: locations("bun"), Metadata: metadata("bun-binary"), }, }, { logicalFixture: "bun/1.1.0/linux-amd64", expected: pkg.Package{ Name: "bun", Version: "1.1.0", Type: "binary", PURL: "pkg:generic/bun@1.1.0", Locations: locations("bun"), Metadata: metadata("bun-binary"), }, }, { logicalFixture: "bun/1.3.5/linux-amd64", expected: pkg.Package{ Name: "bun", Version: "1.3.5", Type: "binary", PURL: "pkg:generic/bun@1.3.5", Locations: locations("bun"), Metadata: metadata("bun-binary"), }, }, { logicalFixture: "haskell-ghc/7.10.3/linux-amd64", expected: pkg.Package{ Name: "haskell/ghc", Version: "7.10.3", Type: "binary", PURL: "pkg:generic/haskell/ghc@7.10.3", Locations: locations("ghc"), Metadata: metadata("haskell-ghc-binary"), }, }, { logicalFixture: "haskell-ghc/8.10.4/linux-amd64", expected: pkg.Package{ Name: "haskell/ghc", Version: "8.10.4", Type: "binary", PURL: "pkg:generic/haskell/ghc@8.10.4", Locations: locations("ghc"), Metadata: metadata("haskell-ghc-binary"), }, }, { logicalFixture: "haskell-ghc/9.6.5/linux-amd64", expected: pkg.Package{ Name: "haskell/ghc", Version: "9.6.5", Type: "binary", PURL: "pkg:generic/haskell/ghc@9.6.5", Locations: locations("ghc-9.6.5"), Metadata: metadata("haskell-ghc-binary"), }, }, { logicalFixture: "haskell-cabal/1.22.6.0/linux-amd64", expected: pkg.Package{ Name: "haskell/cabal", Version: "1.22.6.0", Type: "binary", PURL: "pkg:generic/haskell/cabal@1.22.6.0", Locations: locations("cabal"), Metadata: metadata("haskell-cabal-binary"), }, }, { logicalFixture: "haskell-cabal/3.10.3.0/linux-amd64", expected: pkg.Package{ Name: "haskell/cabal", Version: "3.10.3.0", Type: "binary", PURL: "pkg:generic/haskell/cabal@3.10.3.0", Locations: locations("cabal"), Metadata: metadata("haskell-cabal-binary"), }, }, { logicalFixture: "krb5/1.18.4/linux-amd64", expected: pkg.Package{ Name: "krb5", Version: "1.18.4", Type: "binary", PURL: "pkg:generic/krb5@1.18.4", Locations: locations("libkrb5.so.3.3"), Metadata: metadata("krb5-library"), }, }, { // base releases brand with a 2-component version (e.g. "krb5-1.17-final 1.17") logicalFixture: "krb5/1.17/linux-amd64", expected: pkg.Package{ Name: "krb5", Version: "1.17", Type: "binary", PURL: "pkg:generic/krb5@1.17", Locations: locations("libkrb5.so.3.3"), Metadata: metadata("krb5-library"), }, }, { logicalFixture: "heimdal-krb5/7.8.0/linux-amd64", expected: pkg.Package{ Name: "heimdal-krb5", Version: "7.8.0", Type: "binary", PURL: "pkg:generic/heimdal-krb5@7.8.0", Locations: locations("libkrb5.so.26.0.0"), Metadata: metadata("heimdal-krb5-library"), }, }, { logicalFixture: "nginx/1.25.1/linux-amd64", expected: pkg.Package{ Name: "nginx", Version: "1.25.1", Type: "binary", PURL: "pkg:generic/nginx@1.25.1", Locations: locations("nginx"), Metadata: metadata("nginx-binary"), }, }, { logicalFixture: "nginx-openresty/1.21.4.3/linux-amd64", expected: pkg.Package{ Name: "nginx", Version: "1.21.4", Type: "binary", PURL: "pkg:generic/nginx@1.21.4", Locations: locations("nginx"), Metadata: metadata("nginx-binary"), }, }, { logicalFixture: "bash/5.1.16/linux-amd64", expected: pkg.Package{ Name: "bash", Version: "5.1.16", Type: "binary", PURL: "pkg:generic/bash@5.1.16", Locations: locations("bash"), Metadata: metadata("bash-binary"), }, }, { logicalFixture: "openssl/3.1.4/linux-amd64", expected: pkg.Package{ Name: "openssl", Version: "3.1.4", Type: "binary", PURL: "pkg:generic/openssl@3.1.4", Locations: locations("openssl"), Metadata: metadata("openssl-binary"), }, }, { logicalFixture: "openssl/1.1.1w/linux-arm64", expected: pkg.Package{ Name: "openssl", Version: "1.1.1w", Type: "binary", PURL: "pkg:generic/openssl@1.1.1w", Locations: locations("openssl"), Metadata: metadata("openssl-binary"), }, }, { logicalFixture: "openssl/1.1.1zb/linux-arm64", expected: pkg.Package{ Name: "openssl", Version: "1.1.1zb", Type: "binary", PURL: "pkg:generic/openssl@1.1.1zb", Locations: locations("openssl"), Metadata: metadata("openssl-binary"), }, }, { logicalFixture: "aws-lc/1.69.0/linux-amd64", expected: pkg.Package{ Name: "aws-lc", Version: "1.69.0", Type: "binary", PURL: "pkg:generic/aws-lc@1.69.0", Locations: locations("openssl"), Metadata: metadata("openssl-binary-aws-lc"), }, }, { logicalFixture: "openldap/2.6.10/linux-amd64", expected: pkg.Package{ Name: "openldap", Version: "2.6.10", Type: "binary", PURL: "pkg:generic/openldap@2.6.10", Locations: locations("ldapsearch"), Metadata: metadata("openldap-search-binary"), }, }, { logicalFixture: "qt/4.8.6/linux-amd64", expected: pkg.Package{ Name: "qtbase", Version: "4.8.6", Type: "binary", PURL: "pkg:generic/qtbase@4.8.6", Locations: locations("libQtCore.so.4.8.6"), Metadata: metadata("qt-qtbase-lib"), }, }, { logicalFixture: "qt/5.15.2/linux-amd64", expected: pkg.Package{ Name: "qtbase", Version: "5.15.2", Type: "binary", PURL: "pkg:generic/qtbase@5.15.2", Locations: locations("libQt5Core.so.5.15.2"), Metadata: metadata("qt-qtbase-lib"), }, }, { logicalFixture: "qt/6.5.0/linux-amd64", expected: pkg.Package{ Name: "qtbase", Version: "6.5.0", Type: "binary", PURL: "pkg:generic/qtbase@6.5.0", Locations: locations("libQt6Core.so.6.5.0"), Metadata: metadata("qt-qtbase-lib"), }, }, { logicalFixture: "gcc/12.3.0/linux-amd64", expected: pkg.Package{ Name: "gcc", Version: "12.3.0", Type: "binary", PURL: "pkg:generic/gcc@12.3.0", Locations: locations("gcc"), Metadata: metadata("gcc-binary"), }, }, { logicalFixture: "fluent-bit/3.0.2/linux-amd64", expected: pkg.Package{ Name: "fluent-bit", Version: "3.0.2", Type: "binary", PURL: "pkg:github/fluent/fluent-bit@3.0.2", Locations: locations("fluent-bit"), Metadata: metadata("fluent-bit-binary"), }, }, { logicalFixture: "fluent-bit/2.2.1/linux-arm64", expected: pkg.Package{ Name: "fluent-bit", Version: "2.2.1", Type: "binary", PURL: "pkg:github/fluent/fluent-bit@2.2.1", Locations: locations("fluent-bit"), Metadata: metadata("fluent-bit-binary"), }, }, { logicalFixture: "fluent-bit/1.7.0-dev-3/linux-amd64", expected: pkg.Package{ Name: "fluent-bit", Version: "1.7.0", Type: "binary", PURL: "pkg:github/fluent/fluent-bit@1.7.0", Locations: locations("fluent-bit"), Metadata: metadata("fluent-bit-binary"), }, }, { logicalFixture: "fluent-bit/1.3.10/linux-arm", expected: pkg.Package{ Name: "fluent-bit", Version: "1.3.10", Type: "binary", PURL: "pkg:github/fluent/fluent-bit@1.3.10", Locations: locations("fluent-bit"), Metadata: metadata("fluent-bit-binary"), }, }, { logicalFixture: "wp/2.9.0/linux-amd64", expected: pkg.Package{ Name: "wp-cli", Version: "2.9.0", Type: "binary", PURL: "pkg:generic/wp-cli@2.9.0", Locations: locations("wp"), Metadata: metadata("wordpress-cli-binary"), }, }, { logicalFixture: "lighttpd/1.4.76/linux-amd64", expected: pkg.Package{ Name: "lighttpd", Version: "1.4.76", Type: "binary", PURL: "pkg:generic/lighttpd@1.4.76", Locations: locations("lighttpd"), Metadata: metadata("lighttpd-binary"), }, }, { logicalFixture: "proftpd/1.3.8b/linux-amd64", expected: pkg.Package{ Name: "proftpd", Version: "1.3.8b", Type: "binary", PURL: "pkg:generic/proftpd@1.3.8b", Locations: locations("proftpd"), Metadata: metadata("proftpd-binary"), }, }, { logicalFixture: "zstd/1.5.6/linux-amd64", expected: pkg.Package{ Name: "zstd", Version: "1.5.6", Type: "binary", PURL: "pkg:generic/zstd@1.5.6", Locations: locations("zstd"), Metadata: metadata("zstd-binary"), }, }, { logicalFixture: "zstd/1.5.6/linux-amd64", expected: pkg.Package{ Name: "zstd", Version: "1.5.6", Type: "binary", PURL: "pkg:generic/zstd@1.5.6", Locations: locations("zstd"), Metadata: metadata("zstd-binary"), }, }, { logicalFixture: "xz/5.6.2/linux-amd64", expected: pkg.Package{ Name: "xz", Version: "5.6.2", Type: "binary", PURL: "pkg:generic/xz@5.6.2", Locations: locations("xz"), Metadata: metadata("xz-binary"), }, }, { logicalFixture: "gzip/1.12/linux-amd64", expected: pkg.Package{ Name: "gzip", Version: "1.12", Type: "binary", PURL: "pkg:generic/gzip@1.12", Locations: locations("gzip"), Metadata: metadata("gzip-binary"), }, }, { logicalFixture: "sqlcipher/4.5.5/linux-amd64", expected: pkg.Package{ Name: "sqlcipher", Version: "4.5.5", Type: "binary", PURL: "pkg:generic/sqlcipher@4.5.5", Locations: locations("sqlcipher"), Metadata: metadata("sqlcipher-binary"), }, }, { logicalFixture: "jq/1.7.1/linux-amd64", expected: pkg.Package{ Name: "jq", Version: "1.7.1", Type: "binary", PURL: "pkg:generic/jq@1.7.1", Locations: locations("jq"), Metadata: metadata("jq-binary"), }, }, { logicalFixture: "chrome/126.0.6478.182/linux-amd64", expected: pkg.Package{ Name: "chrome", Version: "126.0.6478.182", Type: "binary", PURL: "pkg:generic/chrome@126.0.6478.182", Locations: locations("chrome"), Metadata: metadata("chrome-binary"), }, }, { logicalFixture: "chrome/127.0.6533.119/linux-amd64", expected: pkg.Package{ Name: "chrome", Version: "127.0.6533.119", Type: "binary", PURL: "pkg:generic/chrome@127.0.6533.119", Locations: locations("chrome"), Metadata: metadata("chrome-binary"), }, }, { logicalFixture: "firefox/151.0/linux-amd64", expected: pkg.Package{ Name: "firefox", Version: "151.0", Type: "binary", PURL: "pkg:generic/firefox@151.0", Locations: locations("firefox", "application.ini"), Metadata: metadata("firefox-binary"), }, }, { logicalFixture: "ffmpeg/7.1.1/darwin-arm64", expected: pkg.Package{ Name: "ffmpeg", Version: "7.1.1", Type: "binary", PURL: "pkg:generic/ffmpeg@7.1.1", Locations: locations("ffmpeg"), Metadata: metadata("ffmpeg-binary"), }, }, { logicalFixture: "ffmpeg/6.1.1/linux-amd64", expected: pkg.Package{ Name: "ffmpeg", Version: "6.1.1", Type: "binary", PURL: "pkg:generic/ffmpeg@6.1.1", Locations: locations("ffmpeg"), Metadata: metadata("ffmpeg-binary"), }, }, { logicalFixture: "ffmpeg-shared-libs/5.1.4/linux-amd64", expected: pkg.Package{ Name: "ffmpeg", Version: "5.1.4", Type: "binary", PURL: "pkg:generic/ffmpeg@5.1.4", Locations: locations("libavcodec-9aae324f.so.59.37.100"), Metadata: metadata("ffmpeg-library"), }, }, { logicalFixture: "elixir/1.19.1/linux-amd64", expected: pkg.Package{ Name: "elixir", Version: "1.19.1", Type: "binary", PURL: "pkg:generic/elixir@1.19.1", Locations: locations("elixir", "lib/elixir/ebin/elixir.app"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("elixir-binary", "elixir"), match("elixir-library", "lib/elixir/ebin/elixir.app"), }, }, }, }, { // release-candidate elixir image — pre-fix the matchers stripped the // "-rc.1" suffix from the elixir-library result and missed the // elixir-binary entirely (#4819). logicalFixture: "elixir/1.12.0-rc.1/linux-amd64", expected: pkg.Package{ Name: "elixir", Version: "1.12.0-rc.1", Type: "binary", PURL: "pkg:generic/elixir@1.12.0-rc.1", Locations: locations("elixir", "lib/elixir/ebin/elixir.app"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("elixir-binary", "elixir"), match("elixir-library", "lib/elixir/ebin/elixir.app"), }, }, }, }, { logicalFixture: "istio_pilot-discovery/1.29.0-alpha.0/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.29.0-alpha.0", Type: "binary", PURL: "pkg:generic/istio@1.29.0-alpha.0", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.29.0-beta.0/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.29.0-beta.0", Type: "binary", PURL: "pkg:generic/istio@1.29.0-beta.0", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.29.0-rc.3/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.29.0-rc.3", Type: "binary", PURL: "pkg:generic/istio@1.29.0-rc.3", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.26.8/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.26.8", Type: "binary", PURL: "pkg:generic/istio@1.26.8", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.10-dev/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.10-dev", Type: "binary", PURL: "pkg:generic/istio@1.10-dev", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.8.0/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.8.0", Type: "binary", PURL: "pkg:generic/istio@1.8.0", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.3.8/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.3.8", Type: "binary", PURL: "pkg:generic/istio@1.3.8", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-discovery/1.1.17/linux-amd64", expected: pkg.Package{ Name: "pilot-discovery", Version: "1.1.17", Type: "binary", PURL: "pkg:generic/istio@1.1.17", Locations: locations("pilot-discovery"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.29.0-alpha.0/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.29.0-alpha.0", Type: "binary", PURL: "pkg:generic/istio@1.29.0-alpha.0", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.29.0-beta.0/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.29.0-beta.0", Type: "binary", PURL: "pkg:generic/istio@1.29.0-beta.0", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.29.0-rc.3/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.29.0-rc.3", Type: "binary", PURL: "pkg:generic/istio@1.29.0-rc.3", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.26.8/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.26.8", Type: "binary", PURL: "pkg:generic/istio@1.26.8", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.10-dev/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.10-dev", Type: "binary", PURL: "pkg:generic/istio@1.10-dev", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.8.0/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.8.0", Type: "binary", PURL: "pkg:generic/istio@1.8.0", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "istio_pilot-agent/1.1.17/linux-amd64", expected: pkg.Package{ Name: "pilot-agent", Version: "1.1.17", Type: "binary", PURL: "pkg:generic/istio@1.1.17", Locations: locations("pilot-agent"), Metadata: metadata("istio-binary"), }, }, { logicalFixture: "grafana/12.4.0-22081664032/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.4.0-22081664032", Type: "binary", PURL: "pkg:generic/grafana@12.4.0-22081664032", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.3.2-security-01/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.3.2", Type: "binary", PURL: "pkg:generic/grafana@12.3.2", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.4.3-security-02/linux-arm", expected: pkg.Package{ Name: "grafana", Version: "12.4.3", Type: "binary", PURL: "pkg:generic/grafana@12.4.3", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.0.0-security-01/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.0.0", Type: "binary", PURL: "pkg:generic/grafana@12.0.0", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/11.0.5-security-01/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "11.0.5", Type: "binary", PURL: "pkg:generic/grafana@11.0.5", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.3.1/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.3.1", Type: "binary", PURL: "pkg:generic/grafana@12.3.1", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.2.0-258092/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.2.0-258092", Type: "binary", PURL: "pkg:generic/grafana@12.2.0-258092", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/12.0.0/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "12.0.0", Type: "binary", PURL: "pkg:generic/grafana@12.0.0", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/11.0.0-preview/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "11.0.0-preview", Type: "binary", PURL: "pkg:generic/grafana@11.0.0-preview", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/11.0.0/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "11.0.0", Type: "binary", PURL: "pkg:generic/grafana@11.0.0", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/10.4.19/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "10.4.19", Type: "binary", PURL: "pkg:generic/grafana@10.4.19", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/10.3.12/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "10.3.12", Type: "binary", PURL: "pkg:generic/grafana@10.3.12", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.5.21/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.5.21", Type: "binary", PURL: "pkg:generic/grafana@9.5.21", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.4.0-beta1/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.4.0-beta1", Type: "binary", PURL: "pkg:generic/grafana@9.4.0-beta1", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.3.0-beta1/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.3.0-beta1", Type: "binary", PURL: "pkg:generic/grafana@9.3.0-beta1", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.2.20/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.2.20", Type: "binary", PURL: "pkg:generic/grafana@9.2.20", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.2.13/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.2.13", Type: "binary", PURL: "pkg:generic/grafana@9.2.13", Locations: locations("grafana"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/9.0.0/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "9.0.0", Type: "binary", PURL: "pkg:generic/grafana@9.0.0", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/7.5.17/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "7.5.17", Type: "binary", PURL: "pkg:generic/grafana@7.5.17", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/6.7.6/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "6.7.6", Type: "binary", PURL: "pkg:generic/grafana@6.7.6", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/6.7.0-test/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "6.7.0-test", Type: "binary", PURL: "pkg:generic/grafana@6.7.0-test", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "grafana/6.0.0-beta1/linux-amd64", expected: pkg.Package{ Name: "grafana", Version: "6.0.0-beta1", Type: "binary", PURL: "pkg:generic/grafana@6.0.0-beta1", Locations: locations("grafana-server"), Metadata: metadata("grafana-binary"), }, }, { logicalFixture: "envoy/1.36.4/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.36.4", Type: "binary", PURL: "pkg:generic/envoy@1.36.4", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.34.5/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.34.5", Type: "binary", PURL: "pkg:generic/envoy@1.34.5", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.28.7/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.28.7", Type: "binary", PURL: "pkg:generic/envoy@1.28.7", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.22.11/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.22.11", Type: "binary", PURL: "pkg:generic/envoy@1.22.11", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.20.7/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.20.7", Type: "binary", PURL: "pkg:generic/envoy@1.20.7", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.18.6/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.18.6-dev", Type: "binary", PURL: "pkg:generic/envoy@1.18.6-dev", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.14.3/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.14.3", Type: "binary", PURL: "pkg:generic/envoy@1.14.3", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.11.0/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.11.0", Type: "binary", PURL: "pkg:generic/envoy@1.11.0", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.6.0/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.6.0", Type: "binary", PURL: "pkg:generic/envoy@1.6.0", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.15.1/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.15.1", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.15.1", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.11.8/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.11.8", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.11.8", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.9.6/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.9.6", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.9.6", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.9.6/linux-arm64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.9.6", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.9.6", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.9.6/linux-arm", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.9.6", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.9.6", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.9.6/linux-s390x", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.9.6", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.9.6", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.7.1/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.7.1", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.7.1", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.12.0-beta.0/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.12.0-beta.0", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.12.0-beta.0", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.2.0-beta.1/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.2.0-beta.1", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.2.0-beta.1", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/1.0.0-alpha.2/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "1.0.0-alpha.2", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@1.0.0-alpha.2", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/0.34.0/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "0.34.0", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@0.34.0", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "nginx-ingress-controller/0.33.0/linux-amd64", expected: pkg.Package{ Name: "nginx-ingress-controller", Version: "0.33.0", Type: "binary", PURL: "pkg:generic/nginx-ingress-controller@0.33.0", Locations: locations("nginx-ingress-controller"), Metadata: metadata("ingress-nginx-binary"), }, }, { logicalFixture: "filebeat/9.4.2/linux-amd64", expected: pkg.Package{ Name: "filebeat", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/filebeat@9.4.2", Locations: locations("filebeat"), Metadata: metadata("filebeat-binary"), }, }, { logicalFixture: "filebeat/8.18.4/linux-amd64", expected: pkg.Package{ Name: "filebeat", Version: "8.18.4", Type: "binary", PURL: "pkg:generic/filebeat@8.18.4", Locations: locations("filebeat"), Metadata: metadata("filebeat-binary"), }, }, { logicalFixture: "filebeat/8.11.2/linux-amd64", expected: pkg.Package{ Name: "filebeat", Version: "8.11.2", Type: "binary", PURL: "pkg:generic/filebeat@8.11.2", Locations: locations("filebeat"), Metadata: metadata("filebeat-binary"), }, }, { logicalFixture: "metricbeat/9.4.2/linux-amd64", expected: pkg.Package{ Name: "metricbeat", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/metricbeat@9.4.2", Locations: locations("metricbeat"), Metadata: metadata("metricbeat-binary"), }, }, { logicalFixture: "heartbeat/9.4.2/linux-amd64", expected: pkg.Package{ Name: "heartbeat", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/heartbeat@9.4.2", Locations: locations("heartbeat"), Metadata: metadata("heartbeat-binary"), }, }, { logicalFixture: "packetbeat/9.4.2/linux-amd64", expected: pkg.Package{ Name: "packetbeat", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/packetbeat@9.4.2", Locations: locations("packetbeat"), Metadata: metadata("packetbeat-binary"), }, }, { logicalFixture: "auditbeat/9.4.2/linux-amd64", expected: pkg.Package{ Name: "auditbeat", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/auditbeat@9.4.2", Locations: locations("auditbeat"), Metadata: metadata("auditbeat-binary"), }, }, { logicalFixture: "elastic-agent/9.4.2/linux-amd64", expected: pkg.Package{ Name: "elastic-agent", Version: "9.4.2", Type: "binary", PURL: "pkg:generic/elastic-agent@9.4.2", Locations: locations("elastic-agent"), Metadata: metadata("elastic-agent-binary"), }, }, { logicalFixture: "elastic-agent/9.0.0/linux-amd64", expected: pkg.Package{ Name: "elastic-agent", Version: "9.0.0", Type: "binary", PURL: "pkg:generic/elastic-agent@9.0.0", Locations: locations("elastic-agent"), Metadata: metadata("elastic-agent-binary"), }, }, { logicalFixture: "elastic-agent/8.19.4/linux-amd64", expected: pkg.Package{ Name: "elastic-agent", Version: "8.19.4", Type: "binary", PURL: "pkg:generic/elastic-agent@8.19.4", Locations: locations("elastic-agent"), Metadata: metadata("elastic-agent-binary"), }, }, { logicalFixture: "elastic-agent/8.11.2/linux-amd64", expected: pkg.Package{ Name: "elastic-agent", Version: "8.11.2", Type: "binary", PURL: "pkg:generic/elastic-agent@8.11.2", Locations: locations("elastic-agent"), Metadata: metadata("elastic-agent-binary"), }, }, { logicalFixture: "julia/1.13.0-alpha2/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.13.0-alpha2", Type: "binary", PURL: "pkg:generic/julia@1.13.0-alpha2", Locations: locations("libjulia-internal.so.1.13.0"), Metadata: metadata("julia-binary"), }, }, { logicalFixture: "julia/1.12.6/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.12.6", Type: "binary", PURL: "pkg:generic/julia@1.12.6", Locations: locations("libjulia-internal.so.1.12.6"), Metadata: metadata("julia-binary"), }, }, { logicalFixture: "julia/1.11.9/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.11.9", Type: "binary", PURL: "pkg:generic/julia@1.11.9", Locations: locations("libjulia-internal.so.1.11.9"), Metadata: metadata("julia-binary"), }, }, { logicalFixture: "julia/1.10.11/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.10.11", Type: "binary", PURL: "pkg:generic/julia@1.10.11", Locations: locations("libjulia-internal.so.1.10.11"), Metadata: metadata("julia-binary"), }, }, { logicalFixture: "julia/1.9.0-alpha1/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.9.0-alpha1", Type: "binary", PURL: "pkg:generic/julia@1.9.0-alpha1", Locations: locations("libjulia-internal.so.1.9"), Metadata: metadata("julia-binary"), }, }, { logicalFixture: "julia/1.8.5/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.8.5", Type: "binary", PURL: "pkg:generic/julia@1.8.5", Locations: locations("libjulia-internal.so.1.8"), Metadata: metadata("julia-binary"), }, }, { // note: dynamic (non-snippet) test case logicalFixture: "julia/1.5.4/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.5.4", Type: "binary", PURL: "pkg:generic/julia@1.5.4", Locations: locations("julia", "libjulia.so.1.5"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("julia-binary", "julia"), match("julia-binary", "libjulia.so.1.5"), }, }, }, }, { // note: dynamic (non-snippet) test case logicalFixture: "julia/1.3.1/linux-amd64", expected: pkg.Package{ Name: "julia", Version: "1.3.1", Type: "binary", PURL: "pkg:generic/julia@1.3.1", Locations: locations("julia", "libjulia.so.1.3"), Metadata: pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match("julia-binary", "julia"), match("julia-binary", "libjulia.so.1.3"), }, }, }, }, { logicalFixture: "envoy/1.22.10/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.22.10", Type: "binary", PURL: "pkg:generic/envoy@1.22.10", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.24.5/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.24.5", Type: "binary", PURL: "pkg:generic/envoy@1.24.5", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.30.2/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.30.2", Type: "binary", PURL: "pkg:generic/envoy@1.30.2", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.31.2/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.31.2", Type: "binary", PURL: "pkg:generic/envoy@1.31.2", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.34.12/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.34.12", Type: "binary", PURL: "pkg:generic/envoy@1.34.12", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.35.4/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.35.4", Type: "binary", PURL: "pkg:generic/envoy@1.35.4", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.23.7/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.23.7", Type: "binary", PURL: "pkg:generic/envoy@1.23.7", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.24.9/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.24.9", Type: "binary", PURL: "pkg:generic/envoy@1.24.9", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.30.1/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.30.1", Type: "binary", PURL: "pkg:generic/envoy@1.30.1", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.30.6/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.30.6", Type: "binary", PURL: "pkg:generic/envoy@1.30.6", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, { logicalFixture: "envoy/1.36.1/linux-amd64", expected: pkg.Package{ Name: "envoy", Version: "1.36.1", Type: "binary", PURL: "pkg:generic/envoy@1.36.1", Locations: locations("envoy"), Metadata: metadata("envoy-binary"), }, }, } for _, test := range tests { t.Run(test.logicalFixture, func(t *testing.T) { c := NewClassifierCataloger(DefaultClassifierCatalogerConfig()) // logicalFixture is the logical path to the full binary or snippet. This is relative to the testdata/classifiers/snippets // or testdata/classifiers/bin directory . Snippets are searched for first, and if not found, then existing binaries are // used. If no binary or snippet is found the test will fail. If '-must-use-original-binaries' is used the only // full binaries are tested (no snippets), and if no binary is found the test will be skipped. path := testutil.SnippetOrBinary(t, test.logicalFixture, *mustUseOriginalBinaries) src, err := directorysource.NewFromPath(path) require.NoError(t, err) resolver, err := src.FileResolver(source.SquashedScope) require.NoError(t, err) packages, _, err := c.Catalog(context.Background(), resolver) require.NoError(t, err) expected := test.expectedPackages if len(expected) == 0 { expected = []pkg.Package{test.expected} } require.Len(t, packages, len(expected), "mismatched package count") for i := range expected { assertPackagesAreEqual(t, expected[i], packages[i]) } }) } } func Test_Cataloger_DefaultClassifiers_PositiveCases_Image(t *testing.T) { tests := []struct { name string fixtureImage string expected pkg.Package }{ { name: "busybox-regression", fixtureImage: "image-busybox", expected: pkg.Package{ Name: "busybox", Version: "1.35.0", PURL: "pkg:generic/busybox@1.35.0", Locations: locations("/bin/busybox"), Metadata: metadata("busybox-binary", "/bin/busybox"), }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { c := NewClassifierCataloger(DefaultClassifierCatalogerConfig()) img := imagetest.GetFixtureImage(t, "docker-archive", test.fixtureImage) src := stereoscopesource.New(img, stereoscopesource.ImageConfig{ Reference: test.fixtureImage, }) resolver, err := src.FileResolver(source.SquashedScope) require.NoError(t, err) packages, _, err := c.Catalog(context.Background(), resolver) require.NoError(t, err) for _, p := range packages { assertPackagesAreEqual(t, test.expected, p) } }) } } // Test_Cataloger_PackageTypes covers what assertPackagesAreEqual deliberately ignores: the package type and CPEs. // The perl interpreter is reported as cpan so it lines up with the rest of the CPAN ecosystem, everything else // keeps the default binary type. func Test_Cataloger_PackageTypes(t *testing.T) { tests := []struct { logicalFixture string wantType pkg.Type wantPURL string wantCPEs []string }{ { logicalFixture: "perl/5.20.0/linux-amd64", wantType: pkg.CpanPkg, wantPURL: "pkg:cpan/perl@5.20.0", wantCPEs: []string{"cpe:2.3:a:perl:perl:5.20.0:*:*:*:*:*:*:*"}, }, { logicalFixture: "haproxy/1.5.14/linux-amd64", wantType: pkg.BinaryPkg, wantPURL: "pkg:generic/haproxy@1.5.14", wantCPEs: []string{"cpe:2.3:a:haproxy:haproxy:1.5.14:*:*:*:*:*:*:*"}, }, } for _, test := range tests { t.Run(test.logicalFixture, func(t *testing.T) { c := NewClassifierCataloger(DefaultClassifierCatalogerConfig()) path := testutil.SnippetOrBinary(t, test.logicalFixture, *mustUseOriginalBinaries) src, err := directorysource.NewFromPath(path) require.NoError(t, err) resolver, err := src.FileResolver(source.SquashedScope) require.NoError(t, err) packages, _, err := c.Catalog(context.Background(), resolver) require.NoError(t, err) require.Len(t, packages, 1) var cpes []string for _, c := range packages[0].CPEs { cpes = append(cpes, c.Attributes.BindToFmtString()) } assert.Equal(t, test.wantType, packages[0].Type) assert.Equal(t, test.wantPURL, packages[0].PURL) assert.Equal(t, test.wantCPEs, cpes) }) } } func TestClassifierCataloger_DefaultClassifiers_NegativeCases(t *testing.T) { c := NewClassifierCataloger(DefaultClassifierCatalogerConfig()) src, err := directorysource.NewFromPath("testdata/classifiers/negative") assert.NoError(t, err) resolver, err := src.FileResolver(source.SquashedScope) assert.NoError(t, err) actualResults, _, err := c.Catalog(context.Background(), resolver) assert.NoError(t, err) assert.Equal(t, 0, len(actualResults)) } func Test_Cataloger_CustomClassifiers(t *testing.T) { defaultClassifers := DefaultClassifiers() golangExpected := pkg.Package{ Name: "go", Version: "1.14", PURL: "pkg:generic/go@1.14", Locations: locations("go"), Metadata: metadata("go-binary"), } customExpected := pkg.Package{ Name: "foo", Version: "1.2.3", PURL: "pkg:generic/foo@1.2.3", Locations: locations("foo"), Metadata: metadata("foo-binary"), } fooClassifier := binutils.Classifier{ Class: "foo-binary", FileGlob: "**/foo", EvidenceMatcher: binutils.FileContentsVersionMatcher( catalogerName, `(?m)foobar\s(?P[0-9]+\.[0-9]+\.[0-9]+)`, ), Package: "foo", PURL: mustPURL("pkg:generic/foo@version"), CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"), } tests := []struct { name string config ClassifierCatalogerConfig fixtureDir string expected *pkg.Package }{ { name: "empty-negative", config: ClassifierCatalogerConfig{ Classifiers: []binutils.Classifier{}, }, fixtureDir: "testdata/custom/go-1.14", expected: nil, }, { name: "default-positive", config: ClassifierCatalogerConfig{ Classifiers: defaultClassifers, }, fixtureDir: "testdata/custom/go-1.14", expected: &golangExpected, }, { name: "nodefault-negative", config: ClassifierCatalogerConfig{ Classifiers: []binutils.Classifier{fooClassifier}, }, fixtureDir: "testdata/custom/go-1.14", expected: nil, }, { name: "default-extended-positive", config: ClassifierCatalogerConfig{ Classifiers: append( append([]binutils.Classifier{}, defaultClassifers...), fooClassifier, ), }, fixtureDir: "testdata/custom/go-1.14", expected: &golangExpected, }, { name: "default-custom-negative", config: ClassifierCatalogerConfig{ Classifiers: append( append([]binutils.Classifier{}, defaultClassifers...), binutils.Classifier{ Class: "foo-binary", FileGlob: "**/foo", EvidenceMatcher: binutils.FileContentsVersionMatcher(catalogerName, `(?m)not there`), Package: "foo", PURL: mustPURL("pkg:generic/foo@version"), CPEs: singleCPE("cpe:2.3:a:foo:foo:*:*:*:*:*:*:*:*"), }, ), }, fixtureDir: "testdata/custom/extra", expected: nil, }, { name: "default-cutsom-positive", config: ClassifierCatalogerConfig{ Classifiers: append( append([]binutils.Classifier{}, defaultClassifers...), fooClassifier, ), }, fixtureDir: "testdata/custom/extra", expected: &customExpected, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { c := NewClassifierCataloger(test.config) src, err := directorysource.NewFromPath(test.fixtureDir) require.NoError(t, err) resolver, err := src.FileResolver(source.SquashedScope) require.NoError(t, err) packages, _, err := c.Catalog(context.Background(), resolver) require.NoError(t, err) if test.expected == nil { assert.Equal(t, 0, len(packages)) } else { require.Len(t, packages, 1) assertPackagesAreEqual(t, *test.expected, packages[0]) } }) } } func locations(locations ...string) file.LocationSet { var locs []file.Location for _, s := range locations { locs = append(locs, file.NewLocation(s)) } return file.NewLocationSet(locs...) } // metadata paths are: realPath, virtualPath func metadata(classifier string, paths ...string) pkg.BinarySignature { return pkg.BinarySignature{ Matches: []pkg.ClassifierMatch{ match(classifier, paths...), }, } } // match paths are: realPath, virtualPath func match(classifier string, paths ...string) pkg.ClassifierMatch { realPath := "" if len(paths) > 0 { realPath = paths[0] } virtualPath := "" if len(paths) > 1 { virtualPath = paths[1] } return pkg.ClassifierMatch{ Classifier: classifier, Location: file.NewVirtualLocationFromCoordinates( file.Coordinates{ RealPath: realPath, }, virtualPath, ), } } func assertPackagesAreEqual(t *testing.T, expected pkg.Package, p pkg.Package) { var failMessages []string expectedLocations := expected.Locations.ToSlice() gotLocations := p.Locations.ToSlice() if len(expectedLocations) != len(gotLocations) { failMessages = append(failMessages, fmt.Sprintf("locations are not equal: %v != %v", expectedLocations, gotLocations)) } else { for _, expectedLocation := range expectedLocations { if !slices.ContainsFunc(gotLocations, func(gotLocation file.Location) bool { return gotLocation.RealPath == expectedLocation.RealPath }) { failMessages = append(failMessages, fmt.Sprintf("location not found; expected: %v in set: %v", expectedLocation.RealPath, gotLocations)) } } } m1 := expected.Metadata.(pkg.BinarySignature).Matches m2 := p.Metadata.(pkg.BinarySignature).Matches matches := true if len(m1) == len(m2) { for i, m1 := range m1 { m2 := m2[i] if m1.Classifier != m2.Classifier { matches = false break } } } else { matches = false } if !matches { failMessages = append(failMessages, "classifier matches not equal") } if expected.Name != p.Name || expected.Version != p.Version || expected.PURL != p.PURL { failMessages = append(failMessages, "packages do not match") } if len(failMessages) > 0 { assert.Failf(t, strings.Join(failMessages, "; "), "diff: %s", cmp.Diff(expected, p, cmp.Transformer("Locations", func(l file.LocationSet) []file.Location { return l.ToSlice() }), cmpopts.IgnoreUnexported(pkg.Package{}, file.LocationData{}), cmpopts.IgnoreFields(pkg.Package{}, "CPEs", "FoundBy", "Type", "Locations", "Licenses"), ), ) } } type panicyResolver struct { searchCalled bool } func (p *panicyResolver) FilesByExtension(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FilesByBasename(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FilesByBasenameGlob(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FileContentsByLocation(_ file.Location) (io.ReadCloser, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) HasPath(_ string) bool { return true } func (p *panicyResolver) FilesByPath(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FilesByGlob(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FilesByMIMEType(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) FilesByMediaType(_ ...string) ([]file.Location, error) { p.searchCalled = true return nil, errors.New("not implemented") } func (p *panicyResolver) RelativeFileByPath(_ file.Location, _ string) *file.Location { return nil } func (p *panicyResolver) AllLocations(_ context.Context) <-chan file.Location { return nil } func (p *panicyResolver) FileMetadataByLocation(_ file.Location) (file.Metadata, error) { return file.Metadata{}, errors.New("not implemented") } var _ file.Resolver = (*panicyResolver)(nil) func Test_Cataloger_ResilientToErrors(t *testing.T) { c := NewClassifierCataloger(DefaultClassifierCatalogerConfig()) resolver := &panicyResolver{} _, _, err := c.Catalog(context.Background(), resolver) assert.Nil(t, err) // non-coordinate-based FindBy* errors are now logged and not returned assert.True(t, resolver.searchCalled) } func TestCatalogerConfig_MarshalJSON(t *testing.T) { tests := []struct { name string cfg ClassifierCatalogerConfig want string wantErr assert.ErrorAssertionFunc }{ { name: "only show names of classes", cfg: ClassifierCatalogerConfig{ Classifiers: []binutils.Classifier{ { Class: "class", FileGlob: "glob", EvidenceMatcher: binutils.FileContentsVersionMatcher(catalogerName, ".thing"), Package: "pkg", PURL: packageurl.PackageURL{ Type: "type", Namespace: "namespace", Name: "name", Version: "version", Qualifiers: nil, Subpath: "subpath", }, CPEs: []cpe.CPE{cpe.Must("cpe:2.3:a:some:app:*:*:*:*:*:*:*:*", cpe.GeneratedSource)}, }, }, }, want: `["class"]`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.wantErr == nil { tt.wantErr = assert.NoError } got, err := tt.cfg.MarshalJSON() if !tt.wantErr(t, err) { return } assert.Equal(t, tt.want, string(got)) }) } }