mirror of
https://github.com/anchore/syft.git
synced 2026-10-22 02:52:32 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f15d4a9984 | ||
|
|
b8d1a46e7e | ||
|
|
f35a252ecf | ||
|
|
05be9e25ce | ||
|
|
5e2ab0874d | ||
|
|
fb699496a8 | ||
|
|
0aea55f880 | ||
|
|
caff67289a | ||
|
|
82de24cf7c | ||
|
|
3db3efacdc | ||
|
|
6ccd460e59 | ||
|
|
7cb8e1fc14 | ||
|
|
c990f425a6 | ||
|
|
d41afe05eb | ||
|
|
0f5a9eed09 | ||
|
|
8420612724 |
@@ -21,3 +21,32 @@ ignore-packages:
|
||||
# All these files have been put into the public domain.
|
||||
# You can do whatever you want with these files.
|
||||
- github.com/xi2/xz
|
||||
|
||||
# from: https://gitlab.com/cznic/sqlite/-/blob/v1.15.4/LICENSE
|
||||
# This is a BSD-3-Clause license
|
||||
- modernc.org/libc
|
||||
- modernc.org/libc/errno
|
||||
- modernc.org/libc/fcntl
|
||||
- modernc.org/libc/fts
|
||||
- modernc.org/libc/grp
|
||||
- modernc.org/libc/langinfo
|
||||
- modernc.org/libc/limits
|
||||
- modernc.org/libc/netdb
|
||||
- modernc.org/libc/netinet/in
|
||||
- modernc.org/libc/poll
|
||||
- modernc.org/libc/pthread
|
||||
- modernc.org/libc/pwd
|
||||
- modernc.org/libc/signal
|
||||
- modernc.org/libc/stdio
|
||||
- modernc.org/libc/stdlib
|
||||
- modernc.org/libc/sys/socket
|
||||
- modernc.org/libc/sys/stat
|
||||
- modernc.org/libc/sys/types
|
||||
- modernc.org/libc/termios
|
||||
- modernc.org/libc/time
|
||||
- modernc.org/libc/unistd
|
||||
- modernc.org/libc/utime
|
||||
- modernc.org/libc/uuid/uuid
|
||||
- modernc.org/libc/wctype
|
||||
- modernc.org/mathutil
|
||||
- modernc.org/memory
|
||||
@@ -0,0 +1,17 @@
|
||||
# Uses https://github.com/actions/add-to-project example to add issues to Anchore OSS project
|
||||
name: Add issues to OSS project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add issue to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/anchore/projects/22
|
||||
github-token: ${{ secrets.CI_WRITE_GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Uses https://github.com/actions/add-to-project example to add PR to Anchore OSS project
|
||||
name: Add pr to OSS project
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add pr to project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/add-to-project@main
|
||||
with:
|
||||
project-url: https://github.com/orgs/anchore/projects/22
|
||||
github-token: ${{ secrets.CI_WRITE_GITHUB_TOKEN }}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
release:
|
||||
prerelease: auto
|
||||
draft: true
|
||||
draft: false
|
||||
|
||||
env:
|
||||
# required to support multi architecture docker builds
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
|
||||
A CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. Exceptional for vulnerability detection when used with a scanner like [Grype](https://github.com/anchore/grype).
|
||||
|
||||
### Join our Virtual OSS Meetup!
|
||||
|
||||
You are invited to join us on June 15th, 11AM-Noon PT for our virtual open source meetup.
|
||||
|
||||
Hosts Amy Bass from Docker Desktop and Christopher Phillips from Anchore OSS will explore how Docker Extensions for Docker Desktop is supporting open source projects and we’ll have the latest update on Syft: in-toto attestations.
|
||||
|
||||
[Register here ->](https://get.anchore.com/anchore-oss-meetup-jun-15-2022/)
|
||||
|
||||
### Join our community meetings!
|
||||
|
||||
- Calendar: https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t
|
||||
@@ -58,6 +66,14 @@ curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b <DESTINATION_DIR> <RELEASE_VERSION>
|
||||
```
|
||||
|
||||
### Chocolatey
|
||||
|
||||
The chocolatey distribution of syft is community maintained and not distributed by the anchore team
|
||||
|
||||
```powershell
|
||||
choco install syft -y
|
||||
```
|
||||
|
||||
### Homebrew
|
||||
```bash
|
||||
brew tap anchore/syft
|
||||
@@ -102,7 +118,7 @@ The ability to convert existing SBOMs means you can create SBOMs in different fo
|
||||
syft convert <ORIGINAL-SBOM-FILE> -o <NEW-SBOM-FORMAT>[=<NEW-SBOM-FILE>]
|
||||
```
|
||||
|
||||
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
|
||||
This feature is experimental and data might be lost when converting formats. Packages are the main SBOM component easily transferable across formats, whereas files and relationships, as well as other information Syft doesn't support, are more likely to be lost.
|
||||
|
||||
We support formats with wide community usage AND good encode/decode support by Syft. The supported formats are:
|
||||
- Syft JSON
|
||||
@@ -140,7 +156,7 @@ COSIGN_EXPERIMENTAL=1 cosign verify-attestation <IMAGE_WITH_ATTESTATIONS>
|
||||
Users should see that the uploaded attestation claims are validated, the claims exist within the transparency log, and certificates on the attestations were verified against [fulcio](https://github.com/SigStore/fulcio).
|
||||
There will also be a printout of the certificates subject `<user identity>` and the certificate issuer URL: `<provider of user identity (Github, Google, Microsoft)>`:
|
||||
```
|
||||
Certificate subject: test.email@testdomain.com
|
||||
Certificate subject: test.email@testdomain.com
|
||||
Certificate issuer URL: https://accounts.google.com
|
||||
```
|
||||
|
||||
@@ -255,7 +271,7 @@ Here's a simple workflow to mount this config file as a secret into a container
|
||||
|
||||
```yaml
|
||||
# secret.yaml
|
||||
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -272,7 +288,7 @@ Here's a simple workflow to mount this config file as a secret into a container
|
||||
|
||||
```yaml
|
||||
# pod.yaml
|
||||
|
||||
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
@@ -519,7 +535,7 @@ anchore:
|
||||
SBOMs themselves can serve as input to different analysis tools. [Grype](https://github.com/anchore/grype), a vulnerability scanner CLI tool from Anchore, is one such tool. Publishers of container images can use attestations to enable their consumers to trust Syft-generated SBOM descriptions of those container images. To create and provide these attestations, image publishers can run `syft attest` in conjunction with the [cosign](https://github.com/sigstore/cosign) tool to attach SBOM attestations to their images.
|
||||
|
||||
#### Example attestation
|
||||
Note for the following example replace `docker.io/image:latest` with an image you own. You should also have push access to
|
||||
Note for the following example replace `docker.io/image:latest` with an image you own. You should also have push access to
|
||||
its remote reference. Replace `$MY_PRIVATE_KEY` with a private key you own or have generated with cosign.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -8,9 +8,10 @@ import (
|
||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/config"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
sigopts "github.com/sigstore/cosign/cmd/cosign/cli/options"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,7 +56,7 @@ func Attest(v *viper.Viper, app *config.Application, ro *options.RootOptions) *c
|
||||
}
|
||||
|
||||
// build cosign key options for attestation
|
||||
ko := sign.KeyOpts{
|
||||
ko := sigopts.KeyOpts{
|
||||
KeyRef: app.Attest.KeyRef,
|
||||
FulcioURL: app.Attest.FulcioURL,
|
||||
IDToken: app.Attest.FulcioIdentityToken,
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
"github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/pkg/errors"
|
||||
sigopts "github.com/sigstore/cosign/cmd/cosign/cli/options"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/rekor"
|
||||
"github.com/sigstore/cosign/cmd/cosign/cli/sign"
|
||||
"github.com/sigstore/cosign/pkg/cosign"
|
||||
@@ -57,7 +58,7 @@ var (
|
||||
intotoJSONDsseType = `application/vnd.in-toto+json`
|
||||
)
|
||||
|
||||
func Run(ctx context.Context, app *config.Application, ko sign.KeyOpts, args []string) error {
|
||||
func Run(ctx context.Context, app *config.Application, ko sigopts.KeyOpts, args []string) error {
|
||||
// We cannot generate an attestation for more than one output
|
||||
if len(app.Outputs) > 1 {
|
||||
return fmt.Errorf("unable to generate attestation for more than one output")
|
||||
|
||||
@@ -10,17 +10,16 @@ require (
|
||||
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074
|
||||
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-rpmdb v0.0.0-20210914181456-a9c52348da63
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7
|
||||
github.com/anchore/stereoscope v0.0.0-20220406160859-c03a18a6b270
|
||||
github.com/anchore/stereoscope v0.0.0-20220518185348-c97a3c6ffc67
|
||||
github.com/antihax/optional v1.0.0
|
||||
github.com/bmatcuk/doublestar/v4 v4.0.2
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/facebookincubator/nvdtools v0.1.4
|
||||
github.com/go-test/deep v1.0.8
|
||||
github.com/google/go-cmp v0.5.7
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
@@ -29,18 +28,18 @@ require (
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/mitchellh/mapstructure v1.4.3
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pelletier/go-toml v1.9.4
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spdx/tools-golang v0.2.0
|
||||
github.com/spf13/afero v1.8.0
|
||||
github.com/spf13/afero v1.8.2
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/spf13/viper v1.12.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/vifraa/gopom v0.1.0
|
||||
github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5
|
||||
@@ -49,7 +48,7 @@ require (
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
@@ -58,41 +57,35 @@ require (
|
||||
github.com/docker/docker v20.10.12+incompatible
|
||||
github.com/google/go-containerregistry v0.8.1-0.20220209165246-a44adc326839
|
||||
github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf
|
||||
github.com/sigstore/cosign v1.7.2
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20220530130908-5101b033fa0d
|
||||
github.com/sigstore/cosign v1.9.0
|
||||
github.com/sigstore/rekor v0.4.1-0.20220114213500-23f583409af3
|
||||
github.com/sigstore/sigstore v1.2.1-0.20220401110139-0e610e39782f
|
||||
github.com/sigstore/sigstore v1.2.1-0.20220424143412-3d41663116d5
|
||||
)
|
||||
|
||||
require (
|
||||
bitbucket.org/creachadair/shell v0.0.6 // indirect
|
||||
cloud.google.com/go v0.100.2 // indirect
|
||||
cloud.google.com/go/compute v1.5.0 // indirect
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
cloud.google.com/go/iam v0.3.0 // indirect
|
||||
cloud.google.com/go/kms v1.4.0 // indirect
|
||||
cloud.google.com/go/storage v1.22.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
|
||||
cloud.google.com/go/storage v1.22.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.3.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.25 // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/PaesslerAG/gval v1.0.0 // indirect
|
||||
github.com/PaesslerAG/jsonpath v0.1.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/ReneKroon/ttlcache/v2 v2.11.0 // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/armon/go-metrics v0.3.10 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aws/aws-sdk-go v1.43.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.14.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.16.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.14.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.9.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.11.0 // indirect
|
||||
@@ -104,13 +97,12 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.10.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.15.0 // indirect
|
||||
github.com/aws/smithy-go v1.11.0 // indirect
|
||||
github.com/aws/smithy-go v1.11.2 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20220119192733-fe33c00cee21 // indirect
|
||||
@@ -132,11 +124,10 @@ require (
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
@@ -147,7 +138,7 @@ require (
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.1 // indirect
|
||||
github.com/go-openapi/runtime v0.23.3 // indirect
|
||||
github.com/go-openapi/runtime v0.24.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.2 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
@@ -171,7 +162,7 @@ require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/trillian v1.4.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.2.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/googleapis/go-type-adapters v1.0.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
@@ -180,22 +171,9 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v1.2.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-plugin v1.4.3 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.3 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.4.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/vault/api v1.5.0 // indirect
|
||||
github.com/hashicorp/vault/sdk v0.4.1 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 // indirect
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
@@ -205,61 +183,59 @@ require (
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/klauspost/compress v1.14.2 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20220331220046-b23ab962616e // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.3.1 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.4.0 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/sigstore/fulcio v0.1.2-0.20220114150912-86a2036f9bc7 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.0.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.3.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.0.0-20220211205608-f0c3294f63b9 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.3.0 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/transparency-dev/merkle v0.0.1 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/urfave/cli v1.22.5 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/xanzy/go-gitlab v0.62.0 // indirect
|
||||
github.com/xanzy/go-gitlab v0.68.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
@@ -267,10 +243,10 @@ require (
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/zeebo/errs v1.2.2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.1 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.4 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/etcdutl/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0 // indirect
|
||||
@@ -293,24 +269,24 @@ require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/api v0.74.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
google.golang.org/api v0.81.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
|
||||
google.golang.org/grpc v1.46.2 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0 // indirect
|
||||
k8s.io/api v0.23.5 // indirect
|
||||
k8s.io/apimachinery v0.23.5 // indirect
|
||||
k8s.io/client-go v0.23.5 // indirect
|
||||
@@ -318,6 +294,16 @@ require (
|
||||
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
knative.dev/pkg v0.0.0-20220325200448-1f7514acd0c2 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
modernc.org/cc/v3 v3.35.22 // indirect
|
||||
modernc.org/ccgo/v3 v3.15.1 // indirect
|
||||
modernc.org/libc v1.14.1 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
modernc.org/memory v1.0.5 // indirect
|
||||
modernc.org/opt v0.1.1 // indirect
|
||||
modernc.org/sqlite v1.14.5 // indirect
|
||||
modernc.org/strutil v1.1.1 // indirect
|
||||
modernc.org/token v1.0.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/release-utils v0.6.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
|
||||
@@ -6,5 +6,5 @@ const (
|
||||
|
||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||
JSONSchemaVersion = "3.2.3"
|
||||
JSONSchemaVersion = "3.2.4"
|
||||
)
|
||||
|
||||
@@ -31,7 +31,9 @@ func GetValidator(format cyclonedx.BOMFileFormat) sbom.Validator {
|
||||
|
||||
func GetDecoder(format cyclonedx.BOMFileFormat) sbom.Decoder {
|
||||
return func(reader io.Reader) (*sbom.SBOM, error) {
|
||||
bom := &cyclonedx.BOM{}
|
||||
bom := &cyclonedx.BOM{
|
||||
Components: &[]cyclonedx.Component{},
|
||||
}
|
||||
err := cyclonedx.NewBOMDecoder(reader, format).Decode(bom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -45,17 +47,17 @@ func GetDecoder(format cyclonedx.BOMFileFormat) sbom.Decoder {
|
||||
}
|
||||
|
||||
func toSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) {
|
||||
meta := source.Metadata{}
|
||||
if bom.Metadata != nil && bom.Metadata.Component != nil {
|
||||
meta = decodeMetadata(bom.Metadata.Component)
|
||||
if bom == nil {
|
||||
return nil, fmt.Errorf("no content defined in CycloneDX BOM")
|
||||
}
|
||||
|
||||
s := &sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
PackageCatalog: pkg.NewCatalog(),
|
||||
LinuxDistribution: linuxReleaseFromComponents(*bom.Components),
|
||||
},
|
||||
Source: meta,
|
||||
//Descriptor: sbom.Descriptor{},
|
||||
Source: extractComponents(bom.Metadata),
|
||||
Descriptor: extractDescriptor(bom.Metadata),
|
||||
}
|
||||
|
||||
idMap := make(map[string]interface{})
|
||||
@@ -205,27 +207,45 @@ func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]int
|
||||
}
|
||||
}
|
||||
|
||||
func decodeMetadata(component *cyclonedx.Component) source.Metadata {
|
||||
switch component.Type {
|
||||
func extractComponents(meta *cyclonedx.Metadata) source.Metadata {
|
||||
if meta == nil || meta.Component == nil {
|
||||
return source.Metadata{}
|
||||
}
|
||||
c := meta.Component
|
||||
|
||||
image := source.ImageMetadata{
|
||||
UserInput: c.Name,
|
||||
ID: c.BOMRef,
|
||||
ManifestDigest: c.Version,
|
||||
}
|
||||
|
||||
switch c.Type {
|
||||
case cyclonedx.ComponentTypeContainer:
|
||||
return source.Metadata{
|
||||
Scheme: source.ImageScheme,
|
||||
ImageMetadata: source.ImageMetadata{
|
||||
UserInput: component.Name,
|
||||
ID: component.BOMRef,
|
||||
ManifestDigest: component.Version,
|
||||
},
|
||||
Scheme: source.ImageScheme,
|
||||
ImageMetadata: image,
|
||||
}
|
||||
case cyclonedx.ComponentTypeFile:
|
||||
return source.Metadata{
|
||||
Scheme: source.FileScheme, // or source.DirectoryScheme
|
||||
Path: component.Name,
|
||||
ImageMetadata: source.ImageMetadata{
|
||||
UserInput: component.Name,
|
||||
ID: component.BOMRef,
|
||||
ManifestDigest: component.Version,
|
||||
},
|
||||
Scheme: source.FileScheme, // or source.DirectoryScheme
|
||||
Path: c.Name,
|
||||
ImageMetadata: image,
|
||||
}
|
||||
}
|
||||
return source.Metadata{}
|
||||
}
|
||||
|
||||
// if there is more than one tool in meta.Tools' list the last item will be used
|
||||
// as descriptor. If there is a way to know which tool to use here please fix it.
|
||||
func extractDescriptor(meta *cyclonedx.Metadata) (desc sbom.Descriptor) {
|
||||
if meta == nil || meta.Tools == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range *meta.Tools {
|
||||
desc.Name = t.Name
|
||||
desc.Version = t.Version
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cyclonedxhelpers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
@@ -283,3 +285,13 @@ func Test_missingDataDecode(t *testing.T) {
|
||||
|
||||
assert.Len(t, pkg.Licenses, 0)
|
||||
}
|
||||
|
||||
func Test_missingComponentsDecode(t *testing.T) {
|
||||
bom := &cyclonedx.BOM{}
|
||||
bomBytes, _ := json.Marshal(&bom)
|
||||
decode := GetDecoder(cyclonedx.BOMFileFormatJSON)
|
||||
|
||||
_, err := decode(bytes.NewReader(bomBytes))
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
@@ -17,13 +16,12 @@ import (
|
||||
|
||||
func ToFormatModel(s sbom.SBOM) *cyclonedx.BOM {
|
||||
cdxBOM := cyclonedx.NewBOM()
|
||||
versionInfo := version.FromBuild()
|
||||
|
||||
// NOTE(jonasagx): cycloneDX requires URN uuids (URN returns the RFC 2141 URN form of uuid):
|
||||
// https://github.com/CycloneDX/specification/blob/master/schema/bom-1.3-strict.schema.json#L36
|
||||
// "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
cdxBOM.SerialNumber = uuid.New().URN()
|
||||
cdxBOM.Metadata = toBomDescriptor(internal.ApplicationName, versionInfo.Version, s.Source)
|
||||
cdxBOM.Metadata = toBomDescriptor(internal.ApplicationName, s.Descriptor.Version, s.Source)
|
||||
|
||||
packages := s.Artifacts.PackageCatalog.Sorted()
|
||||
components := make([]cyclonedx.Component, len(packages))
|
||||
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.4",
|
||||
"serialNumber": "urn:uuid:dec3f6b4-8458-48bb-b60d-dfd312f6ec4e",
|
||||
"serialNumber": "urn:uuid:3ea3363f-3945-4859-9ba1-9a395983d248",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2022-04-01T11:48:04-04:00",
|
||||
"timestamp": "2022-05-23T12:05:00-07:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "[not provided]"
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
|
||||
+6
-6
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.4",
|
||||
"serialNumber": "urn:uuid:054d973e-fe99-4762-92e4-eaf01997ae41",
|
||||
"serialNumber": "urn:uuid:c825402b-bbfa-4ad5-81b1-6a8332a6a8b6",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2022-04-01T11:48:04-04:00",
|
||||
"timestamp": "2022-05-23T12:05:01-07:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "[not provided]"
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"bom-ref": "e777314b02b362e4",
|
||||
"bom-ref": "e779c1ed804ba529",
|
||||
"type": "container",
|
||||
"name": "user-image-input",
|
||||
"version": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
@@ -53,7 +53,7 @@
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:layerID",
|
||||
"value": "sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59"
|
||||
"value": "sha256:cd8f3884f1211d65c19ce5bbc5174bcd2ce8ba96b63e5b3693969a53279c4405"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
@@ -83,7 +83,7 @@
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:layerID",
|
||||
"value": "sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec"
|
||||
"value": "sha256:42d2ea51c688e6dc7be81a305acbe006d27a6ef0c26ae3888fd0d4ce44f69265"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
|
||||
BIN
Binary file not shown.
+3
-3
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:554fd820-210b-40c8-8c0b-75690274e21c" version="1">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:a259c072-aaaf-4a3f-a707-49f691b1e9d9" version="1">
|
||||
<metadata>
|
||||
<timestamp>2022-04-01T11:57:46-04:00</timestamp>
|
||||
<timestamp>2022-05-23T12:02:41-07:00</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
<name>syft</name>
|
||||
<version>[not provided]</version>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</tool>
|
||||
</tools>
|
||||
<component bom-ref="163686ac6e30c752" type="file">
|
||||
|
||||
+6
-6
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1535f940-172f-4d97-8280-d5a5764d1557" version="1">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:155802bd-09e5-4b95-9485-826b94447495" version="1">
|
||||
<metadata>
|
||||
<timestamp>2022-04-01T11:57:46-04:00</timestamp>
|
||||
<timestamp>2022-05-23T12:02:42-07:00</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
<name>syft</name>
|
||||
<version>[not provided]</version>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</tool>
|
||||
</tools>
|
||||
<component bom-ref="e777314b02b362e4" type="container">
|
||||
<component bom-ref="e779c1ed804ba529" type="container">
|
||||
<name>user-image-input</name>
|
||||
<version>sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368</version>
|
||||
</component>
|
||||
@@ -30,7 +30,7 @@
|
||||
<property name="syft:package:language">python</property>
|
||||
<property name="syft:package:metadataType">PythonPackageMetadata</property>
|
||||
<property name="syft:package:type">python</property>
|
||||
<property name="syft:location:0:layerID">sha256:fb6beecb75b39f4bb813dbf177e501edd5ddb3e69bb45cedeb78c676ee1b7a59</property>
|
||||
<property name="syft:location:0:layerID">sha256:cd8f3884f1211d65c19ce5bbc5174bcd2ce8ba96b63e5b3693969a53279c4405</property>
|
||||
<property name="syft:location:0:path">/somefile-1.txt</property>
|
||||
</properties>
|
||||
</component>
|
||||
@@ -43,7 +43,7 @@
|
||||
<property name="syft:package:foundBy">the-cataloger-2</property>
|
||||
<property name="syft:package:metadataType">DpkgMetadata</property>
|
||||
<property name="syft:package:type">deb</property>
|
||||
<property name="syft:location:0:layerID">sha256:319b588ce64253a87b533c8ed01cf0025e0eac98e7b516e12532957e1244fdec</property>
|
||||
<property name="syft:location:0:layerID">sha256:42d2ea51c688e6dc7be81a305acbe006d27a6ef0c26ae3888fd0d4ce44f69265</property>
|
||||
<property name="syft:location:0:path">/somefile-2.txt</property>
|
||||
<property name="syft:metadata:installedSize">0</property>
|
||||
</properties>
|
||||
|
||||
BIN
Binary file not shown.
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
@@ -19,8 +18,8 @@ import (
|
||||
// toGithubModel converts the provided SBOM to a GitHub dependency model
|
||||
func toGithubModel(s *sbom.SBOM) DependencySnapshot {
|
||||
scanTime := time.Now().Format(time.RFC3339) // TODO is there a record of this somewhere?
|
||||
v := version.FromBuild().Version
|
||||
if v == "[not provided]" {
|
||||
v := s.Descriptor.Version
|
||||
if v == "[not provided]" || v == "" {
|
||||
v = "0.0.0-dev"
|
||||
}
|
||||
return DependencySnapshot{
|
||||
|
||||
+4
-4
@@ -3,15 +3,15 @@
|
||||
"name": "/some/path",
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"creationInfo": {
|
||||
"created": "2022-04-01T15:48:39.459232Z",
|
||||
"created": "2022-05-23T19:10:22.25645Z",
|
||||
"creators": [
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: syft-[not provided]"
|
||||
"Tool: syft-v0.42.0-bogus"
|
||||
],
|
||||
"licenseListVersion": "3.16"
|
||||
"licenseListVersion": "3.17"
|
||||
},
|
||||
"dataLicense": "CC0-1.0",
|
||||
"documentNamespace": "https://anchore.com/syft/dir/some/path-8d335d81-29c9-4236-84f1-2292ea92aaf5",
|
||||
"documentNamespace": "https://anchore.com/syft/dir/some/path-81dbcbfa-251d-4ad5-9b01-be91afb16469",
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-b85dbb4e6ece5082",
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
"name": "user-image-input",
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"creationInfo": {
|
||||
"created": "2022-04-01T15:48:39.465643Z",
|
||||
"created": "2022-05-23T19:10:22.412847Z",
|
||||
"creators": [
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: syft-[not provided]"
|
||||
"Tool: syft-v0.42.0-bogus"
|
||||
],
|
||||
"licenseListVersion": "3.16"
|
||||
"licenseListVersion": "3.17"
|
||||
},
|
||||
"dataLicense": "CC0-1.0",
|
||||
"documentNamespace": "https://anchore.com/syft/image/user-image-input-e64e0be8-5031-4eec-842d-e59fb6deb518",
|
||||
"documentNamespace": "https://anchore.com/syft/image/user-image-input-c9945597-78ce-4e9b-89d2-68b8e4e4ccb9",
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-2a46171f91c8d4bc",
|
||||
|
||||
BIN
Binary file not shown.
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/anchore/syft/internal/formats/spdx22json/model"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/spdxlicense"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -34,7 +33,7 @@ func toFormatModel(s sbom.SBOM) *model.Document {
|
||||
Creators: []string{
|
||||
// note: key-value format derived from the JSON example document examples: https://github.com/spdx/spdx-spec/blob/v2.2/examples/SPDXJSONExample-v2.2.spdx.json
|
||||
"Organization: Anchore, Inc",
|
||||
"Tool: " + internal.ApplicationName + "-" + version.FromBuild().Version,
|
||||
"Tool: " + internal.ApplicationName + "-" + s.Descriptor.Version,
|
||||
},
|
||||
LicenseListVersion: spdxlicense.Version,
|
||||
},
|
||||
|
||||
@@ -53,7 +53,13 @@ func TestSPDXJSONSPDXIDs(t *testing.T) {
|
||||
Source: source.Metadata{
|
||||
Scheme: source.DirectoryScheme,
|
||||
},
|
||||
Descriptor: sbom.Descriptor{},
|
||||
Descriptor: sbom.Descriptor{
|
||||
Name: "syft",
|
||||
Version: "v0.42.0-bogus",
|
||||
Configuration: map[string]string{
|
||||
"config-key": "config-value",
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
spdxTagValueRedactor,
|
||||
|
||||
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: .
|
||||
DocumentNamespace: https://anchore.com/syft/dir/8fbb3714-785d-4e3e-95cf-44a258bc65b0
|
||||
LicenseListVersion: 3.16
|
||||
DocumentNamespace: https://anchore.com/syft/dir/422d92b9-57e8-44ee-8039-f75c1d19be87
|
||||
LicenseListVersion: 3.17
|
||||
Creator: Organization: Anchore, Inc
|
||||
Creator: Tool: syft-[not provided]
|
||||
Created: 2022-05-02T15:27:05Z
|
||||
Creator: Tool: syft-v0.42.0-bogus
|
||||
Created: 2022-05-24T22:52:02Z
|
||||
|
||||
##### Package: @at-sign
|
||||
|
||||
|
||||
+4
-4
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: /some/path
|
||||
DocumentNamespace: https://anchore.com/syft/dir/some/path-d227b0f2-4ee8-4e10-ac43-019db86d16ff
|
||||
LicenseListVersion: 3.16
|
||||
DocumentNamespace: https://anchore.com/syft/dir/some/path-c6b20d03-1478-4513-9feb-1ec427d4b547
|
||||
LicenseListVersion: 3.17
|
||||
Creator: Organization: Anchore, Inc
|
||||
Creator: Tool: syft-[not provided]
|
||||
Created: 2022-04-01T15:48:44Z
|
||||
Creator: Tool: syft-v0.42.0-bogus
|
||||
Created: 2022-05-24T22:51:02Z
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
|
||||
+4
-4
@@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: user-image-input
|
||||
DocumentNamespace: https://anchore.com/syft/image/user-image-input-49f98c61-3418-4427-9e00-8b1c735e9799
|
||||
LicenseListVersion: 3.16
|
||||
DocumentNamespace: https://anchore.com/syft/image/user-image-input-12a877bc-fe9b-40ef-aa9c-4d34f108d0d6
|
||||
LicenseListVersion: 3.17
|
||||
Creator: Organization: Anchore, Inc
|
||||
Creator: Tool: syft-[not provided]
|
||||
Created: 2022-04-01T15:48:44Z
|
||||
Creator: Tool: syft-v0.42.0-bogus
|
||||
Created: 2022-05-24T22:51:02Z
|
||||
|
||||
##### Package: package-2
|
||||
|
||||
|
||||
BIN
Binary file not shown.
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/formats/common/spdxhelpers"
|
||||
"github.com/anchore/syft/internal/spdxlicense"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/spdx/tools-golang/spdx"
|
||||
)
|
||||
@@ -69,7 +68,7 @@ func toFormatModel(s sbom.SBOM) *spdx.Document2_2 {
|
||||
// Cardinality: mandatory, one or many
|
||||
CreatorPersons: nil,
|
||||
CreatorOrganizations: []string{"Anchore, Inc"},
|
||||
CreatorTools: []string{internal.ApplicationName + "-" + version.FromBuild().Version},
|
||||
CreatorTools: []string{internal.ApplicationName + "-" + s.Descriptor.Version},
|
||||
|
||||
// 2.9: Created: data format YYYY-MM-DDThh:mm:ssZ
|
||||
// Cardinality: mandatory, one
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.2.3",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.3.json"
|
||||
"version": "3.2.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.2.3",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.3.json"
|
||||
"version": "3.2.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
}
|
||||
},
|
||||
"schema": {
|
||||
"version": "3.2.3",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.3.json"
|
||||
"version": "3.2.4",
|
||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-3.2.4.json"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -534,6 +534,19 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
||||
"cpe:2.3:a:someone:something:3.2:*:*:*:*:*:*:*",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "go product with vendor candidates and an extra sub-item",
|
||||
p: pkg.Package{
|
||||
Name: "github.com/someone/something/more",
|
||||
Version: "3.2",
|
||||
FoundBy: "go-cataloger",
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
},
|
||||
expected: []string{
|
||||
"cpe:2.3:a:someone:something\\/more:3.2:*:*:*:*:*:*:*",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "generate no CPEs for indeterminate golang package name",
|
||||
p: pkg.Package{
|
||||
|
||||
@@ -28,7 +28,9 @@ func candidateProductForGo(name string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pathElements[1]
|
||||
// returning the rest of the path here means longer CPEs, it helps avoiding false-positives
|
||||
// ref: https://github.com/anchore/grype/issues/676
|
||||
return strings.Join(pathElements[1:], "/")
|
||||
}
|
||||
|
||||
// candidateVendorForGo attempts to find a single vendor name in a best-effort attempt. This implementation prefers
|
||||
|
||||
@@ -41,7 +41,11 @@ func TestCandidateProductForGo(t *testing.T) {
|
||||
},
|
||||
{
|
||||
pkg: "github.com/someone/something/long/package/name",
|
||||
expected: "something",
|
||||
expected: "something/long/package/name",
|
||||
},
|
||||
{
|
||||
pkg: "",
|
||||
expected: "",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -56,18 +56,46 @@ func (c *GenericCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package,
|
||||
continue
|
||||
}
|
||||
|
||||
pkgsForRemoval := make(map[artifact.ID]struct{})
|
||||
var cleanedRelationships []artifact.Relationship
|
||||
for _, p := range discoveredPackages {
|
||||
p.FoundBy = c.upstreamCataloger
|
||||
p.Locations.Add(location)
|
||||
p.SetID()
|
||||
// doing it here so all packages have an ID,
|
||||
// IDs are later used to remove relationships
|
||||
if !pkg.IsValid(p) {
|
||||
pkgsForRemoval[p.ID()] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
packages = append(packages, *p)
|
||||
}
|
||||
|
||||
relationships = append(relationships, discoveredRelationships...)
|
||||
cleanedRelationships = removeRelationshipsWithArtifactIDs(pkgsForRemoval, discoveredRelationships)
|
||||
relationships = append(relationships, cleanedRelationships...)
|
||||
}
|
||||
return packages, relationships, nil
|
||||
}
|
||||
|
||||
func removeRelationshipsWithArtifactIDs(artifactsToExclude map[artifact.ID]struct{}, relationships []artifact.Relationship) []artifact.Relationship {
|
||||
if len(artifactsToExclude) == 0 || len(relationships) == 0 {
|
||||
// no removal to do
|
||||
return relationships
|
||||
}
|
||||
|
||||
var cleanedRelationships []artifact.Relationship
|
||||
for _, r := range relationships {
|
||||
_, removeTo := artifactsToExclude[r.To.ID()]
|
||||
_, removaFrom := artifactsToExclude[r.From.ID()]
|
||||
if !removeTo && !removaFrom {
|
||||
cleanedRelationships = append(cleanedRelationships, r)
|
||||
}
|
||||
}
|
||||
|
||||
return cleanedRelationships
|
||||
}
|
||||
|
||||
// SelectFiles takes a set of file trees and resolves and file references of interest for future cataloging
|
||||
func (c *GenericCataloger) selectFiles(resolver source.FilePathResolver) map[source.Location]ParserFn {
|
||||
var parserByLocation = make(map[source.Location]ParserFn)
|
||||
|
||||
@@ -7,28 +7,31 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
func parser(_ string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
contents, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return []*pkg.Package{
|
||||
{
|
||||
Name: string(contents),
|
||||
},
|
||||
}, nil, nil
|
||||
}
|
||||
|
||||
func TestGenericCataloger(t *testing.T) {
|
||||
allParsedPathes := make(map[string]bool)
|
||||
parser := func(path string, reader io.Reader) ([]*pkg.Package, []artifact.Relationship, error) {
|
||||
allParsedPathes[path] = true
|
||||
contents, err := ioutil.ReadAll(reader)
|
||||
require.NoError(t, err)
|
||||
|
||||
p := &pkg.Package{Name: string(contents)}
|
||||
r := artifact.Relationship{From: p, To: p,
|
||||
Type: artifact.ContainsRelationship,
|
||||
}
|
||||
|
||||
return []*pkg.Package{p}, []artifact.Relationship{r}, nil
|
||||
}
|
||||
|
||||
globParsers := map[string]ParserFn{
|
||||
"**/a-path.txt": parser,
|
||||
"**/empty.txt": parser,
|
||||
}
|
||||
pathParsers := map[string]ParserFn{
|
||||
"test-fixtures/another-path.txt": parser,
|
||||
@@ -36,21 +39,27 @@ func TestGenericCataloger(t *testing.T) {
|
||||
}
|
||||
upstream := "some-other-cataloger"
|
||||
|
||||
expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"}
|
||||
expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt", "test-fixtures/empty.txt"}
|
||||
resolver := source.NewMockResolverForPaths(expectedSelection...)
|
||||
cataloger := NewGenericCataloger(pathParsers, globParsers, upstream)
|
||||
|
||||
actualPkgs, relationships, err := cataloger.Catalog(resolver)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expectedPkgs := make(map[string]pkg.Package)
|
||||
for _, path := range expectedSelection {
|
||||
require.True(t, allParsedPathes[path])
|
||||
expectedPkgs[path] = pkg.Package{
|
||||
FoundBy: upstream,
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
}
|
||||
}
|
||||
|
||||
actualPkgs, _, err := cataloger.Catalog(resolver)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, actualPkgs, len(expectedPkgs))
|
||||
assert.Len(t, allParsedPathes, len(expectedSelection))
|
||||
// empty.txt won't become a package
|
||||
assert.Len(t, actualPkgs, len(expectedPkgs)-1)
|
||||
// right now, a relationship is created for each package, but if the relationship includes an invalid package it should be dropped.
|
||||
assert.Len(t, relationships, len(actualPkgs))
|
||||
|
||||
for _, p := range actualPkgs {
|
||||
ref := p.Locations.ToSlice()[0]
|
||||
@@ -69,3 +78,99 @@ func TestGenericCataloger(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_removeRelationshipsWithArtifactIDs(t *testing.T) {
|
||||
one := &pkg.Package{Name: "one", Version: "1.0"}
|
||||
two := &pkg.Package{Name: "two", Version: "1.0"}
|
||||
three := &pkg.Package{Name: "three", Version: "1.0"}
|
||||
four := &pkg.Package{Name: "four", Version: "bla"}
|
||||
five := &pkg.Package{Name: "five", Version: "1.0"}
|
||||
|
||||
pkgs := make([]artifact.Identifiable, 0)
|
||||
for _, p := range []*pkg.Package{one, two, three, four, five} {
|
||||
// IDs are necessary for comparison
|
||||
p.SetID()
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
remove map[artifact.ID]struct{}
|
||||
relationships []artifact.Relationship
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []artifact.Relationship
|
||||
}{
|
||||
{
|
||||
name: "nothing-to-remove",
|
||||
args: args{
|
||||
relationships: []artifact.Relationship{
|
||||
{From: one, To: two},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{From: one, To: two},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove-all-relationships",
|
||||
args: args{
|
||||
remove: map[artifact.ID]struct{}{
|
||||
one.ID(): {},
|
||||
three.ID(): {},
|
||||
},
|
||||
relationships: []artifact.Relationship{
|
||||
{From: one, To: two},
|
||||
{From: two, To: three},
|
||||
{From: three, To: four},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship(nil),
|
||||
},
|
||||
{
|
||||
name: "remove-half-of-relationships",
|
||||
args: args{
|
||||
remove: map[artifact.ID]struct{}{
|
||||
one.ID(): {},
|
||||
},
|
||||
relationships: []artifact.Relationship{
|
||||
{From: one, To: two},
|
||||
{From: one, To: three},
|
||||
{From: two, To: three},
|
||||
{From: three, To: four},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{From: two, To: three},
|
||||
{From: three, To: four},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove-repeated-relationships",
|
||||
args: args{
|
||||
remove: map[artifact.ID]struct{}{
|
||||
one.ID(): {},
|
||||
two.ID(): {},
|
||||
},
|
||||
relationships: []artifact.Relationship{
|
||||
{From: one, To: two},
|
||||
{From: one, To: three},
|
||||
{From: two, To: three},
|
||||
{From: two, To: three},
|
||||
{From: three, To: four},
|
||||
{From: four, To: five},
|
||||
},
|
||||
},
|
||||
want: []artifact.Relationship{
|
||||
{From: three, To: four},
|
||||
{From: four, To: five},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equalf(t, tt.want, removeRelationshipsWithArtifactIDs(tt.args.remove, tt.args.relationships), "removeRelationshipsWithArtifactIDs(%v, %v)", tt.args.remove, tt.args.relationships)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ func TestDpkgCataloger(t *testing.T) {
|
||||
Architecture: "all",
|
||||
Maintainer: "Steve Langasek <vorlon@debian.org>",
|
||||
InstalledSize: 1016,
|
||||
Description: `Runtime support for the PAM library
|
||||
Contains configuration files and directories required for
|
||||
authentication to work on Debian systems. This package is required
|
||||
on almost all installations.`,
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{
|
||||
Path: "/etc/pam.conf",
|
||||
|
||||
@@ -20,8 +20,8 @@ var (
|
||||
sourceRegexp = regexp.MustCompile(`(?P<name>\S+)( \((?P<version>.*)\))?`)
|
||||
)
|
||||
|
||||
func newDpkgPackage(d pkg.DpkgMetadata) pkg.Package {
|
||||
return pkg.Package{
|
||||
func newDpkgPackage(d pkg.DpkgMetadata) *pkg.Package {
|
||||
return &pkg.Package{
|
||||
Name: d.Package,
|
||||
Version: d.Version,
|
||||
Type: pkg.DebPkg,
|
||||
@@ -46,8 +46,9 @@ func parseDpkgStatus(reader io.Reader) ([]pkg.Package, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if entry.Package != "" {
|
||||
packages = append(packages, newDpkgPackage(entry))
|
||||
p := newDpkgPackage(entry)
|
||||
if pkg.IsValid(p) {
|
||||
packages = append(packages, *p)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,20 @@ func TestSinglePackage(t *testing.T) {
|
||||
Architecture: "amd64",
|
||||
InstalledSize: 4064,
|
||||
Maintainer: "APT Development Team <deity@lists.debian.org>",
|
||||
Description: `commandline package manager
|
||||
This package provides commandline tools for searching and
|
||||
managing as well as querying information about packages
|
||||
as a low-level access to all features of the libapt-pkg library.
|
||||
.
|
||||
These include:
|
||||
* apt-get for retrieval of packages and information about them
|
||||
from authenticated sources and for installation, upgrade and
|
||||
removal of packages together with their dependencies
|
||||
* apt-cache for querying available information about installed
|
||||
as well as installable packages
|
||||
* apt-cdrom to use removable media as a source for packages
|
||||
* apt-config as an interface to the configuration settings
|
||||
* apt-key as an interface to manage authentication keys`,
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{
|
||||
Path: "/etc/apt/apt.conf.d/01autoremove",
|
||||
@@ -85,6 +99,20 @@ func TestSinglePackage(t *testing.T) {
|
||||
Architecture: "amd64",
|
||||
InstalledSize: 4000,
|
||||
Maintainer: "APT Development Team <deity@lists.debian.org>",
|
||||
Description: `commandline package manager
|
||||
This package provides commandline tools for searching and
|
||||
managing as well as querying information about packages
|
||||
as a low-level access to all features of the libapt-pkg library.
|
||||
.
|
||||
These include:
|
||||
* apt-get for retrieval of packages and information about them
|
||||
from authenticated sources and for installation, upgrade and
|
||||
removal of packages together with their dependencies
|
||||
* apt-cache for querying available information about installed
|
||||
as well as installable packages
|
||||
* apt-cdrom to use removable media as a source for packages
|
||||
* apt-config as an interface to the configuration settings
|
||||
* apt-key as an interface to manage authentication keys`,
|
||||
},
|
||||
}}
|
||||
|
||||
@@ -121,6 +149,10 @@ func TestMultiplePackages(t *testing.T) {
|
||||
{
|
||||
name: "Test Multiple Package",
|
||||
expected: []pkg.DpkgMetadata{
|
||||
{
|
||||
Package: "no-version",
|
||||
Files: []pkg.DpkgFileRecord{},
|
||||
},
|
||||
{
|
||||
Package: "tzdata",
|
||||
Version: "2020a-0+deb10u1",
|
||||
@@ -128,7 +160,13 @@ func TestMultiplePackages(t *testing.T) {
|
||||
Architecture: "all",
|
||||
InstalledSize: 3036,
|
||||
Maintainer: "GNU Libc Maintainers <debian-glibc@lists.debian.org>",
|
||||
Files: []pkg.DpkgFileRecord{},
|
||||
Description: `time zone and daylight-saving time data
|
||||
This package contains data required for the implementation of
|
||||
standard local time for many representative locations around the
|
||||
globe. It is updated periodically to reflect changes made by
|
||||
political bodies to time zone boundaries, UTC offsets, and
|
||||
daylight-saving rules.`,
|
||||
Files: []pkg.DpkgFileRecord{},
|
||||
},
|
||||
{
|
||||
Package: "util-linux",
|
||||
@@ -136,6 +174,12 @@ func TestMultiplePackages(t *testing.T) {
|
||||
Architecture: "amd64",
|
||||
InstalledSize: 4327,
|
||||
Maintainer: "LaMont Jones <lamont@debian.org>",
|
||||
Description: `miscellaneous system utilities
|
||||
This package contains a number of important utilities, most of which
|
||||
are oriented towards maintenance of your system. Some of the more
|
||||
important utilities included in this package allow you to view kernel
|
||||
messages, create new filesystems, view block device information,
|
||||
interface with real time clock, etc.`,
|
||||
Files: []pkg.DpkgFileRecord{
|
||||
{
|
||||
Path: "/etc/default/hwclock",
|
||||
@@ -209,7 +253,7 @@ func TestMultiplePackages(t *testing.T) {
|
||||
t.Fatal("Unable to read file contents: ", err)
|
||||
}
|
||||
|
||||
if len(pkgs) != 2 {
|
||||
if len(pkgs) != 3 {
|
||||
t.Fatalf("unexpected number of entries: %d", len(pkgs))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
Package:
|
||||
|
||||
Package: libpam-runtime
|
||||
Status: install ok installed
|
||||
Priority: required
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Package:
|
||||
@@ -1,3 +1,7 @@
|
||||
Package:
|
||||
|
||||
Package: no-version
|
||||
|
||||
Package: tzdata
|
||||
Status: install ok installed
|
||||
Priority: required
|
||||
|
||||
@@ -28,7 +28,7 @@ var (
|
||||
|
||||
func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Location) pkg.Package {
|
||||
gbs := getBuildSettings(mod.Settings)
|
||||
main := newGoBinaryPackage(&mod.Main, mod.GoVersion, arch, location, gbs)
|
||||
main := newGoBinaryPackage(&mod.Main, mod.Main.Path, mod.GoVersion, arch, location, gbs)
|
||||
|
||||
if v, ok := gbs["vcs.revision"]; ok {
|
||||
main.Version = v
|
||||
@@ -37,7 +37,7 @@ func makeGoMainPackage(mod *debug.BuildInfo, arch string, location source.Locati
|
||||
return main
|
||||
}
|
||||
|
||||
func newGoBinaryPackage(dep *debug.Module, goVersion, architecture string, location source.Location, buildSettings map[string]string) pkg.Package {
|
||||
func newGoBinaryPackage(dep *debug.Module, mainModule, goVersion, architecture string, location source.Location, buildSettings map[string]string) pkg.Package {
|
||||
if dep.Replace != nil {
|
||||
dep = dep.Replace
|
||||
}
|
||||
@@ -55,6 +55,7 @@ func newGoBinaryPackage(dep *debug.Module, goVersion, architecture string, locat
|
||||
H1Digest: dep.Sum,
|
||||
Architecture: architecture,
|
||||
BuildSettings: buildSettings,
|
||||
MainModule: mainModule,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -172,8 +173,10 @@ func buildGoPkgInfo(location source.Location, mod *debug.BuildInfo, arch string)
|
||||
if dep == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
pkgs = append(pkgs, newGoBinaryPackage(dep, mod.GoVersion, arch, location, nil))
|
||||
p := newGoBinaryPackage(dep, mod.Main.Path, mod.GoVersion, arch, location, nil)
|
||||
if pkg.IsValid(&p) {
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(jonasagx): this use happened originally while creating unit tests. It might never
|
||||
|
||||
@@ -147,6 +147,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
BuildSettings: buildSettings,
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -161,6 +162,38 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
mod: nil,
|
||||
expected: []pkg.Package(nil),
|
||||
},
|
||||
{
|
||||
name: "package without name",
|
||||
mod: &debug.BuildInfo{
|
||||
Deps: []*debug.Module{
|
||||
{
|
||||
Path: "github.com/adrg/xdg",
|
||||
},
|
||||
{
|
||||
Path: "",
|
||||
Version: "v0.2.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "github.com/adrg/xdg",
|
||||
FoundBy: catalogerName,
|
||||
Language: pkg.Go,
|
||||
Type: pkg.GoModulePkg,
|
||||
Locations: source.NewLocationSet(
|
||||
source.Location{
|
||||
Coordinates: source.Coordinates{
|
||||
RealPath: "/a-path",
|
||||
FileSystemID: "layer-id",
|
||||
},
|
||||
},
|
||||
),
|
||||
MetadataType: pkg.GolangBinMetadataType,
|
||||
Metadata: pkg.GolangBinMetadata{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "buildGoPkgInfo parses a blank mod and returns no packages",
|
||||
mod: &debug.BuildInfo{},
|
||||
@@ -266,6 +299,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=",
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -287,6 +321,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:DYssiUV1pBmKqzKsm4mqXx8artqC0Q8HgZsVI3lMsAg=",
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
},
|
||||
expectedMain,
|
||||
@@ -340,7 +375,9 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE="}},
|
||||
H1Digest: "h1:PjhxBct4MZii8FFR8+oeS7QOvxKOTZXgk63EU2XpfJE=",
|
||||
MainModule: "github.com/anchore/syft",
|
||||
}},
|
||||
{
|
||||
Name: "golang.org/x/term",
|
||||
FoundBy: catalogerName,
|
||||
@@ -359,7 +396,9 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
||||
Metadata: pkg.GolangBinMetadata{
|
||||
GoCompiledVersion: goCompiledVersion,
|
||||
Architecture: archDetails,
|
||||
H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI="},
|
||||
H1Digest: "h1:Ihq/mm/suC88gF8WFcVwk+OV6Tq+wyA1O0E5UEvDglI=",
|
||||
MainModule: "github.com/anchore/syft",
|
||||
},
|
||||
},
|
||||
expectedMain,
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ type packageJSON struct {
|
||||
Latest []string `json:"latest"`
|
||||
Author author `json:"author"`
|
||||
License json.RawMessage `json:"license"`
|
||||
Licenses []license `json:"licenses"`
|
||||
Licenses json.RawMessage `json:"licenses"`
|
||||
Name string `json:"name"`
|
||||
Homepage string `json:"homepage"`
|
||||
Description string `json:"description"`
|
||||
@@ -145,8 +145,10 @@ func (p packageJSON) licensesFromJSON() ([]string, error) {
|
||||
return []string{singleLicense}, nil
|
||||
}
|
||||
|
||||
multiLicense, err := licensesFromJSON(p.Licenses)
|
||||
|
||||
// The "licenses" field is deprecated. It should be inspected as a last resort.
|
||||
if p.Licenses != nil {
|
||||
if multiLicense != nil && err == nil {
|
||||
mapLicenses := func(licenses []license) []string {
|
||||
mappedLicenses := make([]string, len(licenses))
|
||||
for i, l := range licenses {
|
||||
@@ -155,10 +157,20 @@ func (p packageJSON) licensesFromJSON() ([]string, error) {
|
||||
return mappedLicenses
|
||||
}
|
||||
|
||||
return mapLicenses(p.Licenses), nil
|
||||
return mapLicenses(multiLicense), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to parse license field: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func licensesFromJSON(b []byte) ([]license, error) {
|
||||
var licenseObject []license
|
||||
err := json.Unmarshal(b, &licenseObject)
|
||||
if err == nil {
|
||||
return licenseObject, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unmarshal failed")
|
||||
}
|
||||
|
||||
// parsePackageJSON parses a package.json and returns the discovered JavaScript packages.
|
||||
|
||||
@@ -71,6 +71,25 @@ func TestParsePackageJSON(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Fixture: "test-fixtures/pkg-json/package-malformed-license.json",
|
||||
ExpectedPkg: pkg.Package{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Type: pkg.NpmPkg,
|
||||
Licenses: nil,
|
||||
Language: pkg.JavaScript,
|
||||
MetadataType: pkg.NpmPackageJSONMetadataType,
|
||||
Metadata: pkg.NpmPackageJSONMetadata{
|
||||
Name: "npm",
|
||||
Version: "6.14.6",
|
||||
Author: "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
Homepage: "https://docs.npmjs.com/",
|
||||
URL: "https://github.com/npm/cli",
|
||||
Licenses: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Fixture: "test-fixtures/pkg-json/package-no-license.json",
|
||||
ExpectedPkg: pkg.Package{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "6.14.6",
|
||||
"name": "npm",
|
||||
"description": "a package manager for JavaScript",
|
||||
"homepage": "https://docs.npmjs.com/",
|
||||
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/npm/cli"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://npm.community/c/bugs"
|
||||
},
|
||||
"main": "./lib/npm.js",
|
||||
"licenses": [ "MIT" ],
|
||||
"engines": {
|
||||
"node": "6 >=6.2.0 || 8 || >=9.3.0"
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (c *PackageCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package,
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to catalog python package=%+v: %w", location.RealPath, err)
|
||||
}
|
||||
if p != nil {
|
||||
if pkg.IsValid(p) {
|
||||
pkgs = append(pkgs, *p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,21 @@ func TestPythonPackageWheelCataloger(t *testing.T) {
|
||||
fixtures []string
|
||||
expectedPackage pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "egg-file-no-version",
|
||||
fixtures: []string{"test-fixtures/no-version-py3.8.egg-info"},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "no-version",
|
||||
Type: pkg.PythonPkg,
|
||||
Language: pkg.Python,
|
||||
FoundBy: "python-package-cataloger",
|
||||
MetadataType: pkg.PythonPackageMetadataType,
|
||||
Metadata: pkg.PythonPackageMetadata{
|
||||
Name: "no-version",
|
||||
SitePackagesRootPath: "test-fixtures",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "egg-info directory",
|
||||
fixtures: []string{
|
||||
@@ -169,6 +184,9 @@ func TestIgnorePackage(t *testing.T) {
|
||||
{
|
||||
MetadataFixture: "test-fixtures/Python-2.7.egg-info",
|
||||
},
|
||||
{
|
||||
MetadataFixture: "test-fixtures/empty-1.0.0-py3.8.egg-info",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Name: no-version
|
||||
@@ -6,13 +6,12 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
|
||||
rpmdb "github.com/anchore/go-rpmdb/pkg"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
rpmdb "github.com/knqyf263/go-rpmdb/pkg"
|
||||
)
|
||||
|
||||
// parseApkDb parses an "Packages" RPM DB and returns the Packages listed within it.
|
||||
@@ -44,40 +43,58 @@ func parseRpmDB(resolver source.FilePathResolver, dbLocation source.Location, re
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allPkgs := make([]pkg.Package, 0)
|
||||
var allPkgs []pkg.Package
|
||||
|
||||
for _, entry := range pkgList {
|
||||
metadata := pkg.RpmdbMetadata{
|
||||
Name: entry.Name,
|
||||
Version: entry.Version,
|
||||
Epoch: entry.Epoch,
|
||||
Arch: entry.Arch,
|
||||
Release: entry.Release,
|
||||
SourceRpm: entry.SourceRpm,
|
||||
Vendor: entry.Vendor,
|
||||
License: entry.License,
|
||||
Size: entry.Size,
|
||||
Files: extractRpmdbFileRecords(resolver, entry),
|
||||
p, err := newPkg(resolver, dbLocation, entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: entry.Name,
|
||||
Version: toELVersion(metadata),
|
||||
Locations: source.NewLocationSet(dbLocation),
|
||||
FoundBy: catalogerName,
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: metadata,
|
||||
if !pkg.IsValid(p) {
|
||||
continue
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
|
||||
allPkgs = append(allPkgs, p)
|
||||
allPkgs = append(allPkgs, *p)
|
||||
}
|
||||
|
||||
return allPkgs, nil
|
||||
}
|
||||
|
||||
func newPkg(resolver source.FilePathResolver, dbLocation source.Location, entry *rpmdb.PackageInfo) (*pkg.Package, error) {
|
||||
fileRecords, err := extractRpmdbFileRecords(resolver, entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
metadata := pkg.RpmdbMetadata{
|
||||
Name: entry.Name,
|
||||
Version: entry.Version,
|
||||
Epoch: entry.Epoch,
|
||||
Arch: entry.Arch,
|
||||
Release: entry.Release,
|
||||
SourceRpm: entry.SourceRpm,
|
||||
Vendor: entry.Vendor,
|
||||
License: entry.License,
|
||||
Size: entry.Size,
|
||||
Files: fileRecords,
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: entry.Name,
|
||||
Version: toELVersion(metadata),
|
||||
Locations: source.NewLocationSet(dbLocation),
|
||||
FoundBy: catalogerName,
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
p.SetID()
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
// The RPM naming scheme is [name]-[version]-[release]-[arch], where version is implicitly expands to [epoch]:[version].
|
||||
// RPM version comparison depends on comparing at least the version and release fields together as a subset of the
|
||||
// naming scheme. This toELVersion function takes a RPM DB package information and converts it into a minimally comparable
|
||||
@@ -91,10 +108,15 @@ func toELVersion(metadata pkg.RpmdbMetadata) string {
|
||||
return fmt.Sprintf("%s-%s", metadata.Version, metadata.Release)
|
||||
}
|
||||
|
||||
func extractRpmdbFileRecords(resolver source.FilePathResolver, entry *rpmdb.PackageInfo) []pkg.RpmdbFileRecord {
|
||||
func extractRpmdbFileRecords(resolver source.FilePathResolver, entry *rpmdb.PackageInfo) ([]pkg.RpmdbFileRecord, error) {
|
||||
var records = make([]pkg.RpmdbFileRecord, 0)
|
||||
|
||||
for _, record := range entry.Files {
|
||||
files, err := entry.InstalledFiles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, record := range files {
|
||||
// only persist RPMDB file records which exist in the image/directory, otherwise ignore them
|
||||
if resolver.HasPath(record.Path) {
|
||||
records = append(records, pkg.RpmdbFileRecord{
|
||||
@@ -111,5 +133,5 @@ func extractRpmdbFileRecords(resolver source.FilePathResolver, entry *rpmdb.Pack
|
||||
})
|
||||
}
|
||||
}
|
||||
return records
|
||||
return records, nil
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ type DpkgMetadata struct {
|
||||
Architecture string `mapstructure:"Architecture" json:"architecture"`
|
||||
Maintainer string `mapstructure:"Maintainer" json:"maintainer"`
|
||||
InstalledSize int `mapstructure:"InstalledSize" json:"installedSize" cyclonedx:"installedSize"`
|
||||
Description string `mapstructure:"Description" hash:"ignore" json:"-"`
|
||||
Files []DpkgFileRecord `json:"files"`
|
||||
}
|
||||
|
||||
|
||||
@@ -6,4 +6,5 @@ type GolangBinMetadata struct {
|
||||
GoCompiledVersion string `json:"goCompiledVersion" cyclonedx:"goCompiledVersion"`
|
||||
Architecture string `json:"architecture" cyclonedx:"architecture"`
|
||||
H1Digest string `json:"h1Digest,omitempty" cyclonedx:"h1Digest"`
|
||||
MainModule string `json:"mainModule,omitempty" cyclonedx:"mainModule"`
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ func LanguageByName(name string) Language {
|
||||
return JavaScript
|
||||
case packageurl.TypePyPi, string(Python):
|
||||
return Python
|
||||
case packageurl.TypeGem:
|
||||
case packageurl.TypeGem, string(Ruby):
|
||||
return Ruby
|
||||
case purlCargoPkgType:
|
||||
case purlCargoPkgType, string(RustPkg), string(Rust):
|
||||
return Rust
|
||||
case packageurl.TypePub, string(Dart):
|
||||
case packageurl.TypePub, string(DartPubPkg), string(Dart):
|
||||
return Dart
|
||||
case packageurl.TypeDotnet:
|
||||
return Dotnet
|
||||
|
||||
@@ -73,3 +73,111 @@ func TestLanguageFromPURL(t *testing.T) {
|
||||
assert.ElementsMatch(t, expectedLanguages.List(), languages, "missing one or more languages to test against (maybe a package type was added?)")
|
||||
|
||||
}
|
||||
|
||||
func TestLanguageByName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
language Language
|
||||
}{
|
||||
{
|
||||
name: "maven",
|
||||
language: Java,
|
||||
},
|
||||
{
|
||||
name: "java",
|
||||
language: Java,
|
||||
},
|
||||
{
|
||||
name: "java-archive",
|
||||
language: Java,
|
||||
},
|
||||
{
|
||||
name: "java",
|
||||
language: Java,
|
||||
},
|
||||
{
|
||||
name: "composer",
|
||||
language: PHP,
|
||||
},
|
||||
{
|
||||
name: "php-composer",
|
||||
language: PHP,
|
||||
},
|
||||
{
|
||||
name: "php",
|
||||
language: PHP,
|
||||
},
|
||||
{
|
||||
name: "go",
|
||||
language: Go,
|
||||
},
|
||||
{
|
||||
name: "golang",
|
||||
language: Go,
|
||||
},
|
||||
{
|
||||
name: "go-module",
|
||||
language: Go,
|
||||
},
|
||||
{
|
||||
name: "npm",
|
||||
language: JavaScript,
|
||||
},
|
||||
{
|
||||
name: "javascript",
|
||||
language: JavaScript,
|
||||
},
|
||||
{
|
||||
name: "pypi",
|
||||
language: Python,
|
||||
},
|
||||
{
|
||||
name: "python",
|
||||
language: Python,
|
||||
},
|
||||
{
|
||||
name: "gem",
|
||||
language: Ruby,
|
||||
},
|
||||
{
|
||||
name: "ruby",
|
||||
language: Ruby,
|
||||
},
|
||||
{
|
||||
name: "rust",
|
||||
language: Rust,
|
||||
},
|
||||
{
|
||||
name: "rust-crate",
|
||||
language: Rust,
|
||||
},
|
||||
{
|
||||
name: "cargo",
|
||||
language: Rust,
|
||||
},
|
||||
{
|
||||
name: "dart",
|
||||
language: Dart,
|
||||
},
|
||||
{
|
||||
name: "dart-pub",
|
||||
language: Dart,
|
||||
},
|
||||
{
|
||||
name: "pub",
|
||||
language: Dart,
|
||||
},
|
||||
{
|
||||
name: "dotnet",
|
||||
language: Dotnet,
|
||||
},
|
||||
{
|
||||
name: "unknown",
|
||||
language: UnknownLanguage,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
assert.Equal(t, LanguageByName(test.name), test.language)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +68,14 @@ func (p *Package) merge(other Package) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid checks whether a package has the minimum necessary info
|
||||
// which is a non-empty name.
|
||||
// The nil-check was added as a helper as often, in this code base, packages
|
||||
// move between callers as pointers.
|
||||
// CycloneDX and SPDX define Name as the minimum required info for a valid package:
|
||||
// * https://spdx.github.io/spdx-spec/package-information/#73-package-version-field
|
||||
// * https://cyclonedx.org/docs/1.4/json/#components_items_name
|
||||
func IsValid(p *Package) bool {
|
||||
return p != nil && p.Name != ""
|
||||
}
|
||||
|
||||
@@ -442,3 +442,31 @@ func TestPackage_Merge(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsValid(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
given *Package
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
given: nil,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "has-name",
|
||||
given: &Package{Name: "paul"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "has-no-name",
|
||||
given: &Package{},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
require.Equal(t, c.want, IsValid(c.given), "when package: %s", c.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ import (
|
||||
"github.com/scylladb/go-set/strset"
|
||||
)
|
||||
|
||||
const RpmDBGlob = "**/var/lib/rpm/Packages"
|
||||
// Packages is the legacy Berkely db based format
|
||||
// Packages.db is the "ndb" format used in SUSE
|
||||
// rpmdb.sqlite is the sqlite format used in fedora + derivates
|
||||
const RpmDBGlob = "**/var/lib/rpm/{Packages,Packages.db,rpmdb.sqlite}"
|
||||
|
||||
var (
|
||||
_ FileOwner = (*RpmdbMetadata)(nil)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
|
||||
func TestSqliteRpm(t *testing.T) {
|
||||
// This is a regression test for issue #469 (https://github.com/anchore/syft/issues/469). Recent RPM
|
||||
// based distribution store package data in an sqlite database
|
||||
sbom, _ := catalogFixtureImage(t, "image-sqlite-rpmdb", source.SquashedScope)
|
||||
|
||||
expectedPkgs := 139
|
||||
actualPkgs := 0
|
||||
for range sbom.Artifacts.PackageCatalog.Enumerate(pkg.RpmPkg) {
|
||||
actualPkgs += 1
|
||||
}
|
||||
|
||||
if actualPkgs != expectedPkgs {
|
||||
t.Errorf("unexpected number of RPM packages: %d != %d", expectedPkgs, actualPkgs)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
FROM fedora:35@sha256:36af84ba69e21c9ef86a0424a090674c433b2b80c2462e57503886f1d823abe8
|
||||
Reference in New Issue
Block a user