diff --git a/syft/pkg/cataloger/php/interpreter_cataloger.go b/syft/pkg/cataloger/php/interpreter_cataloger.go index 80ae69d21..f9022d358 100644 --- a/syft/pkg/cataloger/php/interpreter_cataloger.go +++ b/syft/pkg/cataloger/php/interpreter_cataloger.go @@ -236,7 +236,10 @@ func (p interpreterCataloger) getClassifier(realPath string) (string, *binutils. Vendor: fmt.Sprintf("php-%s", name), Product: fmt.Sprintf("php-%s", name), }, - Source: cpe.GeneratedSource, + // note: we must use a declared source here so that this CPE is treated as authoritative and no + // further CPEs are generated from the (misleading) package name alone, e.g. cpe:...:openssl:openssl + // for the openssl PHP extension, which would imply this is the upstream OpenSSL project. + Source: cpe.DeclaredSource, }, }, } diff --git a/syft/pkg/cataloger/php/interpreter_cataloger_test.go b/syft/pkg/cataloger/php/interpreter_cataloger_test.go index 8d6d9e6d7..bff331d5c 100644 --- a/syft/pkg/cataloger/php/interpreter_cataloger_test.go +++ b/syft/pkg/cataloger/php/interpreter_cataloger_test.go @@ -3,6 +3,10 @@ package php import ( "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/anchore/syft/syft/cpe" "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" ) @@ -147,3 +151,16 @@ func Test_InterpreterCataloger(t *testing.T) { }) } } + +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) +}