Add OCI support + use URI schemes for user image input (#178)

* add oci support + update image schemes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update docs to reflect OCI image sources + URI scheme change

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update to oci-dir

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump upstream stereoscope pin

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2020-09-25 10:24:24 -04:00 committed by GitHub
parent 45b5cab49a
commit 3d91a66536
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 320 additions and 232 deletions

View File

@ -104,15 +104,15 @@ jobs:
- restore_cache:
keys:
- syft-integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }}
- syft-integration-test-cache-{{ checksum "test/integration/test-fixtures/cache.fingerprint" }}
- run:
name: run integration tests
command: make integration
- save_cache:
key: syft-integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }}
key: syft-integration-test-cache-{{ checksum "test/integration/test-fixtures/cache.fingerprint" }}
paths:
- "test/integration/test-fixtures/tar-cache"
- "test/integration/test-fixtures/cache"
workflows:
# Note: changing this workflow name requires making the same update in the .github/workflows/release.yaml pipeline

View File

@ -130,7 +130,7 @@ integration: ## Run integration tests
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
integration-fingerprint:
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/tar-cache.fingerprint
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/cache.fingerprint
.PHONY: java-packages-fingerprint
java-packages-fingerprint:
@ -157,7 +157,7 @@ generate-json-schema: clean-json-schema-examples integration ## Generate a new j
.PHONY: clear-test-cache
clear-test-cache: ## Delete all test cache (built docker image tars)
find . -type f -wholename "**/test-fixtures/tar-cache/*.tar" -delete
find . -type f -wholename "**/test-fixtures/cache/*.tar" -delete
.PHONY: check-pipeline
check-pipeline: ## Run local CircleCI pipeline locally (sanity check)

View File

