mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
fix(sbom): add SBOM file's filePath as Application FilePath if we can't detect its path (#8346)
Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
@@ -411,9 +411,20 @@ Trivy supports the generation of Software Bill of Materials (SBOM) for container
|
||||
|
||||
### Generation
|
||||
Trivy can generate SBOM for container images.
|
||||
See [here](../supply-chain/sbom.md) for the detail.
|
||||
See [here](../supply-chain/sbom.md) for details.
|
||||
|
||||
### Discovery
|
||||
### Discover SBOM inside container images
|
||||
Trivy can search for Software Bill of Materials (SBOMs) within container image files and scan their components for vulnerabilities.
|
||||
|
||||
#### Third-party SBOM files
|
||||
SBOM specifications define key requirements for component documentation[^2].
|
||||
However, different tools and systems often have varying approaches to documenting component types and their relationships.
|
||||
|
||||
Due to these variations, Trivy cannot always accurately interpret SBOMs generated by other tools.
|
||||
For example, it may have difficulty determining the correct file paths to component information files (such as lock files or binaries).
|
||||
In such cases, Trivy uses the path to the scanned SBOM file itself to maintain traceability and ensure accurate dependency reporting.
|
||||
|
||||
### Discover SBOM referencing the container image
|
||||
Trivy can search for Software Bill of Materials (SBOMs) that reference container images.
|
||||
If an SBOM is found, the vulnerability scan is performed using the SBOM instead of the container image.
|
||||
By using the SBOM, you can perform a vulnerability scan more quickly, as it allows you to skip pulling the container image and analyzing its layers.
|
||||
@@ -559,3 +570,4 @@ Error: uncompressed image size (15GB) exceeds maximum allowed size (10GB)
|
||||
```
|
||||
|
||||
[^1]: Trivy uses decimal (SI) prefixes (based on 1000) for size.
|
||||
[^2]: SPDX uses `package` instead of `component`.
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
@@ -58,10 +57,14 @@ func (a sbomAnalyzer) Analyze(ctx context.Context, input analyzer.AnalysisInput)
|
||||
bom.Packages[i].FilePath = path.Join(input.FilePath, pkgInfo.FilePath)
|
||||
}
|
||||
|
||||
// FilePath for apps with aggregatingTypes is empty.
|
||||
// Set the SBOM file path as Application.FilePath to correctly overwrite applications when merging layers.
|
||||
// There are cases when FilePath for Application is empty:
|
||||
// - FilePath for apps with aggregatingTypes is empty.
|
||||
// - Third party SBOM without Application component.
|
||||
// We need to use SBOM file path as Application.FilePath to correctly:
|
||||
// - overwrite applications when merging layers. See https://github.com/aquasecurity/trivy/issues/7851
|
||||
// - show FilePath as Target of Application. See https://github.com/aquasecurity/trivy/issues/8189.
|
||||
for i, app := range bom.Applications {
|
||||
if slices.Contains(ftypes.AggregatingTypes, app.Type) && app.FilePath == "" {
|
||||
if app.FilePath == "" {
|
||||
bom.Applications[i].FilePath = input.FilePath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,57 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "valid sbom spdx file without application component",
|
||||
file: "testdata/sbom-without-app-component.spdx.json",
|
||||
filePath: "layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.spdx.json",
|
||||
want: &analyzer.AnalysisResult{
|
||||
Applications: []types.Application{
|
||||
{
|
||||
Type: types.GoBinary,
|
||||
FilePath: "layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.spdx.json",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
ID: "github.com/buildpacks/lifecycle@v0.20.2",
|
||||
Name: "github.com/buildpacks/lifecycle",
|
||||
Version: "v0.20.2",
|
||||
Identifier: types.PkgIdentifier{
|
||||
PURL: &packageurl.PackageURL{
|
||||
Type: packageurl.TypeGolang,
|
||||
Namespace: "github.com/buildpacks",
|
||||
Name: "lifecycle",
|
||||
Version: "v0.20.2",
|
||||
},
|
||||
},
|
||||
Licenses: []string{
|
||||
"NOASSERTION",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: types.Jar,
|
||||
FilePath: "layers/sbom/launch/buildpacksio_lifecycle/launcher/sbom.spdx.json",
|
||||
Packages: types.Packages{
|
||||
{
|
||||
ID: "co.elastic.apm:apm-agent:1.36.0",
|
||||
Name: "co.elastic.apm:apm-agent",
|
||||
Version: "1.36.0",
|
||||
Identifier: types.PkgIdentifier{
|
||||
PURL: &packageurl.PackageURL{
|
||||
Type: packageurl.TypeMaven,
|
||||
Namespace: "co.elastic.apm",
|
||||
Name: "apm-agent",
|
||||
Version: "1.36.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "valid postgresql spdx file",
|
||||
file: "testdata/postgresql.spdx.json",
|
||||
|
||||
111
pkg/fanal/analyzer/sbom/testdata/sbom-without-app-component.spdx.json
vendored
Normal file
111
pkg/fanal/analyzer/sbom/testdata/sbom-without-app-component.spdx.json
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"spdxVersion": "SPDX-2.3",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "launcher",
|
||||
"documentNamespace": "https://anchore.com/syft/file/launcher-268e7779-ba66-4422-a5b0-d4d83f7b5d8c",
|
||||
"creationInfo": {
|
||||
"licenseListVersion": "3.25",
|
||||
"creators": [
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: syft-1.13.0"
|
||||
],
|
||||
"created": "2024-09-25T21:11:50Z"
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"name": "co.elastic.apm:apm-agent",
|
||||
"SPDXID": "SPDXRef-Package-f0db45781e6813a1",
|
||||
"versionInfo": "1.36.0",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NONE",
|
||||
"licenseConcluded": "NONE",
|
||||
"licenseDeclared": "NONE",
|
||||
"copyrightText": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "PACKAGE_MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": "pkg:maven/co.elastic.apm/apm-agent@1.36.0"
|
||||
}
|
||||
],
|
||||
"filesAnalyzed": false
|
||||
},
|
||||
{
|
||||
"name": "github.com/buildpacks/lifecycle",
|
||||
"SPDXID": "SPDXRef-Package-go-module-github.com-buildpacks-lifecycle-89c3bd8d4c2e75b7",
|
||||
"versionInfo": "v0.20.2",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"sourceInfo": "acquired package info from go module information: /launcher",
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"copyrightText": "NOASSERTION",
|
||||
"externalRefs": [
|
||||
{
|
||||
"referenceCategory": "SECURITY",
|
||||
"referenceType": "cpe23Type",
|
||||
"referenceLocator": "cpe:2.3:a:buildpacks:lifecycle:v0.20.2:*:*:*:*:*:*:*"
|
||||
},
|
||||
{
|
||||
"referenceCategory": "PACKAGE-MANAGER",
|
||||
"referenceType": "purl",
|
||||
"referenceLocator": "pkg:golang/github.com/buildpacks/lifecycle@v0.20.2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "launcher",
|
||||
"SPDXID": "SPDXRef-DocumentRoot-File-launcher",
|
||||
"versionInfo": "sha256:716665ae98fb4b4675d5184f80884547597d47be1395d1049dc9e16035f32cc1",
|
||||
"supplier": "NOASSERTION",
|
||||
"downloadLocation": "NOASSERTION",
|
||||
"filesAnalyzed": false,
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA256",
|
||||
"checksumValue": "716665ae98fb4b4675d5184f80884547597d47be1395d1049dc9e16035f32cc1"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseDeclared": "NOASSERTION",
|
||||
"primaryPackagePurpose": "FILE"
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
{
|
||||
"fileName": "/launcher",
|
||||
"SPDXID": "SPDXRef-File-launcher-361242815a383bec",
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA1",
|
||||
"checksumValue": "0000000000000000000000000000000000000000"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": ""
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"spdxElementId": "SPDXRef-Package-go-module-github.com-buildpacks-lifecycle-89c3bd8d4c2e75b7",
|
||||
"relatedSpdxElement": "SPDXRef-File-launcher-361242815a383bec",
|
||||
"relationshipType": "OTHER",
|
||||
"comment": "evident-by: indicates the package's existence is evident by the given file"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DocumentRoot-File-launcher",
|
||||
"relatedSpdxElement": "SPDXRef-Package-go-module-github.com-buildpacks-lifecycle-89c3bd8d4c2e75b7",
|
||||
"relationshipType": "CONTAINS"
|
||||
},
|
||||
{
|
||||
"spdxElementId": "SPDXRef-DOCUMENT",
|
||||
"relatedSpdxElement": "SPDXRef-DocumentRoot-File-launcher",
|
||||
"relationshipType": "DESCRIBES"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user