mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 23:26:39 -08:00
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:
@@ -11,7 +11,7 @@
|
||||
| | requirements.txt | - | - | ✅ | ✅ | included | - |
|
||||
| | egg package[^1] | ✅ | ✅ | - | - | excluded | - |
|
||||
| | wheel package[^2] | ✅ | ✅ | - | - | excluded | - |
|
||||
| PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded | - |
|
||||
| PHP | composer.lock | ✅ | ✅ | ✅ | ✅ | excluded | ✅ |
|
||||
| Node.js | package-lock.json | - | - | ✅ | ✅ | excluded | ✅ |
|
||||
| | yarn.lock | - | - | ✅ | ✅ | included | ✅ |
|
||||
| | pnpm-lock.yaml | - | - | ✅ | ✅ | excluded | - |
|
||||
|
||||
@@ -35,8 +35,10 @@ The following packages/languages are currently supported:
|
||||
- Bundler: Gemfile.lock
|
||||
- Rust
|
||||
- Binaries built with [cargo-auditable][cargo-auditable]
|
||||
- Go
|
||||
- Go
|
||||
- Modules: go.mod
|
||||
- PHP
|
||||
- Composer
|
||||
|
||||
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.
|
||||
|
||||
18
docs/docs/vulnerability/languages/php.md
Normal file
18
docs/docs/vulnerability/languages/php.md
Normal 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
2
go.mod
@@ -14,7 +14,7 @@ require (
|
||||
github.com/alicebob/miniredis/v2 v2.23.0
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
||||
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-npm-version v0.0.0-20201110091526-0b796d180798
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
|
||||
4
go.sum
4
go.sum
@@ -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/defsec v0.84.1 h1:YwhQprDEy4ZN/c7aDV57O5UkxOusHwtfeENI7wm4/L8=
|
||||
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-20230321131503-05943e2e8dd8/go.mod h1:lI+o04X85vxgx2jPji9G0tZ6AqqhVcXn8A88qimWfOM=
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20230324031819-b0e2fb4e2140 h1:TUt7SV2LJQ5Uw7wjKL6jt33zeQJKEm4gCW5ULZoMlAA=
|
||||
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/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s=
|
||||
github.com/aquasecurity/go-mock-aws v0.0.0-20220726154943-99847deb62b0 h1:tihCUjLWkF0b1SAjAKcFltUs3SpsqGrLtI+Frye0D10=
|
||||
|
||||
@@ -187,6 +187,15 @@ func TestFilesystem(t *testing.T) {
|
||||
},
|
||||
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",
|
||||
args: args{
|
||||
|
||||
96
integration/testdata/composer.lock.json.golden
vendored
Normal file
96
integration/testdata/composer.lock.json.golden
vendored
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
10
integration/testdata/fixtures/db/composer.yaml
vendored
Normal file
10
integration/testdata/fixtures/db/composer.yaml
vendored
Normal 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
|
||||
@@ -1294,6 +1294,24 @@
|
||||
- https://github.com/advisories/GHSA-4rgh-jx4f-qfcq
|
||||
PublishedDate: "2022-05-24T17:37:16Z"
|
||||
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
|
||||
value:
|
||||
Title: "spring-framework: RCE via Data Binding on JDK 9+"
|
||||
|
||||
5
integration/testdata/fixtures/fs/composer/composer.json
vendored
Normal file
5
integration/testdata/fixtures/fs/composer/composer.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "7.4.4"
|
||||
}
|
||||
}
|
||||
256
integration/testdata/fixtures/fs/composer/composer.lock
generated
vendored
Normal file
256
integration/testdata/fixtures/fs/composer/composer.lock
generated
vendored
Normal 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"
|
||||
}
|
||||
@@ -62,6 +62,7 @@ nav:
|
||||
- Go: docs/vulnerability/languages/golang.md
|
||||
- Java: docs/vulnerability/languages/java.md
|
||||
- Node.js: docs/vulnerability/languages/nodejs.md
|
||||
- PHP: docs/vulnerability/languages/php.md
|
||||
- Python: docs/vulnerability/languages/python.md
|
||||
- Misconfiguration:
|
||||
- Scanning: docs/misconfiguration/scanning.md
|
||||
|
||||
@@ -2,57 +2,149 @@ package composer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
dio "github.com/aquasecurity/go-dep-parser/pkg/io"
|
||||
"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/language"
|
||||
"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() {
|
||||
analyzer.RegisterAnalyzer(&composerLibraryAnalyzer{})
|
||||
analyzer.RegisterPostAnalyzer(types.Composer, newComposerAnalyzer)
|
||||
}
|
||||
|
||||
const version = 1
|
||||
|
||||
var requiredFiles = []string{types.ComposerLock}
|
||||
|
||||
type composerLibraryAnalyzer struct{}
|
||||
|
||||
func (a composerLibraryAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
|
||||
res, err := language.Analyze(types.Composer, input.FilePath, input.Content, composer.NewParser())
|
||||
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("error with composer.lock: %w", err)
|
||||
}
|
||||
return res, nil
|
||||
var requiredFiles = []string{
|
||||
types.ComposerLock,
|
||||
types.ComposerJson,
|
||||
}
|
||||
|
||||
func (a composerLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool {
|
||||
type composerAnalyzer struct {
|
||||
lockParser godeptypes.Parser
|
||||
}
|
||||
|
||||
func newComposerAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) {
|
||||
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 {
|
||||
return xerrors.Errorf("parse error: %w", err)
|
||||
} else if app == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if !utils.StringInSlice(fileName, requiredFiles) {
|
||||
if !slices.Contains(requiredFiles, fileName) {
|
||||
return false
|
||||
}
|
||||
|
||||
// we should skip `composer.lock` inside `vendor` folder
|
||||
for _, p := range strings.Split(filepath.ToSlash(filePath), "/") {
|
||||
if p == "vendor" {
|
||||
// Skip `composer.lock` inside `vendor` folder
|
||||
if slices.Contains(strings.Split(filePath, "/"), "vendor") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a composerLibraryAnalyzer) Type() analyzer.Type {
|
||||
func (a composerAnalyzer) Type() analyzer.Type {
|
||||
return analyzer.TypeComposer
|
||||
}
|
||||
|
||||
func (a composerLibraryAnalyzer) Version() int {
|
||||
func (a composerAnalyzer) Version() int {
|
||||
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
|
||||
}
|
||||
|
||||
107
pkg/fanal/analyzer/language/php/composer/composer_test.go
Normal file
107
pkg/fanal/analyzer/language/php/composer/composer_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
5
pkg/fanal/analyzer/language/php/composer/testdata/happy/composer.json
vendored
Normal file
5
pkg/fanal/analyzer/language/php/composer/testdata/happy/composer.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"require": {
|
||||
"pear/log": "^1.13"
|
||||
}
|
||||
}
|
||||
138
pkg/fanal/analyzer/language/php/composer/testdata/happy/composer.lock
generated
vendored
Normal file
138
pkg/fanal/analyzer/language/php/composer/testdata/happy/composer.lock
generated
vendored
Normal 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"
|
||||
}
|
||||
138
pkg/fanal/analyzer/language/php/composer/testdata/no-composer-json/composer.lock
generated
vendored
Normal file
138
pkg/fanal/analyzer/language/php/composer/testdata/no-composer-json/composer.lock
generated
vendored
Normal 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"
|
||||
}
|
||||
1
pkg/fanal/analyzer/language/php/composer/testdata/sad/composer.lock
generated
vendored
Normal file
1
pkg/fanal/analyzer/language/php/composer/testdata/sad/composer.lock
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{
|
||||
@@ -217,17 +217,17 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
|
||||
Args: cache.ArtifactCacheMissingBlobsArgs{
|
||||
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
|
||||
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
Returns: cache.ArtifactCacheMissingBlobsReturns{
|
||||
MissingArtifact: true,
|
||||
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
},
|
||||
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30",
|
||||
BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -294,7 +294,7 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
Name: "../../test/testdata/alpine-311.tar.gz",
|
||||
Type: types.ArtifactContainerImage,
|
||||
ID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
|
||||
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
ImageMetadata: types.ImageMetadata{
|
||||
ID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72",
|
||||
DiffIDs: []string{
|
||||
@@ -353,25 +353,25 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
Args: cache.ArtifactCacheMissingBlobsArgs{
|
||||
ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
|
||||
BlobIDs: []string{
|
||||
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac",
|
||||
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53",
|
||||
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257",
|
||||
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e",
|
||||
"sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
|
||||
"sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
|
||||
"sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
|
||||
"sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
|
||||
},
|
||||
},
|
||||
Returns: cache.ArtifactCacheMissingBlobsReturns{
|
||||
MissingBlobIDs: []string{
|
||||
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac",
|
||||
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53",
|
||||
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257",
|
||||
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e",
|
||||
"sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
|
||||
"sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
|
||||
"sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
|
||||
"sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
|
||||
},
|
||||
},
|
||||
},
|
||||
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac",
|
||||
BlobID: "sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -456,7 +456,7 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53",
|
||||
BlobID: "sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -549,7 +549,7 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257",
|
||||
BlobID: "sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -561,60 +561,108 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
FilePath: "php-app/composer.lock",
|
||||
Libraries: []types.Package{
|
||||
{
|
||||
ID: "guzzlehttp/guzzle@6.2.0",
|
||||
Name: "guzzlehttp/guzzle",
|
||||
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",
|
||||
Version: "v1.3.1",
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []types.Location{{StartLine: 74, EndLine: 124}},
|
||||
},
|
||||
{
|
||||
ID: "guzzlehttp/psr7@1.5.2",
|
||||
Name: "guzzlehttp/psr7",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
Version: "1.0.1",
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []types.Location{{StartLine: 346, EndLine: 395}},
|
||||
},
|
||||
{
|
||||
ID: "ralouphie/getallheaders@2.0.5",
|
||||
Name: "ralouphie/getallheaders",
|
||||
Version: "2.0.5",
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []types.Location{{StartLine: 396, EndLine: 435}},
|
||||
},
|
||||
{
|
||||
ID: "symfony/console@v4.2.7",
|
||||
Name: "symfony/console",
|
||||
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",
|
||||
Version: "v1.0.2",
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []types.Location{{StartLine: 508, EndLine: 575}},
|
||||
},
|
||||
{
|
||||
ID: "symfony/filesystem@v4.2.7",
|
||||
Name: "symfony/filesystem",
|
||||
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",
|
||||
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",
|
||||
Version: "v1.11.0",
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []types.Location{{StartLine: 684, EndLine: 742}},
|
||||
},
|
||||
{
|
||||
ID: "symfony/process@v4.2.7",
|
||||
Name: "symfony/process",
|
||||
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{
|
||||
BlobID: "sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e",
|
||||
BlobID: "sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -1434,10 +1482,10 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
Type: types.ArtifactContainerImage,
|
||||
ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650",
|
||||
BlobIDs: []string{
|
||||
"sha256:ec335b892592429be1caac2726b82a14a65252cb7b2dc3fd65d7b131e6afebac",
|
||||
"sha256:695b29fc394347e9523663f10627032876245ee4f789c5080ccde596deafcc53",
|
||||
"sha256:1266461fba5ebc83c3ac3c983d027d636b1d49d4983dd60923bcc2ad36179257",
|
||||
"sha256:0f6542bb1fbd05fb37bdfca6c023b9320364a2887c446b0d1d9245222edf519e",
|
||||
"sha256:673f305ef9cede893bc9a1851da8152b1f7597321e06f551a1d875f20f947f5b",
|
||||
"sha256:2886467019d514a49e74ce4507da571023c97798e3f0f3805e9c9826b5b993ef",
|
||||
"sha256:f77cea0f8767d9520ea9001de1f1102e0e5e85ccf726c91271e3d63e963ab4d4",
|
||||
"sha256:c5233a461c9ead1191adfa7a34d9cd66e6b319460939bbf0f085a3fa0faae635",
|
||||
},
|
||||
ImageMetadata: types.ImageMetadata{
|
||||
ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
|
||||
@@ -1685,7 +1733,7 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
|
||||
Args: cache.ArtifactCacheMissingBlobsArgs{
|
||||
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
|
||||
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
Returns: cache.ArtifactCacheMissingBlobsReturns{
|
||||
Err: xerrors.New("MissingBlobs failed"),
|
||||
@@ -1699,16 +1747,16 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
|
||||
Args: cache.ArtifactCacheMissingBlobsArgs{
|
||||
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
|
||||
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
Returns: cache.ArtifactCacheMissingBlobsReturns{
|
||||
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
},
|
||||
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30",
|
||||
BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
@@ -1767,17 +1815,17 @@ func TestArtifact_Inspect(t *testing.T) {
|
||||
missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{
|
||||
Args: cache.ArtifactCacheMissingBlobsArgs{
|
||||
ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313",
|
||||
BlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
BlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
Returns: cache.ArtifactCacheMissingBlobsReturns{
|
||||
MissingArtifact: true,
|
||||
MissingBlobIDs: []string{"sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30"},
|
||||
MissingBlobIDs: []string{"sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3"},
|
||||
},
|
||||
},
|
||||
putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{
|
||||
{
|
||||
Args: cache.ArtifactCachePutBlobArgs{
|
||||
BlobID: "sha256:c4d631f4c467a7202d13b02512358984489e8631dba57590cd6322087e0c1a30",
|
||||
BlobID: "sha256:1ee72875fbb6def206801205982d81b4c2be24974906823266224527badad8e3",
|
||||
BlobInfo: types.BlobInfo{
|
||||
SchemaVersion: types.BlobJSONSchemaVersion,
|
||||
Digest: "",
|
||||
|
||||
@@ -1289,73 +1289,237 @@
|
||||
"FilePath": "php-app/composer.lock",
|
||||
"Libraries": [
|
||||
{
|
||||
"ID": "guzzlehttp/guzzle@6.2.0",
|
||||
"Name": "guzzlehttp/guzzle",
|
||||
"Version": "6.2.0",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"DependsOn": [
|
||||
"guzzlehttp/promises@v1.3.1",
|
||||
"guzzlehttp/psr7@1.5.2"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 9,
|
||||
"EndLine": 73
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "guzzlehttp/promises@v1.3.1",
|
||||
"Name": "guzzlehttp/promises",
|
||||
"Version": "v1.3.1",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 74,
|
||||
"EndLine": 124
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "guzzlehttp/psr7@1.5.2",
|
||||
"Name": "guzzlehttp/psr7",
|
||||
"Version": "1.5.2",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"DependsOn": [
|
||||
"psr/http-message@1.0.1",
|
||||
"ralouphie/getallheaders@2.0.5"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 125,
|
||||
"EndLine": 191
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "laravel/installer@v2.0.1",
|
||||
"Name": "laravel/installer",
|
||||
"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": {}
|
||||
},
|
||||
{
|
||||
"ID": "pear/log@1.13.1",
|
||||
"Name": "pear/log",
|
||||
"Version": "1.13.1",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"DependsOn": [
|
||||
"pear/pear_exception@v1.0.0"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 238,
|
||||
"EndLine": 290
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "pear/pear_exception@v1.0.0",
|
||||
"Name": "pear/pear_exception",
|
||||
"Version": "v1.0.0",
|
||||
"Licenses": [
|
||||
"BSD-2-Clause"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 291,
|
||||
"EndLine": 345
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "psr/http-message@1.0.1",
|
||||
"Name": "psr/http-message",
|
||||
"Version": "1.0.1",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 346,
|
||||
"EndLine": 395
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "ralouphie/getallheaders@2.0.5",
|
||||
"Name": "ralouphie/getallheaders",
|
||||
"Version": "2.0.5",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 396,
|
||||
"EndLine": 435
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/console@v4.2.7",
|
||||
"Name": "symfony/console",
|
||||
"Version": "v4.2.7",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"DependsOn": [
|
||||
"symfony/contracts@v1.0.2",
|
||||
"symfony/polyfill-mbstring@v1.11.0"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 436,
|
||||
"EndLine": 507
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/contracts@v1.0.2",
|
||||
"Name": "symfony/contracts",
|
||||
"Version": "v1.0.2",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 508,
|
||||
"EndLine": 575
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/filesystem@v4.2.7",
|
||||
"Name": "symfony/filesystem",
|
||||
"Version": "v4.2.7",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"DependsOn": [
|
||||
"symfony/polyfill-ctype@v1.11.0"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 576,
|
||||
"EndLine": 625
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/polyfill-ctype@v1.11.0",
|
||||
"Name": "symfony/polyfill-ctype",
|
||||
"Version": "v1.11.0",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 626,
|
||||
"EndLine": 683
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/polyfill-mbstring@v1.11.0",
|
||||
"Name": "symfony/polyfill-mbstring",
|
||||
"Version": "v1.11.0",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 684,
|
||||
"EndLine": 742
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
},
|
||||
{
|
||||
"ID": "symfony/process@v4.2.7",
|
||||
"Name": "symfony/process",
|
||||
"Version": "v4.2.7",
|
||||
"Licenses": [
|
||||
"MIT"
|
||||
],
|
||||
"Locations": [
|
||||
{
|
||||
"StartLine": 743,
|
||||
"EndLine": 791
|
||||
}
|
||||
],
|
||||
"Layer": {}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -64,6 +64,7 @@ const (
|
||||
PnpmLock = "pnpm-lock.yaml"
|
||||
|
||||
ComposerLock = "composer.lock"
|
||||
ComposerJson = "composer.json"
|
||||
|
||||
PyProject = "pyproject.toml"
|
||||
PipRequirements = "requirements.txt"
|
||||
|
||||
Reference in New Issue
Block a user