mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 15:16:33 -08:00
feat(python): Include Conda packages in SBOMs (#3379)
Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
@@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
## Other language-specific packages
|
## Other language-specific packages
|
||||||
|
|
||||||
| Language | File | Dependency location[^1] |
|
| Language | File | Dependency location[^1] |
|
||||||
|----------|--------------|:-----------------------:|
|
|----------|-------------------|:-----------------------:|
|
||||||
| Swift | Podfile.lock | - |
|
| Python | conda package[^2] | - |
|
||||||
|
| Swift | Podfile.lock | - |
|
||||||
|
|
||||||
[^1]: Use `startline == 1 and endline == 1` for unsupported file types
|
[^1]: Use `startline == 1 and endline == 1` for unsupported file types
|
||||||
|
[^2]: `envs/*/conda-meta/*.json`
|
||||||
|
|
||||||
[os_packages]: ../vulnerability/detection/os.md
|
[os_packages]: ../vulnerability/detection/os.md
|
||||||
[language_packages]: ../vulnerability/detection/language.md
|
[language_packages]: ../vulnerability/detection/language.md
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ func TestFilesystem(t *testing.T) {
|
|||||||
helmValuesFile []string
|
helmValuesFile []string
|
||||||
skipFiles []string
|
skipFiles []string
|
||||||
skipDirs []string
|
skipDirs []string
|
||||||
|
command string
|
||||||
|
format string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -263,6 +265,24 @@ func TestFilesystem(t *testing.T) {
|
|||||||
},
|
},
|
||||||
golden: "testdata/secrets.json.golden",
|
golden: "testdata/secrets.json.golden",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "conda generating CycloneDX SBOM",
|
||||||
|
args: args{
|
||||||
|
command: "rootfs",
|
||||||
|
format: "cyclonedx",
|
||||||
|
input: "testdata/fixtures/fs/conda",
|
||||||
|
},
|
||||||
|
golden: "testdata/conda-cyclonedx.json.golden",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "conda generating SPDX SBOM",
|
||||||
|
args: args{
|
||||||
|
command: "rootfs",
|
||||||
|
format: "spdx-json",
|
||||||
|
input: "testdata/fixtures/fs/conda",
|
||||||
|
},
|
||||||
|
golden: "testdata/conda-spdx.json.golden",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up testing DB
|
// Set up testing DB
|
||||||
@@ -273,9 +293,24 @@ func TestFilesystem(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
command := "fs"
|
||||||
|
if tt.args.command != "" {
|
||||||
|
command = tt.args.command
|
||||||
|
}
|
||||||
|
|
||||||
|
format := "json"
|
||||||
|
if tt.args.format != "" {
|
||||||
|
format = tt.args.format
|
||||||
|
}
|
||||||
|
|
||||||
osArgs := []string{
|
osArgs := []string{
|
||||||
"-q", "--cache-dir", cacheDir, "fs", "--skip-db-update", "--skip-policy-update",
|
"-q", "--cache-dir", cacheDir, command, "--skip-db-update", "--skip-policy-update",
|
||||||
"--format", "json", "--offline-scan", "--security-checks", tt.args.securityChecks,
|
"--format", format, "--offline-scan",
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.args.securityChecks != "" {
|
||||||
|
osArgs = append(osArgs, "--security-checks", tt.args.securityChecks)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tt.args.policyPaths) != 0 {
|
if len(tt.args.policyPaths) != 0 {
|
||||||
@@ -353,7 +388,16 @@ func TestFilesystem(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Compare want and got
|
// Compare want and got
|
||||||
compareReports(t, tt.golden, outputFile)
|
switch format {
|
||||||
|
case "cyclonedx":
|
||||||
|
compareCycloneDX(t, tt.golden, outputFile)
|
||||||
|
case "spdx-json":
|
||||||
|
compareSpdxJson(t, tt.golden, outputFile)
|
||||||
|
case "json":
|
||||||
|
compareReports(t, tt.golden, outputFile)
|
||||||
|
default:
|
||||||
|
require.Fail(t, "invalid format", "format: %s", format)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||||
|
"github.com/spdx/tools-golang/jsonloader"
|
||||||
|
"github.com/spdx/tools-golang/spdx"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -121,6 +124,50 @@ func readReport(t *testing.T, filePath string) types.Report {
|
|||||||
return report
|
return report
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readCycloneDX(t *testing.T, filePath string) *cdx.BOM {
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
bom := cdx.NewBOM()
|
||||||
|
decoder := cdx.NewBOMDecoder(f, cdx.BOMFileFormatJSON)
|
||||||
|
err = decoder.Decode(bom)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We don't compare values which change each time an SBOM is generated
|
||||||
|
bom.Metadata.Timestamp = ""
|
||||||
|
bom.Metadata.Component.BOMRef = ""
|
||||||
|
bom.SerialNumber = ""
|
||||||
|
if bom.Components != nil {
|
||||||
|
for i := range *bom.Components {
|
||||||
|
(*bom.Components)[i].BOMRef = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bom.Dependencies != nil {
|
||||||
|
for j := range *bom.Dependencies {
|
||||||
|
(*bom.Dependencies)[j].Ref = ""
|
||||||
|
(*bom.Dependencies)[j].Dependencies = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bom
|
||||||
|
}
|
||||||
|
|
||||||
|
func readSpdxJson(t *testing.T, filePath string) *spdx.Document2_2 {
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
bom, err := jsonloader.Load2_2(f)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We don't compare values which change each time an SBOM is generated
|
||||||
|
bom.CreationInfo.Created = ""
|
||||||
|
bom.CreationInfo.DocumentNamespace = ""
|
||||||
|
|
||||||
|
return bom
|
||||||
|
}
|
||||||
|
|
||||||
func execute(osArgs []string) error {
|
func execute(osArgs []string) error {
|
||||||
// Setup CLI App
|
// Setup CLI App
|
||||||
app := commands.NewApp("dev")
|
app := commands.NewApp("dev")
|
||||||
@@ -136,3 +183,15 @@ func compareReports(t *testing.T, wantFile, gotFile string) {
|
|||||||
got := readReport(t, gotFile)
|
got := readReport(t, gotFile)
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareCycloneDX(t *testing.T, wantFile, gotFile string) {
|
||||||
|
want := readCycloneDX(t, wantFile)
|
||||||
|
got := readCycloneDX(t, gotFile)
|
||||||
|
assert.Equal(t, want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareSpdxJson(t *testing.T, wantFile, gotFile string) {
|
||||||
|
want := readSpdxJson(t, wantFile)
|
||||||
|
got := readSpdxJson(t, gotFile)
|
||||||
|
assert.Equal(t, want, got)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -128,9 +126,7 @@ func TestSBOM(t *testing.T) {
|
|||||||
// Compare want and got
|
// Compare want and got
|
||||||
switch tt.args.format {
|
switch tt.args.format {
|
||||||
case "cyclonedx":
|
case "cyclonedx":
|
||||||
want := decodeCycloneDX(t, tt.golden)
|
compareCycloneDX(t, tt.golden, outputFile)
|
||||||
got := decodeCycloneDX(t, outputFile)
|
|
||||||
assert.Equal(t, want, got)
|
|
||||||
case "json":
|
case "json":
|
||||||
compareSBOMReports(t, tt.golden, outputFile, tt.override)
|
compareSBOMReports(t, tt.golden, outputFile, tt.override)
|
||||||
default:
|
default:
|
||||||
@@ -165,18 +161,3 @@ func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant typ
|
|||||||
got := readReport(t, gotFile)
|
got := readReport(t, gotFile)
|
||||||
assert.Equal(t, want, got)
|
assert.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeCycloneDX(t *testing.T, filePath string) *cdx.BOM {
|
|
||||||
f, err := os.Open(filePath)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
bom := cdx.NewBOM()
|
|
||||||
decoder := cdx.NewBOMDecoder(f, cdx.BOMFileFormatJSON)
|
|
||||||
err = decoder.Decode(bom)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
bom.Metadata.Timestamp = ""
|
|
||||||
|
|
||||||
return bom
|
|
||||||
}
|
|
||||||
|
|||||||
83
integration/testdata/conda-cyclonedx.json.golden
vendored
Normal file
83
integration/testdata/conda-cyclonedx.json.golden
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"bomFormat": "CycloneDX",
|
||||||
|
"specVersion": "1.4",
|
||||||
|
"serialNumber": "urn:uuid:4dd4cf4a-d4de-4ea0-b75f-ad617f31b5a9",
|
||||||
|
"version": 1,
|
||||||
|
"metadata": {
|
||||||
|
"timestamp": "2023-01-08T23:57:37+00:00",
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"vendor": "aquasecurity",
|
||||||
|
"name": "trivy",
|
||||||
|
"version": "dev"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"component": {
|
||||||
|
"bom-ref": "582a7c6f-b30e-4b65-a911-f3f5034aa003",
|
||||||
|
"type": "application",
|
||||||
|
"name": "testdata/fixtures/fs/conda",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:SchemaVersion",
|
||||||
|
"value": "2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"bom-ref": "pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json",
|
||||||
|
"type": "library",
|
||||||
|
"name": "openssl",
|
||||||
|
"version": "1.1.1q",
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"expression": "OpenSSL"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"purl": "pkg:conda/openssl@1.1.1q",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:PkgType",
|
||||||
|
"value": "conda-pkg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:FilePath",
|
||||||
|
"value": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bom-ref": "pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json",
|
||||||
|
"type": "library",
|
||||||
|
"name": "pip",
|
||||||
|
"version": "22.2.2",
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"expression": "MIT"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"purl": "pkg:conda/pip@22.2.2",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:PkgType",
|
||||||
|
"value": "conda-pkg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:FilePath",
|
||||||
|
"value": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"ref": "582a7c6f-b30e-4b65-a911-f3f5034aa003",
|
||||||
|
"dependsOn": [
|
||||||
|
"pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json",
|
||||||
|
"pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vulnerabilities": []
|
||||||
|
}
|
||||||
101
integration/testdata/conda-spdx.json.golden
vendored
Normal file
101
integration/testdata/conda-spdx.json.golden
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-DOCUMENT",
|
||||||
|
"creationInfo": {
|
||||||
|
"created": "2023-01-08T23:58:16.700785648Z",
|
||||||
|
"creators": [
|
||||||
|
"Tool: trivy",
|
||||||
|
"Organization: aquasecurity"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"dataLicense": "CC0-1.0",
|
||||||
|
"documentDescribes": [
|
||||||
|
"SPDXRef-Filesystem-6e0ac6a0fab50ab4"
|
||||||
|
],
|
||||||
|
"documentNamespace": "http://aquasecurity.github.io/trivy/filesystem/testdata/fixtures/fs/conda-3be0d21e-5711-451e-8b1b-2ac8775a3abb",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-File-600e5e0110a84891",
|
||||||
|
"fileName": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-File-7eb62e2a3edddc0a",
|
||||||
|
"fileName": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "testdata/fixtures/fs/conda",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-Application-ee5ef1aa4ac89125",
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"name": "conda-pkg",
|
||||||
|
"sourceInfo": "Conda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-Filesystem-6e0ac6a0fab50ab4",
|
||||||
|
"attributionTexts": [
|
||||||
|
"SchemaVersion: 2"
|
||||||
|
],
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"name": "testdata/fixtures/fs/conda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-Package-2984084f02572600",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceLocator": "pkg:conda/openssl@1.1.1q",
|
||||||
|
"referenceType": "purl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"hasFiles": [
|
||||||
|
"SPDXRef-File-600e5e0110a84891"
|
||||||
|
],
|
||||||
|
"licenseConcluded": "OpenSSL",
|
||||||
|
"licenseDeclared": "OpenSSL",
|
||||||
|
"name": "openssl",
|
||||||
|
"versionInfo": "1.1.1q"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"SPDXID": "SPDXRef-Package-ac33eb699b3aa81d",
|
||||||
|
"externalRefs": [
|
||||||
|
{
|
||||||
|
"referenceCategory": "PACKAGE-MANAGER",
|
||||||
|
"referenceLocator": "pkg:conda/pip@22.2.2",
|
||||||
|
"referenceType": "purl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"filesAnalyzed": false,
|
||||||
|
"hasFiles": [
|
||||||
|
"SPDXRef-File-7eb62e2a3edddc0a"
|
||||||
|
],
|
||||||
|
"licenseConcluded": "MIT",
|
||||||
|
"licenseDeclared": "MIT",
|
||||||
|
"name": "pip",
|
||||||
|
"versionInfo": "22.2.2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relationships": [
|
||||||
|
{
|
||||||
|
"relatedSpdxElement": "SPDXRef-Filesystem-6e0ac6a0fab50ab4",
|
||||||
|
"relationshipType": "DESCRIBES",
|
||||||
|
"spdxElementId": "SPDXRef-DOCUMENT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"relatedSpdxElement": "SPDXRef-Application-ee5ef1aa4ac89125",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"spdxElementId": "SPDXRef-Filesystem-6e0ac6a0fab50ab4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-2984084f02572600",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"relatedSpdxElement": "SPDXRef-Package-ac33eb699b3aa81d",
|
||||||
|
"relationshipType": "CONTAINS",
|
||||||
|
"spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"spdxVersion": "SPDX-2.2"
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"build": "h7f8727e_0",
|
||||||
|
"build_number": 0,
|
||||||
|
"channel": "https://repo.anaconda.com/pkgs/main/linux-64",
|
||||||
|
"constrains": [],
|
||||||
|
"depends": [
|
||||||
|
"ca-certificates",
|
||||||
|
"libgcc-ng >=7.5.0"
|
||||||
|
],
|
||||||
|
"extracted_package_dir": "/home/mmaitre/miniconda3/pkgs/openssl-1.1.1q-h7f8727e_0",
|
||||||
|
"features": "",
|
||||||
|
"files": [
|
||||||
|
"bin/c_rehash",
|
||||||
|
"<SNIP>",
|
||||||
|
"ssl/openssl.cnf.dist"
|
||||||
|
],
|
||||||
|
"fn": "openssl-1.1.1q-h7f8727e_0.conda",
|
||||||
|
"legacy_bz2_md5": "ad51928702694e3f6d25b7d4229c84e6",
|
||||||
|
"license": "OpenSSL",
|
||||||
|
"license_family": "Apache",
|
||||||
|
"link": {
|
||||||
|
"source": "/home/user/miniconda3/pkgs/openssl-1.1.1q-h7f8727e_0",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
"md5": "2ac47797afee2ece8d339c18b095b8d8",
|
||||||
|
"name": "openssl",
|
||||||
|
"package_tarball_full_path": "/home/user/miniconda3/pkgs/openssl-1.1.1q-h7f8727e_0.conda",
|
||||||
|
"paths_data": {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"_path": "bin/c_rehash",
|
||||||
|
"file_mode": "text",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"prefix_placeholder": "/opt/conda/conda-bld/openssl_1657551138854/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_place",
|
||||||
|
"sha256": "04c9f4a5c91e20a24d14a36668b5bebe826d6087fb2337b68e33a4d485f5586f",
|
||||||
|
"sha256_in_prefix": "fc2a6b708cccb8ba90d20e54a9b07257fce009bf315a36f73d3e542dd8674921",
|
||||||
|
"size_in_bytes": 6991
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "<SNIP>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "ssl/openssl.cnf.dist",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"sha256": "f10ba64917b4458fafc1e078c2eb9e6a7602e68fc98c2e9e6df5e1636ae27d6b",
|
||||||
|
"sha256_in_prefix": "f10ba64917b4458fafc1e078c2eb9e6a7602e68fc98c2e9e6df5e1636ae27d6b",
|
||||||
|
"size_in_bytes": 10909
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths_version": 1
|
||||||
|
},
|
||||||
|
"requested_spec": "None",
|
||||||
|
"sha256": "49804293b87141523b2606836ece8e2aaa5202983698fd91e7c36bdb8c8a8de5",
|
||||||
|
"size": 2649280,
|
||||||
|
"subdir": "linux-64",
|
||||||
|
"timestamp": 1657551292835,
|
||||||
|
"track_features": "",
|
||||||
|
"url": "https://repo.anaconda.com/pkgs/main/linux-64/openssl-1.1.1q-h7f8727e_0.conda",
|
||||||
|
"version": "1.1.1q"
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"build": "py38h06a4308_0",
|
||||||
|
"build_number": 0,
|
||||||
|
"channel": "https://repo.anaconda.com/pkgs/main/linux-64",
|
||||||
|
"constrains": [],
|
||||||
|
"depends": [
|
||||||
|
"python >=3.8,<3.9.0a0",
|
||||||
|
"setuptools",
|
||||||
|
"wheel"
|
||||||
|
],
|
||||||
|
"extracted_package_dir": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0",
|
||||||
|
"features": "",
|
||||||
|
"files": [
|
||||||
|
"bin/pip",
|
||||||
|
"<SNIP>",
|
||||||
|
"lib/python3.8/site-packages/pip/py.typed"
|
||||||
|
],
|
||||||
|
"fn": "pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"legacy_bz2_md5": "2ac9f1cfec65a1e4ef00cc0132ecd753",
|
||||||
|
"legacy_bz2_size": 2849993,
|
||||||
|
"license": "MIT",
|
||||||
|
"license_family": "MIT",
|
||||||
|
"link": {
|
||||||
|
"source": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
"md5": "ed3e0331e7c614b3148c9911e1fc15e3",
|
||||||
|
"name": "pip",
|
||||||
|
"package_tarball_full_path": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"paths_data": {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"_path": "bin/pip",
|
||||||
|
"file_mode": "text",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"prefix_placeholder": "/opt/conda/conda-bld/pip_1664552683240/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold",
|
||||||
|
"sha256": "1110c03ca2fb86e43e8b52a61cd9d7c722b2817fc893a613e1a947f5d7049008",
|
||||||
|
"sha256_in_prefix": "14ed5ba79d096035b83a469e863acbbaadd3ea6ca5f23f79eefa91fa857d3f19",
|
||||||
|
"size_in_bytes": 475
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "<SNIP>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "lib/python3.8/site-packages/pip/py.typed",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"sha256": "10156fbcf4539ff788a73e5ee50ced48276b317ed0c1ded53fddd14a82256762",
|
||||||
|
"sha256_in_prefix": "10156fbcf4539ff788a73e5ee50ced48276b317ed0c1ded53fddd14a82256762",
|
||||||
|
"size_in_bytes": 286
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths_version": 1
|
||||||
|
},
|
||||||
|
"requested_spec": "None",
|
||||||
|
"sha256": "3fb76b94cfa5ea9732bfb241b3d234ec0a5a48d16755c3c1ef3c94630f91eb26",
|
||||||
|
"size": 2417732,
|
||||||
|
"subdir": "linux-64",
|
||||||
|
"timestamp": 1664552878795,
|
||||||
|
"track_features": "",
|
||||||
|
"url": "https://repo.anaconda.com/pkgs/main/linux-64/pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"version": "22.2.2"
|
||||||
|
}
|
||||||
@@ -65,6 +65,9 @@ func NewDriver(libType string) (Driver, error) {
|
|||||||
case ftypes.Cocoapods:
|
case ftypes.Cocoapods:
|
||||||
log.Logger.Warn("CocoaPods is supported for SBOM, not for vulnerability scanning")
|
log.Logger.Warn("CocoaPods is supported for SBOM, not for vulnerability scanning")
|
||||||
return Driver{}, ErrSBOMSupportOnly
|
return Driver{}, ErrSBOMSupportOnly
|
||||||
|
case ftypes.CondaPkg:
|
||||||
|
log.Logger.Warn("Conda package is supported for SBOM, not for vulnerability scanning")
|
||||||
|
return Driver{}, ErrSBOMSupportOnly
|
||||||
default:
|
default:
|
||||||
return Driver{}, xerrors.Errorf("unsupported type %s", libType)
|
return Driver{}, xerrors.Errorf("unsupported type %s", libType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all"
|
||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/executable"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/executable"
|
||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/c/conan"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/c/conan"
|
||||||
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/conda/meta"
|
||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dart/pub"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dart/pub"
|
||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/deps"
|
||||||
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget"
|
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/dotnet/nuget"
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ const (
|
|||||||
TypeNuget Type = "nuget"
|
TypeNuget Type = "nuget"
|
||||||
TypeDotNetCore Type = "dotnet-core"
|
TypeDotNetCore Type = "dotnet-core"
|
||||||
|
|
||||||
|
// Conda
|
||||||
|
TypeCondaPkg Type = "conda-pkg"
|
||||||
|
|
||||||
// Python
|
// Python
|
||||||
TypePythonPkg Type = "python-pkg"
|
TypePythonPkg Type = "python-pkg"
|
||||||
TypePip Type = "pip"
|
TypePip Type = "pip"
|
||||||
@@ -132,7 +135,7 @@ var (
|
|||||||
// TypeLanguages has all language analyzers
|
// TypeLanguages has all language analyzers
|
||||||
TypeLanguages = []Type{
|
TypeLanguages = []Type{
|
||||||
TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom, TypeGradleLock,
|
TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom, TypeGradleLock,
|
||||||
TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetCore,
|
TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetCore, TypeCondaPkg,
|
||||||
TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, TypeConanLock,
|
TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, TypeRustBinary, TypeConanLock,
|
||||||
TypeCocoaPods, TypePubSpecLock, TypeMixLock,
|
TypeCocoaPods, TypePubSpecLock, TypeMixLock,
|
||||||
}
|
}
|
||||||
@@ -145,7 +148,7 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TypeIndividualPkgs has all analyzers for individual packages
|
// TypeIndividualPkgs has all analyzers for individual packages
|
||||||
TypeIndividualPkgs = []Type{TypeGemSpec, TypeNodePkg, TypePythonPkg, TypeGoBinary, TypeJar, TypeRustBinary}
|
TypeIndividualPkgs = []Type{TypeGemSpec, TypeNodePkg, TypeCondaPkg, TypePythonPkg, TypeGoBinary, TypeJar, TypeRustBinary}
|
||||||
|
|
||||||
// TypeConfigFiles has all config file analyzers
|
// TypeConfigFiles has all config file analyzers
|
||||||
TypeConfigFiles = []Type{TypeYaml, TypeJSON, TypeDockerfile, TypeTerraform, TypeCloudFormation, TypeHelm}
|
TypeConfigFiles = []Type{TypeYaml, TypeJSON, TypeDockerfile, TypeTerraform, TypeCloudFormation, TypeHelm}
|
||||||
|
|||||||
46
pkg/fanal/analyzer/language/conda/meta/meta.go
Normal file
46
pkg/fanal/analyzer/language/conda/meta/meta.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/go-dep-parser/pkg/conda/meta"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer/language"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
analyzer.RegisterAnalyzer(&metaAnalyzer{})
|
||||||
|
}
|
||||||
|
|
||||||
|
const version = 1
|
||||||
|
|
||||||
|
var fileRegex = regexp.MustCompile(`.*/envs/.+/conda-meta/.+-.+-.+\.json`)
|
||||||
|
|
||||||
|
type metaAnalyzer struct{}
|
||||||
|
|
||||||
|
func (a metaAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
|
||||||
|
p := meta.NewParser()
|
||||||
|
libs, deps, err := p.Parse(input.Content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("%s parse error: %w", input.FilePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return language.ToAnalysisResult(types.CondaPkg, input.FilePath, input.FilePath, libs, deps), nil
|
||||||
|
}
|
||||||
|
func (a metaAnalyzer) Required(filePath string, _ os.FileInfo) bool {
|
||||||
|
return fileRegex.MatchString(filepath.ToSlash(filePath))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a metaAnalyzer) Type() analyzer.Type {
|
||||||
|
return analyzer.TypeCondaPkg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a metaAnalyzer) Version() int {
|
||||||
|
return version
|
||||||
|
}
|
||||||
101
pkg/fanal/analyzer/language/conda/meta/meta_test.go
Normal file
101
pkg/fanal/analyzer/language/conda/meta/meta_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package meta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_packagingAnalyzer_Analyze(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputFile string
|
||||||
|
want *analyzer.AnalysisResult
|
||||||
|
wantErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "pip",
|
||||||
|
inputFile: "testdata/pip-22.2.2-py38h06a4308_0.json",
|
||||||
|
want: &analyzer.AnalysisResult{
|
||||||
|
Applications: []types.Application{
|
||||||
|
{
|
||||||
|
Type: types.CondaPkg,
|
||||||
|
FilePath: "testdata/pip-22.2.2-py38h06a4308_0.json",
|
||||||
|
Libraries: []types.Package{
|
||||||
|
{
|
||||||
|
Name: "pip",
|
||||||
|
Version: "22.2.2",
|
||||||
|
Licenses: []string{"MIT"},
|
||||||
|
FilePath: "testdata/pip-22.2.2-py38h06a4308_0.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid",
|
||||||
|
inputFile: "testdata/invalid.json",
|
||||||
|
wantErr: "unable to parse conda package",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
f, err := os.Open(tt.inputFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
stat, err := f.Stat()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
a := metaAnalyzer{}
|
||||||
|
ctx := context.Background()
|
||||||
|
got, err := a.Analyze(ctx, analyzer.AnalysisInput{
|
||||||
|
FilePath: tt.inputFile,
|
||||||
|
Info: stat,
|
||||||
|
Content: f,
|
||||||
|
})
|
||||||
|
|
||||||
|
if tt.wantErr != "" {
|
||||||
|
assert.ErrorContains(t, err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_packagingAnalyzer_Required(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
filePath string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "pip",
|
||||||
|
filePath: "/home/<user>/miniconda3/envs/<env>/conda-meta/pip-22.2.2-py38h06a4308_0.json",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid",
|
||||||
|
filePath: "/home/<user>/miniconda3/envs/<env>/conda-meta/invalid.json",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
a := metaAnalyzer{}
|
||||||
|
got := a.Required(tt.filePath, nil)
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
1
pkg/fanal/analyzer/language/conda/meta/testdata/invalid.json
vendored
Normal file
1
pkg/fanal/analyzer/language/conda/meta/testdata/invalid.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
62
pkg/fanal/analyzer/language/conda/meta/testdata/pip-22.2.2-py38h06a4308_0.json
vendored
Normal file
62
pkg/fanal/analyzer/language/conda/meta/testdata/pip-22.2.2-py38h06a4308_0.json
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"build": "py38h06a4308_0",
|
||||||
|
"build_number": 0,
|
||||||
|
"channel": "https://repo.anaconda.com/pkgs/main/linux-64",
|
||||||
|
"constrains": [],
|
||||||
|
"depends": [
|
||||||
|
"python >=3.8,<3.9.0a0",
|
||||||
|
"setuptools",
|
||||||
|
"wheel"
|
||||||
|
],
|
||||||
|
"extracted_package_dir": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0",
|
||||||
|
"features": "",
|
||||||
|
"files": [
|
||||||
|
"bin/pip",
|
||||||
|
"<SNIP>",
|
||||||
|
"lib/python3.8/site-packages/pip/py.typed"
|
||||||
|
],
|
||||||
|
"fn": "pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"legacy_bz2_md5": "2ac9f1cfec65a1e4ef00cc0132ecd753",
|
||||||
|
"legacy_bz2_size": 2849993,
|
||||||
|
"license": "MIT",
|
||||||
|
"license_family": "MIT",
|
||||||
|
"link": {
|
||||||
|
"source": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0",
|
||||||
|
"type": 1
|
||||||
|
},
|
||||||
|
"md5": "ed3e0331e7c614b3148c9911e1fc15e3",
|
||||||
|
"name": "pip",
|
||||||
|
"package_tarball_full_path": "/home/user/miniconda3/pkgs/pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"paths_data": {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"_path": "bin/pip",
|
||||||
|
"file_mode": "text",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"prefix_placeholder": "/opt/conda/conda-bld/pip_1664552683240/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold",
|
||||||
|
"sha256": "1110c03ca2fb86e43e8b52a61cd9d7c722b2817fc893a613e1a947f5d7049008",
|
||||||
|
"sha256_in_prefix": "14ed5ba79d096035b83a469e863acbbaadd3ea6ca5f23f79eefa91fa857d3f19",
|
||||||
|
"size_in_bytes": 475
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "<SNIP>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_path": "lib/python3.8/site-packages/pip/py.typed",
|
||||||
|
"path_type": "hardlink",
|
||||||
|
"sha256": "10156fbcf4539ff788a73e5ee50ced48276b317ed0c1ded53fddd14a82256762",
|
||||||
|
"sha256_in_prefix": "10156fbcf4539ff788a73e5ee50ced48276b317ed0c1ded53fddd14a82256762",
|
||||||
|
"size_in_bytes": 286
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths_version": 1
|
||||||
|
},
|
||||||
|
"requested_spec": "None",
|
||||||
|
"sha256": "3fb76b94cfa5ea9732bfb241b3d234ec0a5a48d16755c3c1ef3c94630f91eb26",
|
||||||
|
"size": 2417732,
|
||||||
|
"subdir": "linux-64",
|
||||||
|
"timestamp": 1664552878795,
|
||||||
|
"track_features": "",
|
||||||
|
"url": "https://repo.anaconda.com/pkgs/main/linux-64/pip-22.2.2-py38h06a4308_0.conda",
|
||||||
|
"version": "22.2.2"
|
||||||
|
}
|
||||||
@@ -232,12 +232,13 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail {
|
|||||||
return mergedLayer
|
return mergedLayer
|
||||||
}
|
}
|
||||||
|
|
||||||
// aggregate merges all packages installed by pip/gem/npm/jar into each application
|
// aggregate merges all packages installed by pip/gem/npm/jar/conda into each application
|
||||||
func aggregate(detail *types.ArtifactDetail) {
|
func aggregate(detail *types.ArtifactDetail) {
|
||||||
var apps []types.Application
|
var apps []types.Application
|
||||||
|
|
||||||
aggregatedApps := map[string]*types.Application{
|
aggregatedApps := map[string]*types.Application{
|
||||||
types.PythonPkg: {Type: types.PythonPkg},
|
types.PythonPkg: {Type: types.PythonPkg},
|
||||||
|
types.CondaPkg: {Type: types.CondaPkg},
|
||||||
types.GemSpec: {Type: types.GemSpec},
|
types.GemSpec: {Type: types.GemSpec},
|
||||||
types.NodePkg: {Type: types.NodePkg},
|
types.NodePkg: {Type: types.NodePkg},
|
||||||
types.Jar: {Type: types.Jar},
|
types.Jar: {Type: types.Jar},
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ var (
|
|||||||
// python
|
// python
|
||||||
types.PythonPkg,
|
types.PythonPkg,
|
||||||
|
|
||||||
|
// conda
|
||||||
|
types.CondaPkg,
|
||||||
|
|
||||||
// node.js
|
// node.js
|
||||||
types.NodePkg,
|
types.NodePkg,
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
Pip = "pip"
|
Pip = "pip"
|
||||||
Pipenv = "pipenv"
|
Pipenv = "pipenv"
|
||||||
Poetry = "poetry"
|
Poetry = "poetry"
|
||||||
|
CondaPkg = "conda-pkg"
|
||||||
PythonPkg = "python-pkg"
|
PythonPkg = "python-pkg"
|
||||||
NodePkg = "node-pkg"
|
NodePkg = "node-pkg"
|
||||||
Yarn = "yarn"
|
Yarn = "yarn"
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ func (p *PackageURL) PackageType() string {
|
|||||||
return ftypes.Jar
|
return ftypes.Jar
|
||||||
case packageurl.TypeGem:
|
case packageurl.TypeGem:
|
||||||
return ftypes.GemSpec
|
return ftypes.GemSpec
|
||||||
|
case packageurl.TypeConda:
|
||||||
|
return ftypes.CondaPkg
|
||||||
case packageurl.TypePyPi:
|
case packageurl.TypePyPi:
|
||||||
return ftypes.PythonPkg
|
return ftypes.PythonPkg
|
||||||
case packageurl.TypeGolang:
|
case packageurl.TypeGolang:
|
||||||
@@ -305,6 +307,8 @@ func purlType(t string) string {
|
|||||||
return packageurl.TypeGem
|
return packageurl.TypeGem
|
||||||
case ftypes.NuGet, ftypes.DotNetCore:
|
case ftypes.NuGet, ftypes.DotNetCore:
|
||||||
return packageurl.TypeNuget
|
return packageurl.TypeNuget
|
||||||
|
case ftypes.CondaPkg:
|
||||||
|
return packageurl.TypeConda
|
||||||
case ftypes.PythonPkg, ftypes.Pip, ftypes.Pipenv, ftypes.Poetry:
|
case ftypes.PythonPkg, ftypes.Pip, ftypes.Pipenv, ftypes.Poetry:
|
||||||
return packageurl.TypePyPi
|
return packageurl.TypePyPi
|
||||||
case ftypes.GoBinary, ftypes.GoModule:
|
case ftypes.GoBinary, ftypes.GoModule:
|
||||||
|
|||||||
@@ -134,6 +134,21 @@ func TestNewPackageURL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "conda package",
|
||||||
|
typ: ftypes.CondaPkg,
|
||||||
|
pkg: ftypes.Package{
|
||||||
|
Name: "absl-py",
|
||||||
|
Version: "0.4.1",
|
||||||
|
},
|
||||||
|
want: purl.PackageURL{
|
||||||
|
PackageURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeConda,
|
||||||
|
Name: "absl-py",
|
||||||
|
Version: "0.4.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "composer package",
|
name: "composer package",
|
||||||
typ: ftypes.Composer,
|
typ: ftypes.Composer,
|
||||||
@@ -451,6 +466,18 @@ func TestFromString(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "happy path for conda",
|
||||||
|
purl: "pkg:conda/absl-py@0.4.1",
|
||||||
|
want: purl.PackageURL{
|
||||||
|
PackageURL: packageurl.PackageURL{
|
||||||
|
Type: packageurl.TypeConda,
|
||||||
|
Name: "absl-py",
|
||||||
|
Version: "0.4.1",
|
||||||
|
Qualifiers: packageurl.Qualifiers{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "bad rpm",
|
name: "bad rpm",
|
||||||
purl: "pkg:rpm/redhat/a--@1.0.0",
|
purl: "pkg:rpm/redhat/a--@1.0.0",
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result.Type == ftypes.NodePkg || result.Type == ftypes.PythonPkg ||
|
if result.Type == ftypes.NodePkg || result.Type == ftypes.PythonPkg ||
|
||||||
result.Type == ftypes.GemSpec || result.Type == ftypes.Jar {
|
result.Type == ftypes.GemSpec || result.Type == ftypes.Jar || result.Type == ftypes.CondaPkg {
|
||||||
// If a package is language-specific package that isn't associated with a lock file,
|
// If a package is language-specific package that isn't associated with a lock file,
|
||||||
// it will be a dependency of a component under "metadata".
|
// it will be a dependency of a component under "metadata".
|
||||||
// e.g.
|
// e.g.
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func initApplication(pkg spdx.Package2_2) *ftypes.Application {
|
|||||||
FilePath: pkg.PackageSourceInfo,
|
FilePath: pkg.PackageSourceInfo,
|
||||||
}
|
}
|
||||||
if pkg.PackageName == ftypes.NodePkg || pkg.PackageName == ftypes.PythonPkg ||
|
if pkg.PackageName == ftypes.NodePkg || pkg.PackageName == ftypes.PythonPkg ||
|
||||||
pkg.PackageName == ftypes.GemSpec || pkg.PackageName == ftypes.Jar {
|
pkg.PackageName == ftypes.GemSpec || pkg.PackageName == ftypes.Jar || pkg.PackageName == ftypes.CondaPkg {
|
||||||
app.FilePath = ""
|
app.FilePath = ""
|
||||||
}
|
}
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
pkgTargets = map[string]string{
|
pkgTargets = map[string]string{
|
||||||
ftypes.PythonPkg: "Python",
|
ftypes.PythonPkg: "Python",
|
||||||
|
ftypes.CondaPkg: "Conda",
|
||||||
ftypes.GemSpec: "Ruby",
|
ftypes.GemSpec: "Ruby",
|
||||||
ftypes.NodePkg: "Node.js",
|
ftypes.NodePkg: "Node.js",
|
||||||
ftypes.Jar: "Java",
|
ftypes.Jar: "Java",
|
||||||
|
|||||||
Reference in New Issue
Block a user