Files
syft/syft/pkg/cataloger/php/interpreter_cataloger_test.go
T
Alex Goodman 901d7bbab2 fix: don't infer archive nesting from paths in error text
`ProcessPathErrors` cut the `path="..."` it pulled out of an error at the first `!/` and built nested
coordinates from it, so a host file with `!/` in its name was reported as a file inside an archive.

- paths from error text are taken as plain real paths again, as on main
- the php extension reader already has the location in hand, so it records the unknown against that
  instead of re-parsing the error (this is the one caller that could see a nested path). It also
  no longer defers `Close` on a nil reader when the read fails

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-10-21 11:28:53 -04:00

183 lines
12 KiB
Go

package php
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/anchore/syft/internal/unknown"
"github.com/anchore/syft/syft/cpe"
"github.com/anchore/syft/syft/file"
"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.27 (/usr/local/bin/php)",
"php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
// extensions
"bcmath @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so)",
"exif @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so)",
"ftp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so)",
"gd @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so)",
"gmp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so)",
"intl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so)",
"ldap @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so)",
"opcache @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so)",
"pcntl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so)",
"pdo_mysql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so)",
"pdo_pgsql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so)",
"sodium @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so)",
"sysvsem @ 8.3.27 (/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.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"bcmath @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/bcmath.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"exif @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"exif @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/exif.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"ftp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"ftp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ftp.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"gd @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"gd @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gd.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"gmp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"gmp @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/gmp.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"intl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"intl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/intl.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"ldap @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"ldap @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/ldap.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"opcache @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"opcache @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/opcache.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"pcntl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"pcntl @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pcntl.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"pdo_mysql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"pdo_mysql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_mysql.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"pdo_pgsql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"pdo_pgsql @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/pdo_pgsql.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"sodium @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"sodium @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sodium.so) [dependency-of] php-fpm @ 8.3.27 (/usr/local/sbin/php-fpm)",
"sysvsem @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sysvsem.so) [dependency-of] php-cli @ 8.3.27 (/usr/local/bin/php)",
"sysvsem @ 8.3.27 (/usr/local/lib/php/extensions/no-debug-non-zts-20230831/sysvsem.so) [dependency-of] php-fpm @ 8.3.27 (/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.27 (/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.27 (/usr/local/sbin/php-fpm)",
},
},
{
name: "apache installation with libphp and extensions",
fixture: "image-apache",
expectedPkgs: []string{
// interpreters
"libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
// extensions
"calendar @ 8.2.31 (/usr/lib/php/20220829/calendar.so)",
"ctype @ 8.2.31 (/usr/lib/php/20220829/ctype.so)",
"exif @ 8.2.31 (/usr/lib/php/20220829/exif.so)",
"ffi @ 8.2.31 (/usr/lib/php/20220829/ffi.so)",
"fileinfo @ 8.2.31 (/usr/lib/php/20220829/fileinfo.so)",
"ftp @ 8.2.31 (/usr/lib/php/20220829/ftp.so)",
"gettext @ 8.2.31 (/usr/lib/php/20220829/gettext.so)",
"iconv @ 8.2.31 (/usr/lib/php/20220829/iconv.so)",
"mysqli @ 8.2.31 (/usr/lib/php/20220829/mysqli.so)",
"opcache @ 8.2.31 (/usr/lib/php/20220829/opcache.so)",
"pdo @ 8.2.31 (/usr/lib/php/20220829/pdo.so)",
"pdo_mysql @ 8.2.31 (/usr/lib/php/20220829/pdo_mysql.so)",
"phar @ 8.2.31 (/usr/lib/php/20220829/phar.so)",
"posix @ 8.2.31 (/usr/lib/php/20220829/posix.so)",
"readline @ 8.2.31 (/usr/lib/php/20220829/readline.so)",
"shmop @ 8.2.31 (/usr/lib/php/20220829/shmop.so)",
"simplexml @ 8.2.31 (/usr/lib/php/20220829/simplexml.so)",
"sockets @ 8.2.31 (/usr/lib/php/20220829/sockets.so)",
"sysvmsg @ 8.2.31 (/usr/lib/php/20220829/sysvmsg.so)",
"sysvsem @ 8.2.31 (/usr/lib/php/20220829/sysvsem.so)",
"sysvshm @ 8.2.31 (/usr/lib/php/20220829/sysvshm.so)",
"tokenizer @ 8.2.31 (/usr/lib/php/20220829/tokenizer.so)",
"xml @ 8.2.31 (/usr/lib/php/20220829/xml.so)",
"xmlreader @ 8.2.31 (/usr/lib/php/20220829/xmlreader.so)",
"xmlwriter @ 8.2.31 (/usr/lib/php/20220829/xmlwriter.so)",
"xsl @ 8.2.31 (/usr/lib/php/20220829/xsl.so)",
},
expectedRels: []string{
"calendar @ 8.2.31 (/usr/lib/php/20220829/calendar.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ctype @ 8.2.31 (/usr/lib/php/20220829/ctype.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"exif @ 8.2.31 (/usr/lib/php/20220829/exif.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ffi @ 8.2.31 (/usr/lib/php/20220829/ffi.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"fileinfo @ 8.2.31 (/usr/lib/php/20220829/fileinfo.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"ftp @ 8.2.31 (/usr/lib/php/20220829/ftp.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"gettext @ 8.2.31 (/usr/lib/php/20220829/gettext.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"iconv @ 8.2.31 (/usr/lib/php/20220829/iconv.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"mysqli @ 8.2.31 (/usr/lib/php/20220829/mysqli.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"opcache @ 8.2.31 (/usr/lib/php/20220829/opcache.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo @ 8.2.31 (/usr/lib/php/20220829/pdo.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"pdo_mysql @ 8.2.31 (/usr/lib/php/20220829/pdo_mysql.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"phar @ 8.2.31 (/usr/lib/php/20220829/phar.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"posix @ 8.2.31 (/usr/lib/php/20220829/posix.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"readline @ 8.2.31 (/usr/lib/php/20220829/readline.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"shmop @ 8.2.31 (/usr/lib/php/20220829/shmop.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"simplexml @ 8.2.31 (/usr/lib/php/20220829/simplexml.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sockets @ 8.2.31 (/usr/lib/php/20220829/sockets.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvmsg @ 8.2.31 (/usr/lib/php/20220829/sysvmsg.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvsem @ 8.2.31 (/usr/lib/php/20220829/sysvsem.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"sysvshm @ 8.2.31 (/usr/lib/php/20220829/sysvshm.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"tokenizer @ 8.2.31 (/usr/lib/php/20220829/tokenizer.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xml @ 8.2.31 (/usr/lib/php/20220829/xml.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlreader @ 8.2.31 (/usr/lib/php/20220829/xmlreader.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xmlwriter @ 8.2.31 (/usr/lib/php/20220829/xmlwriter.so) [dependency-of] libphp @ 8.2.31 (/usr/lib/apache2/modules/libphp8.2.so)",
"xsl @ 8.2.31 (/usr/lib/php/20220829/xsl.so) [dependency-of] libphp @ 8.2.31 (/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)
})
}
}
func Test_getClassifier_declaredCPESource(t *testing.T) {
// regression test for https://github.com/anchore/syft/issues/5014
// the CPE assigned to a PHP extension must be declared (not generated) so that downstream CPE
// generation does not also add a misleading CPE derived from the bare extension name alone
// (e.g. cpe:2.3:a:openssl:openssl:... for the openssl extension, implying the upstream OpenSSL project).
c := interpreterCataloger{name: "php-interpreter-cataloger"}
name, cls := c.getClassifier("/usr/lib/php85/modules/openssl.so")
require.Equal(t, "openssl", name)
require.NotNil(t, cls)
require.Len(t, cls.CPEs, 1)
assert.Equal(t, cpe.DeclaredSource, cls.CPEs[0].Source)
}
func Test_catalogExtension_unreadableFileKeepsItsCoordinates(t *testing.T) {
nested := file.NewLocationFromCoordinates(file.Coordinates{
RealPath: "/app.tar",
FullPath: "/app.tar!/usr/lib/php83/modules/bcmath.so",
})
c := NewInterpreterCataloger().(interpreterCataloger)
_, err := c.catalogExtension(file.NewMockResolverForPaths(), nested)
var coordinateErr *unknown.CoordinateError
require.ErrorAs(t, err, &coordinateErr)
assert.Equal(t, nested.Coordinates, coordinateErr.Coordinates)
}