feat(php): add support for location, licenses and graph for composer.lock files (#3873)

Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
DmitriyLewen
2023-03-26 15:02:53 +06:00
committed by GitHub
parent c02b15b371
commit edb06826b4
21 changed files with 1192 additions and 83 deletions

View File

@@ -11,7 +11,7 @@
| | requirements.txt | - | - | ✅ | ✅ | included | - | | | requirements.txt | - | - | ✅ | ✅ | included | - |
| | egg package[^1] | ✅ | ✅ | - | - | excluded | - | | | egg package[^1] | ✅ | ✅ | - | - | excluded | - |
| | wheel package[^2] | ✅ | ✅ | - | - | excluded | - | | | wheel package[^2] | ✅ | ✅ | - | - | excluded | - |
| PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded | - | | PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded | |
| Node.js | package-lock.json | - | - | ✅ | ✅ | excluded | ✅ | | Node.js | package-lock.json | - | - | ✅ | ✅ | excluded | ✅ |
| | yarn.lock | - | - | ✅ | ✅ | included | ✅ | | | yarn.lock | - | - | ✅ | ✅ | included | ✅ |
| | pnpm-lock.yaml | - | - | ✅ | ✅ | excluded | - | | | pnpm-lock.yaml | - | - | ✅ | ✅ | excluded | - |

View File

@@ -37,6 +37,8 @@ The following packages/languages are currently supported:
- Binaries built with [cargo-auditable][cargo-auditable] - Binaries built with [cargo-auditable][cargo-auditable]
- Go - Go
- Modules: go.mod - Modules: go.mod
- PHP
- Composer
This tree is the reverse of the npm list command. This tree is the reverse of the npm list command.
However, if you want to resolve a vulnerability in a particular indirect dependency, the reversed tree is useful to know where that dependency comes from and identify which package you actually need to update. However, if you want to resolve a vulnerability in a particular indirect dependency, the reversed tree is useful to know where that dependency comes from and identify which package you actually need to update.

View File

@@ -0,0 +1,18 @@
# PHP
Trivy supports [Composer][composer], which is a tool for dependency management in PHP.
The following table provides an outline of the features Trivy offers.
| Package Manager | File | Transitive dependencies | Dev dependencies | Dependency graph | Position | License |
|-----------------|---------------|:-----------------------:|:----------------:|:----------------:|:--------:|:-------:|
| Composer | composer.lock | ✅ | Excluded | ✅ | ✅ | ✅ |
## Composer
In order to detect dependencies, Trivy searches for `composer.lock`.
Trivy also supports dependency trees; however, to display an accurate tree, it needs to know whether each package is a direct dependency of the project.
Since this information is not included in `composer.lock`, Trivy parses `composer.json`, which should be located next to `composer.lock`.
If you want to see the dependency tree, please ensure that `composer.json` is present.
[composer]: https://getcomposer.org/

2
go.mod
View File

@@ -14,7 +14,7 @@ require (
github.com/alicebob/miniredis/v2 v2.23.0 github.com/alicebob/miniredis/v2 v2.23.0
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
github.com/aquasecurity/defsec v0.84.1 github.com/aquasecurity/defsec v0.84.1
github.com/aquasecurity/go-dep-parser v0.0.0-20230321131503-05943e2e8dd8 github.com/aquasecurity/go-dep-parser v0.0.0-20230324031819-b0e2fb4e2140
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46

4
go.sum
View File

@@ -318,8 +318,8 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8= github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/defsec v0.84.1 h1:YwhQprDEy4ZN/c7aDV57O5UkxOusHwtfeENI7wm4/L8= github.com/aquasecurity/defsec v0.84.1 h1:YwhQprDEy4ZN/c7aDV57O5UkxOusHwtfeENI7wm4/L8=
github.com/aquasecurity/defsec v0.84.1/go.mod h1:AywB8D+RX4X8p2luSlz4ha3w9+q2kuTHtTvJLNxaYjI= github.com/aquasecurity/defsec v0.84.1/go.mod h1:AywB8D+RX4X8p2luSlz4ha3w9+q2kuTHtTvJLNxaYjI=
github.com/aquasecurity/go-dep-parser v0.0.0-20230321131503-05943e2e8dd8 h1:cS2WfKl+kINk3x0+S4UfUHsjFtibgkWog9o+bnmbgEw= github.com/aquasecurity/go-dep-parser v0.0.0-20230324031819-b0e2fb4e2140 h1:TUt7SV2LJQ5Uw7wjKL6jt33zeQJKEm4gCW5ULZoMlAA=
github.com/aquasecurity/go-dep-parser v0.0.0-20230321131503-05943e2e8dd8/go.mod h1:lI+o04X85vxgx2jPji9G0tZ6AqqhVcXn8A88qimWfOM= github.com/aquasecurity/go-dep-parser v0.0.0-20230324031819-b0e2fb4e2140/go.mod h1:lI+o04X85vxgx2jPji9G0tZ6AqqhVcXn8A88qimWfOM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
github.com/aquasecurity/go-mock-aws v0.0.0-20220726154943-99847deb62b0 h1:tihCUjLWkF0b1SAjAKcFltUs3SpsqGrLtI+Frye0D10= github.com/aquasecurity/go-mock-aws v0.0.0-20220726154943-99847deb62b0 h1:tihCUjLWkF0b1SAjAKcFltUs3SpsqGrLtI+Frye0D10=

View File

@@ -187,6 +187,15 @@ func TestFilesystem(t *testing.T) {
}, },
golden: "testdata/mix.lock.json.golden", golden: "testdata/mix.lock.json.golden",
}, },
{
name: "composer.lock",
args: args{
scanner: types.VulnerabilityScanner,
listAllPkgs: true,
input: "testdata/fixtures/fs/composer",
},
golden: "testdata/composer.lock.json.golden",
},
{ {
name: "dockerfile", name: "dockerfile",
args: args{ args: args{

View File

@@ -0,0 +1,96 @@
{
"SchemaVersion": 2,
"ArtifactName": "testdata/fixtures/fs/composer",
"ArtifactType": "filesystem",
"Metadata": {
"ImageConfig": {
"architecture": "",
"created": "0001-01-01T00:00:00Z",
"os": "",
"rootfs": {
"type": "",
"diff_ids": null
},
"config": {}
}
},
"Results": [
{
"Target": "composer.lock",
"Class": "lang-pkgs",
"Type": "composer",
"Packages": [
{
"ID": "guzzlehttp/guzzle@7.4.4",
"Name": "guzzlehttp/guzzle",
"Version": "7.4.4",
"Indirect": false,
"Layer": {},
"Licenses": [
"MIT"
],
"DependsOn": [
"guzzlehttp/psr7@1.8.3"
],
"Locations": [
{
"StartLine": 9,
"EndLine": 129
}
]
},
{
"ID": "guzzlehttp/psr7@1.8.3",
"Name": "guzzlehttp/psr7",
"Version": "1.8.3",
"Indirect": true,
"Layer": {},
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 130,
"EndLine": 245
}
]
}
],
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2022-24775",
"PkgID": "guzzlehttp/psr7@1.8.3",
"PkgName": "guzzlehttp/psr7",
"InstalledVersion": "1.8.3",
"FixedVersion": "1.8.4",
"Layer": {},
"SeveritySource": "ghsa",
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-24775",
"DataSource": {
"ID": "ghsa",
"Name": "GitHub Security Advisory Composer",
"URL": "https://github.com/advisories?query=type%%3Areviewed+ecosystem%%3Acomposer"
},
"Title": "Improper Input Validation in guzzlehttp/psr7",
"Description": "### Impact\nIn proper header parsing. An attacker could sneak in a new line character and pass untrusted values. \n\n### Patches\nThe issue is patched in 1.8.4 and 2.1.1.\n\n### Workarounds\nThere are no known workarounds.\n",
"Severity": "HIGH",
"CweIDs": [
"CWE-20"
],
"CVSS": {
"ghsa": {
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"V3Score": 7.5
}
},
"References": [
"https://github.com/guzzle/psr7/security/advisories/GHSA-q7rv-6hp3-vh96",
"https://nvd.nist.gov/vuln/detail/CVE-2022-24775"
],
"PublishedDate": "2022-03-25T19:26:33Z",
"LastModifiedDate": "2022-06-14T20:02:29Z"
}
]
}
]
}

