mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Add additional PHP metadata (#753)
* add php related metadata Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * enable decoding of php metadata for syftjson format Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add php metadata to json schema Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
814f2bf8b9
commit
829e500aa9
10 changed files with 496 additions and 64 deletions
|
@ -118,6 +118,14 @@ func (p *Package) UnmarshalJSON(b []byte) error {
|
|||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.PhpComposerJSONMetadataType:
|
||||
var payload pkg.PhpComposerJSONMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
default:
|
||||
log.Warnf("unknown package metadata type=%q for packageID=%q", p.MetadataType, p.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -36,6 +36,7 @@ type artifactMetadataContainer struct {
|
|||
Rpm pkg.RpmdbMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -662,6 +662,9 @@
|
|||
{
|
||||
"$ref": "#/definitions/NpmPackageJSONMetadata"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/PhpComposerJSONMetadata"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/PythonPackageMetadata"
|
||||
},
|
||||
|
@ -674,6 +677,144 @@
|
|||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"PhpComposerAuthors": {
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"PhpComposerExternalReference": {
|
||||
"required": [
|
||||
"type",
|
||||
"url",
|
||||
"reference"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"shasum": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"PhpComposerJSONMetadata": {
|
||||
"required": [
|
||||
"name",
|
||||
"version",
|
||||
"source",
|
||||
"dist"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"$ref": "#/definitions/PhpComposerExternalReference"
|
||||
},
|
||||
"dist": {
|
||||
"$ref": "#/definitions/PhpComposerExternalReference"
|
||||
},
|
||||
"require": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"provide": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"require-dev": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"suggest": {
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"notification-url": {
|
||||
"type": "string"
|
||||
},
|
||||
"bin": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"license": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"authors": {
|
||||
"items": {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"$ref": "#/definitions/PhpComposerAuthors"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string"
|
||||
},
|
||||
"keywords": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"time": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"PomParent": {
|
||||
"required": [
|
||||
"groupId",
|
||||
|
|
|
@ -6,18 +6,12 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
type ComposerLock struct {
|
||||
Packages []Dependency `json:"packages"`
|
||||
PackageDev []Dependency `json:"packages-dev"`
|
||||
}
|
||||
|
||||
type Dependency struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
type composerLock struct {
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
PackageDev []pkg.PhpComposerJSONMetadata `json:"packages-dev"`
|
||||
}
|
||||
|
||||
// parseComposerLock is a parser function for Composer.lock contents, returning "Default" php packages discovered.
|
||||
|
@ -26,7 +20,7 @@ func parseComposerLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.R
|
|||
dec := json.NewDecoder(reader)
|
||||
|
||||
for {
|
||||
var lock ComposerLock
|
||||
var lock composerLock
|
||||
if err := dec.Decode(&lock); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
|
@ -36,10 +30,12 @@ func parseComposerLock(_ string, reader io.Reader) ([]*pkg.Package, []artifact.R
|
|||
version := pkgMeta.Version
|
||||
name := pkgMeta.Name
|
||||
packages = append(packages, &pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Name: name,
|
||||
Version: version,
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkgMeta,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,16 +11,98 @@ import (
|
|||
func TestParseComposerFileLock(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "adoy/fastcgi-client",
|
||||
Version: "1.0.2",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Name: "adoy/fastcgi-client",
|
||||
Version: "1.0.2",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "adoy/fastcgi-client",
|
||||
Version: "1.0.2",
|
||||
Source: pkg.PhpComposerExternalReference{
|
||||
Type: "git",
|
||||
URL: "https://github.com/adoy/PHP-FastCGI-Client.git",
|
||||
Reference: "6d9a552f0206a1db7feb442824540aa6c55e5b27",
|
||||
},
|
||||
Dist: pkg.PhpComposerExternalReference{
|
||||
Type: "zip",
|
||||
URL: "https://api.github.com/repos/adoy/PHP-FastCGI-Client/zipball/6d9a552f0206a1db7feb442824540aa6c55e5b27",
|
||||
Reference: "6d9a552f0206a1db7feb442824540aa6c55e5b27",
|
||||
},
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Pierrick Charron",
|
||||
Email: "pierrick@adoy.net",
|
||||
},
|
||||
},
|
||||
Description: "Lightweight, single file FastCGI client for PHP.",
|
||||
Keywords: []string{
|
||||
"fastcgi",
|
||||
"fcgi",
|
||||
},
|
||||
Time: "2019-12-11T13:49:21+00:00",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "alcaeus/mongo-php-adapter",
|
||||
Version: "1.1.11",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Name: "alcaeus/mongo-php-adapter",
|
||||
Version: "1.1.11",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "alcaeus/mongo-php-adapter",
|
||||
Version: "1.1.11",
|
||||
Source: pkg.PhpComposerExternalReference{
|
||||
Type: "git",
|
||||
URL: "https://github.com/alcaeus/mongo-php-adapter.git",
|
||||
Reference: "43b6add94c8b4cb9890d662cba4c0defde733dcf",
|
||||
},
|
||||
Dist: pkg.PhpComposerExternalReference{
|
||||
Type: "zip",
|
||||
URL: "https://api.github.com/repos/alcaeus/mongo-php-adapter/zipball/43b6add94c8b4cb9890d662cba4c0defde733dcf",
|
||||
Reference: "43b6add94c8b4cb9890d662cba4c0defde733dcf",
|
||||
},
|
||||
Require: map[string]string{
|
||||
"ext-ctype": "*",
|
||||
"ext-hash": "*",
|
||||
"ext-mongodb": "^1.2.0",
|
||||
"mongodb/mongodb": "^1.0.1",
|
||||
"php": "^5.6 || ^7.0",
|
||||
},
|
||||
Provide: map[string]string{
|
||||
"ext-mongo": "1.6.14",
|
||||
},
|
||||
RequireDev: map[string]string{
|
||||
"phpunit/phpunit": "^5.7.27 || ^6.0 || ^7.0",
|
||||
"squizlabs/php_codesniffer": "^3.2",
|
||||
},
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "alcaeus",
|
||||
Email: "alcaeus@alcaeus.org",
|
||||
},
|
||||
{
|
||||
Name: "Olivier Lechevalier",
|
||||
Email: "olivier.lechevalier@gmail.com",
|
||||
},
|
||||
},
|
||||
Description: "Adapter to provide ext-mongo interface on top of mongo-php-libary",
|
||||
Keywords: []string{
|
||||
"database",
|
||||
"mongodb",
|
||||
},
|
||||
Time: "2019-11-11T20:47:32+00:00",
|
||||
},
|
||||
},
|
||||
}
|
||||
fixture, err := os.Open("test-fixtures/composer.lock")
|
||||
|
@ -33,9 +115,8 @@ func TestParseComposerFileLock(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to parse requirements: %+v", err)
|
||||
}
|
||||
differences := deep.Equal(expected, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
|
||||
for _, d := range deep.Equal(expected, actual) {
|
||||
t.Errorf("diff: %+v", d)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,19 +12,19 @@ import (
|
|||
|
||||
// Note: composer version 2 introduced a new structure for the installed.json file, so we support both
|
||||
type installedJSONComposerV2 struct {
|
||||
Packages []Dependency `json:"packages"`
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
}
|
||||
|
||||
func (w *installedJSONComposerV2) UnmarshalJSON(data []byte) error {
|
||||
type compv2 struct {
|
||||
Packages []Dependency `json:"packages"`
|
||||
Packages []pkg.PhpComposerJSONMetadata `json:"packages"`
|
||||
}
|
||||
compv2er := new(compv2)
|
||||
err := json.Unmarshal(data, &compv2er)
|
||||
if err != nil {
|
||||
// If we had an err or, we may be dealing with a composer v.1 installed.json
|
||||
// which should be all arrays
|
||||
var packages []Dependency
|
||||
var packages []pkg.PhpComposerJSONMetadata
|
||||
err := json.Unmarshal(data, &packages)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -55,10 +55,12 @@ func parseInstalledJSON(_ string, reader io.Reader) ([]*pkg.Package, []artifact.
|
|||
version := pkgMeta.Version
|
||||
name := pkgMeta.Name
|
||||
packages = append(packages, &pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
Name: name,
|
||||
Version: version,
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkgMeta,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,21 +8,118 @@ import (
|
|||
"github.com/go-test/deep"
|
||||
)
|
||||
|
||||
var expectedInstalledJsonPackages = []*pkg.Package{
|
||||
{
|
||||
Name: "asm89/stack-cors",
|
||||
Version: "1.3.0",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "asm89/stack-cors",
|
||||
Version: "1.3.0",
|
||||
Source: pkg.PhpComposerExternalReference{
|
||||
Type: "git",
|
||||
URL: "https://github.com/asm89/stack-cors.git",
|
||||
Reference: "b9c31def6a83f84b4d4a40d35996d375755f0e08",
|
||||
},
|
||||
Dist: pkg.PhpComposerExternalReference{
|
||||
Type: "zip",
|
||||
URL: "https://api.github.com/repos/asm89/stack-cors/zipball/b9c31def6a83f84b4d4a40d35996d375755f0e08",
|
||||
Reference: "b9c31def6a83f84b4d4a40d35996d375755f0e08",
|
||||
},
|
||||
Require: map[string]string{
|
||||
"php": ">=5.5.9",
|
||||
"symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0",
|
||||
"symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0",
|
||||
},
|
||||
RequireDev: map[string]string{
|
||||
"phpunit/phpunit": "^5.0 || ^4.8.10",
|
||||
"squizlabs/php_codesniffer": "^2.3",
|
||||
},
|
||||
Time: "2019-12-24T22:41:47+00:00",
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Alexander",
|
||||
Email: "iam.asm89@gmail.com",
|
||||
},
|
||||
},
|
||||
|
||||
Description: "Cross-origin resource sharing library and stack middleware",
|
||||
Homepage: "https://github.com/asm89/stack-cors",
|
||||
Keywords: []string{
|
||||
"cors",
|
||||
"stack",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
MetadataType: pkg.PhpComposerJSONMetadataType,
|
||||
Metadata: pkg.PhpComposerJSONMetadata{
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
Source: pkg.PhpComposerExternalReference{
|
||||
Type: "git",
|
||||
URL: "https://github.com/minkphp/Mink.git",
|
||||
Reference: "07c6a9fe3fa98c2de074b25d9ed26c22904e3887",
|
||||
},
|
||||
Dist: pkg.PhpComposerExternalReference{
|
||||
Type: "zip",
|
||||
URL: "https://api.github.com/repos/minkphp/Mink/zipball/07c6a9fe3fa98c2de074b25d9ed26c22904e3887",
|
||||
Reference: "07c6a9fe3fa98c2de074b25d9ed26c22904e3887",
|
||||
},
|
||||
Require: map[string]string{
|
||||
"php": ">=5.3.1",
|
||||
"symfony/css-selector": "^2.7|^3.0|^4.0|^5.0",
|
||||
},
|
||||
RequireDev: map[string]string{
|
||||
"phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20",
|
||||
"symfony/debug": "^2.7|^3.0|^4.0",
|
||||
"symfony/phpunit-bridge": "^3.4.38 || ^5.0.5",
|
||||
},
|
||||
Suggest: map[string]string{
|
||||
"behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
|
||||
"behat/mink-goutte-driver": "fast headless driver for any app without JS emulation",
|
||||
"behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)",
|
||||
"behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)",
|
||||
"dmore/chrome-mink-driver": "fast and JS-enabled driver for any app (requires chromium or google chrome)",
|
||||
},
|
||||
Time: "2020-03-11T15:45:53+00:00",
|
||||
Type: "library",
|
||||
NotificationURL: "https://packagist.org/downloads/",
|
||||
License: []string{
|
||||
"MIT",
|
||||
},
|
||||
Authors: []pkg.PhpComposerAuthors{
|
||||
{
|
||||
Name: "Konstantin Kudryashov",
|
||||
Email: "ever.zet@gmail.com",
|
||||
Homepage: "http://everzet.com",
|
||||
},
|
||||
},
|
||||
|
||||
Description: "Browser controller/emulator abstraction for PHP",
|
||||
Homepage: "http://mink.behat.org/",
|
||||
Keywords: []string{
|
||||
"browser",
|
||||
"testing",
|
||||
"web",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestParseInstalledJsonComposerV1(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "asm89/stack-cors",
|
||||
Version: "1.3.0",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
},
|
||||
{
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
},
|
||||
}
|
||||
|
||||
fixture, err := os.Open("test-fixtures/vendor/composer_1/installed.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
|
@ -33,28 +130,13 @@ func TestParseInstalledJsonComposerV1(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to parse requirements: %+v", err)
|
||||
}
|
||||
differences := deep.Equal(expected, actual)
|
||||
differences := deep.Equal(expectedInstalledJsonPackages, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestParseInstalledJsonComposerV2(t *testing.T) {
|
||||
expected := []*pkg.Package{
|
||||
{
|
||||
Name: "asm89/stack-cors",
|
||||
Version: "1.3.0",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
},
|
||||
{
|
||||
Name: "behat/mink",
|
||||
Version: "v1.8.1",
|
||||
Language: pkg.PHP,
|
||||
Type: pkg.PhpComposerPkg,
|
||||
},
|
||||
}
|
||||
fixture, err := os.Open("test-fixtures/vendor/composer_2/installed.json")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
|
@ -65,7 +147,7 @@ func TestParseInstalledJsonComposerV2(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to parse requirements: %+v", err)
|
||||
}
|
||||
differences := deep.Equal(expected, actual)
|
||||
differences := deep.Equal(expectedInstalledJsonPackages, actual)
|
||||
if differences != nil {
|
||||
t.Errorf("returned package list differed from expectation: %+v", differences)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ type MetadataType string
|
|||
|
||||
const (
|
||||
// this is the full set of data shapes that can be represented within the pkg.Package.Metadata field
|
||||
|
||||
UnknownMetadataType MetadataType = "UnknownMetadata"
|
||||
ApkMetadataType MetadataType = "ApkMetadata"
|
||||
DpkgMetadataType MetadataType = "DpkgMetadata"
|
||||
|
@ -16,6 +17,7 @@ const (
|
|||
RustCargoPackageMetadataType MetadataType = "RustCargoPackageMetadata"
|
||||
KbPackageMetadataType MetadataType = "KbPackageMetadata"
|
||||
GolangBinMetadataType MetadataType = "GolangBinMetadata"
|
||||
PhpComposerJSONMetadataType MetadataType = "PhpComposerJsonMetadata"
|
||||
)
|
||||
|
||||
var AllMetadataTypes = []MetadataType{
|
||||
|
@ -29,4 +31,5 @@ var AllMetadataTypes = []MetadataType{
|
|||
RustCargoPackageMetadataType,
|
||||
KbPackageMetadataType,
|
||||
GolangBinMetadataType,
|
||||
PhpComposerJSONMetadataType,
|
||||
}
|
||||
|
|
67
syft/pkg/php_composer_json_metadata.go
Normal file
67
syft/pkg/php_composer_json_metadata.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package pkg
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
)
|
||||
|
||||
// PhpComposerJSONMetadata represents information found from composer v1/v2 "installed.json" files as well as composer.lock files
|
||||
type PhpComposerJSONMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Source PhpComposerExternalReference `json:"source"`
|
||||
Dist PhpComposerExternalReference `json:"dist"`
|
||||
Require map[string]string `json:"require,omitempty"`
|
||||
Provide map[string]string `json:"provide,omitempty"`
|
||||
RequireDev map[string]string `json:"require-dev,omitempty"`
|
||||
Suggest map[string]string `json:"suggest,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
NotificationURL string `json:"notification-url,omitempty"`
|
||||
Bin []string `json:"bin,omitempty"`
|
||||
License []string `json:"license,omitempty"`
|
||||
Authors []PhpComposerAuthors `json:"authors,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Homepage string `json:"homepage,omitempty"`
|
||||
Keywords []string `json:"keywords,omitempty"`
|
||||
Time string `json:"time,omitempty"`
|
||||
}
|
||||
|
||||
type PhpComposerExternalReference struct {
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
Reference string `json:"reference"`
|
||||
Shasum string `json:"shasum,omitempty"`
|
||||
}
|
||||
|
||||
type PhpComposerAuthors struct {
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Homepage string `json:"homepage,omitempty"`
|
||||
}
|
||||
|
||||
func (m PhpComposerJSONMetadata) PackageURL() string {
|
||||
var name, vendor string
|
||||
fields := strings.Split(m.Name, "/")
|
||||
switch len(fields) {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
name = m.Name
|
||||
case 2:
|
||||
vendor = fields[0]
|
||||
name = fields[1]
|
||||
default:
|
||||
vendor = fields[0]
|
||||
name = strings.Join(fields[1:], "-")
|
||||
}
|
||||
|
||||
pURL := packageurl.NewPackageURL(
|
||||
packageurl.TypeComposer,
|
||||
vendor,
|
||||
name,
|
||||
m.Version,
|
||||
nil,
|
||||
"")
|
||||
return pURL.ToString()
|
||||
}
|
51
syft/pkg/php_composer_json_metadata_test.go
Normal file
51
syft/pkg/php_composer_json_metadata_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPhpComposerJsonMetadata_pURL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
distro *linux.Release
|
||||
metadata PhpComposerJSONMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "with extractable vendor",
|
||||
metadata: PhpComposerJSONMetadata{
|
||||
Name: "ven/name",
|
||||
Version: "1.0.1",
|
||||
},
|
||||
expected: "pkg:composer/ven/name@1.0.1",
|
||||
}, {
|
||||
name: "name with slashes (invalid)",
|
||||
metadata: PhpComposerJSONMetadata{
|
||||
Name: "ven/name/component",
|
||||
Version: "1.0.1",
|
||||
},
|
||||
expected: "pkg:composer/ven/name-component@1.0.1",
|
||||
},
|
||||
{
|
||||
name: "unknown vendor",
|
||||
metadata: PhpComposerJSONMetadata{
|
||||
Name: "name",
|
||||
Version: "1.0.1",
|
||||
},
|
||||
expected: "pkg:composer/name@1.0.1",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := test.metadata.PackageURL()
|
||||
if actual != test.expected {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(test.expected, actual, true)
|
||||
t.Errorf("diff: %s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue