diff --git a/.circleci/config.yml b/.circleci/config.yml index 1bdd2b21a32..24b4534f52d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/Makefile b/Makefile index 83455ecf937..5278387acf4 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/README.md b/README.md index c0012d438ff..f72c25ba501 100644 --- a/README.md +++ b/README.md @@ -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 ``` @@ -32,19 +33,24 @@ syft --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 -o json -syft -o text +syft -o ``` +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** diff --git a/cmd/root.go b/cmd/root.go index 9e37e11aa42..ffa936f90dc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -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, }), diff --git a/go.mod b/go.mod index 5fefcbf7e2a..fa9e3514aaa 100644 --- a/go.mod +++ b/go.mod @@ -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 ) diff --git a/go.sum b/go.sum index 796d695674d..0b39d4c5c8b 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/syft/presenter/cyclonedx/presenter_test.go b/syft/presenter/cyclonedx/presenter_test.go index 0ec73ef1797..2b35368667b 100644 --- a/syft/presenter/cyclonedx/presenter_test.go +++ b/syft/presenter/cyclonedx/presenter_test.go @@ -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 diff --git a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden b/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden index 884e8ec2996..68ca8ae8e26 100644 --- a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden +++ b/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden @@ -1,5 +1,5 @@ - + package1 @@ -21,7 +21,7 @@ - 2020-08-30T21:50:50-04:00 + 2020-09-23T18:26:58-04:00 anchore syft diff --git a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden b/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden index 11245e045ed..03f34889a7a 100644 --- a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden +++ b/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden @@ -1,5 +1,5 @@ - + package1 @@ -21,14 +21,14 @@ - 2020-08-30T21:50:50-04:00 + 2020-09-23T18:26:58-04:00 anchore syft [not provided] - index.docker.io/library/anchore-fixture-image-simple + index.docker.io/library/stereoscope-fixture-image-simple 04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7 diff --git a/syft/presenter/json/presenter_test.go b/syft/presenter/json/presenter_test.go index ff149e1e749..f3e79815b13 100644 --- a/syft/presenter/json/presenter_test.go +++ b/syft/presenter/json/presenter_test.go @@ -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{ diff --git a/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden b/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden index 61219a823a1..41212e6224d 100644 --- a/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden +++ b/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden @@ -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" ] } } diff --git a/syft/presenter/json/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden b/syft/presenter/json/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden new file mode 100644 index 00000000000..4e7ce36e080 Binary files /dev/null and b/syft/presenter/json/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden differ diff --git a/syft/presenter/table/presenter_test.go b/syft/presenter/table/presenter_test.go index 40684af7b85..b4db23a5961 100644 --- a/syft/presenter/table/presenter_test.go +++ b/syft/presenter/table/presenter_test.go @@ -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 diff --git a/syft/presenter/text/presenter_test.go b/syft/presenter/text/presenter_test.go index 0c16b0d3810..f8d81994315 100644 --- a/syft/presenter/text/presenter_test.go +++ b/syft/presenter/text/presenter_test.go @@ -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 diff --git a/syft/scope/protocol.go b/syft/scope/protocol.go deleted file mode 100644 index 0ff37dd483d..00000000000 --- a/syft/scope/protocol.go +++ /dev/null @@ -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] -} diff --git a/syft/scope/protocol_test.go b/syft/scope/protocol_test.go deleted file mode 100644 index bd635562572..00000000000 --- a/syft/scope/protocol_test.go +++ /dev/null @@ -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) - } - - }) - } -} diff --git a/syft/scope/resolvers/all_layers_resolver_test.go b/syft/scope/resolvers/all_layers_resolver_test.go index 00485d1694a..97d30c0e35b 100644 --- a/syft/scope/resolvers/all_layers_resolver_test.go +++ b/syft/scope/resolvers/all_layers_resolver_test.go @@ -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) diff --git a/syft/scope/resolvers/image_squash_resolver_test.go b/syft/scope/resolvers/image_squash_resolver_test.go index ae85cce9103..b3530b5665c 100644 --- a/syft/scope/resolvers/image_squash_resolver_test.go +++ b/syft/scope/resolvers/image_squash_resolver_test.go @@ -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) diff --git a/syft/scope/scope.go b/syft/scope/scope.go index ddb63b36fe6..f32624d6e31 100644 --- a/syft/scope/scope.go +++ b/syft/scope/scope.go @@ -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 fileMeta.IsDir() { - return nil + if source == image.UnknownSource { + fileMeta, err := fs.Stat(userInput) + if err != nil { + return unknownScheme, "" + } + + if fileMeta.IsDir() { + return directoryScheme, userInput + } + return unknownScheme, "" } - return fmt.Errorf("path is not a directory: %s", userInput) + return imageScheme, imageSpec } diff --git a/syft/scope/scope_test.go b/syft/scope/scope_test.go index b67d6440c43..74722cba416 100644 --- a/syft/scope/scope_test.go +++ b/syft/scope/scope_test.go @@ -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", + }, + { + name: "docker-image-ref-no-tag", + userInput: "wagoodman/dive", + detection: detectorResult{ + src: image.DockerDaemonSource, + ref: "wagoodman/dive", + }, + expectedScheme: imageScheme, + expectedLocation: "wagoodman/dive", + }, + { + 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", }, { - desc: "file is invalid", - input: "test-fixtures/.vimrc", - isError: true, + 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", }, { - desc: "path does not exist", - input: "foo/bar/baz", - isError: true, + 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) + } }) } } diff --git a/test/integration/distro_test.go b/test/integration/distro_test.go index b0376de91ce..f3bf1dae69d 100644 --- a/test/integration/distro_test.go +++ b/test/integration/distro_test.go @@ -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) } diff --git a/test/integration/json_schema_test.go b/test/integration/json_schema_test.go index 3b811902420..63e93b0c64e 100644 --- a/test/integration/json_schema_test.go +++ b/test/integration/json_schema_test.go @@ -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) } diff --git a/test/integration/pkg_coverage_test.go b/test/integration/pkg_coverage_test.go index da6f4bc7a7d..333c03bc656 100644 --- a/test/integration/pkg_coverage_test.go +++ b/test/integration/pkg_coverage_test.go @@ -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)