View File

@@ -0,0 +1,10 @@
- bucket: "composer::GitHub Security Advisory Composer"
pairs:
- bucket: guzzlehttp/psr7
pairs:
- key: CVE-2022-24775
value:
PatchedVersions:
- 1.8.4
VulnerableVersions:
- < 1.8.4

View File

@@ -1294,6 +1294,24 @@
- https://github.com/advisories/GHSA-4rgh-jx4f-qfcq - https://github.com/advisories/GHSA-4rgh-jx4f-qfcq
PublishedDate: "2022-05-24T17:37:16Z" PublishedDate: "2022-05-24T17:37:16Z"
LastModifiedDate: "2022-10-06T20:26:08Z" LastModifiedDate: "2022-10-06T20:26:08Z"
- key: CVE-2022-24775
value:
Title: "Improper Input Validation in guzzlehttp/psr7"
Description: "### Impact\nIn proper header parsing. An attacker could sneak in a new line character and pass untrusted values. \n\n### Patches\nThe issue is patched in 1.8.4 and 2.1.1.\n\n### Workarounds\nThere are no known workarounds.\n"
Severity: HIGH
VendorSeverity:
ghsa: 3
CweIDs:
- CWE-20
CVSS:
ghsa:
V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
V3Score: 7.5
References:
- https://github.com/guzzle/psr7/security/advisories/GHSA-q7rv-6hp3-vh96
- https://nvd.nist.gov/vuln/detail/CVE-2022-24775
PublishedDate: "2022-03-25T19:26:33Z"
LastModifiedDate: "2022-06-14T20:02:29Z"
- key: CVE-2022-22965 - key: CVE-2022-22965
value: value:
Title: "spring-framework: RCE via Data Binding on JDK 9+" Title: "spring-framework: RCE via Data Binding on JDK 9+"

