Skip to content

Commit

Permalink
Add support for PHP Pear and unify PECL with it
Browse files Browse the repository at this point in the history
Signed-off-by: Laurent Goderre <[email protected]>
  • Loading branch information
LaurentGoderre committed Apr 12, 2024
1 parent dde5d34 commit 5b03697
Show file tree
Hide file tree
Showing 20 changed files with 72 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ var commonTestCases = []testCase{
},
},
{
name: "find php pecl package",
pkgType: pkg.PhpPeclPkg,
name: "find php pear/pecl package",
pkgType: pkg.PhpPearPkg,
pkgLanguage: pkg.PHP,
pkgInfo: map[string]string{
"memcached": "3.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a:5:{s:4:"name";s:9:"memcached";s:4:"date";s:10:"2022-01-11";s:4:"time";s:8:"15:23:47";s:7:"version";a:2:{s:7:"release";s:5:"3.2.0";s:3:"api";s:5:"3.2.0";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}}
a:6:{s:4:"name";s:9:"memcached";s:7:"channel";s:12:"pecl.php.net";s:4:"date";s:10:"2022-01-11";s:4:"time";s:8:"15:23:47";s:7:"version";a:2:{s:7:"release";s:5:"3.2.0";s:3:"api";s:5:"3.2.0";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}}
2 changes: 1 addition & 1 deletion internal/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package internal
const (
// JSONSchemaVersion is the current schema version output by the JSON encoder
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "16.0.7"
JSONSchemaVersion = "16.0.8"
)
2 changes: 1 addition & 1 deletion internal/task/package_tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func DefaultPackageTaskFactories() PackageTaskFactories {
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "javascript", "node", "npm",
),
newSimplePackageTaskFactory(php.NewComposerLockCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, "php", "composer"),
newSimplePackageTaskFactory(php.NewPeclCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, pkgcataloging.ImageTag, "php", "pecl"),
newSimplePackageTaskFactory(php.NewPearCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.LanguageTag, pkgcataloging.ImageTag, "php", "pear"),
newPackageTaskFactory(
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
return python.NewPackageCataloger(cfg.PackagesConfig.Python)
Expand Down
10 changes: 7 additions & 3 deletions schema/json/schema-latest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "anchore.io/schema/syft/json/16.0.7/document",
"$id": "anchore.io/schema/syft/json/16.0.8/document",
"$ref": "#/$defs/Document",
"$defs": {
"AlpmDbEntry": {
Expand Down Expand Up @@ -1497,7 +1497,7 @@
"$ref": "#/$defs/PhpComposerLockEntry"
},
{
"$ref": "#/$defs/PhpPeclEntry"
"$ref": "#/$defs/PhpPearEntry"
},
{
"$ref": "#/$defs/PortageDbEntry"
Expand Down Expand Up @@ -1782,11 +1782,14 @@
"dist"
]
},
"PhpPeclEntry": {
"PhpPearEntry": {
"properties": {
"name": {
"type": "string"
},
"channel": {
"type": "string"
},
"version": {
"type": "string"
},
Expand All @@ -1800,6 +1803,7 @@
"type": "object",
"required": [
"name",
"channel",
"version"
]
},
Expand Down
4 changes: 2 additions & 2 deletions syft/format/internal/spdxutil/helpers/source_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ func SourceInfo(p pkg.Package) string {
answer = "acquired package info from rust cargo manifest"
case pkg.PhpComposerPkg:
answer = "acquired package info from PHP composer manifest"
case pkg.PhpPeclPkg:
answer = "acquired package info from PHP Pecl manifest"
case pkg.PhpPearPkg:
answer = "acquired package info from PHP Pear manifest"
case pkg.CocoapodsPkg:
answer = "acquired package info from installed cocoapods manifest file"
case pkg.ConanPkg:
Expand Down
4 changes: 2 additions & 2 deletions syft/format/internal/spdxutil/helpers/source_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ func Test_SourceInfo(t *testing.T) {
},
{
input: pkg.Package{
Type: pkg.PhpPeclPkg,
Type: pkg.PhpPearPkg,
},
expected: []string{
"from PHP Pecl manifest",
"from PHP Pear manifest",
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion syft/internal/packagemetadata/generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func AllTypes() []any {
pkg.NpmPackageLockEntry{},
pkg.PhpComposerInstalledEntry{},
pkg.PhpComposerLockEntry{},
pkg.PhpPeclEntry{},
pkg.PhpPearEntry{},
pkg.PortageEntry{},
pkg.PythonPackage{},
pkg.PythonPipfileLockEntry{},
Expand Down
2 changes: 1 addition & 1 deletion syft/internal/packagemetadata/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ var jsonTypes = makeJSONTypes(
jsonNames(pkg.YarnLockEntry{}, "javascript-yarn-lock-entry", "YarnLockJsonMetadata"),
jsonNames(pkg.PhpComposerLockEntry{}, "php-composer-lock-entry", "PhpComposerJsonMetadata"),
jsonNamesWithoutLookup(pkg.PhpComposerInstalledEntry{}, "php-composer-installed-entry", "PhpComposerJsonMetadata"), // the legacy value is split into two types, where the other is preferred
jsonNames(pkg.PhpPeclEntry{}, "php-pecl-entry", "PhpPeclMetadata"),
jsonNames(pkg.PhpPearEntry{}, "php-pear-entry", "PhpPearMetadata"),
jsonNames(pkg.PortageEntry{}, "portage-db-entry", "PortageMetadata"),
jsonNames(pkg.PythonPackage{}, "python-package", "PythonPackageMetadata"),
jsonNames(pkg.PythonPipfileLockEntry{}, "python-pipfile-lock-entry", "PythonPipfileLockMetadata"),
Expand Down
14 changes: 7 additions & 7 deletions syft/internal/packagemetadata/names_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,9 @@ func TestReflectTypeFromJSONName_LegacyValues(t *testing.T) {
expected: reflect.TypeOf(pkg.PythonRequirementsEntry{}),
},
{
name: "map pkg.PhpPeclEntry struct type",
input: "PhpPeclMetadata",
expected: reflect.TypeOf(pkg.PhpPeclEntry{}),
name: "map pkg.PhpPearEntry struct type",
input: "PhpPearMetadata",
expected: reflect.TypeOf(pkg.PhpPearEntry{}),
},
{
name: "map pkg.ErlangRebarLockEntry struct type",
Expand Down Expand Up @@ -420,10 +420,10 @@ func Test_JSONName_JSONLegacyName(t *testing.T) {
expectedLegacyName: "PhpComposerJsonMetadata", // note: maps to multiple entries (v11-12 breaking change)
},
{
name: "PhpPeclMetadata",
metadata: pkg.PhpPeclEntry{},
expectedJSONName: "php-pecl-entry",
expectedLegacyName: "PhpPeclMetadata",
name: "PhpPearMetadata",
metadata: pkg.PhpPearEntry{},
expectedJSONName: "php-pear-entry",
expectedLegacyName: "PhpPearMetadata",
},
{
name: "PortageMetadata",
Expand Down
8 changes: 4 additions & 4 deletions syft/pkg/cataloger/php/cataloger.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func NewComposerLockCataloger() pkg.Cataloger {
WithParserByGlobs(parseComposerLock, "**/composer.lock")
}

// NewPeclCataloger returns a new cataloger for PHP PECL metadata“.
func NewPeclCataloger() pkg.Cataloger {
return generic.NewCataloger("php-pecl-serialized-cataloger").
WithParserByGlobs(parsePeclSerialized, "**/php/.registry/.channel.*/*.reg")
// NewPearCataloger returns a new cataloger for PHP Pear metadata“.
func NewPearCataloger() pkg.Cataloger {
return generic.NewCataloger("php-pear-serialized-cataloger").
WithParserByGlobs(parsePearSerialized, "**/php/.registry/**/*.reg")
}
6 changes: 3 additions & 3 deletions syft/pkg/cataloger/php/cataloger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ func Test_ComposerLockCataloger_Globs(t *testing.T) {
}
}

func Test_PeclCataloger_Globs(t *testing.T) {
func Test_PearCataloger_Globs(t *testing.T) {
tests := []struct {
name string
fixture string
expected []string
}{
{
name: "obtain pecl files",
name: "obtain pear files",
fixture: "test-fixtures/glob-paths",
expected: []string{
"php/.registry/.channel.pecl.php.net/memcached.reg",
Expand All @@ -76,7 +76,7 @@ func Test_PeclCataloger_Globs(t *testing.T) {
pkgtest.NewCatalogTester().
FromDirectory(t, test.fixture).
ExpectsResolverContentQueries(test.expected).
TestCataloger(t, NewPeclCataloger())
TestCataloger(t, NewPearCataloger())
})
}
}
12 changes: 6 additions & 6 deletions syft/pkg/cataloger/php/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ func newComposerInstalledPackage(pd parsedInstalledData, indexLocation file.Loca
return p
}

func newPeclPackage(pd pkg.PhpPeclEntry, indexLocation file.Location) pkg.Package {
func newPearPackage(pd pkg.PhpPearEntry, indexLocation file.Location) pkg.Package {
p := pkg.Package{
Name: pd.Name,
Version: pd.Version,
Locations: file.NewLocationSet(indexLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(indexLocation, pd.License...)...),
PURL: packageURLFromPecl(pd.Name, pd.Version),
PURL: packageURLFromPear(pd.Name, pd.Channel, pd.Version),
Language: pkg.PHP,
Type: pkg.PhpPeclPkg,
Type: pkg.PhpPearPkg,
Metadata: pd,
}

Expand Down Expand Up @@ -82,10 +82,10 @@ func packageURL(name, version string) string {
return pURL.ToString()
}

func packageURLFromPecl(pkgName, version string) string {
func packageURLFromPear(pkgName, channel, version string) string {
pURL := packageurl.NewPackageURL(
"pecl",
"",
"pear",
channel,
pkgName,
version,
nil,
Expand Down
8 changes: 5 additions & 3 deletions syft/pkg/cataloger/php/package_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,24 @@ func Test_packageURL(t *testing.T) {
}
}

func Test_packageURLFromPecl(t *testing.T) {
func Test_packageURLFromPear(t *testing.T) {
tests := []struct {
name string
channel string
version string
expected string
}{
{
name: "memcached",
channel: "pecl.php.net",
version: "3.2.0",
expected: "pkg:pecl/[email protected]",
expected: "pkg:pear/pecl.php.net/[email protected]",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := packageURLFromPecl(test.name, test.version)
actual := packageURLFromPear(test.name, test.channel, test.version)
if actual != test.expected {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(test.expected, actual, true)
Expand Down
18 changes: 12 additions & 6 deletions syft/pkg/cataloger/php/parse_pecl_serialized.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)

// parsePeclSerialized is a parser function for PECL metadata contents, returning "Default" php packages discovered.
func parsePeclSerialized(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
// parsePearSerialized is a parser function for Pear metadata contents, returning "Default" php packages discovered.
func parsePearSerialized(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
var pkgs []pkg.Package
data, err := io.ReadAll(reader)

Expand All @@ -28,22 +28,28 @@ func parsePeclSerialized(_ context.Context, _ file.Resolver, _ *generic.Environm
)

if err != nil {
return nil, nil, fmt.Errorf("failed to parse pecl metadata file: %w", err)
return nil, nil, fmt.Errorf("failed to parse pear metadata file: %w", err)
}

name, ok := metadata["name"].(string)
if !ok {
return nil, nil, fmt.Errorf("failed to parse pecl package name: %w", err)
return nil, nil, fmt.Errorf("failed to parse pear package name: %w", err)
}

channel, ok := metadata["channel"].(string)
if !ok {
return nil, nil, fmt.Errorf("failed to parse pear package channel: %w", err)
}

version := readStruct(metadata, "version", "release")
license := readStruct(metadata, "license", "_content")

pkgs = append(
pkgs,
newPeclPackage(
pkg.PhpPeclEntry{
newPearPackage(
pkg.PhpPearEntry{
Name: name,
Channel: channel,
Version: version,
License: []string{
license,
Expand Down
11 changes: 6 additions & 5 deletions syft/pkg/cataloger/php/parse_pecl_serialized_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,28 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
)

func TestParsePeclSerialized(t *testing.T) {
func TestParsePearSerialized(t *testing.T) {
var expectedRelationships []artifact.Relationship
fixture := "test-fixtures/memcached.reg"
locations := file.NewLocationSet(file.NewLocation(fixture))
expectedPkgs := []pkg.Package{
{
Name: "memcached",
Version: "3.2.0",
PURL: "pkg:pecl/[email protected]",
PURL: "pkg:pear/pecl.php.net/[email protected]",
Locations: locations,
Licenses: pkg.NewLicenseSet(
pkg.NewLicenseFromLocations("PHP License", file.NewLocation(fixture)),
),
Language: pkg.PHP,
Type: pkg.PhpPeclPkg,
Metadata: pkg.PhpPeclEntry{
Type: pkg.PhpPearPkg,
Metadata: pkg.PhpPearEntry{
Name: "memcached",
Channel: "pecl.php.net",
Version: "3.2.0",
License: []string{"PHP License"},
},
},
}
pkgtest.TestFileParser(t, fixture, parsePeclSerialized, expectedPkgs, expectedRelationships)
pkgtest.TestFileParser(t, fixture, parsePearSerialized, expectedPkgs, expectedRelationships)
}
2 changes: 1 addition & 1 deletion syft/pkg/cataloger/php/test-fixtures/memcached.reg
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a:5:{s:4:"name";s:9:"memcached";s:4:"date";s:10:"2022-01-11";s:4:"time";s:8:"15:23:47";s:7:"version";a:2:{s:7:"release";s:5:"3.2.0";s:3:"api";s:5:"3.2.0";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}}
a:6:{s:4:"name";s:9:"memcached";s:7:"channel";s:12:"pecl.php.net";s:4:"date";s:10:"2022-01-11";s:4:"time";s:8:"15:23:47";s:7:"version";a:2:{s:7:"release";s:5:"3.2.0";s:3:"api";s:5:"3.2.0";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:26:"http://www.php.net/license";}s:8:"_content";s:11:"PHP License";}}
3 changes: 2 additions & 1 deletion syft/pkg/php.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ type PhpComposerAuthors struct {
Homepage string `json:"homepage,omitempty"`
}

type PhpPeclEntry struct {
type PhpPearEntry struct {
Name string `json:"name"`
Channel string `json:"channel"`
Version string `json:"version"`
License []string `json:"license,omitempty"`
}
12 changes: 6 additions & 6 deletions syft/pkg/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const (
NixPkg Type = "nix"
NpmPkg Type = "npm"
PhpComposerPkg Type = "php-composer"
PhpPeclPkg Type = "php-pecl"
PhpPearPkg Type = "php-pear"
PortagePkg Type = "portage"
PythonPkg Type = "python"
Rpkg Type = "R-package"
Expand Down Expand Up @@ -69,7 +69,7 @@ var AllPkgs = []Type{
NixPkg,
NpmPkg,
PhpComposerPkg,
PhpPeclPkg,
PhpPearPkg,
PortagePkg,
PythonPkg,
Rpkg,
Expand Down Expand Up @@ -119,8 +119,8 @@ func (t Type) PackageURLType() string {
return packageurl.TypeGeneric
case PhpComposerPkg:
return packageurl.TypeComposer
case PhpPeclPkg:
return "pecl"
case PhpPearPkg:
return "pear"
case PythonPkg:
return packageurl.TypePyPi
case PortagePkg:
Expand Down Expand Up @@ -173,8 +173,8 @@ func TypeByName(name string) Type {
return JavaPkg
case packageurl.TypeComposer:
return PhpComposerPkg
case "pecl":
return PhpPeclPkg
case "pear":
return PhpPearPkg
case packageurl.TypeGolang:
return GoModulePkg
case packageurl.TypeNPM:
Expand Down
4 changes: 2 additions & 2 deletions syft/pkg/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func TestTypeFromPURL(t *testing.T) {
expected: PhpComposerPkg,
},
{
purl: "pkg:pecl/[email protected]",
expected: PhpPeclPkg,
purl: "pkg:pear/pecl.php.net/[email protected]",
expected: PhpPearPkg,
},
{
purl: "pkg:maven/org.apache.xmlgraphics/[email protected]?type=zip&classifier=dist",
Expand Down

0 comments on commit 5b03697

Please sign in to comment.