@ -13,12 +13,13 @@ A CLI tool and go library for generating a Software Bill of Materials (SBOM) fro
- Catalog container images and filesystems to discover packages and libraries.
- Supports packages and libraries from various ecosystems (APK, DEB, RPM, Ruby Bundles, Python Wheel/Egg/requirements.txt, JavaScript NPM/Yarn, Java JAR/EAR/WAR, Jenkins plugins JPI/HPI, Go modules)
- Linux distribution identification (supports Alpine, BusyBox, CentOS/RedHat, Debian/Ubuntu flavored distributions)
- Supports Docker and OCI image formats
> :warning: **This is pre-release software** and it may not work as expected. If you encounter an issue, please [let us know using the issue tracker](https://github.com/anchore/syft/issues).
## Getting started
To generate an SBOM for an image:
To generate an SBOM for a Docker or OCI image:
```
syft <image>
```
@ -32,19 +33,24 @@ syft <image> --scope all-layers
Syft can generate a SBOM from a variety of sources:
```
# catalog a docker image tar (from the result of "docker image save ... -o image.tar" command)
syft docker-archive://path/to/image.tar
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
syft path/to/image.tar
# catalog a directory
syft dir://path/to/dir
syft path/to/dir
```
By default Syft shows a summary table, however, more detailed `text` and `json` formats are also available.
The output format for Syft is configurable as well:
```
syft <image> -o json
syft <image> -o text
syft <image> -o <format>
```
Where the `format`s available are:
- `json`: Use this to get as much information out of Syft as possible!
- `text`: A row-oriented, human-and-machine-friendly output.
- `cyclonedx`: A XML report conforming to the [CycloneDX 1.2](https://cyclonedx.org/) specification.
- `table`: A columnar summary (default).
## Installation
**Recommended**

View File

@ -6,10 +6,6 @@ import (
"os"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
@ -18,6 +14,9 @@ import (
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/presenter"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
"github.com/wagoodman/go-partybus"
)
@ -27,10 +26,15 @@ var rootCmd = &cobra.Command{
Short: "A tool for generating a Software Bill Of Materials (SBOM) from container images and filesystems",
Long: internal.Tprintf(`
Supports the following image sources:
{{.appName}} yourrepo/yourimage:tag defaults to using images from a docker daemon
{{.appName}} docker://yourrepo/yourimage:tag explicitly use the docker daemon
{{.appName}} tar://path/to/yourimage.tar use a tarball from disk
{{.appName}} dir://path/to/yourproject read directly from a path in disk
{{.appName}} yourrepo/yourimage:tag defaults to using images from a Docker daemon
{{.appName}} path/to/yourproject a Docker tar, OCI tar, OCI directory, or generic filesystem directory
You can also explicitly specify the scheme to use:
{{.appName}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon
{{.appName}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
{{.appName}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Podman or otherwise)
{{.appName}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
{{.appName}} dir:path/to/yourproject read directly from a path on disk (any directory)
`, map[string]interface{}{
"appName": internal.ApplicationName,
}),

14
go.mod
View File

@ -3,30 +3,31 @@ module github.com/anchore/syft
go 1.14
require (
github.com/Microsoft/hcsshim v0.8.10 // indirect
github.com/adrg/xdg v0.2.1
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db
github.com/anchore/go-testutils v0.0.0-20200924130829-c7fdedf242b7
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3
github.com/anchore/stereoscope v0.0.0-20200925141829-d086a3427f85
github.com/bmatcuk/doublestar v1.3.1
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/go-test/deep v1.0.6
github.com/google/go-containerregistry v0.1.1 // indirect
github.com/google/uuid v1.1.1
github.com/gookit/color v1.2.7
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-version v1.2.0
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.1
github.com/olekukonko/tablewriter v0.0.4
github.com/opencontainers/runc v0.1.1 // indirect
github.com/package-url/packageurl-go v0.1.0
github.com/pelletier/go-toml v1.8.0
github.com/rogpeppe/go-internal v1.5.2
github.com/sergi/go-diff v1.1.0
github.com/sirupsen/logrus v1.6.0
github.com/spf13/afero v1.2.2
github.com/spf13/cobra v1.0.1-0.20200909172742-8a63648dd905
github.com/spf13/viper v1.7.0
github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d
@ -35,10 +36,5 @@ require (
github.com/x-cray/logrus-prefixed-formatter v0.5.2
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 // indirect
gopkg.in/ini.v1 v1.57.0 // indirect
gopkg.in/yaml.v2 v2.3.0
)

46
go.sum
View File

@ -104,10 +104,12 @@ github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvo
github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.9 h1:VrfodqvztU8YSOvygU+DN1BGaSGxmrNfqOv5oOuX2Bk=
github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab h1:9pygWVFqbY9lPxM0peffumuVDyMuIMzNLyO9uFjJuQo=
github.com/Microsoft/go-winio v0.4.15-0.20200908182639-5b44b70ab3ab/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
github.com/Microsoft/hcsshim v0.8.10 h1:k5wTrpnVU2/xv8ZuzGkbXVd3js5zJ8RnumPo5RxiIxU=
github.com/Microsoft/hcsshim v0.8.10/go.mod h1:g5uw8EV2mAlzqe94tfNBNdr89fnbD/n3HV0OhsddkmM=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us=
@ -126,13 +128,17 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e h1:kty6r0R2JeaNPeWKSYDC+HW3hkqwFh4PP5TQ8pUPYFw=
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e/go.mod h1:iYuIG0Nai8dR0ri3LhZQKUyO1loxUWAGvoWhXDmjy1A=
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db h1:LWKezJnFTFxNkZ4MzajVf+YWvJS0+7hwFr59u6SS7cw=
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db/go.mod h1:D3rc2L/q4Hcp9eeX6AIJH4Q+kPjOtJCFhG9za90j+nU=
github.com/anchore/go-testutils v0.0.0-20200922194607-6dea1542b4ff h1:bCPDn22UX8q6KrJc1tRu7iFF2dLFMKDCHBrNpdw0Nf4=
github.com/anchore/go-testutils v0.0.0-20200922194607-6dea1542b4ff/go.mod h1:utpHUF0ws0l8seM+Dae3moM6S14xH8nqTZVLHAFYBuw=
github.com/anchore/go-testutils v0.0.0-20200924130829-c7fdedf242b7 h1:rhAjS1Hi17C/zyn5maZSDh3Y67szKKJaYk+4xdqLTrU=
github.com/anchore/go-testutils v0.0.0-20200924130829-c7fdedf242b7/go.mod h1:utpHUF0ws0l8seM+Dae3moM6S14xH8nqTZVLHAFYBuw=
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
github.com/anchore/stereoscope v0.0.0-20200520221116-025e07f1c93e/go.mod h1:bkyLl5VITnrmgErv4S1vDfVz/TGAZ5il6161IQo7w2g=
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3 h1:pl+txuYlhK8Mmio4d+4zQI/1xg8X6BtNErTASrx23Wk=
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3/go.mod h1:WntReQTI/I27FOQ87UgLVVzWgku6+ZsqfOTLxpIZFCs=
github.com/anchore/stereoscope v0.0.0-20200922191919-df2d5de22d9d/go.mod h1:W89qUNQ/8ntF5+LY/dynjcvVjWy9ae4TDo48tNK+Cdw=
github.com/anchore/stereoscope v0.0.0-20200925141829-d086a3427f85 h1:w+p0ZFSxV9JhoX5RzjcszH2t/jRRQcQdpGXzbQBIvS0=
github.com/anchore/stereoscope v0.0.0-20200925141829-d086a3427f85/go.mod h1:8RbPl4TvV0Gn15+WIVX6L7Y2io4m9fMHYBQEuNak61E=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
github.com/apex/log v1.3.0 h1:1fyfbPvUwD10nMoh3hY6MXzvZShJQn9/ck7ATgAt5pA=
@ -181,10 +187,12 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@ -209,10 +217,12 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -322,6 +332,7 @@ github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzz
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw=
github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -402,8 +413,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-containerregistry v0.0.0-20200430153450-5cbd060f5c92/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA=
github.com/google/go-containerregistry v0.1.0 h1:hL5mVw7cTX3SBr64Arpv+cJH93L+Z9Q6WjckImYLB3g=
github.com/google/go-containerregistry v0.1.0/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
github.com/google/go-containerregistry v0.1.1 h1:AG8FSAfXglim2l5qSrqp5VK2Xl03PiBf25NiTGGamws=
github.com/google/go-containerregistry v0.1.1/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM=
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
@ -444,9 +453,8 @@ github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1K
github.com/gookit/color v1.2.7 h1:4qePMNWZhrmbfYJDix+J4V2l0iVW+6jQGjicELlN14E=
github.com/gookit/color v1.2.7/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/goreleaser/goreleaser v0.136.0 h1:Z+7XPrfGK11s/Sp+a06sx2FzGuCjTBdxN2ubpGvQbjY=
github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904=
github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w=
@ -668,6 +676,7 @@ github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5X
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/package-url/packageurl-go v0.1.0 h1:efWBc98O/dBZRg1pw2xiDzovnlMjCa9NPnfaiBduh8I=
github.com/package-url/packageurl-go v0.1.0/go.mod h1:C/ApiuWpmbpni4DIOECf6WCjFUZV7O1Fx7VAzrZHgBw=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@ -790,8 +799,8 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho=
github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@ -824,6 +833,7 @@ github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFO
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/uudashr/gocognit v1.0.1 h1:MoG2fZ0b/Eo7NXoIwCVFLG5JED3qgQz5/NEE+rOsjPs=
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@ -961,11 +971,10 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -982,8 +991,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1015,6 +1022,7 @@ golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1022,6 +1030,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1033,11 +1042,10 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38=
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1178,11 +1186,10 @@ google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200519141106-08726f379972/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece h1:1YM0uhfumvoDu9sx8+RyWwTI63zoCQvI23IYFRlvte0=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb h1:ek2py5bOqzR7MR/6obzk0rXUgYCLmjyLnaO9ssT+l6w=
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 h1:1N7l1PuXZwEK7OhHdmKQROOM75PnUjABGwvVRbLBgFk=
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -1225,8 +1232,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
@ -1242,7 +1247,6 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

View File

@ -3,6 +3,7 @@ package cyclonedx
import (
"bytes"
"flag"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/distro"
"regexp"
"testing"
@ -96,7 +97,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
var buffer bytes.Buffer
catalog := pkg.NewCatalog()
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-simple")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple")
defer cleanup()
// populate catalog with test data

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:b3b1786a-2de3-4501-b902-58b701b8ad0e">
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:2bbada20-3e87-44ea-9a56-1aa0e4dd01a0">
<components>
<component type="library">
<name>package1</name>
@ -21,7 +21,7 @@
</component>
</components>
<bd:metadata>
<bd:timestamp>2020-08-30T21:50:50-04:00</bd:timestamp>
<bd:timestamp>2020-09-23T18:26:58-04:00</bd:timestamp>
<bd:tool>
<bd:vendor>anchore</bd:vendor>
<bd:name>syft</bd:name>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:ab970429-e6a2-44a1-810c-f9ed2b7c3147">
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:94dae829-4d5d-482f-afab-27f43f919e2c">
<components>
<component type="library">
<name>package1</name>
@ -21,14 +21,14 @@
</component>
</components>
<bd:metadata>
<bd:timestamp>2020-08-30T21:50:50-04:00</bd:timestamp>
<bd:timestamp>2020-09-23T18:26:58-04:00</bd:timestamp>
<bd:tool>
<bd:vendor>anchore</bd:vendor>
<bd:name>syft</bd:name>
<bd:version>[not provided]</bd:version>
</bd:tool>
<bd:component type="container">
<name>index.docker.io/library/anchore-fixture-image-simple</name>
<name>index.docker.io/library/stereoscope-fixture-image-simple</name>
<version>04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7</version>
</bd:component>
</bd:metadata>

View File

@ -7,6 +7,7 @@ import (
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
"github.com/sergi/go-diff/diffmatchpatch"
@ -72,11 +73,11 @@ func TestJsonImgsPresenter(t *testing.T) {
testImage := "image-simple"
if *update {
testutils.UpdateGoldenFixtureImage(t, testImage)
imagetest.UpdateGoldenFixtureImage(t, testImage)
}
catalog := pkg.NewCatalog()
img := testutils.GetGoldenFixtureImage(t, testImage)
img := imagetest.GetGoldenFixtureImage(t, testImage)
// populate catalog with test data
catalog.Add(pkg.Package{

View File

@ -33,25 +33,25 @@
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:056c0789fa9ad629ceae6d09713fb035f84115af3c4a88a43aa60f13bc683053",
"digest": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b",
"size": 22
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:b461c48116592c570a66fed71d5b09662a8172e168b7938cf317af47872cdc9b",
"digest": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf",
"size": 16
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:00b80053e05c01da485015610d288ce3185fac00d251e2ada02b45a7a7c5f589",
"digest": "sha256:f0e18aa6032c24659a9c741fc36ca56f589782ea132061ccf6f52b952403da94",
"size": 27
}
],
"size": 65,
"digest": "sha256:3c53d2d891940f8d8e95acb77b58752f54dc5de9d91d19dd90ced2db76256cea",
"digest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"tags": [
"anchore-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
"stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
]
}
}

View File

@ -7,6 +7,7 @@ import (
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
"github.com/sergi/go-diff/diffmatchpatch"
@ -20,7 +21,7 @@ func TestTablePresenter(t *testing.T) {
testImage := "image-simple"
catalog := pkg.NewCatalog()
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", testImage)
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", testImage)
defer cleanup()
// populate catalog with test data

View File

@ -7,6 +7,7 @@ import (
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
"github.com/sergi/go-diff/diffmatchpatch"
@ -67,7 +68,7 @@ func TestTextImgPresenter(t *testing.T) {
var buffer bytes.Buffer
catalog := pkg.NewCatalog()
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-simple")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple")
defer cleanup()
// populate catalog with test data

View File

@ -1,59 +0,0 @@
package scope
import "strings"
// Potentially consider moving this out into a generic package that parses user input.
// Aside from scope, this is the 2nd package that looks at a string to parse the input
// and return an Option type.
const (
// nolint:varcheck,deadcode
unknownProtocol protocolType = iota
imageProtocol
directoryProtocol
)
var protocolStr = []string{
"UnknownProtocol",
"Image",
"Directory",
}
type protocolType int
type protocol struct {
Type protocolType
Value string
}
func newProtocol(userStr string) protocol {
candidates := strings.Split(userStr, "://")
switch len(candidates) {
case 2:
if strings.HasPrefix(userStr, "dir://") {
return protocol{
Type: directoryProtocol,
Value: strings.TrimPrefix(userStr, "dir://"),
}
}
// default to an Image for anything else since stereoscope can handle this
return protocol{
Type: imageProtocol,
Value: userStr,
}
default:
return protocol{
Type: imageProtocol,
Value: userStr,
}
}
}
func (o protocolType) String() string {
if int(o) >= len(protocolStr) || o < 0 {
return protocolStr[0]
}
return protocolStr[o]
}

View File

@ -1,43 +0,0 @@
package scope
import "testing"
func TestNewProtocol(t *testing.T) {
testCases := []struct {
desc string
input string
expType protocolType
expValue string
}{
{
desc: "directory protocol",
input: "dir:///opt/",
expType: directoryProtocol,
expValue: "/opt/",
},
{
desc: "unknown protocol",
input: "s4:///opt/",
expType: imageProtocol,
expValue: "s4:///opt/",
},
{
desc: "docker protocol",
input: "docker://ubuntu:20.04",
expType: imageProtocol,
expValue: "docker://ubuntu:20.04",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
p := newProtocol(test.input)
if p.Type != test.expType {
t.Errorf("mismatched type in protocol: '%v' != '%v'", p.Type, test.expType)
}
if p.Value != test.expValue {
t.Errorf("mismatched protocol value: '%s' != '%s'", p.Value, test.expValue)
}
})
}
}

View File

@ -1,9 +1,9 @@
package resolvers
import (
"github.com/anchore/stereoscope/pkg/imagetest"
"testing"
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
)
@ -83,7 +83,7 @@ func TestAllLayersResolver_FilesByPath(t *testing.T) {
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
defer cleanup()
resolver, err := NewAllLayersResolver(img)
@ -191,7 +191,7 @@ func TestAllLayersResolver_FilesByGlob(t *testing.T) {
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
defer cleanup()
resolver, err := NewAllLayersResolver(img)

View File

@ -1,9 +1,9 @@
package resolvers
import (
"github.com/anchore/stereoscope/pkg/imagetest"
"testing"
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/file"
)
@ -47,7 +47,7 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) {
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
defer cleanup()
resolver, err := NewImageSquashResolver(img)
@ -122,7 +122,7 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) {
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-symlinks")
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks")
defer cleanup()
resolver, err := NewImageSquashResolver(img)

View File

@ -7,7 +7,10 @@ package scope
import (
"fmt"
"os"
"strings"
"github.com/anchore/syft/internal/log"
"github.com/spf13/afero"
"github.com/anchore/stereoscope"
@ -15,6 +18,14 @@ import (
"github.com/anchore/syft/syft/scope/resolvers"
)
const (
unknownScheme scheme = "unknown-scheme"
directoryScheme scheme = "directory-scheme"
imageScheme scheme = "image-scheme"
)
type scheme string
// ImageSource represents a data source that is a container image
type ImageSource struct {
Img *image.Image // the image object to be cataloged
@ -34,31 +45,36 @@ type Scope struct {
DirSrc DirSource // the specific directory to be cataloged
}
// NewScope produces a Scope based on userInput like dir:// or image:tag
// NewScope produces a Scope based on userInput like dir: or image:tag
func NewScope(userInput string, o Option) (Scope, func(), error) {
protocol := newProtocol(userInput)
fs := afero.NewOsFs()
parsedScheme, location := detectScheme(fs, image.DetectSource, userInput)
switch protocol.Type {
case directoryProtocol:
err := isValidPath(protocol.Value)
switch parsedScheme {
case directoryScheme:
fileMeta, err := fs.Stat(location)
if err != nil {
return Scope{}, func() {}, fmt.Errorf("unable to process path, must exist and be a directory: %w", err)
return Scope{}, nil, fmt.Errorf("unable to stat dir=%q: %w", location, err)
}
s, err := NewScopeFromDir(protocol.Value)
if !fileMeta.IsDir() {
return Scope{}, nil, fmt.Errorf("given path is not a directory (path=%q): %w", location, err)
}
s, err := NewScopeFromDir(location)
if err != nil {
return Scope{}, func() {}, fmt.Errorf("could not populate scope from path (%s): %w", protocol.Value, err)
return Scope{}, func() {}, fmt.Errorf("could not populate scope from path=%q: %w", location, err)
}
return s, func() {}, nil
case imageProtocol:
img, err := stereoscope.GetImage(userInput)
case imageScheme:
img, err := stereoscope.GetImage(location)
cleanup := func() {
stereoscope.Cleanup()
}
if err != nil || img == nil {
return Scope{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", userInput, err)
return Scope{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
}
s, err := NewScopeFromImage(img, o)
@ -66,10 +82,9 @@ func NewScope(userInput string, o Option) (Scope, func(), error) {
return Scope{}, cleanup, fmt.Errorf("could not populate scope with image: %w", err)
}
return s, cleanup, nil
default:
return Scope{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
}
return Scope{}, func() {}, fmt.Errorf("unable to process input for scanning: '%s'", userInput)
}
// NewScopeFromDir creates a new scope object tailored to catalog a given filesystem directory recursively.
@ -117,16 +132,34 @@ func (s Scope) Source() interface{} {
return nil
}
// isValidPath ensures that the user-provided input will correspond to a path that exists and is a directory
func isValidPath(userInput string) error {
fileMeta, err := os.Stat(userInput)
type sourceDetector func(string) (image.Source, string, error)
func detectScheme(fs afero.Fs, imageDetector sourceDetector, userInput string) (scheme, string) {
if strings.HasPrefix(userInput, "dir:") {
// blindly trust the user's scheme
return directoryScheme, strings.TrimPrefix(userInput, "dir:")
}
// we should attempt to let stereoscope determine what the source is first --just because the source is a valid directory
// doesn't mean we yet know if it is an OCI layout directory (to be treated as an image) or if it is a generic filesystem directory.
source, imageSpec, err := imageDetector(userInput)
if err != nil {
return err
// this is not necessarily an error we care a
log.Debugf("unable to detect the scheme from %q: %w", userInput, err)
return unknownScheme, ""
}
if source == image.UnknownSource {
fileMeta, err := fs.Stat(userInput)
if err != nil {
return unknownScheme, ""
}
if fileMeta.IsDir() {
return nil
return directoryScheme, userInput
}
return unknownScheme, ""
}
return fmt.Errorf("path is not a directory: %s", userInput)
return imageScheme, imageSpec
}

View File

@ -1,6 +1,8 @@
package scope
import (
"github.com/spf13/afero"
"os"
"testing"
"github.com/anchore/stereoscope/pkg/file"
@ -214,39 +216,183 @@ func TestFilesByGlob(t *testing.T) {
}
}
func TestIsValidPath(t *testing.T) {
func TestDetectScheme(t *testing.T) {
type detectorResult struct {
src image.Source
ref string
err error
}
testCases := []struct {
desc string
input string
isError bool
name string
userInput string
dirs []string
detection detectorResult
expectedScheme scheme
expectedLocation string
}{
{
desc: "path is valid",
input: "test-fixtures",
isError: false,
name: "docker-image-ref",
userInput: "wagoodman/dive:latest",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "wagoodman/dive:latest",
},
expectedScheme: imageScheme,
expectedLocation: "wagoodman/dive:latest",
},
{
desc: "file is invalid",
input: "test-fixtures/.vimrc",
isError: true,
name: "docker-image-ref-no-tag",
userInput: "wagoodman/dive",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "wagoodman/dive",
},
expectedScheme: imageScheme,
expectedLocation: "wagoodman/dive",
},
{
desc: "path does not exist",
input: "foo/bar/baz",
isError: true,
name: "docker-image-explicit-scheme",
userInput: "docker:wagoodman/dive:latest",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "wagoodman/dive:latest",
},
expectedScheme: imageScheme,
expectedLocation: "wagoodman/dive:latest",
},
{
name: "docker-image-explicit-scheme-no-tag",
userInput: "docker:wagoodman/dive",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "wagoodman/dive",
},
expectedScheme: imageScheme,
expectedLocation: "wagoodman/dive",
},
{
name: "docker-image-edge-case",
userInput: "docker:latest",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "latest",
},
expectedScheme: imageScheme,
// we want to be able to handle this case better, however, I don't see a way to do this
// the user will need to provide more explicit input (docker:docker:latest)
expectedLocation: "latest",
},
{
name: "docker-image-edge-case-explicit",
userInput: "docker:docker:latest",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "docker:latest",
},
expectedScheme: imageScheme,
// we want to be able to handle this case better, however, I don't see a way to do this
// the user will need to provide more explicit input (docker:docker:latest)
expectedLocation: "docker:latest",
},
{
name: "oci-tar",
userInput: "some/path-to-file",
detection: detectorResult{
src: image.OciTarballSource,
ref: "some/path-to-file",
},
expectedScheme: imageScheme,
expectedLocation: "some/path-to-file",
},
{
name: "oci-dir",
userInput: "some/path-to-dir",
detection: detectorResult{
src: image.OciDirectorySource,
ref: "some/path-to-dir",
},
dirs: []string{"some/path-to-dir"},
expectedScheme: imageScheme,
expectedLocation: "some/path-to-dir",
},
{
name: "guess-dir",
userInput: "some/path-to-dir",
detection: detectorResult{
src: image.UnknownSource,
ref: "",
},
dirs: []string{"some/path-to-dir"},
expectedScheme: directoryScheme,
expectedLocation: "some/path-to-dir",
},
{
name: "generic-dir-does-not-exist",
userInput: "some/path-to-dir",
detection: detectorResult{
src: image.DockerDaemonSource,
ref: "some/path-to-dir",
},
expectedScheme: imageScheme,
expectedLocation: "some/path-to-dir",
},
{
name: "explicit-dir",
userInput: "dir:some/path-to-dir",
detection: detectorResult{
src: image.UnknownSource,
ref: "",
},
dirs: []string{"some/path-to-dir"},
expectedScheme: directoryScheme,
expectedLocation: "some/path-to-dir",
},
{
name: "explicit-current-dir",
userInput: "dir:.",
detection: detectorResult{
src: image.UnknownSource,
ref: "",
},
expectedScheme: directoryScheme,
expectedLocation: ".",
},
{
name: "current-dir",
userInput: ".",
detection: detectorResult{
src: image.UnknownSource,
ref: "",
},
expectedScheme: directoryScheme,
expectedLocation: ".",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
err := isValidPath(test.input)
if err != nil && !test.isError {
t.Errorf("did not expect and error, got: %w", err)
t.Run(test.name, func(t *testing.T) {
fs := afero.NewMemMapFs()
for _, p := range test.dirs {
err := fs.Mkdir(p, os.ModePerm)
if err != nil {
t.Fatalf("failed to create dummy tar: %+v", err)
}
}
if err == nil && test.isError {
t.Errorf("expected an error but didn't get one")
imageDetector := func(string) (image.Source, string, error) {
return test.detection.src, test.detection.ref, test.detection.err
}
actualScheme, actualLocation := detectScheme(fs, imageDetector, test.userInput)
if actualScheme != test.expectedScheme {
t.Errorf("expected scheme %q , got %q", test.expectedScheme, actualScheme)
}
if actualLocation != test.expectedLocation {
t.Errorf("expected location %q , got %q", test.expectedLocation, actualLocation)
}
})
}
}

View File

@ -5,9 +5,8 @@ package integration
import (
"testing"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft"
"github.com/anchore/go-testutils"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/scope"
"github.com/go-test/deep"
@ -15,11 +14,11 @@ import (
func TestDistroImage(t *testing.T) {
fixtureImageName := "image-distro-id"
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
defer cleanup()
_, _, actualDistro, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
_, _, actualDistro, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
if err != nil {
t.Fatalf("failed to catalog image: %+v", err)
}

View File

@ -12,7 +12,7 @@ import (
"strings"
"testing"
"github.com/anchore/go-testutils"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
@ -99,11 +99,11 @@ func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope *scope.Scope, p
func TestJsonSchemaImg(t *testing.T) {
fixtureImageName := "image-pkg-coverage"
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
defer cleanup()
catalog, theScope, _, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
catalog, theScope, _, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
if err != nil {
t.Fatalf("failed to catalog image: %+v", err)
}
@ -116,7 +116,7 @@ func TestJsonSchemaImg(t *testing.T) {
}
func TestJsonSchemaDirs(t *testing.T) {
catalog, theScope, _, err := syft.Catalog("dir://test-fixtures/image-pkg-coverage", scope.AllLayersScope)
catalog, theScope, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", scope.AllLayersScope)
if err != nil {
t.Errorf("unable to create scope from dir: %+v", err)
}

View File

@ -3,24 +3,22 @@
package integration
import (
"github.com/anchore/stereoscope/pkg/imagetest"
"testing"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/internal"
"github.com/anchore/go-testutils"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
)
func TestPkgCoverageImage(t *testing.T) {
fixtureImageName := "image-pkg-coverage"
_, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName)
_, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName)
tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName)
defer cleanup()
catalog, _, _, err := syft.Catalog("docker-archive://"+tarPath, scope.AllLayersScope)
catalog, _, _, err := syft.Catalog("docker-archive:"+tarPath, scope.AllLayersScope)
if err != nil {
t.Fatalf("failed to catalog image: %+v", err)
}
@ -91,7 +89,7 @@ func TestPkgCoverageImage(t *testing.T) {
}
func TestPkgCoverageDirectory(t *testing.T) {
catalog, _, _, err := syft.Catalog("dir://test-fixtures/image-pkg-coverage", scope.AllLayersScope)
catalog, _, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", scope.AllLayersScope)
if err != nil {
t.Errorf("unable to create scope from dir: %+v", err)