View File

@@ -0,0 +1,5 @@
{
"require": {
"guzzlehttp/guzzle": "7.4.4"
}
}

256
integration/testdata/fixtures/fs/composer/composer.lock generated vendored Normal file
View File

@@ -0,0 +1,256 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "31bb67df1cc2bbbb0cd07dd1a0f516df",
"packages": [
{
"name": "guzzlehttp/guzzle",
"version": "7.4.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/e3ff079b22820c2029d4c2a87796b6a0b8716ad8",
"reference": "e3ff079b22820c2029d4c2a87796b6a0b8716ad8",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/psr7": "^1.8.2 || ^2.1",
"php": "^7.2.5 || ^8.0"
},
"provide": {
"psr/http-client-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4.1",
"ext-curl": "*",
"php-http/client-integration-tests": "^3.0",
"phpunit/phpunit": "^8.5.5 || ^9.3.5",
"psr/log": "^1.1 || ^2.0 || ^3.0"
},
"suggest": {
"ext-curl": "Required for CURL handler support",
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "7.4-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"description": "Guzzle is a PHP HTTP client library",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"psr-18",
"psr-7",
"rest",
"web service"
],
"support": {
"issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.4.4"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
"type": "tidelift"
}
],
"time": "2022-06-09T21:39:15+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.8.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"shasum": ""
},
"require": {
"php": "^7.2.5 || ^8.0"
},
"provide": {
"psr/http-factory-implementation": "1.0",
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.1",
"http-interop/http-factory-tests": "^0.9",
"phpunit/phpunit": "^8.5.29 || ^9.5.23"
},
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"forward-command": false
},
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://sagikazarmark.hu"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://github.com/Nyholm",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
"type": "tidelift"
}
],
"time": "2023-03-09T13:19:02+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View File

@@ -62,6 +62,7 @@ nav:
- Go: docs/vulnerability/languages/golang.md - Go: docs/vulnerability/languages/golang.md
- Java: docs/vulnerability/languages/java.md - Java: docs/vulnerability/languages/java.md
- Node.js: docs/vulnerability/languages/nodejs.md - Node.js: docs/vulnerability/languages/nodejs.md
- PHP: docs/vulnerability/languages/php.md
- Python: docs/vulnerability/languages/python.md - Python: docs/vulnerability/languages/python.md
- Misconfiguration: - Misconfiguration:
- Scanning: docs/misconfiguration/scanning.md - Scanning: docs/misconfiguration/scanning.md

View File

