Compare commits

...
9 Commits
Author SHA1 Message Date
Christopher Angelo Phillips 0cbd0cc703 fix: guard for locations < 1 in alpmdb parse (#1366) 2022-11-28 15:43:18 +00:00
Christopher Angelo Phillips b290a445ca fix: remove cabal.project.freeze panic on last pkg (#1363) 2022-11-23 22:33:18 +00:00
Christopher Angelo Phillips bcfe38c009 fix: requirements.txt - return unicode only letter/num for version (#1361) 2022-11-22 10:43:05 -05:00
anchore-actions-token-generator[bot]andspiffcs 74967a28ea Update syft bootstrap tools to latest versions. (#1356)
Co-authored-by: spiffcs <spiffcs@users.noreply.github.com>
2022-11-21 09:57:49 -05:00
Keith Zantow 098e61dcc8 fix: sort relationships in SPDX output (#1350) 2022-11-21 09:26:24 -05:00
Keith Zantow 0dddf51fd5 chore: add debug logging for decode errors (#1352) 2022-11-21 09:26:11 -05:00
mikcl 04880c06ce feat(npm): handle aliases in package-lock.json (#1349) 2022-11-20 11:32:10 -05:00
Christopher Angelo Phillips da4b2df576 fix: spdx java checksum correctness (#1348) 2022-11-18 13:42:55 -05:00
Rob Cresswell 9d8244bae6 feat: Add support for npm lockfile version 3 (#1206)
This PR adds support for npm lockfile version 3, which drops the
"dependencies" key and uses "packages" instead. I've refactored the
lockfile parser to make the distinction between the versions explicit
rather than the implicit behaviour before. It _might_ be worth splitting
into separate files at some point, but the logic is so minimal that I
haven't done it.

Fixes #1203
Signed-off-by: Rob Cresswell <robcresswell@users.noreply.github.com>
2022-11-18 12:41:31 -05:00
30 changed files with 725 additions and 60 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ GOLANGCILINT_VERSION = v1.50.1
GOSIMPORTS_VERSION = v0.3.4
BOUNCER_VERSION = v0.4.0
CHRONICLE_VERSION = v0.4.2
GORELEASER_VERSION = v1.12.3
GORELEASER_VERSION = v1.13.0
YAJSV_VERSION = v1.4.1
COSIGN_VERSION = v1.13.1
QUILL_VERSION = v0.2.0
@@ -105,7 +105,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
},
Packages: toPackages(s.Artifacts.PackageCatalog),
Files: toFiles(s),
Relationships: toRelationships(s.Relationships),
Relationships: toRelationships(s.RelationshipsSorted()),
}
}
@@ -296,8 +296,9 @@ func toPackageChecksums(p pkg.Package) ([]common.Checksum, bool) {
if len(meta.ArchiveDigests) > 0 {
filesAnalyzed = true
for _, digest := range meta.ArchiveDigests {
algo := strings.ToUpper(digest.Algorithm)
checksums = append(checksums, common.Checksum{
Algorithm: common.ChecksumAlgorithm(digest.Algorithm),
Algorithm: common.ChecksumAlgorithm(algo),
Value: digest.Value,
})
}
@@ -15,6 +15,101 @@ import (
"github.com/anchore/syft/syft/source"
)
// TODO: Add ToFormatModel tests
func Test_toPackageChecksums(t *testing.T) {
tests := []struct {
name string
pkg pkg.Package
expected []common.Checksum
filesAnalyzed bool
}{
{
name: "Java Package",
pkg: pkg.Package{
Name: "test",
Version: "1.0.0",
Language: pkg.Java,
Metadata: pkg.JavaMetadata{
ArchiveDigests: []file.Digest{
{
Algorithm: "sha1", // SPDX expects these to be uppercase
Value: "1234",
},
},
},
},
expected: []common.Checksum{
{
Algorithm: "SHA1",
Value: "1234",
},
},
filesAnalyzed: true,
},
{
name: "Java Package with no archive digests",
pkg: pkg.Package{
Name: "test",
Version: "1.0.0",
Language: pkg.Java,
Metadata: pkg.JavaMetadata{
ArchiveDigests: []file.Digest{},
},
},
expected: []common.Checksum{},
filesAnalyzed: false,
},
{
name: "Java Package with no metadata",
pkg: pkg.Package{
Name: "test",
Version: "1.0.0",
Language: pkg.Java,
},
expected: []common.Checksum{},
filesAnalyzed: false,
},
{
name: "Go Binary Package",
pkg: pkg.Package{
Name: "test",
Version: "1.0.0",
Language: pkg.Go,
MetadataType: pkg.GolangBinMetadataType,
Metadata: pkg.GolangBinMetadata{
H1Digest: "h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=",
},
},
expected: []common.Checksum{
{
Algorithm: "SHA256",
Value: "f5f1c0b4ad2e0dfa6f79eaaaa3586411925c16f61702208ddd4bad2fc17dc47c",
},
},
filesAnalyzed: false,
},
{
name: "Package with no metadata type",
pkg: pkg.Package{
Name: "test",
Version: "1.0.0",
Language: pkg.Java,
Metadata: struct{}{},
},
expected: []common.Checksum{},
filesAnalyzed: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
commonSum, filesAnalyzed := toPackageChecksums(test.pkg)
assert.ElementsMatch(t, test.expected, commonSum)
assert.Equal(t, test.filesAnalyzed, filesAnalyzed)
})
}
}
func Test_toFileTypes(t *testing.T) {
tests := []struct {
+25
View File
@@ -2,8 +2,10 @@ package testutils
import (
"bytes"
"math/rand"
"strings"
"testing"
"time"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/stretchr/testify/assert"
@@ -12,6 +14,7 @@ import (
"github.com/anchore/stereoscope/pkg/filetree"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/linux"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/sbom"
@@ -276,3 +279,25 @@ func newDirectoryCatalog() *pkg.Catalog {
return catalog
}
//nolint:gosec
func AddSampleFileRelationships(s *sbom.SBOM) {
catalog := s.Artifacts.PackageCatalog.Sorted()
s.Artifacts.FileMetadata = map[source.Coordinates]source.FileMetadata{}
files := []string{"/f1", "/f2", "/d1/f3", "/d2/f4", "/z1/f5", "/a1/f6"}
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
rnd.Shuffle(len(files), func(i, j int) { files[i], files[j] = files[j], files[i] })
for _, f := range files {
meta := source.FileMetadata{}
coords := source.Coordinates{RealPath: f}
s.Artifacts.FileMetadata[coords] = meta
s.Relationships = append(s.Relationships, artifact.Relationship{
From: catalog[0],
To: coords,
Type: artifact.ContainsRelationship,
})
}
}
+5
View File
@@ -2,10 +2,12 @@ package formats
import (
"bytes"
"errors"
"fmt"
"io"
"strings"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/formats/cyclonedxjson"
"github.com/anchore/syft/syft/formats/cyclonedxxml"
"github.com/anchore/syft/syft/formats/github"
@@ -35,6 +37,9 @@ func Formats() []sbom.Format {
func Identify(by []byte) sbom.Format {
for _, f := range Formats() {
if err := f.Validate(bytes.NewReader(by)); err != nil {
if !errors.Is(err, sbom.ErrValidationNotSupported) {
log.Debugf("format %s returned err: %+v", f.ID(), err)
}
continue
}
return f
+1 -21
View File
@@ -5,10 +5,7 @@ import (
"regexp"
"testing"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/formats/common/testutils"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
var updateSpdxJson = flag.Bool("update-spdx-json", false, "update the *.golden files for spdx-json encoders")
@@ -36,7 +33,7 @@ func TestSPDXJSONImageEncoder(t *testing.T) {
func TestSPDXRelationshipOrder(t *testing.T) {
testImage := "image-simple"
s := testutils.ImageInput(t, testImage, testutils.FromSnapshot())
addRelationships(&s)
testutils.AddSampleFileRelationships(&s)
testutils.AssertEncoderAgainstGoldenImageSnapshot(t,
Format(),
s,
@@ -46,23 +43,6 @@ func TestSPDXRelationshipOrder(t *testing.T) {
)
}
func addRelationships(s *sbom.SBOM) {
catalog := s.Artifacts.PackageCatalog.Sorted()
s.Artifacts.FileMetadata = map[source.Coordinates]source.FileMetadata{}
for _, f := range []string{"/f1", "/f2", "/d1/f3", "/d2/f4", "/z1/f5", "/a1/f6"} {
meta := source.FileMetadata{}
coords := source.Coordinates{RealPath: f}
s.Artifacts.FileMetadata[coords] = meta
s.Relationships = append(s.Relationships, artifact.Relationship{
From: catalog[0],
To: coords,
Type: artifact.ContainsRelationship,
})
}
}
func spdxJsonRedactor(s []byte) []byte {
// each SBOM reports the time it was generated, which is not useful during snapshot testing
s = regexp.MustCompile(`"created": .*`).ReplaceAll(s, []byte("redacted"))
@@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "/some/path",
"documentNamespace": "https://anchore.com/syft/dir/some/path-0f9b165e-1819-43cb-bd58-f61c1c23d6cf",
"documentNamespace": "https://anchore.com/syft/dir/some/path-4bf54cdd-0a0f-4560-bf4f-39cac2ef7a5b",
"creationInfo": {
"licenseListVersion": "3.18",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-11-11T19:24:55Z",
"created": "2022-11-19T13:46:57Z",
"comment": ""
},
"packages": [
@@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "user-image-input",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-5841d063-c3ef-406b-91b4-8a702ef45ce9",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-102ca7dc-3d1e-46d2-b130-28968831ebcc",
"creationInfo": {
"licenseListVersion": "3.18",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-11-11T19:24:55Z",
"created": "2022-11-19T13:46:57Z",
"comment": ""
},
"packages": [
@@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "user-image-input",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-8755f340-f205-4bf2-a909-94c623670734",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-55ad4afc-ecdc-46a4-8bc3-36b3e72da5d1",
"creationInfo": {
"licenseListVersion": "3.18",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-11-11T19:24:55Z",
"created": "2022-11-19T13:46:57Z",
"comment": ""
},
"packages": [
@@ -133,12 +133,12 @@
},
{
"spdxElementId": "SPDXRef-Package-python-package-1-66ba429119b8bec6",
"relatedSpdxElement": "SPDXRef-f9e49132a4b96ccd",
"relatedSpdxElement": "SPDXRef-839d99ee67d9d174",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Package-python-package-1-66ba429119b8bec6",
"relatedSpdxElement": "SPDXRef-c6f5b29dca12661f",
"relatedSpdxElement": "SPDXRef-9c2f7510199b17f6",
"relationshipType": "CONTAINS"
},
{
@@ -148,12 +148,12 @@
},
{
"spdxElementId": "SPDXRef-Package-python-package-1-66ba429119b8bec6",
"relatedSpdxElement": "SPDXRef-839d99ee67d9d174",
"relatedSpdxElement": "SPDXRef-c6f5b29dca12661f",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Package-python-package-1-66ba429119b8bec6",
"relatedSpdxElement": "SPDXRef-9c2f7510199b17f6",
"relatedSpdxElement": "SPDXRef-f9e49132a4b96ccd",
"relationshipType": "CONTAINS"
}
]
+1 -1
View File
@@ -13,7 +13,7 @@ import (
func decoder(reader io.Reader) (*sbom.SBOM, error) {
doc, err := tvloader.Load2_3(reader)
if err != nil {
return nil, fmt.Errorf("unable to decode spdx-json: %w", err)
return nil, fmt.Errorf("unable to decode spdx-tag-value: %w", err)
}
return spdxhelpers.ToSyftModel(doc)
+36
View File
@@ -0,0 +1,36 @@
package spdxtagvalue
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
)
// TODO: this is a temporary coverage see below
// This test should be covered within the encode decode life cycle however
// we're currently blocked on a couple of SPDX fields that change often
// which causes backward compatibility issues.
// This test was added specifically to smoke test the decode function when
// It failed on a released version of syft.
func TestSPDXTagValueDecoder(t *testing.T) {
tests := []struct {
name string
fixture string
}{
{
name: "simple",
fixture: "tag-value.spdx",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
reader, err := os.Open("test-fixtures/" + test.fixture)
assert.NoError(t, err)
_, err = Format().Decode(reader)
assert.NoError(t, err)
})
}
}
+13
View File
@@ -67,6 +67,19 @@ func TestSPDXJSONSPDXIDs(t *testing.T) {
)
}
func TestSPDXRelationshipOrder(t *testing.T) {
testImage := "image-simple"
s := testutils.ImageInput(t, testImage, testutils.FromSnapshot())
testutils.AddSampleFileRelationships(&s)
testutils.AssertEncoderAgainstGoldenImageSnapshot(t,
Format(),
s,
testImage,
*updateSpdxTagValue,
spdxTagValueRedactor,
)
}
func spdxTagValueRedactor(s []byte) []byte {
// each SBOM reports the time it was generated, which is not useful during snapshot testing
s = regexp.MustCompile(`Created: .*`).ReplaceAll(s, []byte("redacted"))
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: foobar/baz
DocumentNamespace: https://anchore.com/syft/dir/foobar/baz-3d730196-4510-4ee4-9743-9322dd27cee7
DocumentNamespace: https://anchore.com/syft/dir/foobar/baz-62bc0aae-2b37-4c86-ab79-63c6fc4198ed
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-18T14:21:45Z
Created: 2022-11-19T13:48:30Z
##### Package: @at-sign
@@ -0,0 +1,79 @@
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-cc20e416-9c74-401c-b4aa-245556bada5e
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-19T13:48:30Z
##### Unpackaged files
FileName: /f1
SPDXID: SPDXRef-5265a4dde3edbf7c
FileType: OTHER
LicenseConcluded: NOASSERTION
FileName: /z1/f5
SPDXID: SPDXRef-839d99ee67d9d174
FileType: OTHER
LicenseConcluded: NOASSERTION
FileName: /a1/f6
SPDXID: SPDXRef-9c2f7510199b17f6
FileType: OTHER
LicenseConcluded: NOASSERTION
FileName: /d2/f4
SPDXID: SPDXRef-c641caa71518099f
FileType: OTHER
LicenseConcluded: NOASSERTION
FileName: /d1/f3
SPDXID: SPDXRef-c6f5b29dca12661f
FileType: OTHER
LicenseConcluded: NOASSERTION
FileName: /f2
SPDXID: SPDXRef-f9e49132a4b96ccd
FileType: OTHER
LicenseConcluded: NOASSERTION
##### Package: package-2
PackageName: package-2
SPDXID: SPDXRef-Package-deb-package-2-958443e2d9304af4
PackageVersion: 2.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageSourceInfo: acquired package info from DPKG DB: /somefile-2.txt
PackageLicenseConcluded: NONE
PackageLicenseDeclared: NONE
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:*:some:package:2:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:deb/debian/package-2@2.0.1
##### Package: package-1
PackageName: package-1
SPDXID: SPDXRef-Package-python-package-1-66ba429119b8bec6
PackageVersion: 1.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageSourceInfo: acquired package info from installed python package manifest file: /somefile-1.txt
PackageLicenseConcluded: MIT
PackageLicenseDeclared: MIT
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:*:some:package:1:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl a-purl-1
##### Relationships
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-5265a4dde3edbf7c
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-839d99ee67d9d174
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-9c2f7510199b17f6
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-c641caa71518099f
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-c6f5b29dca12661f
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-f9e49132a4b96ccd
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: /some/path
DocumentNamespace: https://anchore.com/syft/dir/some/path-b6078c95-5b97-462d-acb3-9e74bc9ddb43
DocumentNamespace: https://anchore.com/syft/dir/some/path-7a4b2140-6669-4a28-80dd-5c8e795c5da0
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-18T14:21:44Z
Created: 2022-11-19T13:48:30Z
##### Package: package-2
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-aa272d1e-8bb4-411f-a554-4c9a16ea66fb
DocumentNamespace: https://anchore.com/syft/image/user-image-input-baff7ada-85cb-403e-90d7-05b0c6d79490
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-18T14:21:45Z
Created: 2022-11-19T13:48:30Z
##### Package: package-2
@@ -0,0 +1,105 @@
SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentNamespace: https://anchore.com/syft/image
LicenseListVersion: 3.18
Creator: Organization: Anchore, Inc
Creator: Tool: syft-
Created: 2022-11-18T16:48:55Z
##### Package: busybox
PackageName: busybox
SPDXID: SPDXRef-Package-apk-busybox-9d15fb154d2c566a
PackageVersion: 1.31.1-r19
PackageOriginator: Person: Natanael Copa <ncopa@alpinelinux.org>
PackageDownloadLocation: https://busybox.net/
FilesAnalyzed: false
PackageSourceInfo: acquired package info from APK DB: /lib/apk/db/installed
PackageLicenseConcluded: GPL-2.0-only
PackageLicenseDeclared: GPL-2.0-only
PackageCopyrightText: NOASSERTION
PackageDescription: Size optimized toolbox of many common UNIX utilities
ExternalRef: SECURITY cpe23Type cpe:2.3:a:busybox:busybox:1.31.1-r19:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:alpine/busybox@1.31.1-r19?arch=x86_64&upstream=busybox&distro=alpine-3.12.5
##### Package: my-app
PackageName: my-app
SPDXID: SPDXRef-Package-java-archive-my-app-4e39fdbdf089a141
PackageVersion: 1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: true
PackageChecksum: SHA1: 11d42fc32de6a699c5705f6e58d2e387c5e9c8b5
PackageSourceInfo: acquired package info from installed java archive: /sandbox/target/my-app-1.jar
PackageLicenseConcluded: NONE
PackageLicenseDeclared: NONE
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:app:1:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:maven/com.mycompany.app/my-app@1
##### Package: my-app
PackageName: my-app
SPDXID: SPDXRef-Package-java-archive-my-app-ad62c29113227c17
PackageVersion: 1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
PackageSourceInfo: acquired package info from installed java archive: /sandbox/target/original-my-app-1.jar
PackageLicenseConcluded: NONE
PackageLicenseDeclared: NONE
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:mycompany:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my-app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my_app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:app:app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:my:app:1:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:maven/com.mycompany.app/my-app@1
##### Package: original-my-app
PackageName: original-my-app
SPDXID: SPDXRef-Package-java-archive-original-my-app-57464fff85325201
PackageVersion: 1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: true
PackageChecksum: SHA1: 11d42fc32de6a699c5705f6e58d2e387c5e9c8b5
PackageSourceInfo: acquired package info from installed java archive: /sandbox/target/original-my-app-1.jar
PackageLicenseConcluded: NONE
PackageLicenseDeclared: NONE
PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original-my-app:original-my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original-my-app:original_my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original_my_app:original-my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original_my_app:original_my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original-my:original-my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original-my:original_my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original_my:original-my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original_my:original_my_app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original:original-my-app:1:*:*:*:*:*:*:*
ExternalRef: SECURITY cpe23Type cpe:2.3:a:original:original_my_app:1:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl pkg:maven/original-my-app/original-my-app@1
+6
View File
@@ -42,10 +42,12 @@ func parseAlpmDB(resolver source.FileResolver, env *generic.Environment, reader
if err != nil {
return nil, nil, err
}
pkgFiles, err := parseMtree(r)
if err != nil {
return nil, nil, err
}
// The replace the files found the the pacman database with the files from the mtree These contain more metadata and
// thus more useful.
metadata.Files = pkgFiles
@@ -106,6 +108,10 @@ func getFileReader(path string, resolver source.FileResolver) (io.Reader, error)
if err != nil {
return nil, err
}
if len(locs) == 0 {
return nil, fmt.Errorf("could not find file: %s", path)
}
// TODO: Should we maybe check if we found the file
dbContentReader, err := resolver.FileContentsByLocation(locs[0])
if err != nil {
@@ -34,6 +34,14 @@ func parseCabalFreeze(_ source.FileResolver, _ *generic.Environment, reader sour
line = strings.TrimSpace(line)
startPkgEncoding, endPkgEncoding := strings.Index(line, "any.")+4, strings.Index(line, ",")
// case where comma not found for last package in constraint list
if endPkgEncoding == -1 {
endPkgEncoding = len(line)
}
if startPkgEncoding >= endPkgEncoding || startPkgEncoding < 0 {
continue
}
line = line[startPkgEncoding:endPkgEncoding]
fields := strings.Split(line, " ==")
@@ -12,6 +12,6 @@ constraints: any.Cabal ==3.2.1.0,
any.RSA ==2.4.1,
any.SHA ==1.6.4.4,
void -safe,
any.Spock ==0.14.0.0,
any.Spock ==0.14.0.0
index-state: hackage.haskell.org 2022-07-07T01:01:53Z
+34 -6
View File
@@ -43,13 +43,41 @@ func newPackageJSONPackage(u packageJSON, locations ...source.Location) pkg.Pack
return p
}
func newPackageLockPackage(resolver source.FileResolver, location source.Location, name string, u lockDependency, licenseMap map[string]string) pkg.Package {
var sb strings.Builder
sb.WriteString(u.Resolved)
sb.WriteString(u.Integrity)
func newPackageLockV1Package(resolver source.FileResolver, location source.Location, name string, u lockDependency) pkg.Package {
version := u.Version
const aliasPrefixPackageLockV1 = "npm:"
// Handles type aliases https://github.com/npm/rfcs/blob/main/implemented/0001-package-aliases.md
if strings.HasPrefix(version, aliasPrefixPackageLockV1) {
// this is an alias.
// `"version": "npm:canonical-name@X.Y.Z"`
canonicalPackageAndVersion := version[len(aliasPrefixPackageLockV1):]
versionSeparator := strings.LastIndex(canonicalPackageAndVersion, "@")
name = canonicalPackageAndVersion[:versionSeparator]
version = canonicalPackageAndVersion[versionSeparator+1:]
}
return finalizeLockPkg(
resolver,
location,
pkg.Package{
Name: name,
Version: version,
Locations: source.NewLocationSet(location),
PURL: packageURL(name, version),
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
)
}
func newPackageLockV2Package(resolver source.FileResolver, location source.Location, name string, u lockPackage) pkg.Package {
var licenses []string
if l, exists := licenseMap[sb.String()]; exists {
licenses = append(licenses, l)
if u.License != "" {
licenses = append(licenses, u.License)
}
return finalizeLockPkg(
@@ -32,10 +32,11 @@ type lockDependency struct {
}
type lockPackage struct {
Name string `json:"name"` // only present in the root package entry (named "")
Version string `json:"version"`
Resolved string `json:"resolved"`
Integrity string `json:"integrity"`
License string `json:""`
License string `json:"license"`
}
// parsePackageLock parses a package-lock.json and returns the discovered JavaScript packages.
@@ -49,23 +50,37 @@ func parsePackageLock(resolver source.FileResolver, _ *generic.Environment, read
var pkgs []pkg.Package
dec := json.NewDecoder(reader)
var lock packageLock
for {
var lock packageLock
if err := dec.Decode(&lock); errors.Is(err, io.EOF) {
break
} else if err != nil {
return nil, nil, fmt.Errorf("failed to parse package-lock.json file: %w", err)
}
licenseMap := make(map[string]string)
for _, pkgMeta := range lock.Packages {
var sb strings.Builder
sb.WriteString(pkgMeta.Resolved)
sb.WriteString(pkgMeta.Integrity)
licenseMap[sb.String()] = pkgMeta.License
}
}
if lock.LockfileVersion == 1 {
for name, pkgMeta := range lock.Dependencies {
pkgs = append(pkgs, newPackageLockPackage(resolver, reader.Location, name, pkgMeta, licenseMap))
pkgs = append(pkgs, newPackageLockV1Package(resolver, reader.Location, name, pkgMeta))
}
}
if lock.LockfileVersion == 2 || lock.LockfileVersion == 3 {
for name, pkgMeta := range lock.Packages {
if name == "" {
if pkgMeta.Name == "" {
continue
} else {
name = pkgMeta.Name
}
}
// handles alias names
if pkgMeta.Name != "" {
name = pkgMeta.Name
}
pkgs = append(pkgs, newPackageLockV2Package(resolver, reader.Location, getNameFromPath(name), pkgMeta))
}
}
@@ -73,3 +88,8 @@ func parsePackageLock(resolver source.FileResolver, _ *generic.Environment, read
return pkgs, nil, nil
}
func getNameFromPath(path string) string {
parts := strings.Split(path, "node_modules/")
return parts[len(parts)-1]
}
@@ -102,6 +102,13 @@ func TestParsePackageLockV2(t *testing.T) {
fixture := "test-fixtures/pkg-lock/package-lock-2.json"
var expectedRelationships []artifact.Relationship
expectedPkgs := []pkg.Package{
{
Name: "npm",
Version: "6.14.6",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/npm@6.14.6",
},
{
Name: "@types/prop-types",
Version: "15.7.5",
@@ -140,3 +147,103 @@ func TestParsePackageLockV2(t *testing.T) {
}
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
}
func TestParsePackageLockV3(t *testing.T) {
fixture := "test-fixtures/pkg-lock/package-lock-3.json"
var expectedRelationships []artifact.Relationship
expectedPkgs := []pkg.Package{
{
Name: "lock-v3-fixture",
Version: "1.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/lock-v3-fixture@1.0.0",
},
{
Name: "@types/prop-types",
Version: "15.7.5",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/%40types/prop-types@15.7.5",
},
{
Name: "@types/react",
Version: "18.0.20",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/%40types/react@18.0.20",
},
{
Name: "@types/scheduler",
Version: "0.16.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/%40types/scheduler@0.16.2",
},
{
Name: "csstype",
Version: "3.1.1",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
PURL: "pkg:npm/csstype@3.1.1",
},
}
for i := range expectedPkgs {
expectedPkgs[i].Locations.Add(source.NewLocation(fixture))
}
pkgtest.TestFileParser(t, fixture, parsePackageLock, expectedPkgs, expectedRelationships)
}
func TestParsePackageLockAlias(t *testing.T) {
var expectedRelationships []artifact.Relationship
commonPkgs := []pkg.Package{
{
Name: "case",
Version: "1.6.2",
PURL: "pkg:npm/case@1.6.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
{
Name: "case",
Version: "1.6.3",
PURL: "pkg:npm/case@1.6.3",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
{
Name: "@bundled-es-modules/chai",
Version: "4.2.2",
PURL: "pkg:npm/%40bundled-es-modules/chai@4.2.2",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
},
}
v2Pkg := pkg.Package{
Name: "alias-check",
Version: "1.0.0",
PURL: "pkg:npm/alias-check@1.0.0",
Language: pkg.JavaScript,
Type: pkg.NpmPkg,
Licenses: []string{"ISC"},
}
packageLockV1 := "test-fixtures/pkg-lock/alias-package-lock-1.json"
packageLockV2 := "test-fixtures/pkg-lock/alias-package-lock-2.json"
packageLocks := []string{packageLockV1, packageLockV2}
for _, packageLock := range packageLocks {
expected := make([]pkg.Package, len(commonPkgs))
copy(expected, commonPkgs)
if packageLock == packageLockV2 {
expected = append(expected, v2Pkg)
}
for i := range expected {
expected[i].Locations.Add(source.NewLocation(packageLock))
}
pkgtest.TestFileParser(t, packageLock, parsePackageLock, expected, expectedRelationships)
}
}
@@ -0,0 +1,23 @@
{
"name": "alias-check",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"case": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.2.tgz",
"integrity": "sha512-ll380ZRoraT7mUK2G92UbH+FJVD5AwdVIAYk9xhV1tauh0carDgYByUD1HhjCWsWgxrfQvCeHvtfj7IYR6TKeg=="
},
"case-alias": {
"version": "npm:case@1.6.3",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz",
"integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ=="
},
"chai": {
"version": "npm:@bundled-es-modules/chai@4.2.2",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/chai/-/chai-4.2.2.tgz",
"integrity": "sha512-iGmVYw2/zJCoqyKTtWEYCtFmMyi8WmACQKtky0lpNyEKWX0YIOpKWGD7saMXL+tPpllss0otilxV0SLwyi3Ytg=="
}
}
}
@@ -0,0 +1,58 @@
{
"name": "alias-check",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "alias-check",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"case": "1.6.2",
"case-alias": "npm:case@^1.6.3",
"chai": "npm:@bundled-es-modules/chai@^4.2.2"
}
},
"node_modules/case": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.2.tgz",
"integrity": "sha512-ll380ZRoraT7mUK2G92UbH+FJVD5AwdVIAYk9xhV1tauh0carDgYByUD1HhjCWsWgxrfQvCeHvtfj7IYR6TKeg==",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/case-alias": {
"name": "case",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz",
"integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/chai": {
"name": "@bundled-es-modules/chai",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/chai/-/chai-4.2.2.tgz",
"integrity": "sha512-iGmVYw2/zJCoqyKTtWEYCtFmMyi8WmACQKtky0lpNyEKWX0YIOpKWGD7saMXL+tPpllss0otilxV0SLwyi3Ytg=="
}
},
"dependencies": {
"case": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.2.tgz",
"integrity": "sha512-ll380ZRoraT7mUK2G92UbH+FJVD5AwdVIAYk9xhV1tauh0carDgYByUD1HhjCWsWgxrfQvCeHvtfj7IYR6TKeg=="
},
"case-alias": {
"version": "npm:case@1.6.3",
"resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz",
"integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ=="
},
"chai": {
"version": "npm:@bundled-es-modules/chai@4.2.2",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/chai/-/chai-4.2.2.tgz",
"integrity": "sha512-iGmVYw2/zJCoqyKTtWEYCtFmMyi8WmACQKtky0lpNyEKWX0YIOpKWGD7saMXL+tPpllss0otilxV0SLwyi3Ytg=="
}
}
}
@@ -0,0 +1,40 @@
{
"name": "lock-v3-fixture",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lock-v3-fixture",
"version": "1.0.0",
"dependencies": {
"@types/react": "^18.0.9"
}
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
"integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
},
"node_modules/@types/react": {
"version": "18.0.20",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.20.tgz",
"integrity": "sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"node_modules/csstype": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
}
}
}
@@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"strings"
"unicode"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/syft/artifact"
@@ -47,8 +48,14 @@ func parseRequirementsTxt(_ source.FileResolver, _ *generic.Environment, reader
log.WithFields("path", reader.RealPath).Warnf("unable to parse requirements.txt line: %q", line)
continue
}
// check if the version contains hash declarations on the same line
version, _ := parseVersionAndHashes(parts[1])
name := strings.TrimSpace(parts[0])
version := strings.TrimSpace(parts[1])
version = strings.TrimFunc(version, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
packages = append(packages, newPackageForIndex(name, version, reader.Location))
}
@@ -59,6 +66,15 @@ func parseRequirementsTxt(_ source.FileResolver, _ *generic.Environment, reader
return packages, nil, nil
}
func parseVersionAndHashes(version string) (string, []string) {
parts := strings.Split(version, "--hash=")
if len(parts) < 2 {
return version, nil
}
return parts[0], parts[1:]
}
// trimRequirementsTxtLine removes content from the given requirements.txt line
// that should not be considered for parsing.
func trimRequirementsTxtLine(line string) string {
@@ -37,6 +37,22 @@ func TestParseRequirementsTxt(t *testing.T) {
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "argh",
Version: "0.26.2",
PURL: "pkg:pypi/argh@0.26.2",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
},
{
Name: "argh",
Version: "0.26.3",
PURL: "pkg:pypi/argh@0.26.3",
Locations: locations,
Language: pkg.Python,
Type: pkg.PythonPkg,
},
}
var expectedRelationships []artifact.Relationship
@@ -10,3 +10,7 @@ coverage != 3.5 # Version Exclusion. Anything except version 3.5
numpyNew; sys_platform == 'win32'
numpy >= 3.4.1; sys_platform == 'win32'
Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.*
argh==0.26.2 \
--hash=sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3 \
--hash=sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65
argh==0.26.3 --hash=sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3 --hash=sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65