@@ -2,57 +2,149 @@ package composer
import ( import (
"context" "context"
"encoding/json"
"errors"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"golang.org/x/exp/slices"
"golang.org/x/xerrors" "golang.org/x/xerrors"
dio "github.com/aquasecurity/go-dep-parser/pkg/io"
"github.com/aquasecurity/go-dep-parser/pkg/php/composer" "github.com/aquasecurity/go-dep-parser/pkg/php/composer"
godeptypes "github.com/aquasecurity/go-dep-parser/pkg/types"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language"
"github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/fanal/utils" "github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
) )
func init() { func init() {
analyzer.RegisterAnalyzer(&composerLibraryAnalyzer{}) analyzer.RegisterPostAnalyzer(types.Composer, newComposerAnalyzer)
} }
const version = 1 const version = 1
var requiredFiles = []string{types.ComposerLock} var requiredFiles = []string{
types.ComposerLock,
types.ComposerJson,
}
type composerLibraryAnalyzer struct{} type composerAnalyzer struct {
lockParser godeptypes.Parser
}
func (a composerLibraryAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { func newComposerAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
res, err := language.Analyze(types.Composer, input.FilePath, input.Content, composer.NewParser()) return &composerAnalyzer{
lockParser: composer.NewParser(),
}, nil
}
func (a composerAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) {
var apps []types.Application
required := func(path string, d fs.DirEntry) bool {
return filepath.Base(path) == types.ComposerLock
}
err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r dio.ReadSeekerAt) error {
// Parse composer.lock
app, err := a.parseComposerLock(path, r)
if err != nil { if err != nil {
return nil, xerrors.Errorf("error with composer.lock: %w", err) return xerrors.Errorf("parse error: %w", err)
} } else if app == nil {
return res, nil return nil
} }
func (a composerLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool { // Parse composer.json alongside composer.lock to identify the direct dependencies
if err = a.mergeComposerJson(input.FS, filepath.Dir(path), app); err != nil {
return err
}
sort.Sort(types.Packages(app.Libraries))
apps = append(apps, *app)
return nil
})
if err != nil {
return nil, xerrors.Errorf("composer walk error: %w", err)
}
return &analyzer.AnalysisResult{
Applications: apps,
}, nil
}
func (a composerAnalyzer) Required(filePath string, _ os.FileInfo) bool {
fileName := filepath.Base(filePath) fileName := filepath.Base(filePath)
if !utils.StringInSlice(fileName, requiredFiles) { if !slices.Contains(requiredFiles, fileName) {
return false return false
} }
// we should skip `composer.lock` inside `vendor` folder // Skip `composer.lock` inside `vendor` folder
for _, p := range strings.Split(filepath.ToSlash(filePath), "/") { if slices.Contains(strings.Split(filePath, "/"), "vendor") {
if p == "vendor" {
return false return false
} }
}
return true return true
} }
func (a composerLibraryAnalyzer) Type() analyzer.Type { func (a composerAnalyzer) Type() analyzer.Type {
return analyzer.TypeComposer return analyzer.TypeComposer
} }
func (a composerLibraryAnalyzer) Version() int { func (a composerAnalyzer) Version() int {
return version return version
} }
func (a composerAnalyzer) parseComposerLock(path string, r dio.ReadSeekerAt) (*types.Application, error) {
libs, deps, err := a.lockParser.Parse(r)
if err != nil {
return nil, xerrors.Errorf("unable to parse composer.lock: %w", err)
}
return language.ToApplication(types.Composer, path, "", libs, deps), nil
}
func (a composerAnalyzer) mergeComposerJson(fsys fs.FS, dir string, app *types.Application) error {
// Parse composer.json to identify the direct dependencies
path := filepath.Join(dir, types.ComposerJson)
p, err := a.parseComposerJson(fsys, path)
if errors.Is(err, fs.ErrNotExist) {
// Assume all the packages are direct dependencies as it cannot identify them from composer.lock
log.Logger.Debugf("Unable to determine the direct dependencies: %s not found", path)
return nil
} else if err != nil {
return xerrors.Errorf("unable to parse %s: %w", path, err)
}
for i, lib := range app.Libraries {
// Identify the direct/transitive dependencies
if _, ok := p[lib.Name]; !ok {
app.Libraries[i].Indirect = true
}
}
return nil
}
type composerJson struct {
Require map[string]string `json:"require"`
}
func (a composerAnalyzer) parseComposerJson(fsys fs.FS, path string) (map[string]string, error) {
// Parse composer.json
f, err := fsys.Open(path)
if err != nil {
return nil, xerrors.Errorf("file open error: %w", err)
}
defer func() { _ = f.Close() }()
jsonFile := composerJson{}
err = json.NewDecoder(f).Decode(&jsonFile)
if err != nil {
return nil, xerrors.Errorf("json decode error: %w", err)
}
return jsonFile.Require, nil
}

View File

@@ -0,0 +1,107 @@
package composer
import (
"context"
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
"github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"os"
"testing"
)
func Test_composerAnalyzer_PostAnalyze(t *testing.T) {
tests := []struct {
name string
dir string
want *analyzer.AnalysisResult
wantErr string
}{
{
name: "happy path",
dir: "testdata/happy",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Composer,
FilePath: "composer.lock",
Libraries: []types.Package{
{
ID: "pear/log@1.13.3",
Name: "pear/log",
Version: "1.13.3",
Indirect: false,
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 9, EndLine: 68}},
DependsOn: []string{"pear/pear_exception@v1.0.2"},
},
{
ID: "pear/pear_exception@v1.0.2",
Name: "pear/pear_exception",
Version: "v1.0.2",
Indirect: true,
Licenses: []string{"BSD-2-Clause"},
Locations: []types.Location{{StartLine: 69, EndLine: 127}},
},
},
},
},
},
},
{
name: "no composer.json",
dir: "testdata/no-composer-json",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Composer,
FilePath: "composer.lock",
Libraries: []types.Package{
{
ID: "pear/log@1.13.3",
Name: "pear/log",
Version: "1.13.3",
Indirect: false,
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 9, EndLine: 68}},
DependsOn: []string{"pear/pear_exception@v1.0.2"},
},
{
ID: "pear/pear_exception@v1.0.2",
Name: "pear/pear_exception",
Version: "v1.0.2",
Indirect: false,
Licenses: []string{"BSD-2-Clause"},
Locations: []types.Location{{StartLine: 69, EndLine: 127}},
},
},
},
},
},
},
{
name: "broken composer.lock",
dir: "testdata/sad",
wantErr: "unable to parse composer.lock",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a, err := newComposerAnalyzer(analyzer.AnalyzerOptions{})
require.NoError(t, err)
got, err := a.PostAnalyze(context.Background(), analyzer.PostAnalysisInput{
FS: os.DirFS(tt.dir),
})
if tt.wantErr != "" {
assert.ErrorContains(t, err, tt.wantErr)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,5 @@
{
"require": {
"pear/log": "^1.13"
}
}

View File

@@ -0,0 +1,138 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2450af46c78f9ecbca6976876bdd04c2",
"packages": [
{
"name": "pear/log",
"version": "1.13.3",
"source": {
"type": "git",
"url": "https://github.com/pear/Log.git",
"reference": "21af0be11669194d72d88b5ee9d5f176dc75d9a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/Log/zipball/21af0be11669194d72d88b5ee9d5f176dc75d9a3",
"reference": "21af0be11669194d72d88b5ee9d5f176dc75d9a3",
"shasum": ""
},
"require": {
"pear/pear_exception": "1.0.1 || 1.0.2",
"php": ">5.2"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"suggest": {
"pear/db": "Install optionally via your project's composer.json"
},
"type": "library",
"autoload": {
"psr-0": {
"Log": "./"
},
"exclude-from-classmap": [
"/examples/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"MIT"
],
"authors": [
{
"name": "Jon Parise",
"email": "jon@php.net",
"homepage": "http://www.indelible.org",
"role": "Developer"
}
],
"description": "PEAR Logging Framework",
"homepage": "http://pear.github.io/Log/",
"keywords": [
"log",
"logging"
],
"support": {
"issues": "https://github.com/pear/Log/issues",
"source": "https://github.com/pear/Log"
},
"time": "2021-05-04T23:51:30+00:00"
},
{
"name": "pear/pear_exception",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/pear/PEAR_Exception.git",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "<9"
},
"type": "class",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"PEAR/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"."
],
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Helgi Thormar",
"email": "dufuz@php.net"
},
{
"name": "Greg Beaver",
"email": "cellog@php.net"
}
],
"description": "The PEAR Exception base class.",
"homepage": "https://github.com/pear/PEAR_Exception",
"keywords": [
"exception"
],
"support": {
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR_Exception",
"source": "https://github.com/pear/PEAR_Exception"
},
"time": "2021-03-21T15:43:46+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View File

@@ -0,0 +1,138 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2450af46c78f9ecbca6976876bdd04c2",
"packages": [
{
"name": "pear/log",
"version": "1.13.3",
"source": {
"type": "git",
"url": "https://github.com/pear/Log.git",
"reference": "21af0be11669194d72d88b5ee9d5f176dc75d9a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/Log/zipball/21af0be11669194d72d88b5ee9d5f176dc75d9a3",
"reference": "21af0be11669194d72d88b5ee9d5f176dc75d9a3",
"shasum": ""
},
"require": {
"pear/pear_exception": "1.0.1 || 1.0.2",
"php": ">5.2"
},
"require-dev": {
"phpunit/phpunit": "*"
},
"suggest": {
"pear/db": "Install optionally via your project's composer.json"
},
"type": "library",
"autoload": {
"psr-0": {
"Log": "./"
},
"exclude-from-classmap": [
"/examples/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"MIT"
],
"authors": [
{
"name": "Jon Parise",
"email": "jon@php.net",
"homepage": "http://www.indelible.org",
"role": "Developer"
}
],
"description": "PEAR Logging Framework",
"homepage": "http://pear.github.io/Log/",
"keywords": [
"log",
"logging"
],
"support": {
"issues": "https://github.com/pear/Log/issues",
"source": "https://github.com/pear/Log"
},
"time": "2021-05-04T23:51:30+00:00"
},
{
"name": "pear/pear_exception",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/pear/PEAR_Exception.git",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "<9"
},
"type": "class",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"PEAR/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"."
],
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Helgi Thormar",
"email": "dufuz@php.net"
},
{
"name": "Greg Beaver",
"email": "cellog@php.net"
}
],
"description": "The PEAR Exception base class.",
"homepage": "https://github.com/pear/PEAR_Exception",
"keywords": [
"exception"
],
"support": {
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR_Exception",
"source": "https://github.com/pear/PEAR_Exception"
},
"time": "2021-03-21T15:43:46+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

View File

@@ -0,0 +1 @@
{

View File

@@ -217,17 +217,17 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
Args: cache.ArtifactCacheMissingBlobsArgs{ Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
Returns: cache.ArtifactCacheMissingBlobsReturns{ Returns: cache.ArtifactCacheMissingBlobsReturns{
MissingArtifact: true, MissingArtifact: true,
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
}, },
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30", BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -294,7 +294,7 @@ func TestArtifact_Inspect(t *testing.T) {
Name: "../../test/testdata/alpine-311.tar.gz", Name: "../../test/testdata/alpine-311.tar.gz",
Type: types.ArtifactContainerImage, Type: types.ArtifactContainerImage,
ID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", ID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
ImageMetadata: types.ImageMetadata{ ImageMetadata: types.ImageMetadata{
ID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", ID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
DiffIDs: []string{ DiffIDs: []string{
@@ -353,25 +353,25 @@ func TestArtifact_Inspect(t *testing.T) {
Args: cache.ArtifactCacheMissingBlobsArgs{ Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
BlobIDs: []string{ BlobIDs: []string{
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac", "sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53", "sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257", "sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e", "sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
}, },
}, },
Returns: cache.ArtifactCacheMissingBlobsReturns{ Returns: cache.ArtifactCacheMissingBlobsReturns{
MissingBlobIDs: []string{ MissingBlobIDs: []string{
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac", "sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53", "sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257", "sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e", "sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
}, },
}, },
}, },
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac", BlobID: "sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -456,7 +456,7 @@ func TestArtifact_Inspect(t *testing.T) {
}, },
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53", BlobID: "sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -549,7 +549,7 @@ func TestArtifact_Inspect(t *testing.T) {
}, },
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257", BlobID: "sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -561,60 +561,108 @@ func TestArtifact_Inspect(t *testing.T) {
FilePath: "php-app/composer.lock", FilePath: "php-app/composer.lock",
Libraries: []types.Package{ Libraries: []types.Package{
{ {
ID: "guzzlehttp/guzzle@6.2.0",
Name: "guzzlehttp/guzzle", Name: "guzzlehttp/guzzle",
Version: "6.2.0", Version: "6.2.0",
Licenses: []string{"MIT"},
DependsOn: []string{"guzzlehttp/promises@v1.3.1", "guzzlehttp/psr7@1.5.2"},
Locations: []types.Location{{StartLine: 9, EndLine: 73}},
}, },
{ {
ID: "guzzlehttp/promises@v1.3.1",
Name: "guzzlehttp/promises", Name: "guzzlehttp/promises",
Version: "v1.3.1", Version: "v1.3.1",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 74, EndLine: 124}},
}, },
{ {
ID: "guzzlehttp/psr7@1.5.2",
Name: "guzzlehttp/psr7", Name: "guzzlehttp/psr7",
Version: "1.5.2", Version: "1.5.2",
Licenses: []string{"MIT"},
DependsOn: []string{"psr/http-message@1.0.1", "ralouphie/getallheaders@2.0.5"},
Locations: []types.Location{{StartLine: 125, EndLine: 191}},
}, },
{ {
ID: "laravel/installer@v2.0.1",
Name: "laravel/installer", Name: "laravel/installer",
Version: "v2.0.1", Version: "v2.0.1",
Licenses: []string{"MIT"},
DependsOn: []string{"guzzlehttp/guzzle@6.2.0", "symfony/console@v4.2.7", "symfony/filesystem@v4.2.7", "symfony/process@v4.2.7"},
Locations: []types.Location{{StartLine: 192, EndLine: 237}},
}, },
{ {
ID: "pear/log@1.13.1",
Name: "pear/log", Name: "pear/log",
Version: "1.13.1", Version: "1.13.1",
Licenses: []string{"MIT"},
DependsOn: []string{"pear/pear_exception@v1.0.0"},
Locations: []types.Location{{StartLine: 238, EndLine: 290}},
}, },
{ {
ID: "pear/pear_exception@v1.0.0",
Name: "pear/pear_exception", Name: "pear/pear_exception",
Version: "v1.0.0", Version: "v1.0.0",
Licenses: []string{"BSD-2-Clause"},
Locations: []types.Location{{StartLine: 291, EndLine: 345}},
}, },
{ {
ID: "psr/http-message@1.0.1",
Name: "psr/http-message", Name: "psr/http-message",
Version: "1.0.1", Version: "1.0.1",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 346, EndLine: 395}},
}, },
{ {
ID: "ralouphie/getallheaders@2.0.5",
Name: "ralouphie/getallheaders", Name: "ralouphie/getallheaders",
Version: "2.0.5", Version: "2.0.5",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 396, EndLine: 435}},
}, },
{ {
ID: "symfony/console@v4.2.7",
Name: "symfony/console", Name: "symfony/console",
Version: "v4.2.7", Version: "v4.2.7",
Licenses: []string{"MIT"},
DependsOn: []string{"symfony/contracts@v1.0.2", "symfony/polyfill-mbstring@v1.11.0"},
Locations: []types.Location{{StartLine: 436, EndLine: 507}},
}, },
{ {
ID: "symfony/contracts@v1.0.2",
Name: "symfony/contracts", Name: "symfony/contracts",
Version: "v1.0.2", Version: "v1.0.2",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 508, EndLine: 575}},
}, },
{ {
ID: "symfony/filesystem@v4.2.7",
Name: "symfony/filesystem", Name: "symfony/filesystem",
Version: "v4.2.7", Version: "v4.2.7",
Licenses: []string{"MIT"},
DependsOn: []string{"symfony/polyfill-ctype@v1.11.0"},
Locations: []types.Location{{StartLine: 576, EndLine: 625}},
}, },
{ {
ID: "symfony/polyfill-ctype@v1.11.0",
Name: "symfony/polyfill-ctype", Name: "symfony/polyfill-ctype",
Version: "v1.11.0", Version: "v1.11.0",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 626, EndLine: 683}},
}, },
{ {
ID: "symfony/polyfill-mbstring@v1.11.0",
Name: "symfony/polyfill-mbstring", Name: "symfony/polyfill-mbstring",
Version: "v1.11.0", Version: "v1.11.0",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 684, EndLine: 742}},
}, },
{ {
ID: "symfony/process@v4.2.7",
Name: "symfony/process", Name: "symfony/process",
Version: "v4.2.7", Version: "v4.2.7",
Licenses: []string{"MIT"},
Locations: []types.Location{{StartLine: 743, EndLine: 791}},
}, },
}, },
}, },
@@ -625,7 +673,7 @@ func TestArtifact_Inspect(t *testing.T) {
}, },
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e", BlobID: "sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -1434,10 +1482,10 @@ func TestArtifact_Inspect(t *testing.T) {
Type: types.ArtifactContainerImage, Type: types.ArtifactContainerImage,
ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
BlobIDs: []string{ BlobIDs: []string{
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac", "sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53", "sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257", "sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e", "sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
}, },
ImageMetadata: types.ImageMetadata{ ImageMetadata: types.ImageMetadata{
ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4", ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
@@ -1685,7 +1733,7 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
Args: cache.ArtifactCacheMissingBlobsArgs{ Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
Returns: cache.ArtifactCacheMissingBlobsReturns{ Returns: cache.ArtifactCacheMissingBlobsReturns{
Err: xerrors.New("MissingBlobs failed"), Err: xerrors.New("MissingBlobs failed"),
@@ -1699,16 +1747,16 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
Args: cache.ArtifactCacheMissingBlobsArgs{ Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
Returns: cache.ArtifactCacheMissingBlobsReturns{ Returns: cache.ArtifactCacheMissingBlobsReturns{
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
}, },
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30", BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",
@@ -1767,17 +1815,17 @@ func TestArtifact_Inspect(t *testing.T) {
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
Args: cache.ArtifactCacheMissingBlobsArgs{ Args: cache.ArtifactCacheMissingBlobsArgs{
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
Returns: cache.ArtifactCacheMissingBlobsReturns{ Returns: cache.ArtifactCacheMissingBlobsReturns{
MissingArtifact: true, MissingArtifact: true,
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"}, MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
}, },
}, },
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
{ {
Args: cache.ArtifactCachePutBlobArgs{ Args: cache.ArtifactCachePutBlobArgs{
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30", BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
BlobInfo: types.BlobInfo{ BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion, SchemaVersion: types.BlobJSONSchemaVersion,
Digest: "", Digest: "",

View File

@@ -1289,73 +1289,237 @@
"FilePath": "php-app/composer.lock", "FilePath": "php-app/composer.lock",
"Libraries": [ "Libraries": [
{ {
"ID": "guzzlehttp/guzzle@6.2.0",
"Name": "guzzlehttp/guzzle", "Name": "guzzlehttp/guzzle",
"Version": "6.2.0", "Version": "6.2.0",
"Licenses": [
"MIT"
],
"DependsOn": [
"guzzlehttp/promises@v1.3.1",
"guzzlehttp/psr7@1.5.2"
],
"Locations": [
{
"StartLine": 9,
"EndLine": 73
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "guzzlehttp/promises@v1.3.1",
"Name": "guzzlehttp/promises", "Name": "guzzlehttp/promises",
"Version": "v1.3.1", "Version": "v1.3.1",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 74,
"EndLine": 124
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "guzzlehttp/psr7@1.5.2",
"Name": "guzzlehttp/psr7", "Name": "guzzlehttp/psr7",
"Version": "1.5.2", "Version": "1.5.2",
"Licenses": [
"MIT"
],
"DependsOn": [
"psr/http-message@1.0.1",
"ralouphie/getallheaders@2.0.5"
],
"Locations": [
{
"StartLine": 125,
"EndLine": 191
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "laravel/installer@v2.0.1",
"Name": "laravel/installer", "Name": "laravel/installer",
"Version": "v2.0.1", "Version": "v2.0.1",
"Licenses": [
"MIT"
],
"DependsOn": [
"guzzlehttp/guzzle@6.2.0",
"symfony/console@v4.2.7",
"symfony/filesystem@v4.2.7",
"symfony/process@v4.2.7"
],
"Locations": [
{
"StartLine": 192,
"EndLine": 237
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "pear/log@1.13.1",
"Name": "pear/log", "Name": "pear/log",
"Version": "1.13.1", "Version": "1.13.1",
"Licenses": [
"MIT"
],
"DependsOn": [
"pear/pear_exception@v1.0.0"
],
"Locations": [
{
"StartLine": 238,
"EndLine": 290
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "pear/pear_exception@v1.0.0",
"Name": "pear/pear_exception", "Name": "pear/pear_exception",
"Version": "v1.0.0", "Version": "v1.0.0",
"Licenses": [
"BSD-2-Clause"
],
"Locations": [
{
"StartLine": 291,
"EndLine": 345
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "psr/http-message@1.0.1",
"Name": "psr/http-message", "Name": "psr/http-message",
"Version": "1.0.1", "Version": "1.0.1",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 346,
"EndLine": 395
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "ralouphie/getallheaders@2.0.5",
"Name": "ralouphie/getallheaders", "Name": "ralouphie/getallheaders",
"Version": "2.0.5", "Version": "2.0.5",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 396,
"EndLine": 435
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/console@v4.2.7",
"Name": "symfony/console", "Name": "symfony/console",
"Version": "v4.2.7", "Version": "v4.2.7",
"Licenses": [
"MIT"
],
"DependsOn": [
"symfony/contracts@v1.0.2",
"symfony/polyfill-mbstring@v1.11.0"
],
"Locations": [
{
"StartLine": 436,
"EndLine": 507
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/contracts@v1.0.2",
"Name": "symfony/contracts", "Name": "symfony/contracts",
"Version": "v1.0.2", "Version": "v1.0.2",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 508,
"EndLine": 575
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/filesystem@v4.2.7",
"Name": "symfony/filesystem", "Name": "symfony/filesystem",
"Version": "v4.2.7", "Version": "v4.2.7",
"Licenses": [
"MIT"
],
"DependsOn": [
"symfony/polyfill-ctype@v1.11.0"
],
"Locations": [
{
"StartLine": 576,
"EndLine": 625
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/polyfill-ctype@v1.11.0",
"Name": "symfony/polyfill-ctype", "Name": "symfony/polyfill-ctype",
"Version": "v1.11.0", "Version": "v1.11.0",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 626,
"EndLine": 683
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/polyfill-mbstring@v1.11.0",
"Name": "symfony/polyfill-mbstring", "Name": "symfony/polyfill-mbstring",
"Version": "v1.11.0", "Version": "v1.11.0",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 684,
"EndLine": 742
}
],
"Layer": {} "Layer": {}
}, },
{ {
"ID": "symfony/process@v4.2.7",
"Name": "symfony/process", "Name": "symfony/process",
"Version": "v4.2.7", "Version": "v4.2.7",
"Licenses": [
"MIT"
],
"Locations": [
{
"StartLine": 743,
"EndLine": 791
}
],
"Layer": {} "Layer": {}
} }
] ]

View File

@@ -64,6 +64,7 @@ const (
PnpmLock = "pnpm-lock.yaml" PnpmLock = "pnpm-lock.yaml"
ComposerLock = "composer.lock" ComposerLock = "composer.lock"
ComposerJson = "composer.json"
PyProject = "pyproject.toml" PyProject = "pyproject.toml"
PipRequirements = "requirements.txt" PipRequirements = "requirements.txt"