From 4666ca84692395db58b3d3f20d1f1aba69091bc7 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:48:20 -0400 Subject: [PATCH 01/29] migrate syft/cataloger to syft/pkg/cataloger Signed-off-by: Alex Goodman --- .../common/generic_cataloger_test.go | 118 ----------- syft/cataloger/deb/cataloger.go | 190 ------------------ ...colon-delimited-with-equals.pom.properties | 5 - .../pom/colon-delimited.pom.properties | 5 - ...quals-delimited-with-colons.pom.properties | 5 - syft/cataloger/python/package_entry.go | 49 ----- syft/{ => pkg}/cataloger/apkdb/cataloger.go | 2 +- .../{ => pkg}/cataloger/apkdb/parse_apk_db.go | 2 +- .../cataloger/apkdb/parse_apk_db_test.go | 0 .../cataloger/apkdb/test-fixtures/base | 0 .../apkdb/test-fixtures/extra-file-attributes | 0 .../cataloger/apkdb/test-fixtures/multiple | 0 .../cataloger/apkdb/test-fixtures/single | 0 syft/{ => pkg}/cataloger/catalog.go | 6 +- syft/{ => pkg}/cataloger/cataloger.go | 20 +- .../cataloger/common/generic_cataloger.go | 104 ++++------ .../common/generic_cataloger_test.go | 73 +++++++ syft/{ => pkg}/cataloger/common/parser.go | 0 .../cataloger/common/test-fixtures/a-path.txt | 1 + .../common/test-fixtures/another-path.txt | 1 + .../common/test-fixtures/last/path.txt | 1 + syft/{ => pkg}/cataloger/cpe.go | 0 syft/{ => pkg}/cataloger/cpe_specificity.go | 0 syft/{ => pkg}/cataloger/cpe_test.go | 0 syft/pkg/cataloger/deb/cataloger.go | 156 ++++++++++++++ .../{ => pkg}/cataloger/deb/cataloger_test.go | 12 +- .../cataloger/deb/parse_copyright.go | 0 .../cataloger/deb/parse_copyright_test.go | 0 .../cataloger/deb/parse_dpkg_info_files.go | 0 .../deb/parse_dpkg_info_files_test.go | 0 .../cataloger/deb/parse_dpkg_status.go | 0 .../cataloger/deb/parse_dpkg_status_test.go | 0 .../test-fixtures/copyright/libaudit-common | 0 .../deb/test-fixtures/copyright/liblzma5 | 0 .../deb/test-fixtures/copyright/python | 0 .../deb/test-fixtures/copyright/trilicense | 0 .../deb/test-fixtures/image-dpkg/Dockerfile | 0 .../usr/share/doc/libpam-runtime/copyright | 0 .../var/lib/dpkg/info/libpam-runtime.md5sums | 0 .../image-dpkg/var/lib/dpkg/status | 0 .../deb/test-fixtures/info/zlib1g.md5sums | 0 .../deb/test-fixtures/status/multiple | 0 .../cataloger/deb/test-fixtures/status/single | 0 syft/{ => pkg}/cataloger/golang/cataloger.go | 2 +- .../cataloger/golang/parse_go_mod.go | 0 .../cataloger/golang/parse_go_mod_test.go | 0 .../golang/test-fixtures/many-packages | 0 .../golang/test-fixtures/one-package | 0 .../cataloger/java/archive_filename.go | 0 .../cataloger/java/archive_filename_test.go | 0 .../cataloger/java/archive_parser.go | 2 +- .../cataloger/java/archive_parser_test.go | 0 syft/{ => pkg}/cataloger/java/cataloger.go | 2 +- .../{ => pkg}/cataloger/java/java_manifest.go | 0 .../cataloger/java/java_manifest_test.go | 0 .../cataloger/java/pom_properties.go | 0 .../cataloger/java/pom_properties_test.go | 0 .../cataloger/java/save_archive_to_tmp.go | 0 .../java/test-fixtures/java-builds/.gitignore | 2 +- .../java/test-fixtures/java-builds/Makefile | 0 .../build-example-java-app-gradle.sh | 0 .../build-example-java-app-maven.sh | 0 .../build-example-jenkins-plugin.sh | 0 .../build-example-sb-app-nestedjar.sh | 0 .../java-builds/example-java-app/.gitignore | 0 .../java-builds/example-java-app/build.gradle | 0 .../java-builds/example-java-app/pom.xml | 0 .../src/main/java/hello/Greeter.java | 0 .../src/main/java/hello/HelloWorld.java | 0 .../example-jenkins-plugin/pom.xml | 0 .../plugins/sample/HelloWorldBuilder.java | 0 .../src/main/resources/index.jelly | 0 .../sample/HelloWorldBuilder/config.jelly | 0 .../HelloWorldBuilder/config.properties | 0 .../HelloWorldBuilder/config_fr.properties | 0 .../sample/HelloWorldBuilder/help-name.html | 0 .../HelloWorldBuilder/help-name_fr.html | 0 .../HelloWorldBuilder/help-useFrench.html | 0 .../HelloWorldBuilder/help-useFrench_fr.html | 0 .../plugins/sample/Messages.properties | 0 .../plugins/sample/Messages_fr.properties | 0 .../java-builds/example-sb-app/.gitignore | 0 .../java-builds/example-sb-app/pom.xml | 0 .../com/example/springboot/Application.java | 0 .../example/springboot/HelloController.java | 0 .../example/springboot/HelloControllerIT.java | 0 .../springboot/HelloControllerTest.java | 0 .../java/test-fixtures/manifest/continuation | 0 .../java/test-fixtures/manifest/extra-info | 0 .../java/test-fixtures/manifest/small | 0 .../java/test-fixtures/manifest/standard-info | 0 .../test-fixtures/manifest/version-with-date | 0 .../test-fixtures/pom/extra.pom.properties | 0 .../test-fixtures/pom/small.pom.properties | 0 .../cataloger/javascript/cataloger.go | 2 +- .../javascript/parse_package_json.go | 4 +- .../javascript/parse_package_json_test.go | 0 .../javascript/parse_package_lock.go | 2 +- .../javascript/parse_package_lock_test.go | 0 .../cataloger/javascript/parse_yarn_lock.go | 2 +- .../javascript/parse_yarn_lock_test.go | 0 .../pkg-json/package-license-object.json | 0 .../pkg-json/package-license-objects.json | 0 .../pkg-json/package-nested-author.json | 0 .../pkg-json/package-no-license.json | 0 .../pkg-json/package-partial.json | 0 .../pkg-json/package-repo-string.json | 0 .../test-fixtures/pkg-json/package.json | 0 .../test-fixtures/pkg-lock/package-lock.json | 0 .../javascript/test-fixtures/yarn/yarn.lock | 0 syft/{ => pkg}/cataloger/package_url.go | 0 syft/{ => pkg}/cataloger/package_url_test.go | 0 .../cataloger/python/index_cataloger.go | 2 +- .../cataloger/python/package_cataloger.go | 167 ++++++++------- .../python/package_cataloger_test.go | 0 .../cataloger/python/parse_poetry_lock.go | 2 +- .../python/parse_poetry_lock_test.go | 0 .../cataloger/python/parse_requirements.go | 2 +- .../python/parse_requirements_test.go | 0 .../{ => pkg}/cataloger/python/parse_setup.go | 2 +- .../cataloger/python/parse_setup_test.go | 0 .../python/parse_wheel_egg_metadata.go | 0 .../python/parse_wheel_egg_metadata_test.go | 0 .../python/parse_wheel_egg_record.go | 0 .../python/parse_wheel_egg_record_test.go | 0 .../cataloger/python/poetry_metadata.go | 0 .../python/poetry_metadata_package.go | 0 .../python/test-fixtures/Python-2.7.egg-info | 0 .../python/test-fixtures/dist-info/METADATA | 0 .../python/test-fixtures/dist-info/RECORD | 0 .../test-fixtures/dist-info/top_level.txt | 0 .../python/test-fixtures/egg-info/PKG-INFO | 0 .../test-fixtures/egg-info/PKG-INFO-INVALID | 0 .../python/test-fixtures/egg-info/RECORD | 0 .../test-fixtures/egg-info/top_level.txt | 0 .../test-fixtures/partial.dist-info/METADATA | 0 .../python/test-fixtures/poetry/poetry.lock | 0 .../test-fixtures/requires/requirements.txt | 0 .../python/test-fixtures/setup/setup.py | 0 .../python/test-fixtures/test.egg-info | 0 syft/{ => pkg}/cataloger/rpmdb/cataloger.go | 2 +- syft/{ => pkg}/cataloger/rpmdb/parse_rpmdb.go | 4 +- .../cataloger/rpmdb/parse_rpmdb_test.go | 0 .../cataloger/rpmdb/test-fixtures/Packages | Bin .../rpmdb/test-fixtures/generate-fixture.sh | 0 syft/{ => pkg}/cataloger/ruby/catalogers.go | 2 +- .../cataloger/ruby/parse_gemfile_lock.go | 2 +- .../cataloger/ruby/parse_gemfile_lock_test.go | 0 .../{ => pkg}/cataloger/ruby/parse_gemspec.go | 2 +- .../cataloger/ruby/parse_gemspec_test.go | 0 .../cataloger/ruby/test-fixtures/Gemfile.lock | 0 .../ruby/test-fixtures/bundler.gemspec | 0 .../cataloger/rust/cargo_metadata.go | 0 syft/{ => pkg}/cataloger/rust/cataloger.go | 2 +- .../cataloger/rust/parse_cargo_lock.go | 0 .../cataloger/rust/parse_cargo_lock_test.go | 0 .../cataloger/rust/test-fixtures/Cargo.lock | 0 157 files changed, 394 insertions(+), 563 deletions(-) delete mode 100644 syft/cataloger/common/generic_cataloger_test.go delete mode 100644 syft/cataloger/deb/cataloger.go delete mode 100644 syft/cataloger/java/test-fixtures/pom/colon-delimited-with-equals.pom.properties delete mode 100644 syft/cataloger/java/test-fixtures/pom/colon-delimited.pom.properties delete mode 100644 syft/cataloger/java/test-fixtures/pom/equals-delimited-with-colons.pom.properties delete mode 100644 syft/cataloger/python/package_entry.go rename syft/{ => pkg}/cataloger/apkdb/cataloger.go (88%) rename syft/{ => pkg}/cataloger/apkdb/parse_apk_db.go (98%) rename syft/{ => pkg}/cataloger/apkdb/parse_apk_db_test.go (100%) rename syft/{ => pkg}/cataloger/apkdb/test-fixtures/base (100%) rename syft/{ => pkg}/cataloger/apkdb/test-fixtures/extra-file-attributes (100%) rename syft/{ => pkg}/cataloger/apkdb/test-fixtures/multiple (100%) rename syft/{ => pkg}/cataloger/apkdb/test-fixtures/single (100%) rename syft/{ => pkg}/cataloger/catalog.go (92%) rename syft/{ => pkg}/cataloger/cataloger.go (78%) rename syft/{ => pkg}/cataloger/common/generic_cataloger.go (54%) create mode 100644 syft/pkg/cataloger/common/generic_cataloger_test.go rename syft/{ => pkg}/cataloger/common/parser.go (100%) create mode 100644 syft/pkg/cataloger/common/test-fixtures/a-path.txt create mode 100644 syft/pkg/cataloger/common/test-fixtures/another-path.txt create mode 100644 syft/pkg/cataloger/common/test-fixtures/last/path.txt rename syft/{ => pkg}/cataloger/cpe.go (100%) rename syft/{ => pkg}/cataloger/cpe_specificity.go (100%) rename syft/{ => pkg}/cataloger/cpe_test.go (100%) create mode 100644 syft/pkg/cataloger/deb/cataloger.go rename syft/{ => pkg}/cataloger/deb/cataloger_test.go (89%) rename syft/{ => pkg}/cataloger/deb/parse_copyright.go (100%) rename syft/{ => pkg}/cataloger/deb/parse_copyright_test.go (100%) rename syft/{ => pkg}/cataloger/deb/parse_dpkg_info_files.go (100%) rename syft/{ => pkg}/cataloger/deb/parse_dpkg_info_files_test.go (100%) rename syft/{ => pkg}/cataloger/deb/parse_dpkg_status.go (100%) rename syft/{ => pkg}/cataloger/deb/parse_dpkg_status_test.go (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/copyright/libaudit-common (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/copyright/liblzma5 (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/copyright/python (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/copyright/trilicense (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/image-dpkg/Dockerfile (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/image-dpkg/usr/share/doc/libpam-runtime/copyright (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/info/libpam-runtime.md5sums (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/status (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/info/zlib1g.md5sums (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/status/multiple (100%) rename syft/{ => pkg}/cataloger/deb/test-fixtures/status/single (100%) rename syft/{ => pkg}/cataloger/golang/cataloger.go (87%) rename syft/{ => pkg}/cataloger/golang/parse_go_mod.go (100%) rename syft/{ => pkg}/cataloger/golang/parse_go_mod_test.go (100%) rename syft/{ => pkg}/cataloger/golang/test-fixtures/many-packages (100%) rename syft/{ => pkg}/cataloger/golang/test-fixtures/one-package (100%) rename syft/{ => pkg}/cataloger/java/archive_filename.go (100%) rename syft/{ => pkg}/cataloger/java/archive_filename_test.go (100%) rename syft/{ => pkg}/cataloger/java/archive_parser.go (99%) rename syft/{ => pkg}/cataloger/java/archive_parser_test.go (100%) rename syft/{ => pkg}/cataloger/java/cataloger.go (89%) rename syft/{ => pkg}/cataloger/java/java_manifest.go (100%) rename syft/{ => pkg}/cataloger/java/java_manifest_test.go (100%) rename syft/{ => pkg}/cataloger/java/pom_properties.go (100%) rename syft/{ => pkg}/cataloger/java/pom_properties_test.go (100%) rename syft/{ => pkg}/cataloger/java/save_archive_to_tmp.go (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/.gitignore (87%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/Makefile (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/build-example-java-app-gradle.sh (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/build-example-java-app-maven.sh (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/build-example-jenkins-plugin.sh (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/build-example-sb-app-nestedjar.sh (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-java-app/.gitignore (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-java-app/build.gradle (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-java-app/pom.xml (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/Greeter.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/HelloWorld.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/pom.xml (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/index.jelly (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_fr.html (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_fr.html (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages.properties (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages_fr.properties (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/.gitignore (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/pom.xml (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/Application.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/HelloController.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerIT.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerTest.java (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/manifest/continuation (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/manifest/extra-info (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/manifest/small (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/manifest/standard-info (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/manifest/version-with-date (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/pom/extra.pom.properties (100%) rename syft/{ => pkg}/cataloger/java/test-fixtures/pom/small.pom.properties (100%) rename syft/{ => pkg}/cataloger/javascript/cataloger.go (94%) rename syft/{ => pkg}/cataloger/javascript/parse_package_json.go (97%) rename syft/{ => pkg}/cataloger/javascript/parse_package_json_test.go (100%) rename syft/{ => pkg}/cataloger/javascript/parse_package_lock.go (96%) rename syft/{ => pkg}/cataloger/javascript/parse_package_lock_test.go (100%) rename syft/{ => pkg}/cataloger/javascript/parse_yarn_lock.go (97%) rename syft/{ => pkg}/cataloger/javascript/parse_yarn_lock_test.go (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-license-object.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-license-objects.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-nested-author.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-no-license.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-partial.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package-repo-string.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-json/package.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/pkg-lock/package-lock.json (100%) rename syft/{ => pkg}/cataloger/javascript/test-fixtures/yarn/yarn.lock (100%) rename syft/{ => pkg}/cataloger/package_url.go (100%) rename syft/{ => pkg}/cataloger/package_url_test.go (100%) rename syft/{ => pkg}/cataloger/python/index_cataloger.go (92%) rename syft/{ => pkg}/cataloger/python/package_cataloger.go (50%) rename syft/{ => pkg}/cataloger/python/package_cataloger_test.go (100%) rename syft/{ => pkg}/cataloger/python/parse_poetry_lock.go (92%) rename syft/{ => pkg}/cataloger/python/parse_poetry_lock_test.go (100%) rename syft/{ => pkg}/cataloger/python/parse_requirements.go (97%) rename syft/{ => pkg}/cataloger/python/parse_requirements_test.go (100%) rename syft/{ => pkg}/cataloger/python/parse_setup.go (95%) rename syft/{ => pkg}/cataloger/python/parse_setup_test.go (100%) rename syft/{ => pkg}/cataloger/python/parse_wheel_egg_metadata.go (100%) rename syft/{ => pkg}/cataloger/python/parse_wheel_egg_metadata_test.go (100%) rename syft/{ => pkg}/cataloger/python/parse_wheel_egg_record.go (100%) rename syft/{ => pkg}/cataloger/python/parse_wheel_egg_record_test.go (100%) rename syft/{ => pkg}/cataloger/python/poetry_metadata.go (100%) rename syft/{ => pkg}/cataloger/python/poetry_metadata_package.go (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/Python-2.7.egg-info (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/dist-info/METADATA (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/dist-info/RECORD (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/dist-info/top_level.txt (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/egg-info/PKG-INFO (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/egg-info/PKG-INFO-INVALID (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/egg-info/RECORD (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/egg-info/top_level.txt (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/partial.dist-info/METADATA (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/poetry/poetry.lock (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/requires/requirements.txt (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/setup/setup.py (100%) rename syft/{ => pkg}/cataloger/python/test-fixtures/test.egg-info (100%) rename syft/{ => pkg}/cataloger/rpmdb/cataloger.go (93%) rename syft/{ => pkg}/cataloger/rpmdb/parse_rpmdb.go (90%) rename syft/{ => pkg}/cataloger/rpmdb/parse_rpmdb_test.go (100%) rename syft/{ => pkg}/cataloger/rpmdb/test-fixtures/Packages (100%) rename syft/{ => pkg}/cataloger/rpmdb/test-fixtures/generate-fixture.sh (100%) rename syft/{ => pkg}/cataloger/ruby/catalogers.go (94%) rename syft/{ => pkg}/cataloger/ruby/parse_gemfile_lock.go (96%) rename syft/{ => pkg}/cataloger/ruby/parse_gemfile_lock_test.go (100%) rename syft/{ => pkg}/cataloger/ruby/parse_gemspec.go (98%) rename syft/{ => pkg}/cataloger/ruby/parse_gemspec_test.go (100%) rename syft/{ => pkg}/cataloger/ruby/test-fixtures/Gemfile.lock (100%) rename syft/{ => pkg}/cataloger/ruby/test-fixtures/bundler.gemspec (100%) rename syft/{ => pkg}/cataloger/rust/cargo_metadata.go (100%) rename syft/{ => pkg}/cataloger/rust/cataloger.go (88%) rename syft/{ => pkg}/cataloger/rust/parse_cargo_lock.go (100%) rename syft/{ => pkg}/cataloger/rust/parse_cargo_lock_test.go (100%) rename syft/{ => pkg}/cataloger/rust/test-fixtures/Cargo.lock (100%) diff --git a/syft/cataloger/common/generic_cataloger_test.go b/syft/cataloger/common/generic_cataloger_test.go deleted file mode 100644 index e390525d1..000000000 --- a/syft/cataloger/common/generic_cataloger_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package common - -import ( - "fmt" - "io" - "io/ioutil" - "strings" - "testing" - - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" -) - -type testResolverMock struct { - contents map[source.Location]io.ReadCloser -} - -func newTestResolver() *testResolverMock { - return &testResolverMock{ - contents: make(map[source.Location]io.ReadCloser), - } -} - -func (r testResolverMock) HasPath(path string) bool { - panic("not implemented") -} - -func (r *testResolverMock) FileContentsByLocation(_ source.Location) (io.ReadCloser, error) { - return nil, fmt.Errorf("not implemented") -} - -func (r *testResolverMock) MultipleFileContentsByLocation([]source.Location) (map[source.Location]io.ReadCloser, error) { - return r.contents, nil -} - -func (r *testResolverMock) FilesByPath(paths ...string) ([]source.Location, error) { - results := make([]source.Location, len(paths)) - - for idx, p := range paths { - results[idx] = source.NewLocation(p) - r.contents[results[idx]] = ioutil.NopCloser(strings.NewReader(fmt.Sprintf("%s file contents!", p))) - } - - return results, nil -} - -func (r *testResolverMock) FilesByGlob(_ ...string) ([]source.Location, error) { - path := "/a-path.txt" - location := source.NewLocation(path) - r.contents[location] = ioutil.NopCloser(strings.NewReader(fmt.Sprintf("%s file contents!", path))) - return []source.Location{location}, nil -} - -func (r *testResolverMock) RelativeFileByPath(_ source.Location, _ string) *source.Location { - panic(fmt.Errorf("not implemented")) - return nil -} - -func parser(_ string, reader io.Reader) ([]pkg.Package, error) { - contents, err := ioutil.ReadAll(reader) - if err != nil { - panic(err) - } - return []pkg.Package{ - { - Name: string(contents), - }, - }, nil -} - -func TestGenericCataloger(t *testing.T) { - - globParsers := map[string]ParserFn{ - "**a-path.txt": parser, - } - pathParsers := map[string]ParserFn{ - "/another-path.txt": parser, - "/last/path.txt": parser, - } - upstream := "some-other-cataloger" - resolver := newTestResolver() - cataloger := NewGenericCataloger(pathParsers, globParsers, upstream) - - expectedSelection := []string{"/last/path.txt", "/another-path.txt", "/a-path.txt"} - expectedPkgs := make(map[string]pkg.Package) - for _, path := range expectedSelection { - expectedPkgs[path] = pkg.Package{ - FoundBy: upstream, - Name: fmt.Sprintf("%s file contents!", path), - } - } - - actualPkgs, err := cataloger.Catalog(resolver) - if err != nil { - t.Fatalf("cataloger catalog action failed: %+v", err) - } - - if len(actualPkgs) != len(expectedPkgs) { - t.Fatalf("unexpected packages len: %d", len(actualPkgs)) - } - - for _, p := range actualPkgs { - ref := p.Locations[0] - exP, ok := expectedPkgs[ref.RealPath] - if !ok { - t.Errorf("missing expected pkg: ref=%+v", ref) - continue - } - - if p.FoundBy != exP.FoundBy { - t.Errorf("bad upstream: %s", p.FoundBy) - } - - if exP.Name != p.Name { - t.Errorf("bad contents mapping: %+v", p.Locations) - } - } -} diff --git a/syft/cataloger/deb/cataloger.go b/syft/cataloger/deb/cataloger.go deleted file mode 100644 index 49694fb38..000000000 --- a/syft/cataloger/deb/cataloger.go +++ /dev/null @@ -1,190 +0,0 @@ -/* -Package dpkg provides a concrete Cataloger implementation for Debian package DB status files. -*/ -package deb - -import ( - "fmt" - "io" - "path" - "path/filepath" - - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" -) - -const ( - md5sumsExt = ".md5sums" - docsPath = "/usr/share/doc" -) - -type Cataloger struct{} - -// NewDpkgdbCataloger returns a new Deb package cataloger object. -func NewDpkgdbCataloger() *Cataloger { - return &Cataloger{} -} - -// Name returns a string that uniquely describes a cataloger -func (c *Cataloger) Name() string { - return "dpkgdb-cataloger" -} - -// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files. -// nolint:funlen -func (c *Cataloger) Catalog(resolver source.Resolver) ([]pkg.Package, error) { - dbFileMatches, err := resolver.FilesByGlob(pkg.DpkgDbGlob) - if err != nil { - return nil, fmt.Errorf("failed to find dpkg status files's by glob: %w", err) - } - - var results []pkg.Package - var pkgs []pkg.Package - for _, dbLocation := range dbFileMatches { - dbContents, err := resolver.FileContentsByLocation(dbLocation) - if err != nil { - return nil, err - } - - pkgs, err = parseDpkgStatus(dbContents) - if err != nil { - return nil, fmt.Errorf("unable to catalog dpkg package=%+v: %w", dbLocation.RealPath, err) - } - - md5ContentsByName, md5RefsByName, err := fetchMd5Contents(resolver, dbLocation, pkgs) - if err != nil { - return nil, fmt.Errorf("unable to find dpkg md5 contents: %w", err) - } - - copyrightContentsByName, copyrightLocationByName, err := fetchCopyrightContents(resolver, dbLocation, pkgs) - if err != nil { - return nil, fmt.Errorf("unable to find dpkg copyright contents: %w", err) - } - - for i := range pkgs { - p := &pkgs[i] - p.FoundBy = c.Name() - p.Locations = []source.Location{dbLocation} - - metadata := p.Metadata.(pkg.DpkgMetadata) - - if md5Reader, ok := md5ContentsByName[md5Key(*p)]; ok { - // attach the file list - metadata.Files = parseDpkgMD5Info(md5Reader) - - // keep a record of the file where this was discovered - if ref, ok := md5RefsByName[md5Key(*p)]; ok { - p.Locations = append(p.Locations, ref) - } - } else { - // ensure the file list is an empty collection (not nil) - metadata.Files = make([]pkg.DpkgFileRecord, 0) - } - - // persist alterations - p.Metadata = metadata - - copyrightReader, ok := copyrightContentsByName[p.Name] - if ok { - // attach the licenses - p.Licenses = parseLicensesFromCopyright(copyrightReader) - - // keep a record of the file where this was discovered - if ref, ok := copyrightLocationByName[p.Name]; ok { - p.Locations = append(p.Locations, ref) - } - } - } - - results = append(results, pkgs...) - } - return results, nil -} - -func fetchMd5Contents(resolver source.Resolver, dbLocation source.Location, pkgs []pkg.Package) (map[string]io.Reader, map[string]source.Location, error) { - // fetch all MD5 file contents. This approach is more efficient than fetching each MD5 file one at a time - - var md5FileMatches []source.Location - var nameByRef = make(map[source.Location]string) - parentPath := filepath.Dir(dbLocation.RealPath) - - for _, p := range pkgs { - // look for /var/lib/dpkg/info/NAME:ARCH.md5sums - name := md5Key(p) - md5SumLocation := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", name+md5sumsExt)) - - if md5SumLocation == nil { - // the most specific key did not work, fallback to just the name - // look for /var/lib/dpkg/info/NAME.md5sums - md5SumLocation = resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", p.Name+md5sumsExt)) - } - // we should have at least one reference - if md5SumLocation != nil { - md5FileMatches = append(md5FileMatches, *md5SumLocation) - nameByRef[*md5SumLocation] = name - } - } - - // fetch the md5 contents - md5ContentsByLocation, err := resolver.MultipleFileContentsByLocation(md5FileMatches) - if err != nil { - return nil, nil, err - } - - // organize content results and refs by a combination of name and architecture - var contentsByName = make(map[string]io.Reader) - var locationByName = make(map[string]source.Location) - for location, contents := range md5ContentsByLocation { - name := nameByRef[location] - contentsByName[name] = contents - locationByName[name] = location - } - - return contentsByName, locationByName, nil -} - -func fetchCopyrightContents(resolver source.Resolver, dbLocation source.Location, pkgs []pkg.Package) (map[string]io.Reader, map[string]source.Location, error) { - // fetch all copyright file contents. This approach is more efficient than fetching each copyright file one at a time - - var copyrightFileMatches []source.Location - var nameByLocation = make(map[source.Location]string) - for _, p := range pkgs { - // look for /usr/share/docs/NAME/copyright files - name := p.Name - copyrightPath := path.Join(docsPath, name, "copyright") - copyrightLocation := resolver.RelativeFileByPath(dbLocation, copyrightPath) - - // we may not have a copyright file for each package, ignore missing files - if copyrightLocation != nil { - copyrightFileMatches = append(copyrightFileMatches, *copyrightLocation) - nameByLocation[*copyrightLocation] = name - } - } - - // fetch the copyright contents - copyrightContentsByLocation, err := resolver.MultipleFileContentsByLocation(copyrightFileMatches) - if err != nil { - return nil, nil, err - } - - // organize content results and refs by package name - var contentsByName = make(map[string]io.Reader) - var refsByName = make(map[string]source.Location) - for location, contents := range copyrightContentsByLocation { - name := nameByLocation[location] - contentsByName[name] = contents - refsByName[name] = location - } - - return contentsByName, refsByName, nil -} - -func md5Key(p pkg.Package) string { - metadata := p.Metadata.(pkg.DpkgMetadata) - - contentKey := p.Name - if metadata.Architecture != "" && metadata.Architecture != "all" { - contentKey = contentKey + ":" + metadata.Architecture - } - return contentKey -} diff --git a/syft/cataloger/java/test-fixtures/pom/colon-delimited-with-equals.pom.properties b/syft/cataloger/java/test-fixtures/pom/colon-delimited-with-equals.pom.properties deleted file mode 100644 index a189c75a6..000000000 --- a/syft/cataloger/java/test-fixtures/pom/colon-delimited-with-equals.pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Tue Jul 07 18:59:56 GMT 2020 -groupId:org.anchore -artifactId: example-java=app-maven -version: 0.1.0=something diff --git a/syft/cataloger/java/test-fixtures/pom/colon-delimited.pom.properties b/syft/cataloger/java/test-fixtures/pom/colon-delimited.pom.properties deleted file mode 100644 index 4069b275c..000000000 --- a/syft/cataloger/java/test-fixtures/pom/colon-delimited.pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Tue Jul 07 18:59:56 GMT 2020 -groupId:org.anchore -artifactId: example-java-app-maven -version: 0.1.0 diff --git a/syft/cataloger/java/test-fixtures/pom/equals-delimited-with-colons.pom.properties b/syft/cataloger/java/test-fixtures/pom/equals-delimited-with-colons.pom.properties deleted file mode 100644 index 7cea7ae6a..000000000 --- a/syft/cataloger/java/test-fixtures/pom/equals-delimited-with-colons.pom.properties +++ /dev/null @@ -1,5 +0,0 @@ -#Generated by Maven -#Tue Jul 07 18:59:56 GMT 2020 -groupId=org.anchore -artifactId= example-java:app-maven -version= 0.1.0:something diff --git a/syft/cataloger/python/package_entry.go b/syft/cataloger/python/package_entry.go deleted file mode 100644 index f27aabae8..000000000 --- a/syft/cataloger/python/package_entry.go +++ /dev/null @@ -1,49 +0,0 @@ -package python - -import ( - "path/filepath" - - "github.com/anchore/syft/syft/source" -) - -type packageEntry struct { - Metadata source.FileData - FileRecord *source.FileData - TopPackage *source.FileData -} - -// newPackageEntry returns a new packageEntry to be processed relative to what information is available in the given FileResolver. -func newPackageEntry(resolver source.FileResolver, metadataLocation source.Location) *packageEntry { - // we've been given a file reference to a specific wheel METADATA file. note: this may be for a directory - // or for an image... for an image the METADATA file may be present within multiple layers, so it is important - // to reconcile the RECORD path to the same layer (or a lower layer). The same is true with the top_level.txt file. - - // lets find the RECORD file relative to the directory where the METADATA file resides (in path AND layer structure) - recordPath := filepath.Join(filepath.Dir(metadataLocation.RealPath), "RECORD") - recordLocation := resolver.RelativeFileByPath(metadataLocation, recordPath) - - // a top_level.txt file specifies the python top-level packages (provided by this python package) installed into site-packages - parentDir := filepath.Dir(metadataLocation.RealPath) - topLevelPath := filepath.Join(parentDir, "top_level.txt") - topLevelLocation := resolver.RelativeFileByPath(metadataLocation, topLevelPath) - - // build an entry that will later be populated with contents when the request is executed - entry := &packageEntry{ - Metadata: source.FileData{ - Location: metadataLocation, - }, - } - - if recordLocation != nil { - entry.FileRecord = &source.FileData{ - Location: *recordLocation, - } - } - - if topLevelLocation != nil { - entry.TopPackage = &source.FileData{ - Location: *topLevelLocation, - } - } - return entry -} diff --git a/syft/cataloger/apkdb/cataloger.go b/syft/pkg/cataloger/apkdb/cataloger.go similarity index 88% rename from syft/cataloger/apkdb/cataloger.go rename to syft/pkg/cataloger/apkdb/cataloger.go index 51ab165f7..6219eaaf7 100644 --- a/syft/cataloger/apkdb/cataloger.go +++ b/syft/pkg/cataloger/apkdb/cataloger.go @@ -4,8 +4,8 @@ Package apkdb provides a concrete Cataloger implementation for Alpine DB files. package apkdb import ( - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewApkdbCataloger returns a new Alpine DB cataloger object. diff --git a/syft/cataloger/apkdb/parse_apk_db.go b/syft/pkg/cataloger/apkdb/parse_apk_db.go similarity index 98% rename from syft/cataloger/apkdb/parse_apk_db.go rename to syft/pkg/cataloger/apkdb/parse_apk_db.go index 98c5d7c07..695553630 100644 --- a/syft/cataloger/apkdb/parse_apk_db.go +++ b/syft/pkg/cataloger/apkdb/parse_apk_db.go @@ -9,8 +9,8 @@ import ( "strings" "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" "github.com/mitchellh/mapstructure" ) diff --git a/syft/cataloger/apkdb/parse_apk_db_test.go b/syft/pkg/cataloger/apkdb/parse_apk_db_test.go similarity index 100% rename from syft/cataloger/apkdb/parse_apk_db_test.go rename to syft/pkg/cataloger/apkdb/parse_apk_db_test.go diff --git a/syft/cataloger/apkdb/test-fixtures/base b/syft/pkg/cataloger/apkdb/test-fixtures/base similarity index 100% rename from syft/cataloger/apkdb/test-fixtures/base rename to syft/pkg/cataloger/apkdb/test-fixtures/base diff --git a/syft/cataloger/apkdb/test-fixtures/extra-file-attributes b/syft/pkg/cataloger/apkdb/test-fixtures/extra-file-attributes similarity index 100% rename from syft/cataloger/apkdb/test-fixtures/extra-file-attributes rename to syft/pkg/cataloger/apkdb/test-fixtures/extra-file-attributes diff --git a/syft/cataloger/apkdb/test-fixtures/multiple b/syft/pkg/cataloger/apkdb/test-fixtures/multiple similarity index 100% rename from syft/cataloger/apkdb/test-fixtures/multiple rename to syft/pkg/cataloger/apkdb/test-fixtures/multiple diff --git a/syft/cataloger/apkdb/test-fixtures/single b/syft/pkg/cataloger/apkdb/test-fixtures/single similarity index 100% rename from syft/cataloger/apkdb/test-fixtures/single rename to syft/pkg/cataloger/apkdb/test-fixtures/single diff --git a/syft/cataloger/catalog.go b/syft/pkg/cataloger/catalog.go similarity index 92% rename from syft/cataloger/catalog.go rename to syft/pkg/cataloger/catalog.go index 27c10556d..962388844 100644 --- a/syft/cataloger/catalog.go +++ b/syft/pkg/cataloger/catalog.go @@ -18,13 +18,13 @@ type Monitor struct { PackagesDiscovered progress.Monitorable // the number of packages discovered from all registered catalogers } -// newMonitor creates a new Monitor object and publishes the object on the bus as a CatalogerStarted event. +// newMonitor creates a new Monitor object and publishes the object on the bus as a PackageCatalogerStarted event. func newMonitor() (*progress.Manual, *progress.Manual) { filesProcessed := progress.Manual{} packagesDiscovered := progress.Manual{} bus.Publish(partybus.Event{ - Type: event.CatalogerStarted, + Type: event.PackageCatalogerStarted, Value: Monitor{ FilesProcessed: progress.Monitorable(&filesProcessed), PackagesDiscovered: progress.Monitorable(&packagesDiscovered), @@ -37,7 +37,7 @@ func newMonitor() (*progress.Manual, *progress.Manual) { // In order to efficiently retrieve contents from a underlying container image the content fetch requests are // done in bulk. Specifically, all files of interest are collected from each catalogers and accumulated into a single // request. -func Catalog(resolver source.Resolver, theDistro *distro.Distro, catalogers ...Cataloger) (*pkg.Catalog, error) { +func Catalog(resolver source.FileResolver, theDistro *distro.Distro, catalogers ...Cataloger) (*pkg.Catalog, error) { catalog := pkg.NewCatalog() filesProcessed, packagesDiscovered := newMonitor() diff --git a/syft/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go similarity index 78% rename from syft/cataloger/cataloger.go rename to syft/pkg/cataloger/cataloger.go index 28a418270..29eb9b933 100644 --- a/syft/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -6,16 +6,16 @@ catalogers defined in child packages as well as the interface definition to impl package cataloger import ( - "github.com/anchore/syft/syft/cataloger/apkdb" - "github.com/anchore/syft/syft/cataloger/deb" - "github.com/anchore/syft/syft/cataloger/golang" - "github.com/anchore/syft/syft/cataloger/java" - "github.com/anchore/syft/syft/cataloger/javascript" - "github.com/anchore/syft/syft/cataloger/python" - "github.com/anchore/syft/syft/cataloger/rpmdb" - "github.com/anchore/syft/syft/cataloger/ruby" - "github.com/anchore/syft/syft/cataloger/rust" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/apkdb" + "github.com/anchore/syft/syft/pkg/cataloger/deb" + "github.com/anchore/syft/syft/pkg/cataloger/golang" + "github.com/anchore/syft/syft/pkg/cataloger/java" + "github.com/anchore/syft/syft/pkg/cataloger/javascript" + "github.com/anchore/syft/syft/pkg/cataloger/python" + "github.com/anchore/syft/syft/pkg/cataloger/rpmdb" + "github.com/anchore/syft/syft/pkg/cataloger/ruby" + "github.com/anchore/syft/syft/pkg/cataloger/rust" "github.com/anchore/syft/syft/source" ) @@ -26,7 +26,7 @@ type Cataloger interface { // Name returns a string that uniquely describes a cataloger Name() string // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source. - Catalog(resolver source.Resolver) ([]pkg.Package, error) + Catalog(resolver source.FileResolver) ([]pkg.Package, error) } // ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages. diff --git a/syft/cataloger/common/generic_cataloger.go b/syft/pkg/cataloger/common/generic_cataloger.go similarity index 54% rename from syft/cataloger/common/generic_cataloger.go rename to syft/pkg/cataloger/common/generic_cataloger.go index c4783b176..5471a9129 100644 --- a/syft/cataloger/common/generic_cataloger.go +++ b/syft/pkg/cataloger/common/generic_cataloger.go @@ -4,7 +4,7 @@ Package common provides generic utilities used by multiple catalogers. package common import ( - "io" + "fmt" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/pkg" @@ -16,8 +16,6 @@ import ( type GenericCataloger struct { globParsers map[string]ParserFn pathParsers map[string]ParserFn - selectedFiles []source.Location - parsers map[source.Location]ParserFn upstreamCataloger string } @@ -26,8 +24,6 @@ func NewGenericCataloger(pathParsers map[string]ParserFn, globParsers map[string return &GenericCataloger{ globParsers: globParsers, pathParsers: pathParsers, - selectedFiles: make([]source.Location, 0), - parsers: make(map[source.Location]ParserFn), upstreamCataloger: upstreamCataloger, } } @@ -37,74 +33,22 @@ func (c *GenericCataloger) Name() string { return c.upstreamCataloger } -// register pairs a set of file references with a parser function for future cataloging (when the file contents are resolved) -func (c *GenericCataloger) register(files []source.Location, parser ParserFn) { - c.selectedFiles = append(c.selectedFiles, files...) - for _, f := range files { - c.parsers[f] = parser - } -} - -// clear deletes all registered file-reference-to-parser-function pairings from former SelectFiles() and register() calls -func (c *GenericCataloger) clear() { - c.selectedFiles = make([]source.Location, 0) - c.parsers = make(map[source.Location]ParserFn) -} - // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing the catalog source. -func (c *GenericCataloger) Catalog(resolver source.Resolver) ([]pkg.Package, error) { - fileSelection := c.selectFiles(resolver) - contents, err := resolver.MultipleFileContentsByLocation(fileSelection) - if err != nil { - return nil, err - } - return c.catalog(contents) -} +func (c *GenericCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, error) { + var packages []pkg.Package + parserByLocation := c.selectFiles(resolver) -// SelectFiles takes a set of file trees and resolves and file references of interest for future cataloging -func (c *GenericCataloger) selectFiles(resolver source.FileResolver) []source.Location { - // select by exact path - for path, parser := range c.pathParsers { - files, err := resolver.FilesByPath(path) + for location, parser := range parserByLocation { + content, err := resolver.FileContentsByLocation(location) if err != nil { - log.Warnf("cataloger failed to select files by path: %+v", err) - } - if files != nil { - c.register(files, parser) - } - } - - // select by glob pattern - for globPattern, parser := range c.globParsers { - fileMatches, err := resolver.FilesByGlob(globPattern) - if err != nil { - log.Warnf("failed to find files by glob: %s", globPattern) - } - if fileMatches != nil { - c.register(fileMatches, parser) - } - } - - return c.selectedFiles -} - -// catalog takes a set of file contents and uses any configured parser functions to resolve and return discovered packages -func (c *GenericCataloger) catalog(contents map[source.Location]io.ReadCloser) ([]pkg.Package, error) { - defer c.clear() - - packages := make([]pkg.Package, 0) - - for location, parser := range c.parsers { - content, ok := contents[location] - if !ok { - log.Warnf("cataloger '%s' missing file content: %+v", c.upstreamCataloger, location) - continue + // TODO: fail or log? + return nil, fmt.Errorf("unable to fetch contents for location=%v : %w", location, err) } entries, err := parser(location.RealPath, content) if err != nil { // TODO: should we fail? or only log? - log.Warnf("cataloger '%s' failed to parse entries (%+v): %+v", c.upstreamCataloger, location, err) + log.Warnf("cataloger '%s' failed to parse entries (location=%+v): %+v", c.upstreamCataloger, location, err) continue } @@ -115,6 +59,34 @@ func (c *GenericCataloger) catalog(contents map[source.Location]io.ReadCloser) ( packages = append(packages, entry) } } - return packages, nil } + +// SelectFiles takes a set of file trees and resolves and file references of interest for future cataloging +func (c *GenericCataloger) selectFiles(resolver source.FilePathResolver) map[source.Location]ParserFn { + var parserByLocation = make(map[source.Location]ParserFn) + + // select by exact path + for path, parser := range c.pathParsers { + files, err := resolver.FilesByPath(path) + if err != nil { + log.Warnf("cataloger failed to select files by path: %+v", err) + } + for _, f := range files { + parserByLocation[f] = parser + } + } + + // select by glob pattern + for globPattern, parser := range c.globParsers { + fileMatches, err := resolver.FilesByGlob(globPattern) + if err != nil { + log.Warnf("failed to find files by glob: %s", globPattern) + } + for _, f := range fileMatches { + parserByLocation[f] = parser + } + } + + return parserByLocation +} diff --git a/syft/pkg/cataloger/common/generic_cataloger_test.go b/syft/pkg/cataloger/common/generic_cataloger_test.go new file mode 100644 index 000000000..8c1f4215c --- /dev/null +++ b/syft/pkg/cataloger/common/generic_cataloger_test.go @@ -0,0 +1,73 @@ +package common + +import ( + "fmt" + "io" + "io/ioutil" + "testing" + + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +func parser(_ string, reader io.Reader) ([]pkg.Package, error) { + contents, err := ioutil.ReadAll(reader) + if err != nil { + panic(err) + } + return []pkg.Package{ + { + Name: string(contents), + }, + }, nil +} + +func TestGenericCataloger(t *testing.T) { + + globParsers := map[string]ParserFn{ + "**a-path.txt": parser, + } + pathParsers := map[string]ParserFn{ + "test-fixtures/another-path.txt": parser, + "test-fixtures/last/path.txt": parser, + } + upstream := "some-other-cataloger" + + expectedSelection := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"} + resolver := source.NewMockResolverForPaths(expectedSelection...) + cataloger := NewGenericCataloger(pathParsers, globParsers, upstream) + + expectedPkgs := make(map[string]pkg.Package) + for _, path := range expectedSelection { + expectedPkgs[path] = pkg.Package{ + FoundBy: upstream, + Name: fmt.Sprintf("%s file contents!", path), + } + } + + actualPkgs, err := cataloger.Catalog(resolver) + if err != nil { + t.Fatalf("cataloger catalog action failed: %+v", err) + } + + if len(actualPkgs) != len(expectedPkgs) { + t.Fatalf("unexpected packages len: %d", len(actualPkgs)) + } + + for _, p := range actualPkgs { + ref := p.Locations[0] + exP, ok := expectedPkgs[ref.RealPath] + if !ok { + t.Errorf("missing expected pkg: ref=%+v", ref) + continue + } + + if p.FoundBy != exP.FoundBy { + t.Errorf("bad upstream: %s", p.FoundBy) + } + + if exP.Name != p.Name { + t.Errorf("bad contents mapping: %+v", p.Locations) + } + } +} diff --git a/syft/cataloger/common/parser.go b/syft/pkg/cataloger/common/parser.go similarity index 100% rename from syft/cataloger/common/parser.go rename to syft/pkg/cataloger/common/parser.go diff --git a/syft/pkg/cataloger/common/test-fixtures/a-path.txt b/syft/pkg/cataloger/common/test-fixtures/a-path.txt new file mode 100644 index 000000000..67e954034 --- /dev/null +++ b/syft/pkg/cataloger/common/test-fixtures/a-path.txt @@ -0,0 +1 @@ +test-fixtures/a-path.txt file contents! \ No newline at end of file diff --git a/syft/pkg/cataloger/common/test-fixtures/another-path.txt b/syft/pkg/cataloger/common/test-fixtures/another-path.txt new file mode 100644 index 000000000..0d654f8fe --- /dev/null +++ b/syft/pkg/cataloger/common/test-fixtures/another-path.txt @@ -0,0 +1 @@ +test-fixtures/another-path.txt file contents! \ No newline at end of file diff --git a/syft/pkg/cataloger/common/test-fixtures/last/path.txt b/syft/pkg/cataloger/common/test-fixtures/last/path.txt new file mode 100644 index 000000000..3d4a165ab --- /dev/null +++ b/syft/pkg/cataloger/common/test-fixtures/last/path.txt @@ -0,0 +1 @@ +test-fixtures/last/path.txt file contents! \ No newline at end of file diff --git a/syft/cataloger/cpe.go b/syft/pkg/cataloger/cpe.go similarity index 100% rename from syft/cataloger/cpe.go rename to syft/pkg/cataloger/cpe.go diff --git a/syft/cataloger/cpe_specificity.go b/syft/pkg/cataloger/cpe_specificity.go similarity index 100% rename from syft/cataloger/cpe_specificity.go rename to syft/pkg/cataloger/cpe_specificity.go diff --git a/syft/cataloger/cpe_test.go b/syft/pkg/cataloger/cpe_test.go similarity index 100% rename from syft/cataloger/cpe_test.go rename to syft/pkg/cataloger/cpe_test.go diff --git a/syft/pkg/cataloger/deb/cataloger.go b/syft/pkg/cataloger/deb/cataloger.go new file mode 100644 index 000000000..34c3df3ac --- /dev/null +++ b/syft/pkg/cataloger/deb/cataloger.go @@ -0,0 +1,156 @@ +/* +Package dpkg provides a concrete Cataloger implementation for Debian package DB status files. +*/ +package deb + +import ( + "fmt" + "io" + "path" + "path/filepath" + + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +const ( + md5sumsExt = ".md5sums" + docsPath = "/usr/share/doc" +) + +type Cataloger struct{} + +// NewDpkgdbCataloger returns a new Deb package cataloger object. +func NewDpkgdbCataloger() *Cataloger { + return &Cataloger{} +} + +// Name returns a string that uniquely describes a cataloger +func (c *Cataloger) Name() string { + return "dpkgdb-cataloger" +} + +// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing dpkg support files. +// nolint:funlen +func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, error) { + dbFileMatches, err := resolver.FilesByGlob(pkg.DpkgDbGlob) + if err != nil { + return nil, fmt.Errorf("failed to find dpkg status files's by glob: %w", err) + } + + var results []pkg.Package + var pkgs []pkg.Package + for _, dbLocation := range dbFileMatches { + dbContents, err := resolver.FileContentsByLocation(dbLocation) + if err != nil { + return nil, err + } + + pkgs, err = parseDpkgStatus(dbContents) + if err != nil { + return nil, fmt.Errorf("unable to catalog dpkg package=%+v: %w", dbLocation.RealPath, err) + } + + for i := range pkgs { + p := &pkgs[i] + p.FoundBy = c.Name() + p.Locations = []source.Location{dbLocation} + + metadata := p.Metadata.(pkg.DpkgMetadata) + + md5Reader, md5Location, err := fetchMd5Contents(resolver, dbLocation, p) + if err != nil { + return nil, fmt.Errorf("unable to find dpkg md5 contents: %w", err) + } + + if md5Reader != nil { + // attach the file list + metadata.Files = parseDpkgMD5Info(md5Reader) + + // keep a record of the file where this was discovered + if md5Location != nil { + p.Locations = append(p.Locations, *md5Location) + } + } else { + // ensure the file list is an empty collection (not nil) + metadata.Files = make([]pkg.DpkgFileRecord, 0) + } + + // persist alterations + p.Metadata = metadata + + // get license information from the copyright file + copyrightReader, copyrightLocation, err := fetchCopyrightContents(resolver, dbLocation, p) + if err != nil { + return nil, fmt.Errorf("unable to find dpkg copyright contents: %w", err) + } + + if copyrightReader != nil { + // attach the licenses + p.Licenses = parseLicensesFromCopyright(copyrightReader) + + // keep a record of the file where this was discovered + if copyrightLocation != nil { + p.Locations = append(p.Locations, *copyrightLocation) + } + } + } + + results = append(results, pkgs...) + } + return results, nil +} + +func fetchMd5Contents(resolver source.FileResolver, dbLocation source.Location, p *pkg.Package) (io.Reader, *source.Location, error) { + parentPath := filepath.Dir(dbLocation.RealPath) + + // look for /var/lib/dpkg/info/NAME:ARCH.md5sums + name := md5Key(p) + md5SumLocation := resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", name+md5sumsExt)) + + if md5SumLocation == nil { + // the most specific key did not work, fallback to just the name + // look for /var/lib/dpkg/info/NAME.md5sums + md5SumLocation = resolver.RelativeFileByPath(dbLocation, path.Join(parentPath, "info", p.Name+md5sumsExt)) + } + + // this is unexpected, but not a show-stopper + if md5SumLocation == nil { + return nil, nil, nil + } + + reader, err := resolver.FileContentsByLocation(*md5SumLocation) + if err != nil { + return nil, nil, fmt.Errorf("failed to fetch deb md5 contents (%+v): %w", p, err) + } + return reader, md5SumLocation, nil +} + +func fetchCopyrightContents(resolver source.FileResolver, dbLocation source.Location, p *pkg.Package) (io.Reader, *source.Location, error) { + // look for /usr/share/docs/NAME/copyright files + name := p.Name + copyrightPath := path.Join(docsPath, name, "copyright") + copyrightLocation := resolver.RelativeFileByPath(dbLocation, copyrightPath) + + // we may not have a copyright file for each package, ignore missing files + if copyrightLocation == nil { + return nil, nil, nil + } + + reader, err := resolver.FileContentsByLocation(*copyrightLocation) + if err != nil { + return nil, nil, fmt.Errorf("failed to fetch deb copyright contents (%+v): %w", p, err) + } + + return reader, copyrightLocation, nil +} + +func md5Key(p *pkg.Package) string { + metadata := p.Metadata.(pkg.DpkgMetadata) + + contentKey := p.Name + if metadata.Architecture != "" && metadata.Architecture != "all" { + contentKey = contentKey + ":" + metadata.Architecture + } + return contentKey +} diff --git a/syft/cataloger/deb/cataloger_test.go b/syft/pkg/cataloger/deb/cataloger_test.go similarity index 89% rename from syft/cataloger/deb/cataloger_test.go rename to syft/pkg/cataloger/deb/cataloger_test.go index d7e9079b5..b856a0cb9 100644 --- a/syft/cataloger/deb/cataloger_test.go +++ b/syft/pkg/cataloger/deb/cataloger_test.go @@ -51,17 +51,21 @@ func TestDpkgCataloger(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-dpkg") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-dpkg") - s, err := source.NewFromImage(img, source.SquashedScope, "") + s, err := source.NewFromImage(img, "") if err != nil { t.Fatal(err) } c := NewDpkgdbCataloger() - actual, err := c.Catalog(s.Resolver) + resolver, err := s.FileResolver(source.SquashedScope) + if err != nil { + t.Errorf("could not get resolver error: %+v", err) + } + + actual, err := c.Catalog(resolver) if err != nil { t.Fatalf("failed to catalog: %+v", err) } diff --git a/syft/cataloger/deb/parse_copyright.go b/syft/pkg/cataloger/deb/parse_copyright.go similarity index 100% rename from syft/cataloger/deb/parse_copyright.go rename to syft/pkg/cataloger/deb/parse_copyright.go diff --git a/syft/cataloger/deb/parse_copyright_test.go b/syft/pkg/cataloger/deb/parse_copyright_test.go similarity index 100% rename from syft/cataloger/deb/parse_copyright_test.go rename to syft/pkg/cataloger/deb/parse_copyright_test.go diff --git a/syft/cataloger/deb/parse_dpkg_info_files.go b/syft/pkg/cataloger/deb/parse_dpkg_info_files.go similarity index 100% rename from syft/cataloger/deb/parse_dpkg_info_files.go rename to syft/pkg/cataloger/deb/parse_dpkg_info_files.go diff --git a/syft/cataloger/deb/parse_dpkg_info_files_test.go b/syft/pkg/cataloger/deb/parse_dpkg_info_files_test.go similarity index 100% rename from syft/cataloger/deb/parse_dpkg_info_files_test.go rename to syft/pkg/cataloger/deb/parse_dpkg_info_files_test.go diff --git a/syft/cataloger/deb/parse_dpkg_status.go b/syft/pkg/cataloger/deb/parse_dpkg_status.go similarity index 100% rename from syft/cataloger/deb/parse_dpkg_status.go rename to syft/pkg/cataloger/deb/parse_dpkg_status.go diff --git a/syft/cataloger/deb/parse_dpkg_status_test.go b/syft/pkg/cataloger/deb/parse_dpkg_status_test.go similarity index 100% rename from syft/cataloger/deb/parse_dpkg_status_test.go rename to syft/pkg/cataloger/deb/parse_dpkg_status_test.go diff --git a/syft/cataloger/deb/test-fixtures/copyright/libaudit-common b/syft/pkg/cataloger/deb/test-fixtures/copyright/libaudit-common similarity index 100% rename from syft/cataloger/deb/test-fixtures/copyright/libaudit-common rename to syft/pkg/cataloger/deb/test-fixtures/copyright/libaudit-common diff --git a/syft/cataloger/deb/test-fixtures/copyright/liblzma5 b/syft/pkg/cataloger/deb/test-fixtures/copyright/liblzma5 similarity index 100% rename from syft/cataloger/deb/test-fixtures/copyright/liblzma5 rename to syft/pkg/cataloger/deb/test-fixtures/copyright/liblzma5 diff --git a/syft/cataloger/deb/test-fixtures/copyright/python b/syft/pkg/cataloger/deb/test-fixtures/copyright/python similarity index 100% rename from syft/cataloger/deb/test-fixtures/copyright/python rename to syft/pkg/cataloger/deb/test-fixtures/copyright/python diff --git a/syft/cataloger/deb/test-fixtures/copyright/trilicense b/syft/pkg/cataloger/deb/test-fixtures/copyright/trilicense similarity index 100% rename from syft/cataloger/deb/test-fixtures/copyright/trilicense rename to syft/pkg/cataloger/deb/test-fixtures/copyright/trilicense diff --git a/syft/cataloger/deb/test-fixtures/image-dpkg/Dockerfile b/syft/pkg/cataloger/deb/test-fixtures/image-dpkg/Dockerfile similarity index 100% rename from syft/cataloger/deb/test-fixtures/image-dpkg/Dockerfile rename to syft/pkg/cataloger/deb/test-fixtures/image-dpkg/Dockerfile diff --git a/syft/cataloger/deb/test-fixtures/image-dpkg/usr/share/doc/libpam-runtime/copyright b/syft/pkg/cataloger/deb/test-fixtures/image-dpkg/usr/share/doc/libpam-runtime/copyright similarity index 100% rename from syft/cataloger/deb/test-fixtures/image-dpkg/usr/share/doc/libpam-runtime/copyright rename to syft/pkg/cataloger/deb/test-fixtures/image-dpkg/usr/share/doc/libpam-runtime/copyright diff --git a/syft/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/info/libpam-runtime.md5sums b/syft/pkg/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/info/libpam-runtime.md5sums similarity index 100% rename from syft/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/info/libpam-runtime.md5sums rename to syft/pkg/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/info/libpam-runtime.md5sums diff --git a/syft/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/status b/syft/pkg/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/status similarity index 100% rename from syft/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/status rename to syft/pkg/cataloger/deb/test-fixtures/image-dpkg/var/lib/dpkg/status diff --git a/syft/cataloger/deb/test-fixtures/info/zlib1g.md5sums b/syft/pkg/cataloger/deb/test-fixtures/info/zlib1g.md5sums similarity index 100% rename from syft/cataloger/deb/test-fixtures/info/zlib1g.md5sums rename to syft/pkg/cataloger/deb/test-fixtures/info/zlib1g.md5sums diff --git a/syft/cataloger/deb/test-fixtures/status/multiple b/syft/pkg/cataloger/deb/test-fixtures/status/multiple similarity index 100% rename from syft/cataloger/deb/test-fixtures/status/multiple rename to syft/pkg/cataloger/deb/test-fixtures/status/multiple diff --git a/syft/cataloger/deb/test-fixtures/status/single b/syft/pkg/cataloger/deb/test-fixtures/status/single similarity index 100% rename from syft/cataloger/deb/test-fixtures/status/single rename to syft/pkg/cataloger/deb/test-fixtures/status/single diff --git a/syft/cataloger/golang/cataloger.go b/syft/pkg/cataloger/golang/cataloger.go similarity index 87% rename from syft/cataloger/golang/cataloger.go rename to syft/pkg/cataloger/golang/cataloger.go index 268bc1cd0..34f33a595 100644 --- a/syft/cataloger/golang/cataloger.go +++ b/syft/pkg/cataloger/golang/cataloger.go @@ -4,7 +4,7 @@ Package golang provides a concrete Cataloger implementation for go.mod files. package golang import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewGoModCataloger returns a new Go module cataloger object. diff --git a/syft/cataloger/golang/parse_go_mod.go b/syft/pkg/cataloger/golang/parse_go_mod.go similarity index 100% rename from syft/cataloger/golang/parse_go_mod.go rename to syft/pkg/cataloger/golang/parse_go_mod.go diff --git a/syft/cataloger/golang/parse_go_mod_test.go b/syft/pkg/cataloger/golang/parse_go_mod_test.go similarity index 100% rename from syft/cataloger/golang/parse_go_mod_test.go rename to syft/pkg/cataloger/golang/parse_go_mod_test.go diff --git a/syft/cataloger/golang/test-fixtures/many-packages b/syft/pkg/cataloger/golang/test-fixtures/many-packages similarity index 100% rename from syft/cataloger/golang/test-fixtures/many-packages rename to syft/pkg/cataloger/golang/test-fixtures/many-packages diff --git a/syft/cataloger/golang/test-fixtures/one-package b/syft/pkg/cataloger/golang/test-fixtures/one-package similarity index 100% rename from syft/cataloger/golang/test-fixtures/one-package rename to syft/pkg/cataloger/golang/test-fixtures/one-package diff --git a/syft/cataloger/java/archive_filename.go b/syft/pkg/cataloger/java/archive_filename.go similarity index 100% rename from syft/cataloger/java/archive_filename.go rename to syft/pkg/cataloger/java/archive_filename.go diff --git a/syft/cataloger/java/archive_filename_test.go b/syft/pkg/cataloger/java/archive_filename_test.go similarity index 100% rename from syft/cataloger/java/archive_filename_test.go rename to syft/pkg/cataloger/java/archive_filename_test.go diff --git a/syft/cataloger/java/archive_parser.go b/syft/pkg/cataloger/java/archive_parser.go similarity index 99% rename from syft/cataloger/java/archive_parser.go rename to syft/pkg/cataloger/java/archive_parser.go index 05446ae08..711ca0d1b 100644 --- a/syft/cataloger/java/archive_parser.go +++ b/syft/pkg/cataloger/java/archive_parser.go @@ -9,8 +9,8 @@ import ( "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/file" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/java/archive_parser_test.go b/syft/pkg/cataloger/java/archive_parser_test.go similarity index 100% rename from syft/cataloger/java/archive_parser_test.go rename to syft/pkg/cataloger/java/archive_parser_test.go diff --git a/syft/cataloger/java/cataloger.go b/syft/pkg/cataloger/java/cataloger.go similarity index 89% rename from syft/cataloger/java/cataloger.go rename to syft/pkg/cataloger/java/cataloger.go index 35d776e93..2285c6474 100644 --- a/syft/cataloger/java/cataloger.go +++ b/syft/pkg/cataloger/java/cataloger.go @@ -4,7 +4,7 @@ Package java provides a concrete Cataloger implementation for Java archives (jar package java import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewJavaCataloger returns a new Java archive cataloger object. diff --git a/syft/cataloger/java/java_manifest.go b/syft/pkg/cataloger/java/java_manifest.go similarity index 100% rename from syft/cataloger/java/java_manifest.go rename to syft/pkg/cataloger/java/java_manifest.go diff --git a/syft/cataloger/java/java_manifest_test.go b/syft/pkg/cataloger/java/java_manifest_test.go similarity index 100% rename from syft/cataloger/java/java_manifest_test.go rename to syft/pkg/cataloger/java/java_manifest_test.go diff --git a/syft/cataloger/java/pom_properties.go b/syft/pkg/cataloger/java/pom_properties.go similarity index 100% rename from syft/cataloger/java/pom_properties.go rename to syft/pkg/cataloger/java/pom_properties.go diff --git a/syft/cataloger/java/pom_properties_test.go b/syft/pkg/cataloger/java/pom_properties_test.go similarity index 100% rename from syft/cataloger/java/pom_properties_test.go rename to syft/pkg/cataloger/java/pom_properties_test.go diff --git a/syft/cataloger/java/save_archive_to_tmp.go b/syft/pkg/cataloger/java/save_archive_to_tmp.go similarity index 100% rename from syft/cataloger/java/save_archive_to_tmp.go rename to syft/pkg/cataloger/java/save_archive_to_tmp.go diff --git a/syft/cataloger/java/test-fixtures/java-builds/.gitignore b/syft/pkg/cataloger/java/test-fixtures/java-builds/.gitignore similarity index 87% rename from syft/cataloger/java/test-fixtures/java-builds/.gitignore rename to syft/pkg/cataloger/java/test-fixtures/java-builds/.gitignore index 1685225cc..b954422b0 100644 --- a/syft/cataloger/java/test-fixtures/java-builds/.gitignore +++ b/syft/pkg/cataloger/java/test-fixtures/java-builds/.gitignore @@ -1,4 +1,4 @@ -/packages/* +/packages/sb *.fingerprint # maven when running in a volume may spit out directories like this **/\?/ diff --git a/syft/cataloger/java/test-fixtures/java-builds/Makefile b/syft/pkg/cataloger/java/test-fixtures/java-builds/Makefile similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/Makefile rename to syft/pkg/cataloger/java/test-fixtures/java-builds/Makefile diff --git a/syft/cataloger/java/test-fixtures/java-builds/build-example-java-app-gradle.sh b/syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-java-app-gradle.sh similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/build-example-java-app-gradle.sh rename to syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-java-app-gradle.sh diff --git a/syft/cataloger/java/test-fixtures/java-builds/build-example-java-app-maven.sh b/syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-java-app-maven.sh similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/build-example-java-app-maven.sh rename to syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-java-app-maven.sh diff --git a/syft/cataloger/java/test-fixtures/java-builds/build-example-jenkins-plugin.sh b/syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-jenkins-plugin.sh similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/build-example-jenkins-plugin.sh rename to syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-jenkins-plugin.sh diff --git a/syft/cataloger/java/test-fixtures/java-builds/build-example-sb-app-nestedjar.sh b/syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-sb-app-nestedjar.sh similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/build-example-sb-app-nestedjar.sh rename to syft/pkg/cataloger/java/test-fixtures/java-builds/build-example-sb-app-nestedjar.sh diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-java-app/.gitignore b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/.gitignore similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-java-app/.gitignore rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/.gitignore diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-java-app/build.gradle b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/build.gradle similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-java-app/build.gradle rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/build.gradle diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-java-app/pom.xml b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/pom.xml similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-java-app/pom.xml rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/pom.xml diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/Greeter.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/Greeter.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/Greeter.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/Greeter.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/HelloWorld.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/HelloWorld.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/HelloWorld.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-java-app/src/main/java/hello/HelloWorld.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/pom.xml b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/pom.xml similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/pom.xml rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/pom.xml diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/java/io/jenkins/plugins/sample/HelloWorldBuilder.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/index.jelly b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/index.jelly similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/index.jelly rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/index.jelly diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.jelly diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config.properties diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/config_fr.properties diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name.html diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_fr.html b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_fr.html similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_fr.html rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-name_fr.html diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench.html diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_fr.html b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_fr.html similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_fr.html rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/HelloWorldBuilder/help-useFrench_fr.html diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages.properties b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages.properties rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages.properties diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages_fr.properties b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages_fr.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages_fr.properties rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-jenkins-plugin/src/main/resources/io/jenkins/plugins/sample/Messages_fr.properties diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/.gitignore b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/.gitignore similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/.gitignore rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/.gitignore diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/pom.xml b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/pom.xml similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/pom.xml rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/pom.xml diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/Application.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/Application.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/Application.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/Application.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/HelloController.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/HelloController.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/HelloController.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/main/java/com/example/springboot/HelloController.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerIT.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerIT.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerIT.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerIT.java diff --git a/syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerTest.java b/syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerTest.java similarity index 100% rename from syft/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerTest.java rename to syft/pkg/cataloger/java/test-fixtures/java-builds/example-sb-app/src/test/java/com/example/springboot/HelloControllerTest.java diff --git a/syft/cataloger/java/test-fixtures/manifest/continuation b/syft/pkg/cataloger/java/test-fixtures/manifest/continuation similarity index 100% rename from syft/cataloger/java/test-fixtures/manifest/continuation rename to syft/pkg/cataloger/java/test-fixtures/manifest/continuation diff --git a/syft/cataloger/java/test-fixtures/manifest/extra-info b/syft/pkg/cataloger/java/test-fixtures/manifest/extra-info similarity index 100% rename from syft/cataloger/java/test-fixtures/manifest/extra-info rename to syft/pkg/cataloger/java/test-fixtures/manifest/extra-info diff --git a/syft/cataloger/java/test-fixtures/manifest/small b/syft/pkg/cataloger/java/test-fixtures/manifest/small similarity index 100% rename from syft/cataloger/java/test-fixtures/manifest/small rename to syft/pkg/cataloger/java/test-fixtures/manifest/small diff --git a/syft/cataloger/java/test-fixtures/manifest/standard-info b/syft/pkg/cataloger/java/test-fixtures/manifest/standard-info similarity index 100% rename from syft/cataloger/java/test-fixtures/manifest/standard-info rename to syft/pkg/cataloger/java/test-fixtures/manifest/standard-info diff --git a/syft/cataloger/java/test-fixtures/manifest/version-with-date b/syft/pkg/cataloger/java/test-fixtures/manifest/version-with-date similarity index 100% rename from syft/cataloger/java/test-fixtures/manifest/version-with-date rename to syft/pkg/cataloger/java/test-fixtures/manifest/version-with-date diff --git a/syft/cataloger/java/test-fixtures/pom/extra.pom.properties b/syft/pkg/cataloger/java/test-fixtures/pom/extra.pom.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/pom/extra.pom.properties rename to syft/pkg/cataloger/java/test-fixtures/pom/extra.pom.properties diff --git a/syft/cataloger/java/test-fixtures/pom/small.pom.properties b/syft/pkg/cataloger/java/test-fixtures/pom/small.pom.properties similarity index 100% rename from syft/cataloger/java/test-fixtures/pom/small.pom.properties rename to syft/pkg/cataloger/java/test-fixtures/pom/small.pom.properties diff --git a/syft/cataloger/javascript/cataloger.go b/syft/pkg/cataloger/javascript/cataloger.go similarity index 94% rename from syft/cataloger/javascript/cataloger.go rename to syft/pkg/cataloger/javascript/cataloger.go index fe709d458..791554a5d 100644 --- a/syft/cataloger/javascript/cataloger.go +++ b/syft/pkg/cataloger/javascript/cataloger.go @@ -4,7 +4,7 @@ Package javascript provides a concrete Cataloger implementation for JavaScript e package javascript import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewJavascriptPackageCataloger returns a new JavaScript cataloger object based on detection of npm based packages. diff --git a/syft/cataloger/javascript/parse_package_json.go b/syft/pkg/cataloger/javascript/parse_package_json.go similarity index 97% rename from syft/cataloger/javascript/parse_package_json.go rename to syft/pkg/cataloger/javascript/parse_package_json.go index 5a4fbadc9..d5ff50142 100644 --- a/syft/cataloger/javascript/parse_package_json.go +++ b/syft/pkg/cataloger/javascript/parse_package_json.go @@ -13,8 +13,8 @@ import ( "github.com/mitchellh/mapstructure" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check @@ -161,7 +161,7 @@ func licensesFromJSON(p PackageJSON) ([]string, error) { return nil, fmt.Errorf("unable to parse license field: %w", err) } -// parsePackageJson parses a package.json and returns the discovered JavaScript packages. +// parsePackageJSON parses a package.json and returns the discovered JavaScript packages. func parsePackageJSON(_ string, reader io.Reader) ([]pkg.Package, error) { packages := make([]pkg.Package, 0) dec := json.NewDecoder(reader) diff --git a/syft/cataloger/javascript/parse_package_json_test.go b/syft/pkg/cataloger/javascript/parse_package_json_test.go similarity index 100% rename from syft/cataloger/javascript/parse_package_json_test.go rename to syft/pkg/cataloger/javascript/parse_package_json_test.go diff --git a/syft/cataloger/javascript/parse_package_lock.go b/syft/pkg/cataloger/javascript/parse_package_lock.go similarity index 96% rename from syft/cataloger/javascript/parse_package_lock.go rename to syft/pkg/cataloger/javascript/parse_package_lock.go index 4018cbf63..c4f3a8f99 100644 --- a/syft/cataloger/javascript/parse_package_lock.go +++ b/syft/pkg/cataloger/javascript/parse_package_lock.go @@ -5,8 +5,8 @@ import ( "fmt" "io" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/javascript/parse_package_lock_test.go b/syft/pkg/cataloger/javascript/parse_package_lock_test.go similarity index 100% rename from syft/cataloger/javascript/parse_package_lock_test.go rename to syft/pkg/cataloger/javascript/parse_package_lock_test.go diff --git a/syft/cataloger/javascript/parse_yarn_lock.go b/syft/pkg/cataloger/javascript/parse_yarn_lock.go similarity index 97% rename from syft/cataloger/javascript/parse_yarn_lock.go rename to syft/pkg/cataloger/javascript/parse_yarn_lock.go index 5e18c5aff..078610d47 100644 --- a/syft/cataloger/javascript/parse_yarn_lock.go +++ b/syft/pkg/cataloger/javascript/parse_yarn_lock.go @@ -8,8 +8,8 @@ import ( "strings" "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/javascript/parse_yarn_lock_test.go b/syft/pkg/cataloger/javascript/parse_yarn_lock_test.go similarity index 100% rename from syft/cataloger/javascript/parse_yarn_lock_test.go rename to syft/pkg/cataloger/javascript/parse_yarn_lock_test.go diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-license-object.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-license-object.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-license-object.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-license-object.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-license-objects.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-license-objects.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-license-objects.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-license-objects.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-nested-author.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-nested-author.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-nested-author.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-nested-author.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-no-license.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-no-license.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-no-license.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-no-license.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-partial.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-partial.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-partial.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-partial.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package-repo-string.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-repo-string.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package-repo-string.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package-repo-string.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-json/package.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-json/package.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-json/package.json diff --git a/syft/cataloger/javascript/test-fixtures/pkg-lock/package-lock.json b/syft/pkg/cataloger/javascript/test-fixtures/pkg-lock/package-lock.json similarity index 100% rename from syft/cataloger/javascript/test-fixtures/pkg-lock/package-lock.json rename to syft/pkg/cataloger/javascript/test-fixtures/pkg-lock/package-lock.json diff --git a/syft/cataloger/javascript/test-fixtures/yarn/yarn.lock b/syft/pkg/cataloger/javascript/test-fixtures/yarn/yarn.lock similarity index 100% rename from syft/cataloger/javascript/test-fixtures/yarn/yarn.lock rename to syft/pkg/cataloger/javascript/test-fixtures/yarn/yarn.lock diff --git a/syft/cataloger/package_url.go b/syft/pkg/cataloger/package_url.go similarity index 100% rename from syft/cataloger/package_url.go rename to syft/pkg/cataloger/package_url.go diff --git a/syft/cataloger/package_url_test.go b/syft/pkg/cataloger/package_url_test.go similarity index 100% rename from syft/cataloger/package_url_test.go rename to syft/pkg/cataloger/package_url_test.go diff --git a/syft/cataloger/python/index_cataloger.go b/syft/pkg/cataloger/python/index_cataloger.go similarity index 92% rename from syft/cataloger/python/index_cataloger.go rename to syft/pkg/cataloger/python/index_cataloger.go index 620892b22..4c821a289 100644 --- a/syft/cataloger/python/index_cataloger.go +++ b/syft/pkg/cataloger/python/index_cataloger.go @@ -4,7 +4,7 @@ Package python provides a concrete Cataloger implementation for Python ecosystem package python import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewPythonIndexCataloger returns a new cataloger for python packages referenced from poetry lock files, requirements.txt files, and setup.py files. diff --git a/syft/cataloger/python/package_cataloger.go b/syft/pkg/cataloger/python/package_cataloger.go similarity index 50% rename from syft/cataloger/python/package_cataloger.go rename to syft/pkg/cataloger/python/package_cataloger.go index af8360792..64540ad7b 100644 --- a/syft/cataloger/python/package_cataloger.go +++ b/syft/pkg/cataloger/python/package_cataloger.go @@ -3,6 +3,7 @@ package python import ( "bufio" "fmt" + "path/filepath" "github.com/anchore/syft/syft/pkg" @@ -28,64 +29,34 @@ func (c *PackageCataloger) Name() string { } // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing python egg and wheel installations. -func (c *PackageCataloger) Catalog(resolver source.Resolver) ([]pkg.Package, error) { - entries, err := c.getPackageEntries(resolver) - if err != nil { - return nil, err +func (c *PackageCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, error) { + // nolint:prealloc + var fileMatches []source.Location + + for _, glob := range []string{eggMetadataGlob, wheelMetadataGlob, eggFileMetadataGlob} { + matches, err := resolver.FilesByGlob(glob) + if err != nil { + return nil, fmt.Errorf("failed to find files by glob: %s", glob) + } + fileMatches = append(fileMatches, matches...) } - var packages []pkg.Package - for _, entry := range entries { - p, err := c.catalogEggOrWheel(entry) + var pkgs []pkg.Package + for _, location := range fileMatches { + p, err := c.catalogEggOrWheel(resolver, location) if err != nil { - return nil, fmt.Errorf("unable to catalog python package=%+v: %w", entry.Metadata.Location.RealPath, err) + return nil, fmt.Errorf("unable to catalog python package=%+v: %w", location.RealPath, err) } if p != nil { - packages = append(packages, *p) + pkgs = append(pkgs, *p) } } - - return packages, nil -} - -// getPackageEntries fetches the contents for all python packages within the given resolver. -func (c *PackageCataloger) getPackageEntries(resolver source.Resolver) ([]*packageEntry, error) { - var metadataLocations []source.Location - - // find all primary record paths - matches, err := resolver.FilesByGlob(eggMetadataGlob, eggFileMetadataGlob, wheelMetadataGlob) - if err != nil { - return nil, fmt.Errorf("failed to find files by glob: %w", err) - } - metadataLocations = append(metadataLocations, matches...) - - // for every primary record path, craft all secondary record paths and build a request object to gather all file contents for each record - requester := source.NewContentRequester() - entries := make([]*packageEntry, len(metadataLocations)) - for i, metadataLocation := range metadataLocations { - // build the entry to process (holding only path information) - entry := newPackageEntry(resolver, metadataLocation) - - // populate the data onto the requester object - requester.Add(&entry.Metadata) - if entry.FileRecord != nil { - requester.Add(entry.FileRecord) - } - if entry.TopPackage != nil { - requester.Add(entry.TopPackage) - } - - // keep track of the entry for later package processing - entries[i] = entry - } - - // return the set of entries and execute the request for fetching contents - return entries, requester.Execute(resolver) + return pkgs, nil } // catalogEggOrWheel takes the primary metadata file reference and returns the python package it represents. -func (c *PackageCataloger) catalogEggOrWheel(entry *packageEntry) (*pkg.Package, error) { - metadata, sources, err := c.assembleEggOrWheelMetadata(entry) +func (c *PackageCataloger) catalogEggOrWheel(resolver source.FileResolver, metadataLocation source.Location) (*pkg.Package, error) { + metadata, sources, err := c.assembleEggOrWheelMetadata(resolver, metadataLocation) if err != nil { return nil, err } @@ -114,45 +85,26 @@ func (c *PackageCataloger) catalogEggOrWheel(entry *packageEntry) (*pkg.Package, }, nil } -// assembleEggOrWheelMetadata discovers and accumulates python package metadata from multiple file sources and returns a single metadata object as well as a list of files where the metadata was derived from. -func (c *PackageCataloger) assembleEggOrWheelMetadata(entry *packageEntry) (*pkg.PythonPackageMetadata, []source.Location, error) { - var sources = []source.Location{entry.Metadata.Location} - - metadata, err := parseWheelOrEggMetadata(entry.Metadata.Location.RealPath, entry.Metadata.Contents) - if err != nil { - return nil, nil, err - } - - // attach any python files found for the given wheel/egg installation - r, s, err := c.processRecordFiles(entry.FileRecord) - if err != nil { - return nil, nil, err - } - sources = append(sources, s...) - metadata.Files = r - - // attach any top-level package names found for the given wheel/egg installation - p, s, err := c.processTopLevelPackages(entry.TopPackage) - if err != nil { - return nil, nil, err - } - sources = append(sources, s...) - metadata.TopLevelPackages = p - - return &metadata, sources, nil -} - -// processRecordFiles takes a corresponding RECORD file for the given python package metadata file and returns the set of file records contained. -func (c *PackageCataloger) processRecordFiles(entry *source.FileData) (files []pkg.PythonFileRecord, sources []source.Location, err error) { +// fetchRecordFiles finds a corresponding RECORD file for the given python package metadata file and returns the set of file records contained. +func (c *PackageCataloger) fetchRecordFiles(resolver source.FileResolver, metadataLocation source.Location) (files []pkg.PythonFileRecord, sources []source.Location, err error) { // we've been given a file reference to a specific wheel METADATA file. note: this may be for a directory // or for an image... for an image the METADATA file may be present within multiple layers, so it is important // to reconcile the RECORD path to the same layer (or the next adjacent lower layer). - if entry != nil { - sources = append(sources, entry.Location) + // lets find the RECORD file relative to the directory where the METADATA file resides (in path AND layer structure) + recordPath := filepath.Join(filepath.Dir(metadataLocation.RealPath), "RECORD") + recordRef := resolver.RelativeFileByPath(metadataLocation, recordPath) + + if recordRef != nil { + sources = append(sources, *recordRef) + + recordContents, err := resolver.FileContentsByLocation(*recordRef) + if err != nil { + return nil, nil, err + } // parse the record contents - records, err := parseWheelOrEggRecord(entry.Contents) + records, err := parseWheelOrEggRecord(recordContents) if err != nil { return nil, nil, err } @@ -162,15 +114,25 @@ func (c *PackageCataloger) processRecordFiles(entry *source.FileData) (files []p return files, sources, nil } -// processTopLevelPackages takes a corresponding top_level.txt file for the given python package metadata file and returns the set of package names contained. -func (c *PackageCataloger) processTopLevelPackages(entry *source.FileData) (pkgs []string, sources []source.Location, err error) { - if entry == nil { +// fetchTopLevelPackages finds a corresponding top_level.txt file for the given python package metadata file and returns the set of package names contained. +func (c *PackageCataloger) fetchTopLevelPackages(resolver source.FileResolver, metadataLocation source.Location) (pkgs []string, sources []source.Location, err error) { + // a top_level.txt file specifies the python top-level packages (provided by this python package) installed into site-packages + parentDir := filepath.Dir(metadataLocation.RealPath) + topLevelPath := filepath.Join(parentDir, "top_level.txt") + topLevelLocation := resolver.RelativeFileByPath(metadataLocation, topLevelPath) + + if topLevelLocation == nil { return nil, nil, nil } - sources = append(sources, entry.Location) + sources = append(sources, *topLevelLocation) - scanner := bufio.NewScanner(entry.Contents) + topLevelContents, err := resolver.FileContentsByLocation(*topLevelLocation) + if err != nil { + return nil, nil, err + } + + scanner := bufio.NewScanner(topLevelContents) for scanner.Scan() { pkgs = append(pkgs, scanner.Text()) } @@ -181,3 +143,36 @@ func (c *PackageCataloger) processTopLevelPackages(entry *source.FileData) (pkgs return pkgs, sources, nil } + +// assembleEggOrWheelMetadata discovers and accumulates python package metadata from multiple file sources and returns a single metadata object as well as a list of files where the metadata was derived from. +func (c *PackageCataloger) assembleEggOrWheelMetadata(resolver source.FileResolver, metadataLocation source.Location) (*pkg.PythonPackageMetadata, []source.Location, error) { + var sources = []source.Location{metadataLocation} + + metadataContents, err := resolver.FileContentsByLocation(metadataLocation) + if err != nil { + return nil, nil, err + } + + metadata, err := parseWheelOrEggMetadata(metadataLocation.RealPath, metadataContents) + if err != nil { + return nil, nil, err + } + + // attach any python files found for the given wheel/egg installation + r, s, err := c.fetchRecordFiles(resolver, metadataLocation) + if err != nil { + return nil, nil, err + } + sources = append(sources, s...) + metadata.Files = r + + // attach any top-level package names found for the given wheel/egg installation + p, s, err := c.fetchTopLevelPackages(resolver, metadataLocation) + if err != nil { + return nil, nil, err + } + sources = append(sources, s...) + metadata.TopLevelPackages = p + + return &metadata, sources, nil +} diff --git a/syft/cataloger/python/package_cataloger_test.go b/syft/pkg/cataloger/python/package_cataloger_test.go similarity index 100% rename from syft/cataloger/python/package_cataloger_test.go rename to syft/pkg/cataloger/python/package_cataloger_test.go diff --git a/syft/cataloger/python/parse_poetry_lock.go b/syft/pkg/cataloger/python/parse_poetry_lock.go similarity index 92% rename from syft/cataloger/python/parse_poetry_lock.go rename to syft/pkg/cataloger/python/parse_poetry_lock.go index 6b08098a4..b6981a1b0 100644 --- a/syft/cataloger/python/parse_poetry_lock.go +++ b/syft/pkg/cataloger/python/parse_poetry_lock.go @@ -4,8 +4,8 @@ import ( "fmt" "io" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" "github.com/pelletier/go-toml" ) diff --git a/syft/cataloger/python/parse_poetry_lock_test.go b/syft/pkg/cataloger/python/parse_poetry_lock_test.go similarity index 100% rename from syft/cataloger/python/parse_poetry_lock_test.go rename to syft/pkg/cataloger/python/parse_poetry_lock_test.go diff --git a/syft/cataloger/python/parse_requirements.go b/syft/pkg/cataloger/python/parse_requirements.go similarity index 97% rename from syft/cataloger/python/parse_requirements.go rename to syft/pkg/cataloger/python/parse_requirements.go index 27ec43cc8..b206224dd 100644 --- a/syft/cataloger/python/parse_requirements.go +++ b/syft/pkg/cataloger/python/parse_requirements.go @@ -6,8 +6,8 @@ import ( "io" "strings" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/python/parse_requirements_test.go b/syft/pkg/cataloger/python/parse_requirements_test.go similarity index 100% rename from syft/cataloger/python/parse_requirements_test.go rename to syft/pkg/cataloger/python/parse_requirements_test.go diff --git a/syft/cataloger/python/parse_setup.go b/syft/pkg/cataloger/python/parse_setup.go similarity index 95% rename from syft/cataloger/python/parse_setup.go rename to syft/pkg/cataloger/python/parse_setup.go index 337c436e7..e1b0c39ce 100644 --- a/syft/cataloger/python/parse_setup.go +++ b/syft/pkg/cataloger/python/parse_setup.go @@ -6,8 +6,8 @@ import ( "regexp" "strings" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/python/parse_setup_test.go b/syft/pkg/cataloger/python/parse_setup_test.go similarity index 100% rename from syft/cataloger/python/parse_setup_test.go rename to syft/pkg/cataloger/python/parse_setup_test.go diff --git a/syft/cataloger/python/parse_wheel_egg_metadata.go b/syft/pkg/cataloger/python/parse_wheel_egg_metadata.go similarity index 100% rename from syft/cataloger/python/parse_wheel_egg_metadata.go rename to syft/pkg/cataloger/python/parse_wheel_egg_metadata.go diff --git a/syft/cataloger/python/parse_wheel_egg_metadata_test.go b/syft/pkg/cataloger/python/parse_wheel_egg_metadata_test.go similarity index 100% rename from syft/cataloger/python/parse_wheel_egg_metadata_test.go rename to syft/pkg/cataloger/python/parse_wheel_egg_metadata_test.go diff --git a/syft/cataloger/python/parse_wheel_egg_record.go b/syft/pkg/cataloger/python/parse_wheel_egg_record.go similarity index 100% rename from syft/cataloger/python/parse_wheel_egg_record.go rename to syft/pkg/cataloger/python/parse_wheel_egg_record.go diff --git a/syft/cataloger/python/parse_wheel_egg_record_test.go b/syft/pkg/cataloger/python/parse_wheel_egg_record_test.go similarity index 100% rename from syft/cataloger/python/parse_wheel_egg_record_test.go rename to syft/pkg/cataloger/python/parse_wheel_egg_record_test.go diff --git a/syft/cataloger/python/poetry_metadata.go b/syft/pkg/cataloger/python/poetry_metadata.go similarity index 100% rename from syft/cataloger/python/poetry_metadata.go rename to syft/pkg/cataloger/python/poetry_metadata.go diff --git a/syft/cataloger/python/poetry_metadata_package.go b/syft/pkg/cataloger/python/poetry_metadata_package.go similarity index 100% rename from syft/cataloger/python/poetry_metadata_package.go rename to syft/pkg/cataloger/python/poetry_metadata_package.go diff --git a/syft/cataloger/python/test-fixtures/Python-2.7.egg-info b/syft/pkg/cataloger/python/test-fixtures/Python-2.7.egg-info similarity index 100% rename from syft/cataloger/python/test-fixtures/Python-2.7.egg-info rename to syft/pkg/cataloger/python/test-fixtures/Python-2.7.egg-info diff --git a/syft/cataloger/python/test-fixtures/dist-info/METADATA b/syft/pkg/cataloger/python/test-fixtures/dist-info/METADATA similarity index 100% rename from syft/cataloger/python/test-fixtures/dist-info/METADATA rename to syft/pkg/cataloger/python/test-fixtures/dist-info/METADATA diff --git a/syft/cataloger/python/test-fixtures/dist-info/RECORD b/syft/pkg/cataloger/python/test-fixtures/dist-info/RECORD similarity index 100% rename from syft/cataloger/python/test-fixtures/dist-info/RECORD rename to syft/pkg/cataloger/python/test-fixtures/dist-info/RECORD diff --git a/syft/cataloger/python/test-fixtures/dist-info/top_level.txt b/syft/pkg/cataloger/python/test-fixtures/dist-info/top_level.txt similarity index 100% rename from syft/cataloger/python/test-fixtures/dist-info/top_level.txt rename to syft/pkg/cataloger/python/test-fixtures/dist-info/top_level.txt diff --git a/syft/cataloger/python/test-fixtures/egg-info/PKG-INFO b/syft/pkg/cataloger/python/test-fixtures/egg-info/PKG-INFO similarity index 100% rename from syft/cataloger/python/test-fixtures/egg-info/PKG-INFO rename to syft/pkg/cataloger/python/test-fixtures/egg-info/PKG-INFO diff --git a/syft/cataloger/python/test-fixtures/egg-info/PKG-INFO-INVALID b/syft/pkg/cataloger/python/test-fixtures/egg-info/PKG-INFO-INVALID similarity index 100% rename from syft/cataloger/python/test-fixtures/egg-info/PKG-INFO-INVALID rename to syft/pkg/cataloger/python/test-fixtures/egg-info/PKG-INFO-INVALID diff --git a/syft/cataloger/python/test-fixtures/egg-info/RECORD b/syft/pkg/cataloger/python/test-fixtures/egg-info/RECORD similarity index 100% rename from syft/cataloger/python/test-fixtures/egg-info/RECORD rename to syft/pkg/cataloger/python/test-fixtures/egg-info/RECORD diff --git a/syft/cataloger/python/test-fixtures/egg-info/top_level.txt b/syft/pkg/cataloger/python/test-fixtures/egg-info/top_level.txt similarity index 100% rename from syft/cataloger/python/test-fixtures/egg-info/top_level.txt rename to syft/pkg/cataloger/python/test-fixtures/egg-info/top_level.txt diff --git a/syft/cataloger/python/test-fixtures/partial.dist-info/METADATA b/syft/pkg/cataloger/python/test-fixtures/partial.dist-info/METADATA similarity index 100% rename from syft/cataloger/python/test-fixtures/partial.dist-info/METADATA rename to syft/pkg/cataloger/python/test-fixtures/partial.dist-info/METADATA diff --git a/syft/cataloger/python/test-fixtures/poetry/poetry.lock b/syft/pkg/cataloger/python/test-fixtures/poetry/poetry.lock similarity index 100% rename from syft/cataloger/python/test-fixtures/poetry/poetry.lock rename to syft/pkg/cataloger/python/test-fixtures/poetry/poetry.lock diff --git a/syft/cataloger/python/test-fixtures/requires/requirements.txt b/syft/pkg/cataloger/python/test-fixtures/requires/requirements.txt similarity index 100% rename from syft/cataloger/python/test-fixtures/requires/requirements.txt rename to syft/pkg/cataloger/python/test-fixtures/requires/requirements.txt diff --git a/syft/cataloger/python/test-fixtures/setup/setup.py b/syft/pkg/cataloger/python/test-fixtures/setup/setup.py similarity index 100% rename from syft/cataloger/python/test-fixtures/setup/setup.py rename to syft/pkg/cataloger/python/test-fixtures/setup/setup.py diff --git a/syft/cataloger/python/test-fixtures/test.egg-info b/syft/pkg/cataloger/python/test-fixtures/test.egg-info similarity index 100% rename from syft/cataloger/python/test-fixtures/test.egg-info rename to syft/pkg/cataloger/python/test-fixtures/test.egg-info diff --git a/syft/cataloger/rpmdb/cataloger.go b/syft/pkg/cataloger/rpmdb/cataloger.go similarity index 93% rename from syft/cataloger/rpmdb/cataloger.go rename to syft/pkg/cataloger/rpmdb/cataloger.go index 6f7a93288..eca4c60c7 100644 --- a/syft/cataloger/rpmdb/cataloger.go +++ b/syft/pkg/cataloger/rpmdb/cataloger.go @@ -25,7 +25,7 @@ func (c *Cataloger) Name() string { } // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation. -func (c *Cataloger) Catalog(resolver source.Resolver) ([]pkg.Package, error) { +func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, error) { fileMatches, err := resolver.FilesByGlob(pkg.RpmDbGlob) if err != nil { return nil, fmt.Errorf("failed to find rpmdb's by glob: %w", err) diff --git a/syft/cataloger/rpmdb/parse_rpmdb.go b/syft/pkg/cataloger/rpmdb/parse_rpmdb.go similarity index 90% rename from syft/cataloger/rpmdb/parse_rpmdb.go rename to syft/pkg/cataloger/rpmdb/parse_rpmdb.go index f67a123e7..103de4f5f 100644 --- a/syft/cataloger/rpmdb/parse_rpmdb.go +++ b/syft/pkg/cataloger/rpmdb/parse_rpmdb.go @@ -14,7 +14,7 @@ import ( ) // parseApkDb parses an "Packages" RPM DB and returns the Packages listed within it. -func parseRpmDB(resolver source.FileResolver, dbLocation source.Location, reader io.Reader) ([]pkg.Package, error) { +func parseRpmDB(resolver source.FilePathResolver, dbLocation source.Location, reader io.Reader) ([]pkg.Package, error) { f, err := ioutil.TempFile("", internal.ApplicationName+"-rpmdb") if err != nil { return nil, fmt.Errorf("failed to create temp rpmdb file: %w", err) @@ -72,7 +72,7 @@ func parseRpmDB(resolver source.FileResolver, dbLocation source.Location, reader return allPkgs, nil } -func extractRpmdbFileRecords(resolver source.FileResolver, entry *rpmdb.PackageInfo) []pkg.RpmdbFileRecord { +func extractRpmdbFileRecords(resolver source.FilePathResolver, entry *rpmdb.PackageInfo) []pkg.RpmdbFileRecord { var records = make([]pkg.RpmdbFileRecord, 0) for _, record := range entry.Files { diff --git a/syft/cataloger/rpmdb/parse_rpmdb_test.go b/syft/pkg/cataloger/rpmdb/parse_rpmdb_test.go similarity index 100% rename from syft/cataloger/rpmdb/parse_rpmdb_test.go rename to syft/pkg/cataloger/rpmdb/parse_rpmdb_test.go diff --git a/syft/cataloger/rpmdb/test-fixtures/Packages b/syft/pkg/cataloger/rpmdb/test-fixtures/Packages similarity index 100% rename from syft/cataloger/rpmdb/test-fixtures/Packages rename to syft/pkg/cataloger/rpmdb/test-fixtures/Packages diff --git a/syft/cataloger/rpmdb/test-fixtures/generate-fixture.sh b/syft/pkg/cataloger/rpmdb/test-fixtures/generate-fixture.sh similarity index 100% rename from syft/cataloger/rpmdb/test-fixtures/generate-fixture.sh rename to syft/pkg/cataloger/rpmdb/test-fixtures/generate-fixture.sh diff --git a/syft/cataloger/ruby/catalogers.go b/syft/pkg/cataloger/ruby/catalogers.go similarity index 94% rename from syft/cataloger/ruby/catalogers.go rename to syft/pkg/cataloger/ruby/catalogers.go index e9d9b7cec..6e7499fce 100644 --- a/syft/cataloger/ruby/catalogers.go +++ b/syft/pkg/cataloger/ruby/catalogers.go @@ -4,7 +4,7 @@ Package bundler provides a concrete Cataloger implementation for Ruby Gemfile.lo package ruby import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewGemFileLockCataloger returns a new Bundler cataloger object tailored for parsing index-oriented files (e.g. Gemfile.lock). diff --git a/syft/cataloger/ruby/parse_gemfile_lock.go b/syft/pkg/cataloger/ruby/parse_gemfile_lock.go similarity index 96% rename from syft/cataloger/ruby/parse_gemfile_lock.go rename to syft/pkg/cataloger/ruby/parse_gemfile_lock.go index 23a4a7756..b27b3ba66 100644 --- a/syft/cataloger/ruby/parse_gemfile_lock.go +++ b/syft/pkg/cataloger/ruby/parse_gemfile_lock.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/anchore/syft/internal" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/ruby/parse_gemfile_lock_test.go b/syft/pkg/cataloger/ruby/parse_gemfile_lock_test.go similarity index 100% rename from syft/cataloger/ruby/parse_gemfile_lock_test.go rename to syft/pkg/cataloger/ruby/parse_gemfile_lock_test.go diff --git a/syft/cataloger/ruby/parse_gemspec.go b/syft/pkg/cataloger/ruby/parse_gemspec.go similarity index 98% rename from syft/cataloger/ruby/parse_gemspec.go rename to syft/pkg/cataloger/ruby/parse_gemspec.go index 239d2a4eb..d2fd0ba60 100644 --- a/syft/cataloger/ruby/parse_gemspec.go +++ b/syft/pkg/cataloger/ruby/parse_gemspec.go @@ -12,8 +12,8 @@ import ( "github.com/mitchellh/mapstructure" - "github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // integrity check diff --git a/syft/cataloger/ruby/parse_gemspec_test.go b/syft/pkg/cataloger/ruby/parse_gemspec_test.go similarity index 100% rename from syft/cataloger/ruby/parse_gemspec_test.go rename to syft/pkg/cataloger/ruby/parse_gemspec_test.go diff --git a/syft/cataloger/ruby/test-fixtures/Gemfile.lock b/syft/pkg/cataloger/ruby/test-fixtures/Gemfile.lock similarity index 100% rename from syft/cataloger/ruby/test-fixtures/Gemfile.lock rename to syft/pkg/cataloger/ruby/test-fixtures/Gemfile.lock diff --git a/syft/cataloger/ruby/test-fixtures/bundler.gemspec b/syft/pkg/cataloger/ruby/test-fixtures/bundler.gemspec similarity index 100% rename from syft/cataloger/ruby/test-fixtures/bundler.gemspec rename to syft/pkg/cataloger/ruby/test-fixtures/bundler.gemspec diff --git a/syft/cataloger/rust/cargo_metadata.go b/syft/pkg/cataloger/rust/cargo_metadata.go similarity index 100% rename from syft/cataloger/rust/cargo_metadata.go rename to syft/pkg/cataloger/rust/cargo_metadata.go diff --git a/syft/cataloger/rust/cataloger.go b/syft/pkg/cataloger/rust/cataloger.go similarity index 88% rename from syft/cataloger/rust/cataloger.go rename to syft/pkg/cataloger/rust/cataloger.go index bd2625c5d..df0f9ee40 100644 --- a/syft/cataloger/rust/cataloger.go +++ b/syft/pkg/cataloger/rust/cataloger.go @@ -4,7 +4,7 @@ Package rust provides a concrete Cataloger implementation for Cargo.lock files. package rust import ( - "github.com/anchore/syft/syft/cataloger/common" + "github.com/anchore/syft/syft/pkg/cataloger/common" ) // NewCargoLockCataloger returns a new Rust Cargo lock file cataloger object. diff --git a/syft/cataloger/rust/parse_cargo_lock.go b/syft/pkg/cataloger/rust/parse_cargo_lock.go similarity index 100% rename from syft/cataloger/rust/parse_cargo_lock.go rename to syft/pkg/cataloger/rust/parse_cargo_lock.go diff --git a/syft/cataloger/rust/parse_cargo_lock_test.go b/syft/pkg/cataloger/rust/parse_cargo_lock_test.go similarity index 100% rename from syft/cataloger/rust/parse_cargo_lock_test.go rename to syft/pkg/cataloger/rust/parse_cargo_lock_test.go diff --git a/syft/cataloger/rust/test-fixtures/Cargo.lock b/syft/pkg/cataloger/rust/test-fixtures/Cargo.lock similarity index 100% rename from syft/cataloger/rust/test-fixtures/Cargo.lock rename to syft/pkg/cataloger/rust/test-fixtures/Cargo.lock From ff4ed40d509e9a7cf121b1e5e1d21c6fdead9a9f Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:49:08 -0400 Subject: [PATCH 02/29] migrate syft/presenter to internal/presenter Signed-off-by: Alex Goodman --- .../packages/cyclonedx_bom_descriptor.go | 69 +++++++++++ .../presenter/packages/cyclonedx_component.go | 27 +++++ .../presenter/packages/cyclonedx_document.go | 57 +++++++++ .../presenter/packages/cyclonedx_presenter.go | 16 +-- .../packages/cyclonedx_presenter_test.go | 11 +- .../presenter/packages/json_distribution.go | 14 +-- internal/presenter/packages/json_document.go | 62 ++++++++++ internal/presenter/packages/json_package.go | 68 +++++++++++ internal/presenter/packages/json_presenter.go | 43 +++++++ .../presenter/packages/json_presenter_test.go | 20 ++-- .../presenter/packages/json_relationship.go | 10 +- internal/presenter/packages/json_source.go | 39 ++++++ internal/presenter/packages/presenter.go | 25 ++++ .../presenter/packages/presenter_config.go | 14 +++ .../presenter/packages/presenter_option.go | 35 ++++++ .../presenter/packages/table_presenter.go | 12 +- .../packages/table_presenter_test.go | 11 +- .../test-fixtures/image-simple/Dockerfile | 0 .../test-fixtures/image-simple/file-1.txt | 0 .../test-fixtures/image-simple/file-2.txt | 0 .../TestCycloneDxDirsPresenter.golden | 0 .../TestCycloneDxImgsPresenter.golden | 0 .../snapshot/TestTablePresenter.golden | 0 .../snapshot/TestTextDirPresenter.golden | 0 .../snapshot/TestTextImgPresenter.golden | 0 .../snapshot/TestTextPresenter.golden | 0 .../presenter/packages/text_presenter.go | 14 +-- .../presenter/packages/text_presenter_test.go | 17 ++- internal/presenter/poweruser/json_document.go | 32 +++++ .../poweruser/json_document_config.go | 18 +++ .../presenter/poweruser/json_file_metadata.go | 50 ++++++++ .../presenter/poweruser/json_presenter.go | 32 +++++ internal/presenter/presenter.go | 9 ++ syft/presenter/cyclonedx/bom-descriptor.go | 69 ----------- syft/presenter/cyclonedx/component.go | 27 ----- syft/presenter/cyclonedx/document.go | 57 --------- .../test-fixtures/image-simple/Dockerfile | 6 - .../target/really/nested/file-3.txt | 2 - syft/presenter/json/descriptor.go | 7 -- syft/presenter/json/document.go | 54 --------- syft/presenter/json/presenter.go | 40 ------- syft/presenter/json/schema.go | 6 - syft/presenter/json/source.go | 75 ------------ .../test-fixtures/image-simple/Dockerfile | 6 - .../test-fixtures/image-simple/file-1.txt | 1 - .../test-fixtures/image-simple/file-2.txt | 1 - .../target/really/nested/file-3.txt | 2 - .../snapshot/TestJsonDirsPresenter.golden | 81 ------------- .../snapshot/TestJsonImgsPresenter.golden | 112 ------------------ .../stereoscope-fixture-image-simple.golden | Bin 23552 -> 0 bytes syft/presenter/option.go | 35 ------ syft/presenter/presenter.go | 41 ------- .../test-fixtures/image-simple/Dockerfile | 6 - .../test-fixtures/image-simple/file-1.txt | 1 - .../test-fixtures/image-simple/file-2.txt | 1 - .../target/really/nested/file-3.txt | 2 - .../test-fixtures/image-simple/file-1.txt | 1 - .../test-fixtures/image-simple/file-2.txt | 1 - .../snapshot/TestJsonPresenter.golden | 1 - 59 files changed, 641 insertions(+), 699 deletions(-) create mode 100644 internal/presenter/packages/cyclonedx_bom_descriptor.go create mode 100644 internal/presenter/packages/cyclonedx_component.go create mode 100644 internal/presenter/packages/cyclonedx_document.go rename syft/presenter/cyclonedx/presenter.go => internal/presenter/packages/cyclonedx_presenter.go (57%) rename syft/presenter/cyclonedx/presenter_test.go => internal/presenter/packages/cyclonedx_presenter_test.go (93%) rename syft/presenter/json/distribution.go => internal/presenter/packages/json_distribution.go (54%) create mode 100644 internal/presenter/packages/json_document.go create mode 100644 internal/presenter/packages/json_package.go create mode 100644 internal/presenter/packages/json_presenter.go rename syft/presenter/json/presenter_test.go => internal/presenter/packages/json_presenter_test.go (89%) rename syft/presenter/json/relationship.go => internal/presenter/packages/json_relationship.go (63%) create mode 100644 internal/presenter/packages/json_source.go create mode 100644 internal/presenter/packages/presenter.go create mode 100644 internal/presenter/packages/presenter_config.go create mode 100644 internal/presenter/packages/presenter_option.go rename syft/presenter/table/presenter.go => internal/presenter/packages/table_presenter.go (86%) rename syft/presenter/table/presenter_test.go => internal/presenter/packages/table_presenter_test.go (87%) rename {syft/presenter/text => internal/presenter/packages}/test-fixtures/image-simple/Dockerfile (100%) rename {syft/presenter/cyclonedx => internal/presenter/packages}/test-fixtures/image-simple/file-1.txt (100%) rename {syft/presenter/cyclonedx => internal/presenter/packages}/test-fixtures/image-simple/file-2.txt (100%) rename {syft/presenter/cyclonedx => internal/presenter/packages}/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden (100%) rename {syft/presenter/cyclonedx => internal/presenter/packages}/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden (100%) rename {syft/presenter/table => internal/presenter/packages}/test-fixtures/snapshot/TestTablePresenter.golden (100%) rename {syft/presenter/text => internal/presenter/packages}/test-fixtures/snapshot/TestTextDirPresenter.golden (100%) rename {syft/presenter/text => internal/presenter/packages}/test-fixtures/snapshot/TestTextImgPresenter.golden (100%) rename {syft/presenter/text => internal/presenter/packages}/test-fixtures/snapshot/TestTextPresenter.golden (100%) rename syft/presenter/text/presenter.go => internal/presenter/packages/text_presenter.go (77%) rename syft/presenter/text/presenter_test.go => internal/presenter/packages/text_presenter_test.go (86%) create mode 100644 internal/presenter/poweruser/json_document.go create mode 100644 internal/presenter/poweruser/json_document_config.go create mode 100644 internal/presenter/poweruser/json_file_metadata.go create mode 100644 internal/presenter/poweruser/json_presenter.go create mode 100644 internal/presenter/presenter.go delete mode 100644 syft/presenter/cyclonedx/bom-descriptor.go delete mode 100644 syft/presenter/cyclonedx/component.go delete mode 100644 syft/presenter/cyclonedx/document.go delete mode 100644 syft/presenter/cyclonedx/test-fixtures/image-simple/Dockerfile delete mode 100644 syft/presenter/cyclonedx/test-fixtures/image-simple/target/really/nested/file-3.txt delete mode 100644 syft/presenter/json/descriptor.go delete mode 100644 syft/presenter/json/document.go delete mode 100644 syft/presenter/json/presenter.go delete mode 100644 syft/presenter/json/schema.go delete mode 100644 syft/presenter/json/source.go delete mode 100644 syft/presenter/json/test-fixtures/image-simple/Dockerfile delete mode 100644 syft/presenter/json/test-fixtures/image-simple/file-1.txt delete mode 100644 syft/presenter/json/test-fixtures/image-simple/file-2.txt delete mode 100644 syft/presenter/json/test-fixtures/image-simple/target/really/nested/file-3.txt delete mode 100644 syft/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden delete mode 100644 syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden delete mode 100644 syft/presenter/json/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden delete mode 100644 syft/presenter/option.go delete mode 100644 syft/presenter/presenter.go delete mode 100644 syft/presenter/table/test-fixtures/image-simple/Dockerfile delete mode 100644 syft/presenter/table/test-fixtures/image-simple/file-1.txt delete mode 100644 syft/presenter/table/test-fixtures/image-simple/file-2.txt delete mode 100644 syft/presenter/table/test-fixtures/image-simple/target/really/nested/file-3.txt delete mode 100644 syft/presenter/text/test-fixtures/image-simple/file-1.txt delete mode 100644 syft/presenter/text/test-fixtures/image-simple/file-2.txt delete mode 100644 syft/presenter/text/test-fixtures/snapshot/TestJsonPresenter.golden diff --git a/internal/presenter/packages/cyclonedx_bom_descriptor.go b/internal/presenter/packages/cyclonedx_bom_descriptor.go new file mode 100644 index 000000000..eeaac61f7 --- /dev/null +++ b/internal/presenter/packages/cyclonedx_bom_descriptor.go @@ -0,0 +1,69 @@ +package packages + +import ( + "encoding/xml" + "time" + + "github.com/anchore/syft/syft/source" +) + +// Source: https://cyclonedx.org/ext/bom-descriptor/ + +// CycloneDxBomDescriptor represents all metadata surrounding the BOM report (such as when the BOM was made, with which tool, and the item being cataloged). +type CycloneDxBomDescriptor struct { + XMLName xml.Name `xml:"metadata"` + Timestamp string `xml:"timestamp,omitempty"` // The date and time (timestamp) when the document was created + Tools []CycloneDxBdTool `xml:"tools>tool"` // The tool used to create the BOM. + Component *CycloneDxBdComponent `xml:"component"` // The component that the BOM describes. +} + +// CycloneDxBdTool represents the tool that created the BOM report. +type CycloneDxBdTool struct { + XMLName xml.Name `xml:"tool"` + Vendor string `xml:"vendor,omitempty"` // The vendor of the tool used to create the BOM. + Name string `xml:"name,omitempty"` // The name of the tool used to create the BOM. + Version string `xml:"version,omitempty"` // The version of the tool used to create the BOM. + // TODO: hashes, author, manufacture, supplier + // TODO: add user-defined fields for the remaining build/version parameters +} + +// CycloneDxBdComponent represents the software/package being cataloged. +type CycloneDxBdComponent struct { + XMLName xml.Name `xml:"component"` + CycloneDxComponent +} + +// NewCycloneDxBomDescriptor returns a new CycloneDxBomDescriptor tailored for the current time and "syft" tool details. +func NewCycloneDxBomDescriptor(name, version string, srcMetadata source.Metadata) *CycloneDxBomDescriptor { + descriptor := CycloneDxBomDescriptor{ + XMLName: xml.Name{}, + Timestamp: time.Now().Format(time.RFC3339), + Tools: []CycloneDxBdTool{ + { + Vendor: "anchore", + Name: name, + Version: version, + }, + }, + } + + switch srcMetadata.Scheme { + case source.ImageScheme: + descriptor.Component = &CycloneDxBdComponent{ + CycloneDxComponent: CycloneDxComponent{ + Type: "container", + Name: srcMetadata.ImageMetadata.UserInput, + Version: srcMetadata.ImageMetadata.ManifestDigest, + }, + } + case source.DirectoryScheme: + descriptor.Component = &CycloneDxBdComponent{ + CycloneDxComponent: CycloneDxComponent{ + Type: "file", + Name: srcMetadata.Path, + }, + } + } + + return &descriptor +} diff --git a/internal/presenter/packages/cyclonedx_component.go b/internal/presenter/packages/cyclonedx_component.go new file mode 100644 index 000000000..9ff1877dd --- /dev/null +++ b/internal/presenter/packages/cyclonedx_component.go @@ -0,0 +1,27 @@ +package packages + +import "encoding/xml" + +// CycloneDxComponent represents a single element in the CycloneDX BOM +type CycloneDxComponent struct { + XMLName xml.Name `xml:"component"` + Type string `xml:"type,attr"` // Required; Describes if the component is a library, framework, application, container, operating system, firmware, hardware device, or file + Supplier string `xml:"supplier,omitempty"` // The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager. + Author string `xml:"author,omitempty"` // The person(s) or organization(s) that authored the component + Publisher string `xml:"publisher,omitempty"` // The person(s) or organization(s) that published the component + Group string `xml:"group,omitempty"` // The high-level classification that a project self-describes as. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. + Name string `xml:"name"` // Required; The name of the component as defined by the project + Version string `xml:"version"` // Required; The version of the component as defined by the project + Description string `xml:"description,omitempty"` // A description of the component + Licenses *[]CycloneDxLicense `xml:"licenses>license"` // A node describing zero or more license names, SPDX license IDs or expressions + PackageURL string `xml:"purl,omitempty"` // Specifies the package-url (PackageURL). The purl, if specified, must be valid and conform to the specification defined at: https://github.com/package-url/purl-spec + // TODO: source, hashes, copyright, cpe, purl, swid, modified, pedigree, externalReferences + // TODO: add user-defined parameters for syft-specific values (image layer index, cataloger, location path, etc.) +} + +// CycloneDxLicense represents a single software license for a CycloneDxComponent +type CycloneDxLicense struct { + XMLName xml.Name `xml:"license"` + ID string `xml:"id,omitempty"` // A valid SPDX license ID + Name string `xml:"name,omitempty"` // If SPDX does not define the license used, this field may be used to provide the license name +} diff --git a/internal/presenter/packages/cyclonedx_document.go b/internal/presenter/packages/cyclonedx_document.go new file mode 100644 index 000000000..9278dc6d1 --- /dev/null +++ b/internal/presenter/packages/cyclonedx_document.go @@ -0,0 +1,57 @@ +package packages + +import ( + "encoding/xml" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/version" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" + "github.com/google/uuid" +) + +// Source: https://github.com/CycloneDX/specification + +// CycloneDxDocument represents a CycloneDX BOM CycloneDxDocument. +type CycloneDxDocument struct { + XMLName xml.Name `xml:"bom"` + XMLNs string `xml:"xmlns,attr"` + Version int `xml:"version,attr"` + SerialNumber string `xml:"serialNumber,attr"` + BomDescriptor *CycloneDxBomDescriptor `xml:"metadata"` // The BOM descriptor extension + Components []CycloneDxComponent `xml:"components>component"` // The BOM contents +} + +// NewCycloneDxDocument returns a CycloneDX CycloneDxDocument object populated with the catalog contents. +func NewCycloneDxDocument(catalog *pkg.Catalog, srcMetadata source.Metadata) CycloneDxDocument { + versionInfo := version.FromBuild() + + doc := CycloneDxDocument{ + XMLNs: "http://cyclonedx.org/schema/bom/1.2", + Version: 1, + SerialNumber: uuid.New().URN(), + BomDescriptor: NewCycloneDxBomDescriptor(internal.ApplicationName, versionInfo.Version, srcMetadata), + } + + // attach components + for p := range catalog.Enumerate() { + component := CycloneDxComponent{ + Type: "library", // TODO: this is not accurate + Name: p.Name, + Version: p.Version, + PackageURL: p.PURL, + } + var licenses []CycloneDxLicense + for _, licenseName := range p.Licenses { + licenses = append(licenses, CycloneDxLicense{ + Name: licenseName, + }) + } + if len(licenses) > 0 { + component.Licenses = &licenses + } + doc.Components = append(doc.Components, component) + } + + return doc +} diff --git a/syft/presenter/cyclonedx/presenter.go b/internal/presenter/packages/cyclonedx_presenter.go similarity index 57% rename from syft/presenter/cyclonedx/presenter.go rename to internal/presenter/packages/cyclonedx_presenter.go index 1c044c56c..f844fbf02 100644 --- a/syft/presenter/cyclonedx/presenter.go +++ b/internal/presenter/packages/cyclonedx_presenter.go @@ -1,7 +1,7 @@ /* Package cyclonedx is responsible for generating a CycloneDX XML report for the given container image or file system. */ -package cyclonedx +package packages import ( "encoding/xml" @@ -11,23 +11,23 @@ import ( "github.com/anchore/syft/syft/source" ) -// Presenter writes a CycloneDX report from the given Catalog and Locations contents -type Presenter struct { +// CycloneDxPresenter writes a CycloneDX report from the given Catalog and Locations contents +type CycloneDxPresenter struct { catalog *pkg.Catalog srcMetadata source.Metadata } -// NewPresenter creates a CycloneDX presenter from the given Catalog and Locations objects. -func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *Presenter { - return &Presenter{ +// NewCycloneDxPresenter creates a CycloneDX presenter from the given Catalog and Locations objects. +func NewCycloneDxPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *CycloneDxPresenter { + return &CycloneDxPresenter{ catalog: catalog, srcMetadata: srcMetadata, } } // Present writes the CycloneDX report to the given io.Writer. -func (pres *Presenter) Present(output io.Writer) error { - bom := NewDocument(pres.catalog, pres.srcMetadata) +func (pres *CycloneDxPresenter) Present(output io.Writer) error { + bom := NewCycloneDxDocument(pres.catalog, pres.srcMetadata) encoder := xml.NewEncoder(output) encoder.Indent("", " ") diff --git a/syft/presenter/cyclonedx/presenter_test.go b/internal/presenter/packages/cyclonedx_presenter_test.go similarity index 93% rename from syft/presenter/cyclonedx/presenter_test.go rename to internal/presenter/packages/cyclonedx_presenter_test.go index 9ef9cbb24..46d3364f4 100644 --- a/syft/presenter/cyclonedx/presenter_test.go +++ b/internal/presenter/packages/cyclonedx_presenter_test.go @@ -1,4 +1,4 @@ -package cyclonedx +package packages import ( "bytes" @@ -62,7 +62,7 @@ func TestCycloneDxDirsPresenter(t *testing.T) { t.Fatal(err) } - pres := NewPresenter(catalog, s.Metadata) + pres := NewCycloneDxPresenter(catalog, s.Metadata) // run presenter err = pres.Present(&buffer) @@ -93,8 +93,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) { var buffer bytes.Buffer catalog := pkg.NewCatalog() - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-simple") _, ref1, _ := img.SquashedTree().File("/somefile-1.txt", filetree.FollowBasenameLinks) _, ref2, _ := img.SquashedTree().File("/somefile-2.txt", filetree.FollowBasenameLinks) @@ -125,7 +124,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) { PURL: "the-purl-2", }) - s, err := source.NewFromImage(img, source.SquashedScope, "user-image-input") + s, err := source.NewFromImage(img, "user-image-input") if err != nil { t.Fatal(err) } @@ -138,7 +137,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) { // This value is sourced from the "version" node in "./test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden" s.Metadata.ImageMetadata.ManifestDigest = "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368" - pres := NewPresenter(catalog, s.Metadata) + pres := NewCycloneDxPresenter(catalog, s.Metadata) // run presenter err = pres.Present(&buffer) diff --git a/syft/presenter/json/distribution.go b/internal/presenter/packages/json_distribution.go similarity index 54% rename from syft/presenter/json/distribution.go rename to internal/presenter/packages/json_distribution.go index 07eb5ba23..5ba939c03 100644 --- a/syft/presenter/json/distribution.go +++ b/internal/presenter/packages/json_distribution.go @@ -1,21 +1,21 @@ -package json +package packages import "github.com/anchore/syft/syft/distro" -// Distribution provides information about a detected Linux Distribution. -type Distribution struct { +// JSONDistribution provides information about a detected Linux JSONDistribution. +type JSONDistribution struct { Name string `json:"name"` // Name of the Linux distribution Version string `json:"version"` // Version of the Linux distribution (major or major.minor version) IDLike string `json:"idLike"` // the ID_LIKE field found within the /etc/os-release file } -// NewDistribution creates a struct with the Linux distribution to be represented in JSON. -func NewDistribution(d *distro.Distro) Distribution { +// NewJSONDistribution creates a struct with the Linux distribution to be represented in JSON. +func NewJSONDistribution(d *distro.Distro) JSONDistribution { if d == nil { - return Distribution{} + return JSONDistribution{} } - return Distribution{ + return JSONDistribution{ Name: d.Name(), Version: d.FullVersion(), IDLike: d.IDLike, diff --git a/internal/presenter/packages/json_document.go b/internal/presenter/packages/json_document.go new file mode 100644 index 000000000..399d037ae --- /dev/null +++ b/internal/presenter/packages/json_document.go @@ -0,0 +1,62 @@ +package packages + +import ( + "fmt" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/version" + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +// JSONDocument represents the syft cataloging findings as a JSON document +type JSONDocument struct { + Artifacts []JSONPackage `json:"artifacts"` // Artifacts is the list of packages discovered and placed into the catalog + ArtifactRelationships []JSONRelationship `json:"artifactRelationships"` + Source JSONSource `json:"source"` // Source represents the original object that was cataloged + Distro JSONDistribution `json:"distro"` // Distro represents the Linux distribution that was detected from the source + Descriptor JSONDescriptor `json:"descriptor"` // Descriptor is a block containing self-describing information about syft + Schema JSONSchema `json:"schema"` // Schema is a block reserved for defining the version for the shape of this JSON document and where to find the schema document to validate the shape +} + +// NewJSONDocument creates and populates a new JSON document struct from the given cataloging results. +func NewJSONDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d *distro.Distro, scope source.Scope, configuration interface{}) (JSONDocument, error) { + src, err := NewJSONSource(srcMetadata, scope) + if err != nil { + return JSONDocument{}, err + } + + artifacts, err := NewJSONPackages(catalog) + if err != nil { + return JSONDocument{}, err + } + + return JSONDocument{ + Artifacts: artifacts, + ArtifactRelationships: newJSONRelationships(pkg.NewRelationships(catalog)), + Source: src, + Distro: NewJSONDistribution(d), + Descriptor: JSONDescriptor{ + Name: internal.ApplicationName, + Version: version.FromBuild().Version, + Configuration: configuration, + }, + Schema: JSONSchema{ + Version: internal.JSONSchemaVersion, + URL: fmt.Sprintf("https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-%s.json", internal.JSONSchemaVersion), + }, + }, nil +} + +// JSONDescriptor describes what created the document as well as surrounding metadata +type JSONDescriptor struct { + Name string `json:"name"` + Version string `json:"version"` + Configuration interface{} `json:"configuration,omitempty"` +} + +type JSONSchema struct { + Version string `json:"version"` + URL string `json:"url"` +} diff --git a/internal/presenter/packages/json_package.go b/internal/presenter/packages/json_package.go new file mode 100644 index 000000000..c3be8ff1f --- /dev/null +++ b/internal/presenter/packages/json_package.go @@ -0,0 +1,68 @@ +package packages + +import ( + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +// JSONPackage represents a pkg.Package object specialized for JSON marshaling and unmarshaling. +type JSONPackage struct { + ID string `json:"id"` + Name string `json:"name"` + Version string `json:"version"` + Type string `json:"type"` + FoundBy string `json:"foundBy"` + Locations []source.Location `json:"locations"` + Licenses []string `json:"licenses"` + Language string `json:"language"` + CPEs []string `json:"cpes"` + PURL string `json:"purl"` + MetadataType string `json:"metadataType"` + Metadata interface{} `json:"metadata"` +} + +func NewJSONPackages(catalog *pkg.Catalog) ([]JSONPackage, error) { + artifacts := make([]JSONPackage, 0) + for _, p := range catalog.Sorted() { + art, err := NewJSONPackage(p) + if err != nil { + return nil, err + } + artifacts = append(artifacts, art) + } + return artifacts, nil +} + +// NewJSONPackage crates a new JSONPackage from the given pkg.Package. +func NewJSONPackage(p *pkg.Package) (JSONPackage, error) { + var cpes = make([]string, len(p.CPEs)) + for i, c := range p.CPEs { + cpes[i] = c.BindToFmtString() + } + + // ensure collections are never nil for presentation reasons + var locations = make([]source.Location, 0) + if p.Locations != nil { + locations = p.Locations + } + + var licenses = make([]string, 0) + if p.Licenses != nil { + licenses = p.Licenses + } + + return JSONPackage{ + ID: string(p.ID), + Name: p.Name, + Version: p.Version, + Type: string(p.Type), + FoundBy: p.FoundBy, + Locations: locations, + Licenses: licenses, + Language: string(p.Language), + CPEs: cpes, + PURL: p.PURL, + MetadataType: string(p.MetadataType), + Metadata: p.Metadata, + }, nil +} diff --git a/internal/presenter/packages/json_presenter.go b/internal/presenter/packages/json_presenter.go new file mode 100644 index 000000000..cbdc4d107 --- /dev/null +++ b/internal/presenter/packages/json_presenter.go @@ -0,0 +1,43 @@ +package packages + +import ( + "encoding/json" + "io" + + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +// JSONPresenter is a JSON presentation object for the syft results +type JSONPresenter struct { + catalog *pkg.Catalog + srcMetadata source.Metadata + distro *distro.Distro + scope source.Scope +} + +// NewJSONPresenter creates a new JSON presenter object for the given cataloging results. +func NewJSONPresenter(catalog *pkg.Catalog, s source.Metadata, d *distro.Distro, scope source.Scope) *JSONPresenter { + return &JSONPresenter{ + catalog: catalog, + srcMetadata: s, + distro: d, + scope: scope, + } +} + +// Present the catalog results to the given writer. +func (pres *JSONPresenter) Present(output io.Writer) error { + // we do not pass in configuration for backwards compatibility + doc, err := NewJSONDocument(pres.catalog, pres.srcMetadata, pres.distro, pres.scope, nil) + if err != nil { + return err + } + + enc := json.NewEncoder(output) + // prevent > and < from being escaped in the payload + enc.SetEscapeHTML(false) + enc.SetIndent("", " ") + return enc.Encode(&doc) +} diff --git a/syft/presenter/json/presenter_test.go b/internal/presenter/packages/json_presenter_test.go similarity index 89% rename from syft/presenter/json/presenter_test.go rename to internal/presenter/packages/json_presenter_test.go index f76215c93..582efdbe0 100644 --- a/syft/presenter/json/presenter_test.go +++ b/internal/presenter/packages/json_presenter_test.go @@ -1,4 +1,4 @@ -package json +package packages import ( "bytes" @@ -15,7 +15,7 @@ import ( "github.com/sergi/go-diff/diffmatchpatch" ) -var update = flag.Bool("update", false, "update the *.golden files for json presenters") +var updateJSONGoldenFiles = flag.Bool("update-json", false, "update the *.golden files for json presenters") func must(c pkg.CPE, e error) pkg.CPE { if e != nil { @@ -24,7 +24,7 @@ func must(c pkg.CPE, e error) pkg.CPE { return c } -func TestJsonDirsPresenter(t *testing.T) { +func TestJSONDirsPresenter(t *testing.T) { var buffer bytes.Buffer catalog := pkg.NewCatalog() @@ -75,7 +75,7 @@ func TestJsonDirsPresenter(t *testing.T) { if err != nil { t.Fatal(err) } - pres := NewPresenter(catalog, s.Metadata, d) + pres := NewJSONPresenter(catalog, s.Metadata, d, source.SquashedScope) // run presenter err = pres.Present(&buffer) @@ -84,7 +84,7 @@ func TestJsonDirsPresenter(t *testing.T) { } actual := buffer.Bytes() - if *update { + if *updateJSONGoldenFiles { testutils.UpdateGoldenFileContents(t, actual) } @@ -98,12 +98,12 @@ func TestJsonDirsPresenter(t *testing.T) { } -func TestJsonImgsPresenter(t *testing.T) { +func TestJSONImgsPresenter(t *testing.T) { var buffer bytes.Buffer testImage := "image-simple" - if *update { + if *updateJSONGoldenFiles { imagetest.UpdateGoldenFixtureImage(t, testImage) } @@ -158,9 +158,9 @@ func TestJsonImgsPresenter(t *testing.T) { // this is a hard coded value that is not given by the fixture helper and must be provided manually img.Metadata.ManifestDigest = "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368" - s, err := source.NewFromImage(img, source.SquashedScope, "user-image-input") + s, err := source.NewFromImage(img, "user-image-input") var d *distro.Distro - pres := NewPresenter(catalog, s.Metadata, d) + pres := NewJSONPresenter(catalog, s.Metadata, d, source.SquashedScope) // run presenter err = pres.Present(&buffer) @@ -169,7 +169,7 @@ func TestJsonImgsPresenter(t *testing.T) { } actual := buffer.Bytes() - if *update { + if *updateJSONGoldenFiles { testutils.UpdateGoldenFileContents(t, actual) } diff --git a/syft/presenter/json/relationship.go b/internal/presenter/packages/json_relationship.go similarity index 63% rename from syft/presenter/json/relationship.go rename to internal/presenter/packages/json_relationship.go index 25eee2a3c..326e4a4a5 100644 --- a/syft/presenter/json/relationship.go +++ b/internal/presenter/packages/json_relationship.go @@ -1,18 +1,18 @@ -package json +package packages import "github.com/anchore/syft/syft/pkg" -type Relationship struct { +type JSONRelationship struct { Parent string `json:"parent"` Child string `json:"child"` Type string `json:"type"` Metadata interface{} `json:"metadata"` } -func newRelationships(relationships []pkg.Relationship) []Relationship { - result := make([]Relationship, len(relationships)) +func newJSONRelationships(relationships []pkg.Relationship) []JSONRelationship { + result := make([]JSONRelationship, len(relationships)) for i, r := range relationships { - result[i] = Relationship{ + result[i] = JSONRelationship{ Parent: string(r.Parent), Child: string(r.Child), Type: string(r.Type), diff --git a/internal/presenter/packages/json_source.go b/internal/presenter/packages/json_source.go new file mode 100644 index 000000000..d0c2a477f --- /dev/null +++ b/internal/presenter/packages/json_source.go @@ -0,0 +1,39 @@ +package packages + +import ( + "fmt" + + "github.com/anchore/syft/syft/source" +) + +// JSONSource object represents the thing that was cataloged +type JSONSource struct { + Type string `json:"type"` + Target interface{} `json:"target"` +} + +type JSONImageSource struct { + source.ImageMetadata + Scope source.Scope `json:"scope"` +} + +// NewJSONSource creates a new source object to be represented into JSON. +func NewJSONSource(src source.Metadata, scope source.Scope) (JSONSource, error) { + switch src.Scheme { + case source.ImageScheme: + return JSONSource{ + Type: "image", + Target: JSONImageSource{ + Scope: scope, + ImageMetadata: src.ImageMetadata, + }, + }, nil + case source.DirectoryScheme: + return JSONSource{ + Type: "directory", + Target: src.Path, + }, nil + default: + return JSONSource{}, fmt.Errorf("unsupported source: %q", src.Scheme) + } +} diff --git a/internal/presenter/packages/presenter.go b/internal/presenter/packages/presenter.go new file mode 100644 index 000000000..c73763b5c --- /dev/null +++ b/internal/presenter/packages/presenter.go @@ -0,0 +1,25 @@ +/* +Defines a Presenter interface for displaying catalog results to an io.Writer as well as a helper utility to obtain +a specific Presenter implementation given user configuration. +*/ +package packages + +import ( + "github.com/anchore/syft/internal/presenter" +) + +// Presenter returns a presenter for images or directories +func Presenter(option PresenterOption, config PresenterConfig) presenter.Presenter { + switch option { + case JSONPresenterOption: + return NewJSONPresenter(config.Catalog, config.SourceMetadata, config.Distro, config.Scope) + case TextPresenterOption: + return NewTextPresenter(config.Catalog, config.SourceMetadata) + case TablePresenterOption: + return NewTablePresenter(config.Catalog) + case CycloneDxPresenterOption: + return NewCycloneDxPresenter(config.Catalog, config.SourceMetadata) + default: + return nil + } +} diff --git a/internal/presenter/packages/presenter_config.go b/internal/presenter/packages/presenter_config.go new file mode 100644 index 000000000..d318e4288 --- /dev/null +++ b/internal/presenter/packages/presenter_config.go @@ -0,0 +1,14 @@ +package packages + +import ( + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +type PresenterConfig struct { + SourceMetadata source.Metadata + Catalog *pkg.Catalog + Distro *distro.Distro + Scope source.Scope +} diff --git a/internal/presenter/packages/presenter_option.go b/internal/presenter/packages/presenter_option.go new file mode 100644 index 000000000..9bfe1f6f2 --- /dev/null +++ b/internal/presenter/packages/presenter_option.go @@ -0,0 +1,35 @@ +package packages + +import "strings" + +const ( + UnknownPresenterOption PresenterOption = "UnknownPresenterOption" + JSONPresenterOption PresenterOption = "json" + TextPresenterOption PresenterOption = "text" + TablePresenterOption PresenterOption = "table" + CycloneDxPresenterOption PresenterOption = "cyclonedx" +) + +var AllPresenters = []PresenterOption{ + JSONPresenterOption, + TextPresenterOption, + TablePresenterOption, + CycloneDxPresenterOption, +} + +type PresenterOption string + +func ParsePresenterOption(userStr string) PresenterOption { + switch strings.ToLower(userStr) { + case string(JSONPresenterOption): + return JSONPresenterOption + case string(TextPresenterOption): + return TextPresenterOption + case string(TablePresenterOption): + return TablePresenterOption + case string(CycloneDxPresenterOption), "cyclone", "cyclone-dx": + return CycloneDxPresenterOption + default: + return UnknownPresenterOption + } +} diff --git a/syft/presenter/table/presenter.go b/internal/presenter/packages/table_presenter.go similarity index 86% rename from syft/presenter/table/presenter.go rename to internal/presenter/packages/table_presenter.go index c7303e8a5..c3313996e 100644 --- a/syft/presenter/table/presenter.go +++ b/internal/presenter/packages/table_presenter.go @@ -1,4 +1,4 @@ -package table +package packages import ( "fmt" @@ -11,17 +11,17 @@ import ( "github.com/anchore/syft/syft/pkg" ) -type Presenter struct { +type TablePresenter struct { catalog *pkg.Catalog } -func NewPresenter(catalog *pkg.Catalog) *Presenter { - return &Presenter{ +func NewTablePresenter(catalog *pkg.Catalog) *TablePresenter { + return &TablePresenter{ catalog: catalog, } } -func (pres *Presenter) Present(output io.Writer) error { +func (pres *TablePresenter) Present(output io.Writer) error { rows := make([][]string, 0) columns := []string{"Name", "Version", "Type"} @@ -42,7 +42,7 @@ func (pres *Presenter) Present(output io.Writer) error { // sort by name, version, then type sort.SliceStable(rows, func(i, j int) bool { for col := 0; col < len(columns); col++ { - if rows[i][0] != rows[j][0] { + if rows[i][col] != rows[j][col] { return rows[i][col] < rows[j][col] } } diff --git a/syft/presenter/table/presenter_test.go b/internal/presenter/packages/table_presenter_test.go similarity index 87% rename from syft/presenter/table/presenter_test.go rename to internal/presenter/packages/table_presenter_test.go index fb120494b..54e1db38e 100644 --- a/syft/presenter/table/presenter_test.go +++ b/internal/presenter/packages/table_presenter_test.go @@ -1,4 +1,4 @@ -package table +package packages import ( "bytes" @@ -16,7 +16,7 @@ import ( "github.com/sergi/go-diff/diffmatchpatch" ) -var update = flag.Bool("update", false, "update the *.golden files for table presenters") +var updateTablePresenterGoldenFiles = flag.Bool("update-table", false, "update the *.golden files for table presenters") func TestTablePresenter(t *testing.T) { var buffer bytes.Buffer @@ -24,8 +24,7 @@ func TestTablePresenter(t *testing.T) { testImage := "image-simple" catalog := pkg.NewCatalog() - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", testImage) - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", testImage) _, ref1, _ := img.SquashedTree().File("/somefile-1.txt", filetree.FollowBasenameLinks) _, ref2, _ := img.SquashedTree().File("/somefile-2.txt", filetree.FollowBasenameLinks) @@ -48,7 +47,7 @@ func TestTablePresenter(t *testing.T) { Type: pkg.DebPkg, }) - pres := NewPresenter(catalog) + pres := NewTablePresenter(catalog) // run presenter err := pres.Present(&buffer) @@ -57,7 +56,7 @@ func TestTablePresenter(t *testing.T) { } actual := buffer.Bytes() - if *update { + if *updateTablePresenterGoldenFiles { testutils.UpdateGoldenFileContents(t, actual) } diff --git a/syft/presenter/text/test-fixtures/image-simple/Dockerfile b/internal/presenter/packages/test-fixtures/image-simple/Dockerfile similarity index 100% rename from syft/presenter/text/test-fixtures/image-simple/Dockerfile rename to internal/presenter/packages/test-fixtures/image-simple/Dockerfile diff --git a/syft/presenter/cyclonedx/test-fixtures/image-simple/file-1.txt b/internal/presenter/packages/test-fixtures/image-simple/file-1.txt similarity index 100% rename from syft/presenter/cyclonedx/test-fixtures/image-simple/file-1.txt rename to internal/presenter/packages/test-fixtures/image-simple/file-1.txt diff --git a/syft/presenter/cyclonedx/test-fixtures/image-simple/file-2.txt b/internal/presenter/packages/test-fixtures/image-simple/file-2.txt similarity index 100% rename from syft/presenter/cyclonedx/test-fixtures/image-simple/file-2.txt rename to internal/presenter/packages/test-fixtures/image-simple/file-2.txt diff --git a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden similarity index 100% rename from syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestCycloneDxDirsPresenter.golden diff --git a/syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden similarity index 100% rename from syft/presenter/cyclonedx/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden diff --git a/syft/presenter/table/test-fixtures/snapshot/TestTablePresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestTablePresenter.golden similarity index 100% rename from syft/presenter/table/test-fixtures/snapshot/TestTablePresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestTablePresenter.golden diff --git a/syft/presenter/text/test-fixtures/snapshot/TestTextDirPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestTextDirPresenter.golden similarity index 100% rename from syft/presenter/text/test-fixtures/snapshot/TestTextDirPresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestTextDirPresenter.golden diff --git a/syft/presenter/text/test-fixtures/snapshot/TestTextImgPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestTextImgPresenter.golden similarity index 100% rename from syft/presenter/text/test-fixtures/snapshot/TestTextImgPresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestTextImgPresenter.golden diff --git a/syft/presenter/text/test-fixtures/snapshot/TestTextPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestTextPresenter.golden similarity index 100% rename from syft/presenter/text/test-fixtures/snapshot/TestTextPresenter.golden rename to internal/presenter/packages/test-fixtures/snapshot/TestTextPresenter.golden diff --git a/syft/presenter/text/presenter.go b/internal/presenter/packages/text_presenter.go similarity index 77% rename from syft/presenter/text/presenter.go rename to internal/presenter/packages/text_presenter.go index 8e86fea47..44127da64 100644 --- a/syft/presenter/text/presenter.go +++ b/internal/presenter/packages/text_presenter.go @@ -1,4 +1,4 @@ -package text +package packages import ( "fmt" @@ -10,22 +10,22 @@ import ( "github.com/anchore/syft/syft/source" ) -// Presenter is a human-friendly text presenter to represent package and source data. -type Presenter struct { +// TextPresenter is a human-friendly text presenter to represent package and source data. +type TextPresenter struct { catalog *pkg.Catalog srcMetadata source.Metadata } -// NewPresenter creates a new presenter for the given set of catalog and image data. -func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *Presenter { - return &Presenter{ +// NewTextPresenter creates a new presenter for the given set of catalog and image data. +func NewTextPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *TextPresenter { + return &TextPresenter{ catalog: catalog, srcMetadata: srcMetadata, } } // Present is a method that is in charge of writing to an output buffer -func (pres *Presenter) Present(output io.Writer) error { +func (pres *TextPresenter) Present(output io.Writer) error { // init the tabular writer w := new(tabwriter.Writer) w.Init(output, 0, 8, 0, '\t', tabwriter.AlignRight) diff --git a/syft/presenter/text/presenter_test.go b/internal/presenter/packages/text_presenter_test.go similarity index 86% rename from syft/presenter/text/presenter_test.go rename to internal/presenter/packages/text_presenter_test.go index ccac4b3d9..3633149cb 100644 --- a/syft/presenter/text/presenter_test.go +++ b/internal/presenter/packages/text_presenter_test.go @@ -1,4 +1,4 @@ -package text +package packages import ( "bytes" @@ -14,7 +14,7 @@ import ( "github.com/sergi/go-diff/diffmatchpatch" ) -var update = flag.Bool("update", false, "update the *.golden files for text presenters") +var updateTextPresenterGoldenFiles = flag.Bool("update-text", false, "update the *.golden files for text presenters") func TestTextDirPresenter(t *testing.T) { var buffer bytes.Buffer @@ -37,7 +37,7 @@ func TestTextDirPresenter(t *testing.T) { if err != nil { t.Fatalf("unable to create source: %+v", err) } - pres := NewPresenter(catalog, s.Metadata) + pres := NewTextPresenter(catalog, s.Metadata) // run presenter err = pres.Present(&buffer) @@ -46,7 +46,7 @@ func TestTextDirPresenter(t *testing.T) { } actual := buffer.Bytes() - if *update { + if *updateTextPresenterGoldenFiles { testutils.UpdateGoldenFileContents(t, actual) } @@ -69,8 +69,7 @@ func TestTextImgPresenter(t *testing.T) { var buffer bytes.Buffer catalog := pkg.NewCatalog() - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-simple") _, ref1, _ := img.SquashedTree().File("/somefile-1.txt", filetree.FollowBasenameLinks) _, ref2, _ := img.SquashedTree().File("/somefile-2.txt", filetree.FollowBasenameLinks) @@ -102,18 +101,18 @@ func TestTextImgPresenter(t *testing.T) { l.Metadata.Digest = "sha256:ad8ecdc058976c07e7e347cb89fa9ad86a294b5ceaae6d09713fb035f84115abf3c4a2388a4af3aa60f13b94f4c6846930bdf53" } - s, err := source.NewFromImage(img, source.SquashedScope, "user-image-input") + s, err := source.NewFromImage(img, "user-image-input") if err != nil { t.Fatal(err) } - pres := NewPresenter(catalog, s.Metadata) + pres := NewTextPresenter(catalog, s.Metadata) // run presenter err = pres.Present(&buffer) if err != nil { t.Fatal(err) } actual := buffer.Bytes() - if *update { + if *updateTextPresenterGoldenFiles { testutils.UpdateGoldenFileContents(t, actual) } diff --git a/internal/presenter/poweruser/json_document.go b/internal/presenter/poweruser/json_document.go new file mode 100644 index 000000000..d59b38c93 --- /dev/null +++ b/internal/presenter/poweruser/json_document.go @@ -0,0 +1,32 @@ +package poweruser + +import ( + "github.com/anchore/syft/internal/presenter/packages" +) + +type JSONDocument struct { + // note: poweruser.JSONDocument is meant to always be a superset of packages.JSONDocument, any additional fields + // here should be optional by supplying "omitempty" on these fields hint to the jsonschema generator to not + // require these fields. As an accepted rule in this repo all collections should still be initialized in the + // context of being used in a JSON document. + FileMetadata []JSONFileMetadata `json:"fileMetadata,omitempty"` + packages.JSONDocument +} + +// NewJSONDocument creates and populates a new JSON document struct from the given cataloging results. +func NewJSONDocument(config JSONDocumentConfig) (JSONDocument, error) { + pkgsDoc, err := packages.NewJSONDocument(config.PackageCatalog, config.SourceMetadata, config.Distro, config.ApplicationConfig.Packages.ScopeOpt, config.ApplicationConfig) + if err != nil { + return JSONDocument{}, err + } + + fileMetadata, err := NewJSONFileMetadata(config.FileMetadata, config.FileDigests) + if err != nil { + return JSONDocument{}, err + } + + return JSONDocument{ + FileMetadata: fileMetadata, + JSONDocument: pkgsDoc, + }, nil +} diff --git a/internal/presenter/poweruser/json_document_config.go b/internal/presenter/poweruser/json_document_config.go new file mode 100644 index 000000000..fc2f053da --- /dev/null +++ b/internal/presenter/poweruser/json_document_config.go @@ -0,0 +1,18 @@ +package poweruser + +import ( + "github.com/anchore/syft/internal/config" + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +type JSONDocumentConfig struct { + ApplicationConfig config.Application + PackageCatalog *pkg.Catalog + FileMetadata map[source.Location]source.FileMetadata + FileDigests map[source.Location][]file.Digest + Distro *distro.Distro + SourceMetadata source.Metadata +} diff --git a/internal/presenter/poweruser/json_file_metadata.go b/internal/presenter/poweruser/json_file_metadata.go new file mode 100644 index 000000000..368525a91 --- /dev/null +++ b/internal/presenter/poweruser/json_file_metadata.go @@ -0,0 +1,50 @@ +package poweruser + +import ( + "fmt" + "strconv" + + "github.com/anchore/syft/syft/file" + + "github.com/anchore/syft/syft/source" +) + +type JSONFileMetadata struct { + Location source.Location `json:"location"` + Metadata JSONFileMetadataEntry `json:"metadata"` +} + +type JSONFileMetadataEntry struct { + Mode int `json:"mode"` + Type source.FileType `json:"type"` + UserID int `json:"userID"` + GroupID int `json:"groupID"` + Digests []file.Digest `json:"digests"` +} + +func NewJSONFileMetadata(data map[source.Location]source.FileMetadata, digests map[source.Location][]file.Digest) ([]JSONFileMetadata, error) { + results := make([]JSONFileMetadata, 0) + for location, metadata := range data { + mode, err := strconv.Atoi(fmt.Sprintf("%o", metadata.Mode)) + if err != nil { + return nil, fmt.Errorf("invalid mode found in file catalog @ location=%+v mode=%q: %w", location, metadata.Mode, err) + } + + digestResults := make([]file.Digest, 0) + if digestsForLocation, exists := digests[location]; exists { + digestResults = digestsForLocation + } + + results = append(results, JSONFileMetadata{ + Location: location, + Metadata: JSONFileMetadataEntry{ + Mode: mode, + Type: metadata.Type, + UserID: metadata.UserID, + GroupID: metadata.GroupID, + Digests: digestResults, + }, + }) + } + return results, nil +} diff --git a/internal/presenter/poweruser/json_presenter.go b/internal/presenter/poweruser/json_presenter.go new file mode 100644 index 000000000..9432693f3 --- /dev/null +++ b/internal/presenter/poweruser/json_presenter.go @@ -0,0 +1,32 @@ +package poweruser + +import ( + "encoding/json" + "io" +) + +// JSONPresenter is a JSON presentation object for the syft results +type JSONPresenter struct { + config JSONDocumentConfig +} + +// NewJSONPresenter creates a new JSON presenter object for the given cataloging results. +func NewJSONPresenter(config JSONDocumentConfig) *JSONPresenter { + return &JSONPresenter{ + config: config, + } +} + +// Present the PackageCatalog results to the given writer. +func (p *JSONPresenter) Present(output io.Writer) error { + doc, err := NewJSONDocument(p.config) + if err != nil { + return err + } + + enc := json.NewEncoder(output) + // prevent > and < from being escaped in the payload + enc.SetEscapeHTML(false) + enc.SetIndent("", " ") + return enc.Encode(&doc) +} diff --git a/internal/presenter/presenter.go b/internal/presenter/presenter.go new file mode 100644 index 000000000..823a2e38d --- /dev/null +++ b/internal/presenter/presenter.go @@ -0,0 +1,9 @@ +package presenter + +import "io" + +// Presenter defines the expected behavior for an object responsible for displaying arbitrary input and processed data +// to a given io.Writer. +type Presenter interface { + Present(io.Writer) error +} diff --git a/syft/presenter/cyclonedx/bom-descriptor.go b/syft/presenter/cyclonedx/bom-descriptor.go deleted file mode 100644 index a9a3301dd..000000000 --- a/syft/presenter/cyclonedx/bom-descriptor.go +++ /dev/null @@ -1,69 +0,0 @@ -package cyclonedx - -import ( - "encoding/xml" - "time" - - "github.com/anchore/syft/syft/source" -) - -// Source: https://cyclonedx.org/ext/bom-descriptor/ - -// BomDescriptor represents all metadata surrounding the BOM report (such as when the BOM was made, with which tool, and the item being cataloged). -type BomDescriptor struct { - XMLName xml.Name `xml:"metadata"` - Timestamp string `xml:"timestamp,omitempty"` // The date and time (timestamp) when the document was created - Tools []BdTool `xml:"tools>tool"` // The tool used to create the BOM. - Component *BdComponent `xml:"component"` // The component that the BOM describes. -} - -// BdTool represents the tool that created the BOM report. -type BdTool struct { - XMLName xml.Name `xml:"tool"` - Vendor string `xml:"vendor,omitempty"` // The vendor of the tool used to create the BOM. - Name string `xml:"name,omitempty"` // The name of the tool used to create the BOM. - Version string `xml:"version,omitempty"` // The version of the tool used to create the BOM. - // TODO: hashes, author, manufacture, supplier - // TODO: add user-defined fields for the remaining build/version parameters -} - -// BdComponent represents the software/package being cataloged. -type BdComponent struct { - XMLName xml.Name `xml:"component"` - Component -} - -// NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details. -func NewBomDescriptor(name, version string, srcMetadata source.Metadata) *BomDescriptor { - descriptor := BomDescriptor{ - XMLName: xml.Name{}, - Timestamp: time.Now().Format(time.RFC3339), - Tools: []BdTool{ - { - Vendor: "anchore", - Name: name, - Version: version, - }, - }, - } - - switch srcMetadata.Scheme { - case source.ImageScheme: - descriptor.Component = &BdComponent{ - Component: Component{ - Type: "container", - Name: srcMetadata.ImageMetadata.UserInput, - Version: srcMetadata.ImageMetadata.ManifestDigest, - }, - } - case source.DirectoryScheme: - descriptor.Component = &BdComponent{ - Component: Component{ - Type: "file", - Name: srcMetadata.Path, - }, - } - } - - return &descriptor -} diff --git a/syft/presenter/cyclonedx/component.go b/syft/presenter/cyclonedx/component.go deleted file mode 100644 index e540ef9ea..000000000 --- a/syft/presenter/cyclonedx/component.go +++ /dev/null @@ -1,27 +0,0 @@ -package cyclonedx - -import "encoding/xml" - -// Component represents a single element in the CycloneDX BOM -type Component struct { - XMLName xml.Name `xml:"component"` - Type string `xml:"type,attr"` // Required; Describes if the component is a library, framework, application, container, operating system, firmware, hardware device, or file - Supplier string `xml:"supplier,omitempty"` // The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager. - Author string `xml:"author,omitempty"` // The person(s) or organization(s) that authored the component - Publisher string `xml:"publisher,omitempty"` // The person(s) or organization(s) that published the component - Group string `xml:"group,omitempty"` // The high-level classification that a project self-describes as. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name. - Name string `xml:"name"` // Required; The name of the component as defined by the project - Version string `xml:"version"` // Required; The version of the component as defined by the project - Description string `xml:"description,omitempty"` // A description of the component - Licenses *[]License `xml:"licenses>license"` // A node describing zero or more license names, SPDX license IDs or expressions - PackageURL string `xml:"purl,omitempty"` // Specifies the package-url (PackageURL). The purl, if specified, must be valid and conform to the specification defined at: https://github.com/package-url/purl-spec - // TODO: source, hashes, copyright, cpe, purl, swid, modified, pedigree, externalReferences - // TODO: add user-defined parameters for syft-specific values (image layer index, cataloger, location path, etc.) -} - -// License represents a single software license for a Component -type License struct { - XMLName xml.Name `xml:"license"` - ID string `xml:"id,omitempty"` // A valid SPDX license ID - Name string `xml:"name,omitempty"` // If SPDX does not define the license used, this field may be used to provide the license name -} diff --git a/syft/presenter/cyclonedx/document.go b/syft/presenter/cyclonedx/document.go deleted file mode 100644 index 8791d3f9c..000000000 --- a/syft/presenter/cyclonedx/document.go +++ /dev/null @@ -1,57 +0,0 @@ -package cyclonedx - -import ( - "encoding/xml" - - "github.com/anchore/syft/internal" - "github.com/anchore/syft/internal/version" - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" - "github.com/google/uuid" -) - -// Source: https://github.com/CycloneDX/specification - -// Document represents a CycloneDX BOM Document. -type Document struct { - XMLName xml.Name `xml:"bom"` - XMLNs string `xml:"xmlns,attr"` - Version int `xml:"version,attr"` - SerialNumber string `xml:"serialNumber,attr"` - BomDescriptor *BomDescriptor `xml:"metadata"` // The BOM descriptor extension - Components []Component `xml:"components>component"` // The BOM contents -} - -// NewDocumentFromCatalog returns a CycloneDX Document object populated with the catalog contents. -func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata) Document { - versionInfo := version.FromBuild() - - doc := Document{ - XMLNs: "http://cyclonedx.org/schema/bom/1.2", - Version: 1, - SerialNumber: uuid.New().URN(), - BomDescriptor: NewBomDescriptor(internal.ApplicationName, versionInfo.Version, srcMetadata), - } - - // attach components - for p := range catalog.Enumerate() { - component := Component{ - Type: "library", // TODO: this is not accurate - Name: p.Name, - Version: p.Version, - PackageURL: p.PURL, - } - var licenses []License - for _, licenseName := range p.Licenses { - licenses = append(licenses, License{ - Name: licenseName, - }) - } - if len(licenses) > 0 { - component.Licenses = &licenses - } - doc.Components = append(doc.Components, component) - } - - return doc -} diff --git a/syft/presenter/cyclonedx/test-fixtures/image-simple/Dockerfile b/syft/presenter/cyclonedx/test-fixtures/image-simple/Dockerfile deleted file mode 100644 index 62fb151e4..000000000 --- a/syft/presenter/cyclonedx/test-fixtures/image-simple/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -# Note: changes to this file will result in updating several test values. Consider making a new image fixture instead of editing this one. -FROM scratch -ADD file-1.txt /somefile-1.txt -ADD file-2.txt /somefile-2.txt -# note: adding a directory will behave differently on docker engine v18 vs v19 -ADD target / diff --git a/syft/presenter/cyclonedx/test-fixtures/image-simple/target/really/nested/file-3.txt b/syft/presenter/cyclonedx/test-fixtures/image-simple/target/really/nested/file-3.txt deleted file mode 100644 index f85472c93..000000000 --- a/syft/presenter/cyclonedx/test-fixtures/image-simple/target/really/nested/file-3.txt +++ /dev/null @@ -1,2 +0,0 @@ -another file! -with lines... \ No newline at end of file diff --git a/syft/presenter/json/descriptor.go b/syft/presenter/json/descriptor.go deleted file mode 100644 index de07721fc..000000000 --- a/syft/presenter/json/descriptor.go +++ /dev/null @@ -1,7 +0,0 @@ -package json - -// Descriptor describes what created the document as well as surrounding metadata -type Descriptor struct { - Name string `json:"name"` - Version string `json:"version"` -} diff --git a/syft/presenter/json/document.go b/syft/presenter/json/document.go deleted file mode 100644 index 5f04cdfcf..000000000 --- a/syft/presenter/json/document.go +++ /dev/null @@ -1,54 +0,0 @@ -package json - -import ( - "fmt" - - "github.com/anchore/syft/internal" - "github.com/anchore/syft/internal/version" - "github.com/anchore/syft/syft/distro" - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" -) - -// Document represents the syft cataloging findings as a JSON document -type Document struct { - Artifacts []Package `json:"artifacts"` // Artifacts is the list of packages discovered and placed into the catalog - Source Source `json:"source"` // Source represents the original object that was cataloged - Distro Distribution `json:"distro"` // Distro represents the Linux distribution that was detected from the source - Descriptor Descriptor `json:"descriptor"` // Descriptor is a block containing self-describing information about syft - Schema Schema `json:"schema"` // Schema is a block reserved for defining the version for the shape of this JSON document and where to find the schema document to validate the shape - ArtifactRelationships []Relationship `json:"artifactRelationships"` -} - -// NewDocument creates and populates a new JSON document struct from the given cataloging results. -func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d *distro.Distro) (Document, error) { - src, err := NewSource(srcMetadata) - if err != nil { - return Document{}, nil - } - - doc := Document{ - Artifacts: make([]Package, 0), - Source: src, - Distro: NewDistribution(d), - Descriptor: Descriptor{ - Name: internal.ApplicationName, - Version: version.FromBuild().Version, - }, - Schema: Schema{ - Version: internal.JSONSchemaVersion, - URL: fmt.Sprintf("https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-%s.json", internal.JSONSchemaVersion), - }, - ArtifactRelationships: newRelationships(pkg.NewRelationships(catalog)), - } - - for _, p := range catalog.Sorted() { - art, err := NewPackage(p) - if err != nil { - return Document{}, err - } - doc.Artifacts = append(doc.Artifacts, art) - } - - return doc, nil -} diff --git a/syft/presenter/json/presenter.go b/syft/presenter/json/presenter.go deleted file mode 100644 index 845ecd1bf..000000000 --- a/syft/presenter/json/presenter.go +++ /dev/null @@ -1,40 +0,0 @@ -package json - -import ( - "encoding/json" - "io" - - "github.com/anchore/syft/syft/distro" - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" -) - -// Presenter is a JSON presentation object for the syft results -type Presenter struct { - catalog *pkg.Catalog - srcMetadata source.Metadata - distro *distro.Distro -} - -// NewPresenter creates a new JSON presenter object for the given cataloging results. -func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d *distro.Distro) *Presenter { - return &Presenter{ - catalog: catalog, - srcMetadata: s, - distro: d, - } -} - -// Present the catalog results to the given writer. -func (pres *Presenter) Present(output io.Writer) error { - doc, err := NewDocument(pres.catalog, pres.srcMetadata, pres.distro) - if err != nil { - return err - } - - enc := json.NewEncoder(output) - // prevent > and < from being escaped in the payload - enc.SetEscapeHTML(false) - enc.SetIndent("", " ") - return enc.Encode(&doc) -} diff --git a/syft/presenter/json/schema.go b/syft/presenter/json/schema.go deleted file mode 100644 index d7f8d27ec..000000000 --- a/syft/presenter/json/schema.go +++ /dev/null @@ -1,6 +0,0 @@ -package json - -type Schema struct { - Version string `json:"version"` - URL string `json:"url"` -} diff --git a/syft/presenter/json/source.go b/syft/presenter/json/source.go deleted file mode 100644 index 7a5ad6ad2..000000000 --- a/syft/presenter/json/source.go +++ /dev/null @@ -1,75 +0,0 @@ -package json - -import ( - "encoding/json" - "fmt" - - "github.com/anchore/syft/syft/source" -) - -// Source object represents the thing that was cataloged -type Source struct { - Type string `json:"type"` - Target interface{} `json:"target"` -} - -// sourceUnpacker is used to unmarshal Source objects -type sourceUnpacker struct { - Type string `json:"type"` - Target json.RawMessage `json:"target"` -} - -// NewSource creates a new source object to be represented into JSON. -func NewSource(src source.Metadata) (Source, error) { - switch src.Scheme { - case source.ImageScheme: - return Source{ - Type: "image", - Target: src.ImageMetadata, - }, nil - case source.DirectoryScheme: - return Source{ - Type: "directory", - Target: src.Path, - }, nil - default: - return Source{}, fmt.Errorf("unsupported source: %T", src) - } -} - -// UnmarshalJSON populates a source object from JSON bytes. -func (s *Source) UnmarshalJSON(b []byte) error { - var unpacker sourceUnpacker - if err := json.Unmarshal(b, &unpacker); err != nil { - return err - } - - s.Type = unpacker.Type - - switch s.Type { - case "image": - var payload source.ImageMetadata - if err := json.Unmarshal(unpacker.Target, &payload); err != nil { - return err - } - s.Target = payload - default: - return fmt.Errorf("unsupported package metadata type: %+v", s.Type) - } - - return nil -} - -// ToSourceMetadata takes a source object represented from JSON and creates a source.Metadata object. -func (s *Source) ToSourceMetadata() source.Metadata { - var metadata source.Metadata - switch s.Type { - case "directory": - metadata.Scheme = source.DirectoryScheme - metadata.Path = s.Target.(string) - case "image": - metadata.Scheme = source.ImageScheme - metadata.ImageMetadata = s.Target.(source.ImageMetadata) - } - return metadata -} diff --git a/syft/presenter/json/test-fixtures/image-simple/Dockerfile b/syft/presenter/json/test-fixtures/image-simple/Dockerfile deleted file mode 100644 index 62fb151e4..000000000 --- a/syft/presenter/json/test-fixtures/image-simple/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -# Note: changes to this file will result in updating several test values. Consider making a new image fixture instead of editing this one. -FROM scratch -ADD file-1.txt /somefile-1.txt -ADD file-2.txt /somefile-2.txt -# note: adding a directory will behave differently on docker engine v18 vs v19 -ADD target / diff --git a/syft/presenter/json/test-fixtures/image-simple/file-1.txt b/syft/presenter/json/test-fixtures/image-simple/file-1.txt deleted file mode 100644 index 985d3408e..000000000 --- a/syft/presenter/json/test-fixtures/image-simple/file-1.txt +++ /dev/null @@ -1 +0,0 @@ -this file has contents \ No newline at end of file diff --git a/syft/presenter/json/test-fixtures/image-simple/file-2.txt b/syft/presenter/json/test-fixtures/image-simple/file-2.txt deleted file mode 100644 index 396d08bbc..000000000 --- a/syft/presenter/json/test-fixtures/image-simple/file-2.txt +++ /dev/null @@ -1 +0,0 @@ -file-2 contents! \ No newline at end of file diff --git a/syft/presenter/json/test-fixtures/image-simple/target/really/nested/file-3.txt b/syft/presenter/json/test-fixtures/image-simple/target/really/nested/file-3.txt deleted file mode 100644 index f85472c93..000000000 --- a/syft/presenter/json/test-fixtures/image-simple/target/really/nested/file-3.txt +++ /dev/null @@ -1,2 +0,0 @@ -another file! -with lines... \ No newline at end of file diff --git a/syft/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden b/syft/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden deleted file mode 100644 index 721fe5bac..000000000 --- a/syft/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden +++ /dev/null @@ -1,81 +0,0 @@ -{ - "artifacts": [ - { - "id": "package-1-id", - "name": "package-1", - "version": "1.0.1", - "type": "python", - "foundBy": "the-cataloger-1", - "locations": [ - { - "path": "/some/path/pkg1" - } - ], - "licenses": [ - "MIT" - ], - "language": "python", - "cpes": [ - "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" - ], - "purl": "a-purl-2", - "metadataType": "PythonPackageMetadata", - "metadata": { - "name": "package-1", - "version": "1.0.1", - "license": "", - "author": "", - "authorEmail": "", - "platform": "", - "sitePackagesRootPath": "" - } - }, - { - "id": "package-2-id", - "name": "package-2", - "version": "2.0.1", - "type": "deb", - "foundBy": "the-cataloger-2", - "locations": [ - { - "path": "/some/path/pkg1" - } - ], - "licenses": [], - "language": "", - "cpes": [ - "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" - ], - "purl": "a-purl-2", - "metadataType": "DpkgMetadata", - "metadata": { - "package": "package-2", - "source": "", - "version": "2.0.1", - "sourceVersion": "", - "architecture": "", - "maintainer": "", - "installedSize": 0, - "files": null - } - } - ], - "source": { - "type": "directory", - "target": "/some/path" - }, - "distro": { - "name": "", - "version": "", - "idLike": "" - }, - "descriptor": { - "name": "syft", - "version": "[not provided]" - }, - "schema": { - "version": "1.0.3", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.0.3.json" - }, - "artifactRelationships": [] -} diff --git a/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden b/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden deleted file mode 100644 index 7d9e4889d..000000000 --- a/syft/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden +++ /dev/null @@ -1,112 +0,0 @@ -{ - "artifacts": [ - { - "id": "package-1-id", - "name": "package-1", - "version": "1.0.1", - "type": "python", - "foundBy": "the-cataloger-1", - "locations": [ - { - "path": "/somefile-1.txt", - "layerID": "sha256:2abd6dc7d143b384177da9a30f5311eb1f6c4e920eb6e218ec32b58c1a8806b1" - } - ], - "licenses": [ - "MIT" - ], - "language": "python", - "cpes": [ - "cpe:2.3:*:some:package:1:*:*:*:*:*:*:*" - ], - "purl": "a-purl-1", - "metadataType": "PythonPackageMetadata", - "metadata": { - "name": "package-1", - "version": "1.0.1", - "license": "", - "author": "", - "authorEmail": "", - "platform": "", - "sitePackagesRootPath": "" - } - }, - { - "id": "package-2-id", - "name": "package-2", - "version": "2.0.1", - "type": "deb", - "foundBy": "the-cataloger-2", - "locations": [ - { - "path": "/somefile-2.txt", - "layerID": "sha256:63574b0cbd9fcfc799d82a449c0975ee3f3560747b0957f042938bdec902c4cc" - } - ], - "licenses": [], - "language": "", - "cpes": [ - "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" - ], - "purl": "a-purl-2", - "metadataType": "DpkgMetadata", - "metadata": { - "package": "package-2", - "source": "", - "version": "2.0.1", - "sourceVersion": "", - "architecture": "", - "maintainer": "", - "installedSize": 0, - "files": null - } - } - ], - "source": { - "type": "image", - "target": { - "userInput": "user-image-input", - "imageID": "sha256:0a7326bbb1c3c467969c7a73deb6366b1e34eb034616b97f8614ad662cad1ce1", - "manifestDigest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368", - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "tags": [ - "stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7" - ], - "imageSize": 65, - "scope": "Squashed", - "layers": [ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:2abd6dc7d143b384177da9a30f5311eb1f6c4e920eb6e218ec32b58c1a8806b1", - "size": 22 - }, - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:63574b0cbd9fcfc799d82a449c0975ee3f3560747b0957f042938bdec902c4cc", - "size": 16 - }, - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:b102400548006e8dfa3abf6e2b2e6f1c440e29936d91a36e145736e2fd8cf0a1", - "size": 27 - } - ], - "manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjoxODA4LCJkaWdlc3QiOiJzaGEyNTY6MGE3MzI2YmJiMWMzYzQ2Nzk2OWM3YTczZGViNjM2NmIxZTM0ZWIwMzQ2MTZiOTdmODYxNGFkNjYyY2FkMWNlMSJ9LCJsYXllcnMiOlt7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLCJzaXplIjoyMDQ4LCJkaWdlc3QiOiJzaGEyNTY6MmFiZDZkYzdkMTQzYjM4NDE3N2RhOWEzMGY1MzExZWIxZjZjNGU5MjBlYjZlMjE4ZWMzMmI1OGMxYTg4MDZiMSJ9LHsibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1Njo2MzU3NGIwY2JkOWZjZmM3OTlkODJhNDQ5YzA5NzVlZTNmMzU2MDc0N2IwOTU3ZjA0MjkzOGJkZWM5MDJjNGNjIn0seyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmltYWdlLnJvb3Rmcy5kaWZmLnRhci5nemlwIiwic2l6ZSI6MzU4NCwiZGlnZXN0Ijoic2hhMjU2OmIxMDI0MDA1NDgwMDZlOGRmYTNhYmY2ZTJiMmU2ZjFjNDQwZTI5OTM2ZDkxYTM2ZTE0NTczNmUyZmQ4Y2YwYTEifV19", - "config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJIb3N0bmFtZSI6IiIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpudWxsLCJJbWFnZSI6InNoYTI1Njo4YjlhNTM1MmM3YzU3M2RmNTkxYTYwMzA0NzIxMmU3ZmYzOGI3YjRiYzZiMzk1NmI3Zjk2Nzk0MWU3NGMyMjhkIiwiVm9sdW1lcyI6bnVsbCwiV29ya2luZ0RpciI6IiIsIkVudHJ5cG9pbnQiOm51bGwsIk9uQnVpbGQiOm51bGwsIkxhYmVscyI6bnVsbH0sImNvbnRhaW5lcl9jb25maWciOnsiSG9zdG5hbWUiOiIiLCJEb21haW5uYW1lIjoiIiwiVXNlciI6IiIsIkF0dGFjaFN0ZGluIjpmYWxzZSwiQXR0YWNoU3Rkb3V0IjpmYWxzZSwiQXR0YWNoU3RkZXJyIjpmYWxzZSwiVHR5IjpmYWxzZSwiT3BlblN0ZGluIjpmYWxzZSwiU3RkaW5PbmNlIjpmYWxzZSwiRW52IjpbIlBBVEg9L3Vzci9sb2NhbC9zYmluOi91c3IvbG9jYWwvYmluOi91c3Ivc2JpbjovdXNyL2Jpbjovc2JpbjovYmluIl0sIkNtZCI6WyIvYmluL3NoIiwiLWMiLCIjKG5vcCkgQUREIGRpcjpjOTM3YzZhYTUwODkwN2UyODUwOWI2NDRhMTJmOGQ2YzY3ZDM0ZTk2OWY4M2IxNGRlZTkzZWExN2Q3NjkwMjhhIGluIC8gIl0sIkltYWdlIjoic2hhMjU2OjhiOWE1MzUyYzdjNTczZGY1OTFhNjAzMDQ3MjEyZTdmZjM4YjdiNGJjNmIzOTU2YjdmOTY3OTQxZTc0YzIyOGQiLCJWb2x1bWVzIjpudWxsLCJXb3JraW5nRGlyIjoiIiwiRW50cnlwb2ludCI6bnVsbCwiT25CdWlsZCI6bnVsbCwiTGFiZWxzIjpudWxsfSwiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTM6MDg6MzUuNDkyOTI1MzAzWiIsImRvY2tlcl92ZXJzaW9uIjoiMjAuMTAuMiIsImhpc3RvcnkiOlt7ImNyZWF0ZWQiOiIyMDIxLTAzLTIyVDEzOjA4OjM1LjA5NDMxMjQ3NloiLCJjcmVhdGVkX2J5IjoiL2Jpbi9zaCAtYyAjKG5vcCkgQUREIGZpbGU6YWMzMmRhMjNkNTFlODAxZjAyZjkyNDEyM2VkMzA5OTBlYjNmMGZlYzFiOWVkNGYwYjA2YzI0ZTg4YjljMzY5NSBpbiAvc29tZWZpbGUtMS50eHQgIn0seyJjcmVhdGVkIjoiMjAyMS0wMy0yMlQxMzowODozNS4yODk5MjIwNTFaIiwiY3JlYXRlZF9ieSI6Ii9iaW4vc2ggLWMgIyhub3ApIEFERCBmaWxlOmRmM2I3NDRmNTRhOWIxNmI5YjlhZWQ0MGUzZTk4ZDljYTJiNDlmNWE3N2Q5ZmE4YTk3NjkwZDdiYWY1ODg4MjAgaW4gL3NvbWVmaWxlLTIudHh0ICJ9LHsiY3JlYXRlZCI6IjIwMjEtMDMtMjJUMTM6MDg6MzUuNDkyOTI1MzAzWiIsImNyZWF0ZWRfYnkiOiIvYmluL3NoIC1jICMobm9wKSBBREQgZGlyOmM5MzdjNmFhNTA4OTA3ZTI4NTA5YjY0NGExMmY4ZDZjNjdkMzRlOTY5ZjgzYjE0ZGVlOTNlYTE3ZDc2OTAyOGEgaW4gLyAifV0sIm9zIjoibGludXgiLCJyb290ZnMiOnsidHlwZSI6ImxheWVycyIsImRpZmZfaWRzIjpbInNoYTI1NjoyYWJkNmRjN2QxNDNiMzg0MTc3ZGE5YTMwZjUzMTFlYjFmNmM0ZTkyMGViNmUyMThlYzMyYjU4YzFhODgwNmIxIiwic2hhMjU2OjYzNTc0YjBjYmQ5ZmNmYzc5OWQ4MmE0NDljMDk3NWVlM2YzNTYwNzQ3YjA5NTdmMDQyOTM4YmRlYzkwMmM0Y2MiLCJzaGEyNTY6YjEwMjQwMDU0ODAwNmU4ZGZhM2FiZjZlMmIyZTZmMWM0NDBlMjk5MzZkOTFhMzZlMTQ1NzM2ZTJmZDhjZjBhMSJdfX0=" - } - }, - "distro": { - "name": "", - "version": "", - "idLike": "" - }, - "descriptor": { - "name": "syft", - "version": "[not provided]" - }, - "schema": { - "version": "1.0.3", - "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.0.3.json" - }, - "artifactRelationships": [] -} 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 deleted file mode 100644 index 6c23e82fd2aa604af4d39cdcc204da4c4935b164..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23552 zcmeHPTW{Mo6wdR0g{Qr2K;rOzF|dcOEzkkQI&9entSAazYpu5ANy^qB$ba9F?Id>E z+D;`K=}IFPNhA;HbD<8u!$ZV~4%k?&0yQ3E?K#(;66d4GL?ESQ(9{#JjFpiYM3Lf{ zF-`*K#){LU?H_~~lAIr*#pmw-_URF3hzN`+CG-ekDFr_o@a?3#*Ep{mQ^AnBQo8%) zy3#vPd(>6_zd!xu*B@W}v}w2qBP1BREBEVr;2d3-KfwspV9;46n+A1V_JzwI4-dlS zYi_6i4~zqy?fJaoFO!t|NPljD2vAAMW|lGRm|UHqs#1BSvQ55251E}o|IFlaC`q-9jZmiqoy%# z{A=U$A{#|Bsl#!0^Q=5?-hUV>Xu7O<)?D0NznFz$ozDF3Md4r&%lc1?f3i_=KA9Y6 zkEigB7MDLx&70*we=jHJ(@92$ z8z#%plW>BE&AX;Qx~r77$RB~{KcD|Op#lK9sCdQAHU2^%GdZnoUW``mZ*Ff3=8qP)aGAaO;3BUc8^Xm%S#7{AB~CgHMiIHjMgRuR zB*7%e7^$+-GV6q;nhSu)HP{ftK{7{(^1#TR*NUInD!NYzz06KQV5jvMxO(E?&o|!| zvX`%_Ih_c4FotJ=~ zWCRT{8WJc1-@hp@TDDj3+ z&v8%)M?|6~3=T9&96YuSAeJEtSZYU0uptZH5aq?RWOHk>Q;sF7+>ce%3fwmlOV==;hprD zQA-trkexT$P!u`EI9MEo16v~?WDy8f0d&D~<*-o-fm;Domy`tMl3C;|FxEvUwf2e_ z#zHfjfh8piVIu&OI8zXB3d%=Ajg8Q~B|${& z7>JW-O@)V9oQi-M%;``Zy>by5oV~g_H2ijmSNz64oNC`*)_`WChy@ogGfFLW1eOz! zCkq&1Fk|ovBlu|w0ox78*FM&;5K#*DFUq&OFmRAxvSv! z6#oTKGU0!Rm;i2;*YhRoetO&<|6Sm}tMOl!_W$ii79uoEHq|A&x&!v7Az<%ioxXZ!Dt{}J*&{zpmL|8o$fS>k_P)nFC> z>k28Y;eQ|6jIbUw|GctF(ten|?26j3$>p<1HtJI?*0Yr!>=vev>^of9lJdoE#yH4~ zzurmLiN6Q@U%sFJMPRF0^8eQ*wVylK$~T!@?6Qjg^!|4}|KS$@hdo??|EKdGKAq>g zwp_}8`0sc)|1D>K@7i?ddhO8|+s^-J>nuNz|3?^4{{PPW?NV_m|02|oyS=Ar;Qsax zUVl3OrHfd1Zo4l3c{Gsroe8`({!167>r5Ge{Cd zkYOYOV_0AZnRLovqXm@&MUNPx&PEwRRInqQQRZM@fDcL%?z~pc!48EsUGsT+2GP8` zu6vJf;jA_a(KR>f=4>P&)*sLYX=<;&x|fhQRIWf)bq-medDz>jFWc;&+@1~ELIAD( x!vO=y|KA|C-ij_WSom+W&^95ovyqNE>wk82)tl1y#=S%+aUgLZap3diz<<+T&G7&L diff --git a/syft/presenter/option.go b/syft/presenter/option.go deleted file mode 100644 index fe9b125d9..000000000 --- a/syft/presenter/option.go +++ /dev/null @@ -1,35 +0,0 @@ -package presenter - -import "strings" - -const ( - UnknownPresenter Option = "UnknownPresenter" - JSONPresenter Option = "json" - TextPresenter Option = "text" - TablePresenter Option = "table" - CycloneDxPresenter Option = "cyclonedx" -) - -var Options = []Option{ - JSONPresenter, - TextPresenter, - TablePresenter, - CycloneDxPresenter, -} - -type Option string - -func ParseOption(userStr string) Option { - switch strings.ToLower(userStr) { - case string(JSONPresenter): - return JSONPresenter - case string(TextPresenter): - return TextPresenter - case string(TablePresenter): - return TablePresenter - case string(CycloneDxPresenter), "cyclone", "cyclone-dx": - return CycloneDxPresenter - default: - return UnknownPresenter - } -} diff --git a/syft/presenter/presenter.go b/syft/presenter/presenter.go deleted file mode 100644 index 8bf3e46fb..000000000 --- a/syft/presenter/presenter.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Defines a Presenter interface for displaying catalog results to an io.Writer as well as a helper utility to obtain -a specific Presenter implementation given user configuration. -*/ -package presenter - -import ( - "io" - - "github.com/anchore/syft/syft/distro" - - "github.com/anchore/syft/syft/presenter/cyclonedx" - - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/presenter/json" - "github.com/anchore/syft/syft/presenter/table" - "github.com/anchore/syft/syft/presenter/text" - "github.com/anchore/syft/syft/source" -) - -// Presenter defines the expected behavior for an object responsible for displaying arbitrary input and processed data -// to a given io.Writer. -type Presenter interface { - Present(io.Writer) error -} - -// GetPresenter returns a presenter for images or directories -func GetPresenter(option Option, srcMetadata source.Metadata, catalog *pkg.Catalog, d *distro.Distro) Presenter { - switch option { - case JSONPresenter: - return json.NewPresenter(catalog, srcMetadata, d) - case TextPresenter: - return text.NewPresenter(catalog, srcMetadata) - case TablePresenter: - return table.NewPresenter(catalog) - case CycloneDxPresenter: - return cyclonedx.NewPresenter(catalog, srcMetadata) - default: - return nil - } -} diff --git a/syft/presenter/table/test-fixtures/image-simple/Dockerfile b/syft/presenter/table/test-fixtures/image-simple/Dockerfile deleted file mode 100644 index 62fb151e4..000000000 --- a/syft/presenter/table/test-fixtures/image-simple/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -# Note: changes to this file will result in updating several test values. Consider making a new image fixture instead of editing this one. -FROM scratch -ADD file-1.txt /somefile-1.txt -ADD file-2.txt /somefile-2.txt -# note: adding a directory will behave differently on docker engine v18 vs v19 -ADD target / diff --git a/syft/presenter/table/test-fixtures/image-simple/file-1.txt b/syft/presenter/table/test-fixtures/image-simple/file-1.txt deleted file mode 100644 index 985d3408e..000000000 --- a/syft/presenter/table/test-fixtures/image-simple/file-1.txt +++ /dev/null @@ -1 +0,0 @@ -this file has contents \ No newline at end of file diff --git a/syft/presenter/table/test-fixtures/image-simple/file-2.txt b/syft/presenter/table/test-fixtures/image-simple/file-2.txt deleted file mode 100644 index 396d08bbc..000000000 --- a/syft/presenter/table/test-fixtures/image-simple/file-2.txt +++ /dev/null @@ -1 +0,0 @@ -file-2 contents! \ No newline at end of file diff --git a/syft/presenter/table/test-fixtures/image-simple/target/really/nested/file-3.txt b/syft/presenter/table/test-fixtures/image-simple/target/really/nested/file-3.txt deleted file mode 100644 index f85472c93..000000000 --- a/syft/presenter/table/test-fixtures/image-simple/target/really/nested/file-3.txt +++ /dev/null @@ -1,2 +0,0 @@ -another file! -with lines... \ No newline at end of file diff --git a/syft/presenter/text/test-fixtures/image-simple/file-1.txt b/syft/presenter/text/test-fixtures/image-simple/file-1.txt deleted file mode 100644 index 985d3408e..000000000 --- a/syft/presenter/text/test-fixtures/image-simple/file-1.txt +++ /dev/null @@ -1 +0,0 @@ -this file has contents \ No newline at end of file diff --git a/syft/presenter/text/test-fixtures/image-simple/file-2.txt b/syft/presenter/text/test-fixtures/image-simple/file-2.txt deleted file mode 100644 index 396d08bbc..000000000 --- a/syft/presenter/text/test-fixtures/image-simple/file-2.txt +++ /dev/null @@ -1 +0,0 @@ -file-2 contents! \ No newline at end of file diff --git a/syft/presenter/text/test-fixtures/snapshot/TestJsonPresenter.golden b/syft/presenter/text/test-fixtures/snapshot/TestJsonPresenter.golden deleted file mode 100644 index ab2fd8317..000000000 --- a/syft/presenter/text/test-fixtures/snapshot/TestJsonPresenter.golden +++ /dev/null @@ -1 +0,0 @@ -{"artifacts":[{"name":"package-1","version":"1.0.1","type":"deb","cataloger":"","sources":[],"metadata":null},{"name":"package-2","version":"2.0.1","type":"deb","cataloger":"","sources":[],"metadata":null}],"Source":"/some/path"} \ No newline at end of file From f22d7d23c169aa6341c05567c778f9f8737b5a89 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:50:13 -0400 Subject: [PATCH 03/29] add poweruser concerns to the application config Signed-off-by: Alex Goodman --- internal/config/anchore.go | 13 ++ internal/config/application.go | 181 ++++++++++++++++++++++ internal/config/cli_only_options.go | 7 + internal/config/config.go | 228 ---------------------------- internal/config/development.go | 6 + internal/config/file_metadata.go | 24 +++ internal/config/logging.go | 11 ++ internal/config/packages.go | 23 +++ 8 files changed, 265 insertions(+), 228 deletions(-) create mode 100644 internal/config/anchore.go create mode 100644 internal/config/application.go create mode 100644 internal/config/cli_only_options.go delete mode 100644 internal/config/config.go create mode 100644 internal/config/development.go create mode 100644 internal/config/file_metadata.go create mode 100644 internal/config/logging.go create mode 100644 internal/config/packages.go diff --git a/internal/config/anchore.go b/internal/config/anchore.go new file mode 100644 index 000000000..7b363baa0 --- /dev/null +++ b/internal/config/anchore.go @@ -0,0 +1,13 @@ +package config + +type anchore struct { + // upload options + Host string `yaml:"host" json:"host" mapstructure:"host"` // -H , hostname of the engine/enterprise instance to upload to (setting this value enables upload) + Path string `yaml:"path" json:"path" mapstructure:"path"` // override the engine/enterprise API upload path + // IMPORTANT: do not show the username in any YAML/JSON output (sensitive information) + Username string `yaml:"-" json:"-" mapstructure:"username"` // -u , username to authenticate upload + // IMPORTANT: do not show the password in any YAML/JSON output (sensitive information) + Password string `yaml:"-" json:"-" mapstructure:"password"` // -p , password to authenticate upload + Dockerfile string `yaml:"dockerfile" json:"dockerfile" mapstructure:"dockerfile"` // -d , dockerfile to attach for upload + OverwriteExistingImage bool `yaml:"overwrite-existing-image" json:"overwrite-existing-image" mapstructure:"overwrite-existing-image"` // --overwrite-existing-image , if any of the SBOM components have already been uploaded this flag will ensure they are overwritten with the current upload +} diff --git a/internal/config/application.go b/internal/config/application.go new file mode 100644 index 000000000..7ec137331 --- /dev/null +++ b/internal/config/application.go @@ -0,0 +1,181 @@ +package config + +import ( + "fmt" + "path" + "strings" + + "github.com/anchore/syft/syft/source" + + "github.com/adrg/xdg" + "github.com/anchore/syft/internal" + "github.com/mitchellh/go-homedir" + "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "gopkg.in/yaml.v2" +) + +// Application is the main syft application configuration. +type Application struct { + ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading) + Output string `yaml:"output" json:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting + Quiet bool `yaml:"quiet" json:"quiet" mapstructure:"quiet"` // -q, indicates to not show any status output to stderr (ETUI or logging UI) + Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options + CliOptions CliOnlyOptions `yaml:"-" json:"-"` // all options only available through the CLI (not via env vars or config) + Dev Development `yaml:"dev" json:"dev" mapstructure:"dev"` + CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not + Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise + Packages Packages `yaml:"packages" json:"packages" mapstructure:"packages"` + FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"` +} + +// LoadApplicationConfig populates the given viper object with application configuration discovered on disk +func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) (*Application, error) { + // the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead + setNonCliDefaultAppConfigValues(v) + _ = readConfig(v, cliOpts.ConfigPath) + + config := &Application{ + CliOptions: cliOpts, + } + + if err := v.Unmarshal(config); err != nil { + return nil, fmt.Errorf("unable to parse config: %w", err) + } + config.ConfigPath = v.ConfigFileUsed() + + if err := config.build(); err != nil { + return nil, fmt.Errorf("invalid application config: %w", err) + } + + return config, nil +} + +// build inflates simple config values into syft native objects (or other complex objects) after the config is fully read in. +func (cfg *Application) build() error { + if cfg.Quiet { + // TODO: this is bad: quiet option trumps all other logging options + // we should be able to quiet the console logging and leave file logging alone... + // ... this will be an enhancement for later + cfg.Log.LevelOpt = logrus.PanicLevel + } else { + if cfg.Log.Level != "" { + if cfg.CliOptions.Verbosity > 0 { + return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together") + } + + lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level)) + if err != nil { + return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err) + } + // set the log level explicitly + cfg.Log.LevelOpt = lvl + } else { + // set the log level implicitly + switch v := cfg.CliOptions.Verbosity; { + case v == 1: + cfg.Log.LevelOpt = logrus.InfoLevel + case v >= 2: + cfg.Log.LevelOpt = logrus.DebugLevel + default: + cfg.Log.LevelOpt = logrus.WarnLevel + } + } + } + + if cfg.Anchore.Host == "" && cfg.Anchore.Dockerfile != "" { + return fmt.Errorf("cannot provide dockerfile option without enabling upload") + } + + for _, builder := range []func() error{ + cfg.Packages.build, + cfg.FileMetadata.build, + } { + if err := builder(); err != nil { + return err + } + } + + return nil +} + +func (cfg Application) String() string { + // yaml is pretty human friendly (at least when compared to json) + appCfgStr, err := yaml.Marshal(&cfg) + + if err != nil { + return err.Error() + } + + return string(appCfgStr) +} + +// readConfig attempts to read the given config path from disk or discover an alternate store location +func readConfig(v *viper.Viper, configPath string) error { + v.AutomaticEnv() + v.SetEnvPrefix(internal.ApplicationName) + // allow for nested options to be specified via environment variables + // e.g. pod.context = APPNAME_POD_CONTEXT + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) + + // use explicitly the given user config + if configPath != "" { + v.SetConfigFile(configPath) + if err := v.ReadInConfig(); err != nil { + return fmt.Errorf("unable to read application config=%q : %w", configPath, err) + } + // don't fall through to other options if the config path was explicitly provided + return nil + } + + // start searching for valid configs in order... + + // 1. look for ..yaml (in the current directory) + v.AddConfigPath(".") + v.SetConfigName(internal.ApplicationName) + if err := v.ReadInConfig(); err == nil { + return nil + } + + // 2. look for ./config.yaml (in the current directory) + v.AddConfigPath("." + internal.ApplicationName) + v.SetConfigName("config") + if err := v.ReadInConfig(); err == nil { + return nil + } + + // 3. look for ~/..yaml + home, err := homedir.Dir() + if err == nil { + v.AddConfigPath(home) + v.SetConfigName("." + internal.ApplicationName) + if err := v.ReadInConfig(); err == nil { + return nil + } + } + + // 4. look for /config.yaml in xdg locations (starting with xdg home config dir, then moving upwards) + v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName)) + for _, dir := range xdg.ConfigDirs { + v.AddConfigPath(path.Join(dir, internal.ApplicationName)) + } + v.SetConfigName("config") + if err := v.ReadInConfig(); err == nil { + return nil + } + + return fmt.Errorf("application config not found") +} + +// setNonCliDefaultAppConfigValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value) +func setNonCliDefaultAppConfigValues(v *viper.Viper) { + v.SetDefault("anchore.path", "") + v.SetDefault("log.structured", false) + v.SetDefault("check-for-app-update", true) + v.SetDefault("dev.profile-cpu", false) + v.SetDefault("dev.profile-mem", false) + v.SetDefault("packages.cataloging-enabled", true) + v.SetDefault("file-metadata.cataloging-enabled", true) + v.SetDefault("file-metadata.scope", source.SquashedScope) + v.SetDefault("file-metadata.digests", []string{"sha256"}) +} diff --git a/internal/config/cli_only_options.go b/internal/config/cli_only_options.go new file mode 100644 index 000000000..5ece4d7eb --- /dev/null +++ b/internal/config/cli_only_options.go @@ -0,0 +1,7 @@ +package config + +// CliOnlyOptions are options that are in the application config in memory, but are only exposed via CLI switches (not from unmarshaling a config file) +type CliOnlyOptions struct { + ConfigPath string // -c. where the read config is on disk + Verbosity int // -v or -vv , controlling which UI (ETUI vs logging) and what the log level should be +} diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index b957ae588..000000000 --- a/internal/config/config.go +++ /dev/null @@ -1,228 +0,0 @@ -package config - -import ( - "fmt" - "path" - "strings" - - "github.com/adrg/xdg" - "github.com/anchore/syft/internal" - "github.com/anchore/syft/syft/presenter" - "github.com/anchore/syft/syft/source" - "github.com/mitchellh/go-homedir" - "github.com/sirupsen/logrus" - "github.com/spf13/viper" - "gopkg.in/yaml.v2" -) - -// Application is the main syft application configuration. -type Application struct { - ConfigPath string `yaml:",omitempty"` // the location where the application config was read from (either from -c or discovered while loading) - PresenterOpt presenter.Option `yaml:"-"` // -o, the native Presenter.Option to use for report formatting - Output string `yaml:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting - ScopeOpt source.Scope `yaml:"-"` // -s, the native source.Scope option to use for how to catalog the container image - Scope string `yaml:"scope" mapstructure:"scope"` // -s, the source.Scope string hint for how to catalog the container image - Quiet bool `yaml:"quiet" mapstructure:"quiet"` // -q, indicates to not show any status output to stderr (ETUI or logging UI) - Log logging `yaml:"log" mapstructure:"log"` // all logging-related options - CliOptions CliOnlyOptions `yaml:"-"` // all options only available through the CLI (not via env vars or config) - Dev Development `mapstructure:"dev"` - CheckForAppUpdate bool `yaml:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not - Anchore anchore `yaml:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise -} - -// CliOnlyOptions are options that are in the application config in memory, but are only exposed via CLI switches (not from unmarshaling a config file) -type CliOnlyOptions struct { - ConfigPath string // -c. where the read config is on disk - Verbosity int // -v or -vv , controlling which UI (ETUI vs logging) and what the log level should be -} - -// logging contains all logging-related configuration options available to the user via the application config. -type logging struct { - Structured bool `yaml:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings - LevelOpt logrus.Level `yaml:"level"` // the native log level object used by the logger - Level string `yaml:"-" mapstructure:"level"` // the log level string hint - FileLocation string `yaml:"file" mapstructure:"file"` // the file path to write logs to -} - -type anchore struct { - // upload options - UploadEnabled bool `yaml:"upload-enabled" mapstructure:"upload-enabled"` // whether to upload results to Anchore Engine/Enterprise (defaults to "false" unless there is the presence of -h CLI option) - Host string `yaml:"host" mapstructure:"host"` // -H , hostname of the engine/enterprise instance to upload to - Path string `yaml:"path" mapstructure:"path"` // override the engine/enterprise API upload path - Username string `yaml:"username" mapstructure:"username"` // -u , username to authenticate upload - Password string `yaml:"password" mapstructure:"password"` // -p , password to authenticate upload - Dockerfile string `yaml:"dockerfile" mapstructure:"dockerfile"` // -d , dockerfile to attach for upload - OverwriteExistingImage bool `yaml:"overwrite-existing-image" mapstructure:"overwrite-existing-image"` // --overwrite-existing-image , if any of the SBOM components have already been uploaded this flag will ensure they are overwritten with the current upload -} - -type Development struct { - ProfileCPU bool `mapstructure:"profile-cpu"` - ProfileMem bool `mapstructure:"profile-mem"` -} - -// LoadApplicationConfig populates the given viper object with application configuration discovered on disk -func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions, wasHostnameSet bool) (*Application, error) { - // the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead - setNonCliDefaultValues(v) - _ = readConfig(v, cliOpts.ConfigPath) - - config := &Application{ - CliOptions: cliOpts, - } - - if err := v.Unmarshal(config); err != nil { - return nil, fmt.Errorf("unable to parse config: %w", err) - } - config.ConfigPath = v.ConfigFileUsed() - - if err := config.build(v, wasHostnameSet); err != nil { - return nil, fmt.Errorf("invalid config: %w", err) - } - - return config, nil -} - -// build inflates simple config values into syft native objects (or other complex objects) after the config is fully read in. -func (cfg *Application) build(v *viper.Viper, wasHostnameSet bool) error { - // set the presenter - presenterOption := presenter.ParseOption(cfg.Output) - if presenterOption == presenter.UnknownPresenter { - return fmt.Errorf("bad --output value '%s'", cfg.Output) - } - cfg.PresenterOpt = presenterOption - - // set the source - scopeOption := source.ParseScope(cfg.Scope) - if scopeOption == source.UnknownScope { - return fmt.Errorf("bad --scope value '%s'", cfg.Scope) - } - cfg.ScopeOpt = scopeOption - - if cfg.Quiet { - // TODO: this is bad: quiet option trumps all other logging options - // we should be able to quiet the console logging and leave file logging alone... - // ... this will be an enhancement for later - cfg.Log.LevelOpt = logrus.PanicLevel - } else { - if cfg.Log.Level != "" { - if cfg.CliOptions.Verbosity > 0 { - return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together") - } - - lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level)) - if err != nil { - return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err) - } - // set the log level explicitly - cfg.Log.LevelOpt = lvl - } else { - // set the log level implicitly - switch v := cfg.CliOptions.Verbosity; { - case v == 1: - cfg.Log.LevelOpt = logrus.InfoLevel - case v >= 2: - cfg.Log.LevelOpt = logrus.DebugLevel - default: - cfg.Log.LevelOpt = logrus.WarnLevel - } - } - } - // check if upload should be done relative to the CLI and config behavior - if !v.IsSet("anchore.upload-enabled") && wasHostnameSet { - // we know the user didn't specify to upload in the config file and a --hostname option was provided (so set upload) - cfg.Anchore.UploadEnabled = true - } - - if !cfg.Anchore.UploadEnabled && cfg.Anchore.Dockerfile != "" { - return fmt.Errorf("cannot provide dockerfile option without enabling upload") - } - - return nil -} - -func (cfg Application) String() string { - // redact sensitive information - if cfg.Anchore.Username != "" { - cfg.Anchore.Username = "********" - } - - if cfg.Anchore.Password != "" { - cfg.Anchore.Password = "********" - } - - // yaml is pretty human friendly (at least when compared to json) - appCfgStr, err := yaml.Marshal(&cfg) - - if err != nil { - return err.Error() - } - - return string(appCfgStr) -} - -// readConfig attempts to read the given config path from disk or discover an alternate store location -func readConfig(v *viper.Viper, configPath string) error { - v.AutomaticEnv() - v.SetEnvPrefix(internal.ApplicationName) - // allow for nested options to be specified via environment variables - // e.g. pod.context = APPNAME_POD_CONTEXT - v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) - - // use explicitly the given user config - if configPath != "" { - v.SetConfigFile(configPath) - if err := v.ReadInConfig(); err == nil { - return nil - } - // don't fall through to other options if this fails - return fmt.Errorf("unable to read config: %v", configPath) - } - - // start searching for valid configs in order... - - // 1. look for ..yaml (in the current directory) - v.AddConfigPath(".") - v.SetConfigName(internal.ApplicationName) - if err := v.ReadInConfig(); err == nil { - return nil - } - - // 2. look for ./config.yaml (in the current directory) - v.AddConfigPath("." + internal.ApplicationName) - v.SetConfigName("config") - if err := v.ReadInConfig(); err == nil { - return nil - } - - // 3. look for ~/..yaml - home, err := homedir.Dir() - if err == nil { - v.AddConfigPath(home) - v.SetConfigName("." + internal.ApplicationName) - if err := v.ReadInConfig(); err == nil { - return nil - } - } - - // 4. look for /config.yaml in xdg locations (starting with xdg home config dir, then moving upwards) - v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName)) - for _, dir := range xdg.ConfigDirs { - v.AddConfigPath(path.Join(dir, internal.ApplicationName)) - } - v.SetConfigName("config") - if err := v.ReadInConfig(); err == nil { - return nil - } - - return fmt.Errorf("application config not found") -} - -// setNonCliDefaultValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value) -func setNonCliDefaultValues(v *viper.Viper) { - v.SetDefault("log.level", "") - v.SetDefault("log.file", "") - v.SetDefault("log.structured", false) - v.SetDefault("check-for-app-update", true) - v.SetDefault("dev.profile-cpu", false) - v.SetDefault("dev.profile-mem", false) -} diff --git a/internal/config/development.go b/internal/config/development.go new file mode 100644 index 000000000..dbb38ff08 --- /dev/null +++ b/internal/config/development.go @@ -0,0 +1,6 @@ +package config + +type Development struct { + ProfileCPU bool `yaml:"profile-cpu" json:"profile-cpu" mapstructure:"profile-cpu"` + ProfileMem bool `yaml:"profile-mem" json:"profile-mem" mapstructure:"profile-mem"` +} diff --git a/internal/config/file_metadata.go b/internal/config/file_metadata.go new file mode 100644 index 000000000..a58f6410c --- /dev/null +++ b/internal/config/file_metadata.go @@ -0,0 +1,24 @@ +package config + +import ( + "fmt" + + "github.com/anchore/syft/syft/source" +) + +type FileMetadata struct { + CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"` + Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` + ScopeOpt source.Scope `yaml:"-" json:"-"` + Digests []string `yaml:"digests" json:"digests" mapstructure:"digests"` +} + +func (cfg *FileMetadata) build() error { + scopeOption := source.ParseScope(cfg.Scope) + if scopeOption == source.UnknownScope { + return fmt.Errorf("bad scope value %q", cfg.Scope) + } + cfg.ScopeOpt = scopeOption + + return nil +} diff --git a/internal/config/logging.go b/internal/config/logging.go new file mode 100644 index 000000000..53139419a --- /dev/null +++ b/internal/config/logging.go @@ -0,0 +1,11 @@ +package config + +import "github.com/sirupsen/logrus" + +// logging contains all logging-related configuration options available to the user via the application config. +type logging struct { + Structured bool `yaml:"structured" json:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings + LevelOpt logrus.Level `yaml:"-" json:"-"` // the native log level object used by the logger + Level string `yaml:"level" json:"level" mapstructure:"level"` // the log level string hint + FileLocation string `yaml:"file" json:"file-location" mapstructure:"file"` // the file path to write logs to +} diff --git a/internal/config/packages.go b/internal/config/packages.go new file mode 100644 index 000000000..63a1245f6 --- /dev/null +++ b/internal/config/packages.go @@ -0,0 +1,23 @@ +package config + +import ( + "fmt" + + "github.com/anchore/syft/syft/source" +) + +type Packages struct { + CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"` + Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` + ScopeOpt source.Scope `yaml:"-" json:"-"` +} + +func (cfg *Packages) build() error { + scopeOption := source.ParseScope(cfg.Scope) + if scopeOption == source.UnknownScope { + return fmt.Errorf("bad scope value %q", cfg.Scope) + } + cfg.ScopeOpt = scopeOption + + return nil +} From a6cba5d9db1e00621cfd1c3342e15d0967afc7f0 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:51:43 -0400 Subject: [PATCH 04/29] remove multi* content fetching from resolvers Signed-off-by: Alex Goodman --- syft/source/all_layers_resolver.go | 83 +++++++------------- syft/source/all_layers_resolver_test.go | 10 +-- syft/source/content_requester.go | 56 -------------- syft/source/content_requester_test.go | 74 ------------------ syft/source/directory_resolver.go | 88 ++++++++++++++++------ syft/source/directory_resolver_test.go | 60 ++------------- syft/source/file_data.go | 8 -- syft/source/file_metadata.go | 28 +++++++ syft/source/file_resolver.go | 39 ++++++++++ syft/source/file_type.go | 34 +++++++++ syft/source/image_metadata.go | 6 +- syft/source/image_squash_resolver.go | 52 ++++++++----- syft/source/image_squash_resolver_test.go | 10 +-- syft/source/location.go | 8 ++ syft/source/mock_resolver.go | 26 +++---- syft/source/resolver.go | 46 ------------ syft/source/source.go | 37 +++++---- syft/source/source_test.go | 92 +++++------------------ 18 files changed, 297 insertions(+), 460 deletions(-) delete mode 100644 syft/source/content_requester.go delete mode 100644 syft/source/content_requester_test.go delete mode 100644 syft/source/file_data.go create mode 100644 syft/source/file_metadata.go create mode 100644 syft/source/file_resolver.go create mode 100644 syft/source/file_type.go delete mode 100644 syft/source/resolver.go diff --git a/syft/source/all_layers_resolver.go b/syft/source/all_layers_resolver.go index f2f248ee2..6437fb4bc 100644 --- a/syft/source/all_layers_resolver.go +++ b/syft/source/all_layers_resolver.go @@ -2,10 +2,8 @@ package source import ( "archive/tar" - "bytes" "fmt" "io" - "io/ioutil" "github.com/anchore/stereoscope/pkg/file" "github.com/anchore/stereoscope/pkg/filetree" @@ -13,16 +11,16 @@ import ( "github.com/anchore/syft/internal/log" ) -var _ Resolver = (*AllLayersResolver)(nil) +var _ FileResolver = (*allLayersResolver)(nil) -// AllLayersResolver implements path and content access for the AllLayers source option for container image data sources. -type AllLayersResolver struct { +// allLayersResolver implements path and content access for the AllLayers source option for container image data sources. +type allLayersResolver struct { img *image.Image layers []int } -// NewAllLayersResolver returns a new resolver from the perspective of all image layers for the given image. -func NewAllLayersResolver(img *image.Image) (*AllLayersResolver, error) { +// newAllLayersResolver returns a new resolver from the perspective of all image layers for the given image. +func newAllLayersResolver(img *image.Image) (*allLayersResolver, error) { if len(img.Layers) == 0 { return nil, fmt.Errorf("the image does not contain any layers") } @@ -31,14 +29,14 @@ func NewAllLayersResolver(img *image.Image) (*AllLayersResolver, error) { for idx := range img.Layers { layers = append(layers, idx) } - return &AllLayersResolver{ + return &allLayersResolver{ img: img, layers: layers, }, nil } // HasPath indicates if the given path exists in the underlying source. -func (r *AllLayersResolver) HasPath(path string) bool { +func (r *allLayersResolver) HasPath(path string) bool { p := file.Path(path) for _, layerIdx := range r.layers { tree := r.img.Layers[layerIdx].Tree @@ -49,7 +47,7 @@ func (r *AllLayersResolver) HasPath(path string) bool { return false } -func (r *AllLayersResolver) fileByRef(ref file.Reference, uniqueFileIDs file.ReferenceSet, layerIdx int) ([]file.Reference, error) { +func (r *allLayersResolver) fileByRef(ref file.Reference, uniqueFileIDs file.ReferenceSet, layerIdx int) ([]file.Reference, error) { uniqueFiles := make([]file.Reference, 0) // since there is potentially considerable work for each symlink/hardlink that needs to be resolved, let's check to see if this is a symlink/hardlink first @@ -80,7 +78,7 @@ func (r *AllLayersResolver) fileByRef(ref file.Reference, uniqueFileIDs file.Ref } // FilesByPath returns all file.References that match the given paths from any layer in the image. -func (r *AllLayersResolver) FilesByPath(paths ...string) ([]Location, error) { +func (r *allLayersResolver) FilesByPath(paths ...string) ([]Location, error) { uniqueFileIDs := file.NewFileReferenceSet() uniqueLocations := make([]Location, 0) @@ -123,7 +121,7 @@ func (r *AllLayersResolver) FilesByPath(paths ...string) ([]Location, error) { // FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image. // nolint:gocognit -func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]Location, error) { +func (r *allLayersResolver) FilesByGlob(patterns ...string) ([]Location, error) { uniqueFileIDs := file.NewFileReferenceSet() uniqueLocations := make([]Location, 0) @@ -164,7 +162,7 @@ func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]Location, error) // RelativeFileByPath fetches a single file at the given path relative to the layer squash of the given reference. // This is helpful when attempting to find a file that is in the same layer or lower as another file. -func (r *AllLayersResolver) RelativeFileByPath(location Location, path string) *Location { +func (r *allLayersResolver) RelativeFileByPath(location Location, path string) *Location { entry, err := r.img.FileCatalog.Get(location.ref) if err != nil { return nil @@ -184,55 +182,26 @@ func (r *AllLayersResolver) RelativeFileByPath(location Location, path string) * return &relativeLocation } -// MultipleFileContentsByLocation returns the file contents for all file.References relative to the image. Note that a -// file.Reference is a path relative to a particular layer. -func (r *AllLayersResolver) MultipleFileContentsByLocation(locations []Location) (map[Location]io.ReadCloser, error) { - return mapLocationRefs(r.img.MultipleFileContentsByRef, locations) -} - // FileContentsByLocation fetches file contents for a single file reference, irregardless of the source layer. // If the path does not exist an error is returned. -func (r *AllLayersResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { +func (r *allLayersResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { return r.img.FileContentsByRef(location.ref) } -type multiContentFetcher func(refs ...file.Reference) (map[file.Reference]io.ReadCloser, error) - -func mapLocationRefs(callback multiContentFetcher, locations []Location) (map[Location]io.ReadCloser, error) { - var fileRefs = make([]file.Reference, len(locations)) - var locationByRefs = make(map[file.Reference][]Location) - var results = make(map[Location]io.ReadCloser) - - for i, location := range locations { - locationByRefs[location.ref] = append(locationByRefs[location.ref], location) - fileRefs[i] = location.ref - } - - contentsByRef, err := callback(fileRefs...) - if err != nil { - return nil, err - } - - // TODO: this is not tested, we need a test case that covers a mapLocationRefs which has multiple Locations with the same reference in the request. The io.Reader should be copied. - for ref, content := range contentsByRef { - mappedLocations := locationByRefs[ref] - switch { - case len(mappedLocations) > 1: - // TODO: fixme... this can lead to lots of unexpected memory usage in unusual circumstances (cache is not leveraged for large files). - // stereoscope wont duplicate content requests if the caller asks for the same file multiple times... thats up to the caller - contentsBytes, err := ioutil.ReadAll(content) - if err != nil { - return nil, fmt.Errorf("unable to read ref=%+v :%w", ref, err) +func (r *allLayersResolver) AllLocations() <-chan Location { + results := make(chan Location) + go func() { + defer close(results) + for _, layerIdx := range r.layers { + tree := r.img.Layers[layerIdx].Tree + for _, ref := range tree.AllFiles() { + results <- NewLocationFromImage(string(ref.RealPath), ref, r.img) } - for _, loc := range mappedLocations { - results[loc] = ioutil.NopCloser(bytes.NewReader(contentsBytes)) - } - - case len(mappedLocations) == 1: - results[locationByRefs[ref][0]] = content - default: - return nil, fmt.Errorf("unexpected ref-location count=%d for ref=%v", len(mappedLocations), ref) } - } - return results, nil + }() + return results +} + +func (r *allLayersResolver) FileMetadataByLocation(location Location) (FileMetadata, error) { + return fileMetadataByLocation(r.img, location) } diff --git a/syft/source/all_layers_resolver_test.go b/syft/source/all_layers_resolver_test.go index 54b50c38b..421a6663d 100644 --- a/syft/source/all_layers_resolver_test.go +++ b/syft/source/all_layers_resolver_test.go @@ -82,10 +82,9 @@ func TestAllLayersResolver_FilesByPath(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - resolver, err := NewAllLayersResolver(img) + resolver, err := newAllLayersResolver(img) if err != nil { t.Fatalf("could not create resolver: %+v", err) } @@ -201,10 +200,9 @@ func TestAllLayersResolver_FilesByGlob(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - resolver, err := NewAllLayersResolver(img) + resolver, err := newAllLayersResolver(img) if err != nil { t.Fatalf("could not create resolver: %+v", err) } diff --git a/syft/source/content_requester.go b/syft/source/content_requester.go deleted file mode 100644 index ef99513c0..000000000 --- a/syft/source/content_requester.go +++ /dev/null @@ -1,56 +0,0 @@ -package source - -import "sync" - -// ContentRequester is an object tailored for taking source.Location objects which file contents will be resolved -// upon invoking Execute(). -type ContentRequester struct { - request map[Location][]*FileData - lock sync.Mutex -} - -// NewContentRequester creates a new ContentRequester object with the given initial request data. -func NewContentRequester(data ...*FileData) *ContentRequester { - requester := &ContentRequester{ - request: make(map[Location][]*FileData), - } - for _, d := range data { - requester.Add(d) - } - return requester -} - -// Add appends a new single FileData containing a source.Location to later have the contents fetched and stored within -// the given FileData object. -func (r *ContentRequester) Add(data *FileData) { - r.lock.Lock() - defer r.lock.Unlock() - - r.request[data.Location] = append(r.request[data.Location], data) -} - -// Execute takes the previously provided source.Location's and resolves the file contents, storing the results within -// the previously provided FileData objects. -func (r *ContentRequester) Execute(resolver ContentResolver) error { - r.lock.Lock() - defer r.lock.Unlock() - - var locations = make([]Location, len(r.request)) - idx := 0 - for l := range r.request { - locations[idx] = l - idx++ - } - - response, err := resolver.MultipleFileContentsByLocation(locations) - if err != nil { - return err - } - - for l, contents := range response { - for i := range r.request[l] { - r.request[l][i].Contents = contents - } - } - return nil -} diff --git a/syft/source/content_requester_test.go b/syft/source/content_requester_test.go deleted file mode 100644 index f46498e63..000000000 --- a/syft/source/content_requester_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package source - -import ( - "io/ioutil" - "testing" - - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/sergi/go-diff/diffmatchpatch" -) - -func TestContentRequester(t *testing.T) { - tests := []struct { - fixture string - expectedContents map[string]string - }{ - { - fixture: "image-simple", - expectedContents: map[string]string{ - "/somefile-1.txt": "this file has contents", - "/somefile-2.txt": "file-2 contents!", - "/really/nested/file-3.txt": "another file!\nwith lines...", - }, - }, - } - - for _, test := range tests { - t.Run(test.fixture, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-simple") - defer cleanup() - - resolver, err := NewAllLayersResolver(img) - if err != nil { - t.Fatalf("could not create resolver: %+v", err) - } - - var data []*FileData - for path := range test.expectedContents { - - locations, err := resolver.FilesByPath(path) - if err != nil { - t.Fatalf("could not build request: %+v", err) - } - if len(locations) != 1 { - t.Fatalf("bad resolver paths: %+v", locations) - } - - data = append(data, &FileData{ - Location: locations[0], - }) - } - - if err := NewContentRequester(data...).Execute(resolver); err != nil { - t.Fatalf("could not execute request: %+v", err) - } - - for _, entry := range data { - if expected, ok := test.expectedContents[entry.Location.RealPath]; ok { - actualBytes, err := ioutil.ReadAll(entry.Contents) - if err != nil { - t.Fatalf("could not read %q: %+v", entry.Location.RealPath, err) - } - for expected != string(actualBytes) { - t.Errorf("mismatched contents for %q", entry.Location.RealPath) - dmp := diffmatchpatch.New() - diffs := dmp.DiffMain(expected, string(actualBytes), true) - t.Errorf("diff: %s", dmp.DiffPrettyText(diffs)) - } - continue - } - t.Errorf("could not find %q", entry.Location.RealPath) - } - }) - } -} diff --git a/syft/source/directory_resolver.go b/syft/source/directory_resolver.go index 7ef68bae8..9645cfee7 100644 --- a/syft/source/directory_resolver.go +++ b/syft/source/directory_resolver.go @@ -12,35 +12,39 @@ import ( "github.com/bmatcuk/doublestar/v2" ) -var _ Resolver = (*DirectoryResolver)(nil) +var _ FileResolver = (*directoryResolver)(nil) -// DirectoryResolver implements path and content access for the directory data source. -type DirectoryResolver struct { - Path string +// directoryResolver implements path and content access for the directory data source. +type directoryResolver struct { + path string } -func (r DirectoryResolver) requestPath(userPath string) string { +func newDirectoryResolver(path string) *directoryResolver { + return &directoryResolver{path: path} +} + +func (r directoryResolver) requestPath(userPath string) string { fullPath := userPath if filepath.IsAbs(fullPath) { // a path relative to root should be prefixed with the resolvers directory path, otherwise it should be left as is - fullPath = path.Join(r.Path, fullPath) + fullPath = path.Join(r.path, fullPath) } return fullPath } // HasPath indicates if the given path exists in the underlying source. -func (r *DirectoryResolver) HasPath(userPath string) bool { +func (r *directoryResolver) HasPath(userPath string) bool { _, err := os.Stat(r.requestPath(userPath)) return !os.IsNotExist(err) } // Stringer to represent a directory path data source -func (r DirectoryResolver) String() string { - return fmt.Sprintf("dir:%s", r.Path) +func (r directoryResolver) String() string { + return fmt.Sprintf("dir:%s", r.path) } // FilesByPath returns all file.References that match the given paths from the directory. -func (r DirectoryResolver) FilesByPath(userPaths ...string) ([]Location, error) { +func (r directoryResolver) FilesByPath(userPaths ...string) ([]Location, error) { var references = make([]Location, 0) for _, userPath := range userPaths { @@ -64,11 +68,11 @@ func (r DirectoryResolver) FilesByPath(userPaths ...string) ([]Location, error) } // FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image. -func (r DirectoryResolver) FilesByGlob(patterns ...string) ([]Location, error) { +func (r directoryResolver) FilesByGlob(patterns ...string) ([]Location, error) { result := make([]Location, 0) for _, pattern := range patterns { - pathPattern := path.Join(r.Path, pattern) + pathPattern := path.Join(r.path, pattern) pathMatches, err := doublestar.Glob(pathPattern) if err != nil { return nil, err @@ -93,8 +97,8 @@ func (r DirectoryResolver) FilesByGlob(patterns ...string) ([]Location, error) { // RelativeFileByPath fetches a single file at the given path relative to the layer squash of the given reference. // This is helpful when attempting to find a file that is in the same layer or lower as another file. For the -// DirectoryResolver, this is a simple path lookup. -func (r *DirectoryResolver) RelativeFileByPath(_ Location, path string) *Location { +// directoryResolver, this is a simple path lookup. +func (r *directoryResolver) RelativeFileByPath(_ Location, path string) *Location { paths, err := r.FilesByPath(path) if err != nil { return nil @@ -106,17 +110,51 @@ func (r *DirectoryResolver) RelativeFileByPath(_ Location, path string) *Locatio return &paths[0] } -// MultipleFileContentsByLocation returns the file contents for all file.References relative a directory. -func (r DirectoryResolver) MultipleFileContentsByLocation(locations []Location) (map[Location]io.ReadCloser, error) { - refContents := make(map[Location]io.ReadCloser) - for _, location := range locations { - refContents[location] = file.NewDeferredReadCloser(location.RealPath) - } - return refContents, nil -} - // FileContentsByLocation fetches file contents for a single file reference relative to a directory. // If the path does not exist an error is returned. -func (r DirectoryResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { - return file.NewDeferredReadCloser(location.RealPath), nil +func (r directoryResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { + return file.NewLazyReadCloser(location.RealPath), nil +} + +func (r *directoryResolver) AllLocations() <-chan Location { + results := make(chan Location) + go func() { + defer close(results) + err := filepath.Walk(r.path, + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + results <- NewLocation(path) + return nil + }) + if err != nil { + log.Errorf("unable to walk path=%q : %+v", r.path, err) + } + }() + return results +} + +func (r *directoryResolver) FileMetadataByLocation(location Location) (FileMetadata, error) { + fi, err := os.Stat(location.RealPath) + if err != nil { + return FileMetadata{}, err + } + + // best effort + ty := UnknownFileType + switch { + case fi.Mode().IsDir(): + ty = Directory + case fi.Mode().IsRegular(): + ty = RegularFile + } + + return FileMetadata{ + Mode: fi.Mode(), + Type: ty, + // unsupported across platforms + UserID: -1, + GroupID: -1, + }, nil } diff --git a/syft/source/directory_resolver_test.go b/syft/source/directory_resolver_test.go index dc88876c7..db0ccd0c1 100644 --- a/syft/source/directory_resolver_test.go +++ b/syft/source/directory_resolver_test.go @@ -57,7 +57,7 @@ func TestDirectoryResolver_FilesByPath(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - resolver := DirectoryResolver{c.root} + resolver := directoryResolver{c.root} hasPath := resolver.HasPath(c.input) if !c.forcePositiveHasPath { @@ -112,7 +112,7 @@ func TestDirectoryResolver_MultipleFilesByPath(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - resolver := DirectoryResolver{"test-fixtures"} + resolver := directoryResolver{"test-fixtures"} refs, err := resolver.FilesByPath(c.input...) if err != nil { @@ -126,59 +126,9 @@ func TestDirectoryResolver_MultipleFilesByPath(t *testing.T) { } } -func TestDirectoryResolver_MultipleFileContentsByRef(t *testing.T) { - cases := []struct { - name string - input []string - refCount int - contents []string - }{ - { - name: "gets multiple file contents", - input: []string{"test-fixtures/image-symlinks/file-1.txt", "test-fixtures/image-symlinks/file-2.txt"}, - refCount: 2, - }, - { - name: "skips non-existing files", - input: []string{"test-fixtures/image-symlinks/bogus.txt", "test-fixtures/image-symlinks/file-1.txt"}, - refCount: 1, - }, - { - name: "does not return anything for non-existing directories", - input: []string{"test-fixtures/non-existing/bogus.txt", "test-fixtures/non-existing/file-1.txt"}, - refCount: 0, - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - locations := make([]Location, 0) - resolver := DirectoryResolver{"test-fixtures"} - - for _, p := range c.input { - newRefs, err := resolver.FilesByPath(p) - if err != nil { - t.Errorf("could not generate locations: %+v", err) - } - for _, ref := range newRefs { - locations = append(locations, ref) - } - } - - contents, err := resolver.MultipleFileContentsByLocation(locations) - if err != nil { - t.Fatalf("unable to generate file contents by ref: %+v", err) - } - if len(contents) != c.refCount { - t.Errorf("unexpected number of locations produced: %d != %d", len(contents), c.refCount) - } - - }) - } -} - func TestDirectoryResolver_FilesByGlobMultiple(t *testing.T) { t.Run("finds multiple matching files", func(t *testing.T) { - resolver := DirectoryResolver{"test-fixtures"} + resolver := directoryResolver{"test-fixtures"} refs, err := resolver.FilesByGlob("image-symlinks/file*") if err != nil { @@ -195,7 +145,7 @@ func TestDirectoryResolver_FilesByGlobMultiple(t *testing.T) { func TestDirectoryResolver_FilesByGlobRecursive(t *testing.T) { t.Run("finds multiple matching files", func(t *testing.T) { - resolver := DirectoryResolver{"test-fixtures/image-symlinks"} + resolver := directoryResolver{"test-fixtures/image-symlinks"} refs, err := resolver.FilesByGlob("**/*.txt") if err != nil { @@ -212,7 +162,7 @@ func TestDirectoryResolver_FilesByGlobRecursive(t *testing.T) { func TestDirectoryResolver_FilesByGlobSingle(t *testing.T) { t.Run("finds multiple matching files", func(t *testing.T) { - resolver := DirectoryResolver{"test-fixtures"} + resolver := directoryResolver{"test-fixtures"} refs, err := resolver.FilesByGlob("image-symlinks/*1.txt") if err != nil { t.Fatalf("could not use resolver: %+v, %+v", err, refs) diff --git a/syft/source/file_data.go b/syft/source/file_data.go deleted file mode 100644 index bd3d0c849..000000000 --- a/syft/source/file_data.go +++ /dev/null @@ -1,8 +0,0 @@ -package source - -import "io" - -type FileData struct { - Location Location - Contents io.ReadCloser -} diff --git a/syft/source/file_metadata.go b/syft/source/file_metadata.go new file mode 100644 index 000000000..45c6a877a --- /dev/null +++ b/syft/source/file_metadata.go @@ -0,0 +1,28 @@ +package source + +import ( + "os" + + "github.com/anchore/stereoscope/pkg/image" +) + +type FileMetadata struct { + Mode os.FileMode + Type FileType + UserID int + GroupID int +} + +func fileMetadataByLocation(img *image.Image, location Location) (FileMetadata, error) { + entry, err := img.FileCatalog.Get(location.ref) + if err != nil { + return FileMetadata{}, err + } + + return FileMetadata{ + Mode: entry.Metadata.Mode, + Type: newFileTypeFromTarHeaderTypeFlag(entry.Metadata.TypeFlag), + UserID: entry.Metadata.UserID, + GroupID: entry.Metadata.GroupID, + }, nil +} diff --git a/syft/source/file_resolver.go b/syft/source/file_resolver.go new file mode 100644 index 000000000..331820af2 --- /dev/null +++ b/syft/source/file_resolver.go @@ -0,0 +1,39 @@ +package source + +import ( + "io" +) + +// FileResolver is an interface that encompasses how to get specific file references and file contents for a generic data source. +type FileResolver interface { + FileContentResolver + FilePathResolver + FileLocationResolver + FileMetadataResolver +} + +// FileContentResolver knows how to get file content for a given Location +type FileContentResolver interface { + FileContentsByLocation(Location) (io.ReadCloser, error) +} + +type FileMetadataResolver interface { + FileMetadataByLocation(Location) (FileMetadata, error) +} + +// FilePathResolver knows how to get a Location for given string paths and globs +type FilePathResolver interface { + // HasPath indicates if the given path exists in the underlying source. + HasPath(string) bool + // FilesByPath fetches a set of file references which have the given path (for an image, there may be multiple matches) + FilesByPath(paths ...string) ([]Location, error) + // FilesByGlob fetches a set of file references which the given glob matches + FilesByGlob(patterns ...string) ([]Location, error) + // RelativeFileByPath fetches a single file at the given path relative to the layer squash of the given reference. + // This is helpful when attempting to find a file that is in the same layer or lower as another file. + RelativeFileByPath(_ Location, path string) *Location +} + +type FileLocationResolver interface { + AllLocations() <-chan Location +} diff --git a/syft/source/file_type.go b/syft/source/file_type.go new file mode 100644 index 000000000..3718b12c4 --- /dev/null +++ b/syft/source/file_type.go @@ -0,0 +1,34 @@ +package source + +const ( + UnknownFileType FileType = "unknownFileType" + RegularFile FileType = "regularFile" + HardLink FileType = "hardLink" + SymbolicLink FileType = "symbolicLink" + CharacterDevice FileType = "characterDevice" + BlockDevice FileType = "blockDevice" + Directory FileType = "directory" + FIFONode FileType = "fifoNode" +) + +type FileType string + +func newFileTypeFromTarHeaderTypeFlag(flag byte) FileType { + switch flag { + case '0', '\x00': + return RegularFile + case '1': + return HardLink + case '2': + return SymbolicLink + case '3': + return CharacterDevice + case '4': + return BlockDevice + case '5': + return Directory + case '6': + return FIFONode + } + return UnknownFileType +} diff --git a/syft/source/image_metadata.go b/syft/source/image_metadata.go index a00803caa..38a351ca3 100644 --- a/syft/source/image_metadata.go +++ b/syft/source/image_metadata.go @@ -3,7 +3,7 @@ package source import "github.com/anchore/stereoscope/pkg/image" // ImageMetadata represents all static metadata that defines what a container image is. This is useful to later describe -// "what" was cataloged without needing the more complicated stereoscope Image objects or Resolver objects. +// "what" was cataloged without needing the more complicated stereoscope Image objects or FileResolver objects. type ImageMetadata struct { UserInput string `json:"userInput"` ID string `json:"imageID"` @@ -11,7 +11,6 @@ type ImageMetadata struct { MediaType string `json:"mediaType"` Tags []string `json:"tags"` Size int64 `json:"imageSize"` - Scope Scope `json:"scope"` // specific perspective to catalog Layers []LayerMetadata `json:"layers"` RawManifest []byte `json:"manifest"` RawConfig []byte `json:"config"` @@ -25,7 +24,7 @@ type LayerMetadata struct { } // NewImageMetadata creates a new ImageMetadata object populated from the given stereoscope Image object and user configuration. -func NewImageMetadata(img *image.Image, userInput string, scope Scope) ImageMetadata { +func NewImageMetadata(img *image.Image, userInput string) ImageMetadata { // populate artifacts... tags := make([]string, len(img.Metadata.Tags)) for idx, tag := range img.Metadata.Tags { @@ -34,7 +33,6 @@ func NewImageMetadata(img *image.Image, userInput string, scope Scope) ImageMeta theImg := ImageMetadata{ ID: img.Metadata.ID, UserInput: userInput, - Scope: scope, ManifestDigest: img.Metadata.ManifestDigest, Size: img.Metadata.Size, MediaType: string(img.Metadata.MediaType), diff --git a/syft/source/image_squash_resolver.go b/syft/source/image_squash_resolver.go index 137d498b5..3500a80a2 100644 --- a/syft/source/image_squash_resolver.go +++ b/syft/source/image_squash_resolver.go @@ -9,28 +9,31 @@ import ( "github.com/anchore/stereoscope/pkg/image" ) -var _ Resolver = (*ImageSquashResolver)(nil) +var _ FileResolver = (*imageSquashResolver)(nil) -// ImageSquashResolver implements path and content access for the Squashed source option for container image data sources. -type ImageSquashResolver struct { +// imageSquashResolver implements path and content access for the Squashed source option for container image data sources. +type imageSquashResolver struct { img *image.Image } -// NewImageSquashResolver returns a new resolver from the perspective of the squashed representation for the given image. -func NewImageSquashResolver(img *image.Image) (*ImageSquashResolver, error) { +// newImageSquashResolver returns a new resolver from the perspective of the squashed representation for the given image. +func newImageSquashResolver(img *image.Image) (*imageSquashResolver, error) { if img.SquashedTree() == nil { return nil, fmt.Errorf("the image does not have have a squashed tree") } - return &ImageSquashResolver{img: img}, nil + + return &imageSquashResolver{ + img: img, + }, nil } // HasPath indicates if the given path exists in the underlying source. -func (r *ImageSquashResolver) HasPath(path string) bool { +func (r *imageSquashResolver) HasPath(path string) bool { return r.img.SquashedTree().HasPath(file.Path(path)) } // FilesByPath returns all file.References that match the given paths within the squashed representation of the image. -func (r *ImageSquashResolver) FilesByPath(paths ...string) ([]Location, error) { +func (r *imageSquashResolver) FilesByPath(paths ...string) ([]Location, error) { uniqueFileIDs := file.NewFileReferenceSet() uniqueLocations := make([]Location, 0) @@ -74,7 +77,7 @@ func (r *ImageSquashResolver) FilesByPath(paths ...string) ([]Location, error) { } // FilesByGlob returns all file.References that match the given path glob pattern within the squashed representation of the image. -func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]Location, error) { +func (r *imageSquashResolver) FilesByGlob(patterns ...string) ([]Location, error) { uniqueFileIDs := file.NewFileReferenceSet() uniqueLocations := make([]Location, 0) @@ -88,7 +91,9 @@ func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]Location, error // don't consider directories (special case: there is no path information for /) if result.MatchPath == "/" { continue - } else if r.img.FileCatalog.Exists(result.Reference) { + } + + if r.img.FileCatalog.Exists(result.Reference) { metadata, err := r.img.FileCatalog.Get(result.Reference) if err != nil { return nil, fmt.Errorf("unable to get file metadata for path=%q: %w", result.MatchPath, err) @@ -116,8 +121,8 @@ func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]Location, error // RelativeFileByPath fetches a single file at the given path relative to the layer squash of the given reference. // This is helpful when attempting to find a file that is in the same layer or lower as another file. For the -// ImageSquashResolver, this is a simple path lookup. -func (r *ImageSquashResolver) RelativeFileByPath(_ Location, path string) *Location { +// imageSquashResolver, this is a simple path lookup. +func (r *imageSquashResolver) RelativeFileByPath(_ Location, path string) *Location { paths, err := r.FilesByPath(path) if err != nil { return nil @@ -129,14 +134,23 @@ func (r *ImageSquashResolver) RelativeFileByPath(_ Location, path string) *Locat return &paths[0] } -// MultipleFileContentsByLocation returns the file contents for all file.References relative to the image. Note that a -// file.Reference is a path relative to a particular layer, in this case only from the squashed representation. -func (r *ImageSquashResolver) MultipleFileContentsByLocation(locations []Location) (map[Location]io.ReadCloser, error) { - return mapLocationRefs(r.img.MultipleFileContentsByRef, locations) -} - // FileContentsByLocation fetches file contents for a single file reference, irregardless of the source layer. // If the path does not exist an error is returned. -func (r *ImageSquashResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { +func (r *imageSquashResolver) FileContentsByLocation(location Location) (io.ReadCloser, error) { return r.img.FileContentsByRef(location.ref) } + +func (r *imageSquashResolver) AllLocations() <-chan Location { + results := make(chan Location) + go func() { + defer close(results) + for _, ref := range r.img.SquashedTree().AllFiles() { + results <- NewLocationFromImage(string(ref.RealPath), ref, r.img) + } + }() + return results +} + +func (r *imageSquashResolver) FileMetadataByLocation(location Location) (FileMetadata, error) { + return fileMetadataByLocation(r.img, location) +} diff --git a/syft/source/image_squash_resolver_test.go b/syft/source/image_squash_resolver_test.go index a866f0a91..4d8c1556f 100644 --- a/syft/source/image_squash_resolver_test.go +++ b/syft/source/image_squash_resolver_test.go @@ -62,10 +62,9 @@ func TestImageSquashResolver_FilesByPath(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - resolver, err := NewImageSquashResolver(img) + resolver, err := newImageSquashResolver(img) if err != nil { t.Fatalf("could not create resolver: %+v", err) } @@ -179,10 +178,9 @@ func TestImageSquashResolver_FilesByGlob(t *testing.T) { } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - defer cleanup() + img := imagetest.GetFixtureImage(t, "docker-archive", "image-symlinks") - resolver, err := NewImageSquashResolver(img) + resolver, err := newImageSquashResolver(img) if err != nil { t.Fatalf("could not create resolver: %+v", err) } diff --git a/syft/source/location.go b/syft/source/location.go index 50083166a..532b01623 100644 --- a/syft/source/location.go +++ b/syft/source/location.go @@ -45,6 +45,14 @@ func NewLocationFromImage(virtualPath string, ref file.Reference, img *image.Ima } } +func NewLocationFromReference(ref file.Reference) Location { + return Location{ + VirtualPath: string(ref.RealPath), + RealPath: string(ref.RealPath), + ref: ref, + } +} + func (l Location) String() string { str := "" if l.ref.ID() != 0 { diff --git a/syft/source/mock_resolver.go b/syft/source/mock_resolver.go index ba815f3c3..31d129449 100644 --- a/syft/source/mock_resolver.go +++ b/syft/source/mock_resolver.go @@ -8,9 +8,9 @@ import ( "github.com/anchore/syft/internal/file" ) -var _ Resolver = (*MockResolver)(nil) +var _ FileResolver = (*MockResolver)(nil) -// MockResolver implements the Resolver interface and is intended for use *only in test code*. +// MockResolver implements the FileResolver interface and is intended for use *only in test code*. // It provides an implementation that can resolve local filesystem paths using only a provided discrete list of file // paths, which are typically paths to test fixtures. type MockResolver struct { @@ -55,20 +55,6 @@ func (r MockResolver) FileContentsByLocation(location Location) (io.ReadCloser, return nil, fmt.Errorf("no file for location: %v", location) } -// MultipleFileContentsByLocation returns the file contents for all specified Locations. -func (r MockResolver) MultipleFileContentsByLocation(locations []Location) (map[Location]io.ReadCloser, error) { - results := make(map[Location]io.ReadCloser) - for _, l := range locations { - contents, err := r.FileContentsByLocation(l) - if err != nil { - return nil, err - } - results[l] = contents - } - - return results, nil -} - // FilesByPath returns all Locations that match the given paths. func (r MockResolver) FilesByPath(paths ...string) ([]Location, error) { var results []Location @@ -110,3 +96,11 @@ func (r MockResolver) RelativeFileByPath(_ Location, path string) *Location { return &paths[0] } + +func (r MockResolver) AllLocations() <-chan Location { + panic("not implemented") +} + +func (r MockResolver) FileMetadataByLocation(Location) (FileMetadata, error) { + panic("not implemented") +} diff --git a/syft/source/resolver.go b/syft/source/resolver.go deleted file mode 100644 index 019536aca..000000000 --- a/syft/source/resolver.go +++ /dev/null @@ -1,46 +0,0 @@ -package source - -import ( - "fmt" - "io" - - "github.com/anchore/stereoscope/pkg/image" -) - -// Resolver is an interface that encompasses how to get specific file references and file contents for a generic data source. -type Resolver interface { - ContentResolver - FileResolver -} - -// ContentResolver knows how to get file content for given file.References -type ContentResolver interface { - FileContentsByLocation(Location) (io.ReadCloser, error) - // TODO: it is possible to be given duplicate locations that will be overridden in the map (key), a subtle problem that coule easily be misued. - MultipleFileContentsByLocation([]Location) (map[Location]io.ReadCloser, error) -} - -// FileResolver knows how to get a Location for given string paths and globs -type FileResolver interface { - // HasPath indicates if the given path exists in the underlying source. - HasPath(path string) bool - // FilesByPath fetches a set of file references which have the given path (for an image, there may be multiple matches) - FilesByPath(paths ...string) ([]Location, error) - // FilesByGlob fetches a set of file references which the given glob matches - FilesByGlob(patterns ...string) ([]Location, error) - // RelativeFileByPath fetches a single file at the given path relative to the layer squash of the given reference. - // This is helpful when attempting to find a file that is in the same layer or lower as another file. - RelativeFileByPath(_ Location, path string) *Location -} - -// getImageResolver returns the appropriate resolve for a container image given the source option -func getImageResolver(img *image.Image, scope Scope) (Resolver, error) { - switch scope { - case SquashedScope: - return NewImageSquashResolver(img) - case AllLayersScope: - return NewAllLayersResolver(img) - default: - return nil, fmt.Errorf("bad scope provided: %+v", scope) - } -} diff --git a/syft/source/source.go b/syft/source/source.go index 182a87f71..b1e081db6 100644 --- a/syft/source/source.go +++ b/syft/source/source.go @@ -18,7 +18,6 @@ import ( // Source is an object that captures the data source to be cataloged, configuration, and a specific resolver used // in cataloging (based on the data source and configuration) type Source struct { - Resolver Resolver // a Resolver object to use in file path/glob resolution and file contents resolution Image *image.Image // the image object to be cataloged (image only) Metadata Metadata } @@ -26,7 +25,7 @@ type Source struct { type sourceDetector func(string) (image.Source, string, error) // New produces a Source based on userInput like dir: or image:tag -func New(userInput string, o Scope) (Source, func(), error) { +func New(userInput string) (Source, func(), error) { fs := afero.NewOsFs() parsedScheme, location, err := detectScheme(fs, image.DetectSource, userInput) if err != nil { @@ -60,7 +59,7 @@ func New(userInput string, o Scope) (Source, func(), error) { return Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err) } - s, err := NewFromImage(img, o, location) + s, err := NewFromImage(img, location) if err != nil { return Source{}, cleanup, fmt.Errorf("could not populate source with image: %w", err) } @@ -73,9 +72,6 @@ func New(userInput string, o Scope) (Source, func(), error) { // NewFromDirectory creates a new source object tailored to catalog a given filesystem directory recursively. func NewFromDirectory(path string) (Source, error) { return Source{ - Resolver: &DirectoryResolver{ - Path: path, - }, Metadata: Metadata{ Scheme: DirectoryScheme, Path: path, @@ -85,22 +81,33 @@ func NewFromDirectory(path string) (Source, error) { // NewFromImage creates a new source object tailored to catalog a given container image, relative to the // option given (e.g. all-layers, squashed, etc) -func NewFromImage(img *image.Image, scope Scope, userImageStr string) (Source, error) { +func NewFromImage(img *image.Image, userImageStr string) (Source, error) { if img == nil { return Source{}, fmt.Errorf("no image given") } - resolver, err := getImageResolver(img, scope) - if err != nil { - return Source{}, fmt.Errorf("could not determine file resolver: %w", err) - } - return Source{ - Resolver: resolver, - Image: img, + Image: img, Metadata: Metadata{ Scheme: ImageScheme, - ImageMetadata: NewImageMetadata(img, userImageStr, scope), + ImageMetadata: NewImageMetadata(img, userImageStr), }, }, nil } + +func (s Source) FileResolver(scope Scope) (FileResolver, error) { + switch s.Metadata.Scheme { + case DirectoryScheme: + return newDirectoryResolver(s.Metadata.Path), nil + case ImageScheme: + switch scope { + case SquashedScope: + return newImageSquashResolver(s.Image) + case AllLayersScope: + return newAllLayersResolver(s.Image) + default: + return nil, fmt.Errorf("bad image scope provided: %+v", scope) + } + } + return nil, fmt.Errorf("unable to determine FilePathResolver with current scheme=%q", s.Metadata.Scheme) +} diff --git a/syft/source/source_test.go b/syft/source/source_test.go index 35117a3f1..72a97653b 100644 --- a/syft/source/source_test.go +++ b/syft/source/source_test.go @@ -1,7 +1,6 @@ package source import ( - "io/ioutil" "os" "testing" @@ -12,18 +11,7 @@ import ( func TestNewFromImageFails(t *testing.T) { t.Run("no image given", func(t *testing.T) { - _, err := NewFromImage(nil, AllLayersScope, "") - if err == nil { - t.Errorf("expected an error condition but none was given") - } - }) -} - -func TestNewFromImageUnknownOption(t *testing.T) { - img := image.Image{} - - t.Run("unknown option is an error", func(t *testing.T) { - _, err := NewFromImage(&img, UnknownScope, "") + _, err := NewFromImage(nil, "") if err == nil { t.Errorf("expected an error condition but none was given") } @@ -37,7 +25,7 @@ func TestNewFromImage(t *testing.T) { } t.Run("create a new source object from image", func(t *testing.T) { - _, err := NewFromImage(&img, AllLayersScope, "") + _, err := NewFromImage(&img, "") if err != nil { t.Errorf("unexpected error when creating a new Locations from img: %+v", err) } @@ -87,8 +75,11 @@ func TestNewFromDirectory(t *testing.T) { if src.Metadata.Path != test.input { t.Errorf("mismatched stringer: '%s' != '%s'", src.Metadata.Path, test.input) } - - refs, err := src.Resolver.FilesByPath(test.inputPaths...) + resolver, err := src.FileResolver(SquashedScope) + if err != nil { + t.Errorf("could not get resolver error: %+v", err) + } + refs, err := resolver.FilesByPath(test.inputPaths...) if err != nil { t.Errorf("FilesByPath call produced an error: %+v", err) } @@ -101,58 +92,6 @@ func TestNewFromDirectory(t *testing.T) { } } -func TestMultipleFileContentsByLocation(t *testing.T) { - testCases := []struct { - desc string - input string - path string - expected string - }{ - { - input: "test-fixtures/path-detected", - desc: "empty file", - path: "test-fixtures/path-detected/empty", - expected: "", - }, - { - input: "test-fixtures/path-detected", - desc: "file has contents", - path: "test-fixtures/path-detected/.vimrc", - expected: "\" A .vimrc file\n", - }, - } - for _, test := range testCases { - t.Run(test.desc, func(t *testing.T) { - p, err := NewFromDirectory(test.input) - if err != nil { - t.Errorf("could not create NewDirScope: %+v", err) - } - locations, err := p.Resolver.FilesByPath(test.path) - if err != nil { - t.Errorf("could not get file references from path: %s, %v", test.path, err) - } - - if len(locations) != 1 { - t.Fatalf("expected a single location to be generated but got: %d", len(locations)) - } - location := locations[0] - - contents, err := p.Resolver.MultipleFileContentsByLocation([]Location{location}) - contentReader := contents[location] - - content, err := ioutil.ReadAll(contentReader) - if err != nil { - t.Fatalf("cannot read contents: %+v", err) - } - - if string(content) != test.expected { - t.Errorf("unexpected contents from file: '%s' != '%s'", content, test.expected) - } - - }) - } -} - func TestFilesByPathDoesNotExist(t *testing.T) { testCases := []struct { desc string @@ -168,11 +107,15 @@ func TestFilesByPathDoesNotExist(t *testing.T) { } for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { - p, err := NewFromDirectory(test.input) + src, err := NewFromDirectory(test.input) if err != nil { t.Errorf("could not create NewDirScope: %+v", err) } - refs, err := p.Resolver.FilesByPath(test.path) + resolver, err := src.FileResolver(SquashedScope) + if err != nil { + t.Errorf("could not get resolver error: %+v", err) + } + refs, err := resolver.FilesByPath(test.path) if err != nil { t.Errorf("could not get file references from path: %s, %v", test.path, err) } @@ -213,12 +156,15 @@ func TestFilesByGlob(t *testing.T) { } for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { - p, err := NewFromDirectory(test.input) + src, err := NewFromDirectory(test.input) if err != nil { t.Errorf("could not create NewDirScope: %+v", err) } - - contents, err := p.Resolver.FilesByGlob(test.glob) + resolver, err := src.FileResolver(SquashedScope) + if err != nil { + t.Errorf("could not get resolver error: %+v", err) + } + contents, err := resolver.FilesByGlob(test.glob) if len(contents) != test.expected { t.Errorf("unexpected number of files found by glob (%s): %d != %d", test.glob, len(contents), test.expected) From 97f0f83544ac3874119b30d052051e2bc1af7484 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:53:31 -0400 Subject: [PATCH 05/29] add poweruser command and alias root to packages subcommand Signed-off-by: Alex Goodman --- README.md | 23 ++- cmd/check_for_application_update.go | 30 ++++ cmd/cmd.go | 144 +++++---------- cmd/completion.go | 53 +++++- cmd/packages.go | 270 ++++++++++++++++++++++++++++ cmd/power_user.go | 100 +++++++++++ cmd/power_user_tasks.go | 106 +++++++++++ cmd/root.go | 230 +++--------------------- cmd/version.go | 3 +- 9 files changed, 646 insertions(+), 313 deletions(-) create mode 100644 cmd/check_for_application_update.go create mode 100644 cmd/packages.go create mode 100644 cmd/power_user.go create mode 100644 cmd/power_user_tasks.go diff --git a/README.md b/README.md index efcfbe7eb..83d1f2f6e 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,6 @@ Configuration options (example values are the default): # same as -o ; SYFT_OUTPUT env var output: "table" -# the search space to look for packages (options: all-layers, squashed) -# same as -s ; SYFT_SCOPE env var -scope: "squashed" - # suppress all output (except for the SBOM report) # same as -q ; SYFT_QUIET env var quiet: false @@ -97,6 +93,21 @@ quiet: false # same as SYFT_CHECK_FOR_APP_UPDATE env var check-for-app-update: true +packages: + # the search space to look for packages (options: all-layers, squashed) + # same as -s ; SYFT_SCOPE env var + scope: "squashed" + +file-metadata: + # enable/disable cataloging if file metadata + cataloging-enabled: true + + # the search space to look for file metadata (options: all-layers, squashed) + scope: "squashed" + + # the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1") + digests: ["sha256"] + log: # use structured logging # same as SYFT_LOG_STRUCTURED env var @@ -111,10 +122,6 @@ log: file: "" anchore: - # (feature-preview) enable uploading of results to Anchore Enterprise automatically (supported on Enterprise 3.0+) - # same as SYFT_ANCHORE_UPLOAD_ENABLED env var - upload-enabled: false - # (feature-preview) the Anchore Enterprise Host or URL to upload results to (supported on Enterprise 3.0+) # same as -H ; SYFT_ANCHORE_HOST env var host: "" diff --git a/cmd/check_for_application_update.go b/cmd/check_for_application_update.go new file mode 100644 index 000000000..409d6beb0 --- /dev/null +++ b/cmd/check_for_application_update.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/internal/version" + "github.com/anchore/syft/syft/event" + "github.com/wagoodman/go-partybus" +) + +func checkForApplicationUpdate() { + if appConfig.CheckForAppUpdate { + isAvailable, newVersion, err := version.IsUpdateAvailable() + if err != nil { + // this should never stop the application + log.Errorf(err.Error()) + } + if isAvailable { + log.Infof("new version of %s is available: %s (current version is %s)", internal.ApplicationName, newVersion, version.FromBuild().Version) + + bus.Publish(partybus.Event{ + Type: event.AppUpdateAvailable, + Value: newVersion, + }) + } else { + log.Debugf("no new %s update available", internal.ApplicationName) + } + } +} diff --git a/cmd/cmd.go b/cmd/cmd.go index e813174a9..450d3e469 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -3,29 +3,29 @@ package cmd import ( "fmt" "os" + "strings" + + "github.com/spf13/cobra" "github.com/anchore/stereoscope" "github.com/anchore/syft/internal/config" "github.com/anchore/syft/internal/log" "github.com/anchore/syft/internal/logger" "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/presenter" - "github.com/anchore/syft/syft/source" "github.com/gookit/color" - "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/wagoodman/go-partybus" ) -var appConfig *config.Application -var eventBus *partybus.Bus -var eventSubscription *partybus.Subscription -var cliOpts = config.CliOnlyOptions{} +var ( + appConfig *config.Application + eventBus *partybus.Bus + eventSubscription *partybus.Subscription +) func init() { - setGlobalCliOptions() - cobra.OnInitialize( + initCmdAliasBindings, initAppConfig, initLogging, logAppConfig, @@ -33,111 +33,55 @@ func init() { ) } +// provided to disambiguate the root vs packages command, whichever is indicated by the cli args will be set here. +// TODO: when the root alias command is removed, this function (hack) can be removed +var activeCmd *cobra.Command + func Execute() { if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err.Error()) + fmt.Fprintln(os.Stderr, color.Red.Sprint(err.Error())) os.Exit(1) } } -func setGlobalCliOptions() { - rootCmd.PersistentFlags().StringVarP(&cliOpts.ConfigPath, "config", "c", "", "application config file") +func initCmdAliasBindings() { + // TODO: when the root alias command is removed, this function (hack) can be removed - // scan options - flag := "scope" - rootCmd.Flags().StringP( - "scope", "s", source.SquashedScope.String(), - fmt.Sprintf("selection of layers to catalog, options=%v", source.AllScopes)) - if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) + activeCmd = rootCmd + for i, a := range os.Args { + if i == 0 { + // don't consider the bin + continue + } + if a == "packages" { + // this is positively the first subcommand directive, and is "packages" + activeCmd = packagesCmd + break + } + if !strings.HasPrefix("-", a) { + // this is the first non-switch provided and was not "packages" + break + } } - setGlobalFormatOptions() - setGlobalUploadOptions() -} - -func setGlobalFormatOptions() { - // output & formatting options - flag := "output" - rootCmd.Flags().StringP( - flag, "o", string(presenter.TablePresenter), - fmt.Sprintf("report output formatter, options=%v", presenter.Options), - ) - if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) + if activeCmd == rootCmd { + // note: cobra supports command deprecation, however the command name is empty and does not report to stderr + fmt.Fprintln(os.Stderr, color.New(color.Bold, color.Red).Sprintf("The root command is deprecated, please use the 'packages' subcommand")) } - flag = "quiet" - rootCmd.Flags().BoolP( - flag, "q", false, - "suppress all logging output", - ) - if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) - } - - rootCmd.Flags().CountVarP(&cliOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)") -} - -func setGlobalUploadOptions() { - flag := "host" - rootCmd.Flags().StringP( - flag, "H", "", - "the hostname or URL of the Anchore Enterprise instance to upload to", - ) - if err := viper.BindPFlag("anchore.host", rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) - } - - flag = "username" - rootCmd.Flags().StringP( - flag, "u", "", - "the username to authenticate against Anchore Enterprise", - ) - if err := viper.BindPFlag("anchore.username", rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) - } - - flag = "password" - rootCmd.Flags().StringP( - flag, "p", "", - "the password to authenticate against Anchore Enterprise", - ) - if err := viper.BindPFlag("anchore.password", rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '%s': %+v", flag, err) - os.Exit(1) - } - - flag = "dockerfile" - rootCmd.Flags().StringP( - flag, "d", "", - "include dockerfile for upload to Anchore Enterprise", - ) - if err := viper.BindPFlag("anchore.dockerfile", rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '#{flag}': #{err}") - os.Exit(1) - } - - flag = "overwrite-existing-image" - rootCmd.Flags().Bool( - flag, false, - "overwrite an existing image during the upload to Anchore Enterprise", - ) - if err := viper.BindPFlag("anchore.overwrite-existing-image", rootCmd.Flags().Lookup(flag)); err != nil { - fmt.Printf("unable to bind flag '#{flag}': #{err}") - os.Exit(1) + // note: we need to lazily bind config options since they are shared between both the root command + // and the packages command. Otherwise there will be global viper state that is in contention. + // See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE + // reading the application configuration, which implies that it must be an initializer (or rewrite the command + // initialization structure against typical patterns used with cobra, which is somewhat extreme for a + // temporary alias) + if err := bindConfigOptions(activeCmd.Flags()); err != nil { + panic(err) } } func initAppConfig() { - cfgVehicle := viper.GetViper() - wasHostnameSet := rootCmd.Flags().Changed("host") - cfg, err := config.LoadApplicationConfig(cfgVehicle, cliOpts, wasHostnameSet) + cfg, err := config.LoadApplicationConfig(viper.GetViper(), persistentOpts) if err != nil { fmt.Printf("failed to load application config: \n\t%+v\n", err) os.Exit(1) @@ -163,7 +107,7 @@ func initLogging() { } func logAppConfig() { - log.Debugf("Application config:\n%+v", color.Magenta.Sprint(appConfig.String())) + log.Debugf("application config:\n%+v", color.Magenta.Sprint(appConfig.String())) } func initEventBus() { diff --git a/cmd/completion.go b/cmd/completion.go index 7ec259b58..d71c0b4eb 100644 --- a/cmd/completion.go +++ b/cmd/completion.go @@ -1,15 +1,22 @@ package cmd import ( + "context" "os" + "strings" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/client" "github.com/spf13/cobra" ) // completionCmd represents the completion command var completionCmd = &cobra.Command{ - Use: "completion [bash|zsh|fish]", - Short: "Generate a shell completion for Syft (listing local docker images)", + Hidden: true, + Use: "completion [bash|zsh|fish]", + Short: "Generate a shell completion for Syft (listing local docker images)", Long: `To load completions (docker image list): Bash: @@ -63,3 +70,45 @@ $ syft completion fish > ~/.config/fish/completions/syft.fish func init() { rootCmd.AddCommand(completionCmd) } + +func dockerImageValidArgsFunction(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // Since we use ValidArgsFunction, Cobra will call this AFTER having parsed all flags and arguments provided + dockerImageRepoTags, err := listLocalDockerImages(toComplete) + if err != nil { + // Indicates that an error occurred and completions should be ignored + return []string{"completion failed"}, cobra.ShellCompDirectiveError + } + if len(dockerImageRepoTags) == 0 { + return []string{"no docker images found"}, cobra.ShellCompDirectiveError + } + // ShellCompDirectiveDefault indicates that the shell will perform its default behavior after completions have + // been provided (without implying other possible directives) + return dockerImageRepoTags, cobra.ShellCompDirectiveDefault +} + +func listLocalDockerImages(prefix string) ([]string, error) { + var repoTags = make([]string, 0) + ctx := context.Background() + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return repoTags, err + } + + // Only want to return tagged images + imageListArgs := filters.NewArgs() + imageListArgs.Add("dangling", "false") + images, err := cli.ImageList(ctx, types.ImageListOptions{All: false, Filters: imageListArgs}) + if err != nil { + return repoTags, err + } + + for _, image := range images { + // image may have multiple tags + for _, tag := range image.RepoTags { + if strings.HasPrefix(tag, prefix) { + repoTags = append(repoTags, tag) + } + } + } + return repoTags, nil +} diff --git a/cmd/packages.go b/cmd/packages.go new file mode 100644 index 000000000..1e95adec5 --- /dev/null +++ b/cmd/packages.go @@ -0,0 +1,270 @@ +package cmd + +import ( + "context" + "fmt" + "io/ioutil" + "os" + + "github.com/spf13/viper" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/anchore" + "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/log" + "github.com/anchore/syft/internal/presenter/packages" + "github.com/anchore/syft/internal/ui" + "github.com/anchore/syft/syft" + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/event" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" + "github.com/pkg/profile" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/wagoodman/go-partybus" +) + +const ( + packagesExample = ` {{.appName}} {{.command}} alpine:latest a summary of discovered packages + {{.appName}} {{.command}} alpine:latest -o json show all possible cataloging details + {{.appName}} {{.command}} alpine:latest -o cyclonedx show a CycloneDX SBOM + {{.appName}} {{.command}} alpine:latest -vv show verbose debug information + + Supports the following image sources: + {{.appName}} {{.command}} yourrepo/yourimage:tag defaults to using images from a Docker daemon + {{.appName}} {{.command}} path/to/a/file/or/dir a Docker tar, OCI tar, OCI directory, or generic filesystem directory + + You can also explicitly specify the scheme to use: + {{.appName}} {{.command}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon + {{.appName}} {{.command}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save" + {{.appName}} {{.command}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise) + {{.appName}} {{.command}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise) + {{.appName}} {{.command}} dir:path/to/yourproject read directly from a path on disk (any directory) +` +) + +var ( + packagesPresenterOpt packages.PresenterOption + packagesArgs = cobra.MinimumNArgs(1) + packagesCmd = &cobra.Command{ + Use: "packages [SOURCE]", + Short: "Generate a package SBOM", + Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems", + Example: internal.Tprintf(packagesExample, map[string]interface{}{ + "appName": internal.ApplicationName, + "command": "packages", + }), + Args: packagesArgs, + SilenceUsage: true, + SilenceErrors: true, + PreRunE: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + err := cmd.Help() + if err != nil { + return err + } + // silently exit + return fmt.Errorf("") + } + + // set the presenter + presenterOption := packages.ParsePresenterOption(appConfig.Output) + if presenterOption == packages.UnknownPresenterOption { + return fmt.Errorf("bad --output value '%s'", appConfig.Output) + } + packagesPresenterOpt = presenterOption + + if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem { + return fmt.Errorf("cannot profile CPU and memory simultaneously") + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + if appConfig.Dev.ProfileCPU { + defer profile.Start(profile.CPUProfile).Stop() + } else if appConfig.Dev.ProfileMem { + defer profile.Start(profile.MemProfile).Stop() + } + + return packagesExec(cmd, args) + }, + ValidArgsFunction: dockerImageValidArgsFunction, + } +) + +func init() { + setPackageFlags(packagesCmd.Flags()) + + rootCmd.AddCommand(packagesCmd) +} + +func setPackageFlags(flags *pflag.FlagSet) { + ///////// Formatting & Input options ////////////////////////////////////////////// + + flags.StringP( + "scope", "s", source.SquashedScope.String(), + fmt.Sprintf("selection of layers to catalog, options=%v", source.AllScopes)) + + flags.StringP( + "output", "o", string(packages.TablePresenterOption), + fmt.Sprintf("report output formatter, options=%v", packages.AllPresenters), + ) + + ///////// Upload options ////////////////////////////////////////////////////////// + flags.StringP( + "host", "H", "", + "the hostname or URL of the Anchore Enterprise instance to upload to", + ) + + flags.StringP( + "username", "u", "", + "the username to authenticate against Anchore Enterprise", + ) + + flags.StringP( + "password", "p", "", + "the password to authenticate against Anchore Enterprise", + ) + + flags.StringP( + "dockerfile", "d", "", + "include dockerfile for upload to Anchore Enterprise", + ) + + flags.Bool( + "overwrite-existing-image", false, + "overwrite an existing image during the upload to Anchore Enterprise", + ) +} + +func bindConfigOptions(flags *pflag.FlagSet) error { + ///////// Formatting & Input options ////////////////////////////////////////////// + + if err := viper.BindPFlag("packages.scope", flags.Lookup("scope")); err != nil { + return err + } + + if err := viper.BindPFlag("output", flags.Lookup("output")); err != nil { + return err + } + + ///////// Upload options ////////////////////////////////////////////////////////// + + if err := viper.BindPFlag("anchore.host", flags.Lookup("host")); err != nil { + return err + } + + if err := viper.BindPFlag("anchore.username", flags.Lookup("username")); err != nil { + return err + } + + if err := viper.BindPFlag("anchore.password", flags.Lookup("password")); err != nil { + return err + } + + if err := viper.BindPFlag("anchore.dockerfile", flags.Lookup("dockerfile")); err != nil { + return err + } + + if err := viper.BindPFlag("anchore.overwrite-existing-image", flags.Lookup("overwrite-existing-image")); err != nil { + return err + } + + return nil +} + +func packagesExec(_ *cobra.Command, args []string) error { + errs := packagesExecWorker(args[0]) + ux := ui.Select(appConfig.CliOptions.Verbosity > 0, appConfig.Quiet) + return ux(errs, eventSubscription) +} + +func packagesExecWorker(userInput string) <-chan error { + errs := make(chan error) + go func() { + defer close(errs) + + checkForApplicationUpdate() + + src, cleanup, err := source.New(userInput) + if err != nil { + errs <- fmt.Errorf("failed to determine image source: %+v", err) + return + } + defer cleanup() + + catalog, d, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt) + if err != nil { + errs <- fmt.Errorf("failed to catalog input: %+v", err) + return + } + + if appConfig.Anchore.Host != "" { + if err := runPackageSbomUpload(src, src.Metadata, catalog, d, appConfig.Packages.ScopeOpt); err != nil { + errs <- err + return + } + } + + bus.Publish(partybus.Event{ + Type: event.PresenterReady, + Value: packages.Presenter(packagesPresenterOpt, packages.PresenterConfig{ + SourceMetadata: src.Metadata, + Catalog: catalog, + Distro: d, + Scope: appConfig.Packages.ScopeOpt, + }), + }) + }() + return errs +} + +func runPackageSbomUpload(src source.Source, s source.Metadata, catalog *pkg.Catalog, d *distro.Distro, scope source.Scope) error { + log.Infof("uploading results to %s", appConfig.Anchore.Host) + + if src.Metadata.Scheme != source.ImageScheme { + return fmt.Errorf("unable to upload results: only images are supported") + } + + var dockerfileContents []byte + if appConfig.Anchore.Dockerfile != "" { + if _, err := os.Stat(appConfig.Anchore.Dockerfile); os.IsNotExist(err) { + return fmt.Errorf("unable dockerfile=%q does not exist: %w", appConfig.Anchore.Dockerfile, err) + } + + fh, err := os.Open(appConfig.Anchore.Dockerfile) + if err != nil { + return fmt.Errorf("unable to open dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) + } + + dockerfileContents, err = ioutil.ReadAll(fh) + if err != nil { + return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) + } + } + + c, err := anchore.NewClient(anchore.Configuration{ + BaseURL: appConfig.Anchore.Host, + Username: appConfig.Anchore.Username, + Password: appConfig.Anchore.Password, + }) + if err != nil { + return fmt.Errorf("failed to create anchore client: %+v", err) + } + + importCfg := anchore.ImportConfig{ + ImageMetadata: src.Image.Metadata, + SourceMetadata: s, + Catalog: catalog, + Distro: d, + Dockerfile: dockerfileContents, + OverwriteExistingUpload: appConfig.Anchore.OverwriteExistingImage, + Scope: scope, + } + + if err := c.Import(context.Background(), importCfg); err != nil { + return fmt.Errorf("failed to upload results to host=%s: %+v", appConfig.Anchore.Host, err) + } + return nil +} diff --git a/cmd/power_user.go b/cmd/power_user.go new file mode 100644 index 000000000..1f48459a6 --- /dev/null +++ b/cmd/power_user.go @@ -0,0 +1,100 @@ +package cmd + +import ( + "fmt" + + "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/presenter/poweruser" + "github.com/anchore/syft/internal/ui" + "github.com/anchore/syft/syft/event" + "github.com/anchore/syft/syft/source" + "github.com/pkg/profile" + "github.com/spf13/cobra" + "github.com/wagoodman/go-partybus" +) + +var powerUserOpts = struct { + configPath string +}{} + +var powerUserCmd = &cobra.Command{ + Use: "power-user [SOURCE]", + Short: "Run bulk operations on container images", + Example: ` {{.appName}} power-user `, + Args: cobra.ExactArgs(1), + Hidden: true, + SilenceUsage: true, + SilenceErrors: true, + PreRunE: func(cmd *cobra.Command, args []string) error { + if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem { + return fmt.Errorf("cannot profile CPU and memory simultaneously") + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + if appConfig.Dev.ProfileCPU { + defer profile.Start(profile.CPUProfile).Stop() + } else if appConfig.Dev.ProfileMem { + defer profile.Start(profile.MemProfile).Stop() + } + + return powerUserExec(cmd, args) + }, + ValidArgsFunction: dockerImageValidArgsFunction, +} + +func init() { + powerUserCmd.Flags().StringVarP(&powerUserOpts.configPath, "config", "c", "", "config file path with all power-user options") + + rootCmd.AddCommand(powerUserCmd) +} + +func powerUserExec(_ *cobra.Command, args []string) error { + errs := powerUserExecWorker(args[0]) + ux := ui.Select(appConfig.CliOptions.Verbosity > 0, appConfig.Quiet) + return ux(errs, eventSubscription) +} + +func powerUserExecWorker(userInput string) <-chan error { + errs := make(chan error) + go func() { + defer close(errs) + + checkForApplicationUpdate() + + src, cleanup, err := source.New(userInput) + if err != nil { + errs <- err + return + } + defer cleanup() + + if src.Metadata.Scheme != source.ImageScheme { + errs <- fmt.Errorf("the power-user subcommand only allows for 'image' schemes, given %q", src.Metadata.Scheme) + return + } + + analysisResults := poweruser.JSONDocumentConfig{ + SourceMetadata: src.Metadata, + ApplicationConfig: *appConfig, + } + tasks, err := powerUserTasks(src) + if err != nil { + errs <- err + return + } + + for _, task := range tasks { + if err = task(&analysisResults); err != nil { + errs <- err + return + } + } + + bus.Publish(partybus.Event{ + Type: event.PresenterReady, + Value: poweruser.NewJSONPresenter(analysisResults), + }) + }() + return errs +} diff --git a/cmd/power_user_tasks.go b/cmd/power_user_tasks.go new file mode 100644 index 000000000..0d5c21746 --- /dev/null +++ b/cmd/power_user_tasks.go @@ -0,0 +1,106 @@ +package cmd + +import ( + "github.com/anchore/syft/internal/presenter/poweruser" + "github.com/anchore/syft/syft" + "github.com/anchore/syft/syft/file" + "github.com/anchore/syft/syft/source" +) + +type powerUserTask func(*poweruser.JSONDocumentConfig) error + +func powerUserTasks(src source.Source) ([]powerUserTask, error) { + var tasks []powerUserTask + var err error + var task powerUserTask + + task = catalogPackagesTask(src) + if task != nil { + tasks = append(tasks, task) + } + + task, err = catalogFileMetadataTask(src) + if err != nil { + return nil, err + } else if task != nil { + tasks = append(tasks, task) + } + + task, err = catalogFileDigestTask(src) + if err != nil { + return nil, err + } else if task != nil { + tasks = append(tasks, task) + } + + return tasks, nil +} + +func catalogPackagesTask(src source.Source) powerUserTask { + if !appConfig.Packages.CatalogingEnabled { + return nil + } + + task := func(results *poweruser.JSONDocumentConfig) error { + packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt) + if err != nil { + return err + } + + results.PackageCatalog = packageCatalog + results.Distro = theDistro + + return nil + } + + return task +} + +func catalogFileMetadataTask(src source.Source) (powerUserTask, error) { + if !appConfig.FileMetadata.CatalogingEnabled { + return nil, nil + } + + resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt) + if err != nil { + return nil, err + } + + task := func(results *poweruser.JSONDocumentConfig) error { + result, err := file.NewMetadataCataloger(resolver).Catalog() + if err != nil { + return err + } + results.FileMetadata = result + return nil + } + + return task, nil +} + +func catalogFileDigestTask(src source.Source) (powerUserTask, error) { + if !appConfig.FileMetadata.CatalogingEnabled { + return nil, nil + } + + resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt) + if err != nil { + return nil, err + } + + cataloger, err := file.NewDigestsCataloger(resolver, appConfig.FileMetadata.Digests) + if err != nil { + return nil, err + } + + task := func(results *poweruser.JSONDocumentConfig) error { + result, err := cataloger.Catalog() + if err != nil { + return err + } + results.FileDigests = result + return nil + } + + return task, nil +} diff --git a/cmd/root.go b/cmd/root.go index d89f8e739..cb131972e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,217 +1,45 @@ package cmd import ( - "context" "fmt" - "io/ioutil" "os" - "strings" - "github.com/pkg/profile" - - "github.com/anchore/syft/internal" - "github.com/anchore/syft/internal/anchore" - "github.com/anchore/syft/internal/bus" - "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/internal/ui" - "github.com/anchore/syft/internal/version" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/distro" - "github.com/anchore/syft/syft/event" - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/presenter" - "github.com/anchore/syft/syft/source" - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/filters" - "github.com/docker/docker/client" + "github.com/anchore/syft/internal/config" "github.com/spf13/cobra" - "github.com/wagoodman/go-partybus" + "github.com/spf13/viper" ) +var persistentOpts = config.CliOnlyOptions{} + +// rootCmd is currently an alias for the packages command var rootCmd = &cobra.Command{ - Use: fmt.Sprintf("%s [SOURCE]", internal.ApplicationName), - Short: "A tool for generating a Software Bill Of Materials (PackageSBOM) 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}} 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, - }), - Args: cobra.MaximumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - if len(args) == 0 { - err := cmd.Help() - if err != nil { - log.Errorf(err.Error()) - os.Exit(1) - } - os.Exit(1) - } - - if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem { - log.Errorf("cannot profile CPU and memory simultaneously") - os.Exit(1) - } - - if appConfig.Dev.ProfileCPU { - defer profile.Start(profile.CPUProfile).Stop() - } else if appConfig.Dev.ProfileMem { - defer profile.Start(profile.MemProfile).Stop() - } - - err := doRunCmd(cmd, args) - - if err != nil { - log.Errorf(err.Error()) - os.Exit(1) - } - }, - ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - // Since we use ValidArgsFunction, Cobra will call this AFTER having parsed all flags and arguments provided - dockerImageRepoTags, err := ListLocalDockerImages(toComplete) - if err != nil { - // Indicates that an error occurred and completions should be ignored - return []string{"completion failed"}, cobra.ShellCompDirectiveError - } - if len(dockerImageRepoTags) == 0 { - return []string{"no docker images found"}, cobra.ShellCompDirectiveError - } - // ShellCompDirectiveDefault indicates that the shell will perform its default behavior after completions have - // been provided (without implying other possible directives) - return dockerImageRepoTags, cobra.ShellCompDirectiveDefault - }, + Short: packagesCmd.Short, + Long: packagesCmd.Long, + Args: packagesCmd.Args, + Example: packagesCmd.Example, + SilenceUsage: true, + SilenceErrors: true, + PreRunE: packagesCmd.PreRunE, + RunE: packagesCmd.RunE, + ValidArgsFunction: packagesCmd.ValidArgsFunction, } -func startWorker(userInput string) <-chan error { - errs := make(chan error) - go func() { - defer close(errs) +func init() { + // set universal flags + rootCmd.PersistentFlags().StringVarP(&persistentOpts.ConfigPath, "config", "c", "", "application config file") - if appConfig.CheckForAppUpdate { - isAvailable, newVersion, err := version.IsUpdateAvailable() - if err != nil { - log.Errorf(err.Error()) - } - if isAvailable { - log.Infof("new version of %s is available: %s", internal.ApplicationName, newVersion) + flag := "quiet" + rootCmd.PersistentFlags().BoolP( + flag, "q", false, + "suppress all logging output", + ) + if err := viper.BindPFlag(flag, rootCmd.PersistentFlags().Lookup(flag)); err != nil { + fmt.Printf("unable to bind flag '%s': %+v", flag, err) + os.Exit(1) + } - bus.Publish(partybus.Event{ - Type: event.AppUpdateAvailable, - Value: newVersion, - }) - } else { - log.Debugf("no new %s update available", internal.ApplicationName) - } - } + rootCmd.PersistentFlags().CountVarP(&persistentOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)") - src, catalog, distro, err := syft.Catalog(userInput, appConfig.ScopeOpt) - if err != nil { - errs <- fmt.Errorf("failed to catalog input: %+v", err) - return - } - - if appConfig.Anchore.UploadEnabled { - if err := doImport(src, src.Metadata, catalog, distro); err != nil { - errs <- err - return - } - } - - bus.Publish(partybus.Event{ - Type: event.CatalogerFinished, - Value: presenter.GetPresenter(appConfig.PresenterOpt, src.Metadata, catalog, distro), - }) - }() - return errs -} - -func doImport(src source.Source, s source.Metadata, catalog *pkg.Catalog, d *distro.Distro) error { - // TODO: ETUI element for this - log.Infof("uploading results to %s", appConfig.Anchore.Host) - - if src.Metadata.Scheme != source.ImageScheme { - return fmt.Errorf("unable to upload results: only images are supported") - } - - var dockerfileContents []byte - if appConfig.Anchore.Dockerfile != "" { - if _, err := os.Stat(appConfig.Anchore.Dockerfile); os.IsNotExist(err) { - return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) - } - - fh, err := os.Open(appConfig.Anchore.Dockerfile) - if err != nil { - return fmt.Errorf("unable to open dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) - } - - dockerfileContents, err = ioutil.ReadAll(fh) - if err != nil { - return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err) - } - } - - c, err := anchore.NewClient(anchore.Configuration{ - BaseURL: appConfig.Anchore.Host, - Username: appConfig.Anchore.Username, - Password: appConfig.Anchore.Password, - }) - if err != nil { - return fmt.Errorf("unable to upload results: %w", err) - } - - importCfg := anchore.ImportConfig{ - ImageMetadata: src.Image.Metadata, - SourceMetadata: s, - Catalog: catalog, - Distro: d, - Dockerfile: dockerfileContents, - OverwriteExistingUpload: appConfig.Anchore.OverwriteExistingImage, - } - - if err := c.Import(context.Background(), importCfg); err != nil { - return fmt.Errorf("failed to upload results to host=%s: %+v", appConfig.Anchore.Host, err) - } - return nil -} - -func doRunCmd(_ *cobra.Command, args []string) error { - userInput := args[0] - errs := startWorker(userInput) - ux := ui.Select(appConfig.CliOptions.Verbosity > 0, appConfig.Quiet) - return ux(errs, eventSubscription) -} - -func ListLocalDockerImages(prefix string) ([]string, error) { - var repoTags = make([]string, 0) - ctx := context.Background() - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - return repoTags, err - } - - // Only want to return tagged images - imageListArgs := filters.NewArgs() - imageListArgs.Add("dangling", "false") - images, err := cli.ImageList(ctx, types.ImageListOptions{All: false, Filters: imageListArgs}) - if err != nil { - return repoTags, err - } - - for _, image := range images { - // image may have multiple tags - for _, tag := range image.RepoTags { - if strings.HasPrefix(tag, prefix) { - repoTags = append(repoTags, tag) - } - } - } - return repoTags, nil + // set common options that are not universal (package subcommand-alias specific) + setPackageFlags(rootCmd.Flags()) } diff --git a/cmd/version.go b/cmd/version.go index 8ceddca02..757132ec5 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -8,7 +8,6 @@ import ( "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/version" - "github.com/anchore/syft/syft/presenter" "github.com/spf13/cobra" ) @@ -21,7 +20,7 @@ var versionCmd = &cobra.Command{ } func init() { - versionCmd.Flags().StringVarP(&outputFormat, "output", "o", string(presenter.TextPresenter), "format to show version information (available=[text, json])") + versionCmd.Flags().StringVarP(&outputFormat, "output", "o", "text", "format to show version information (available=[text, json])") rootCmd.AddCommand(versionCmd) } From 6a960ec1f315da7ba5d3fc31d8b9d310636d4c0f Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:56:00 -0400 Subject: [PATCH 06/29] update json schema with optional poweruser data shape Signed-off-by: Alex Goodman --- internal/constants.go | 2 +- schema/json/README.md | 8 +-- schema/json/generate.go | 44 +++++++++++---- schema/json/schema-1.0.3.json | 2 +- syft/distro/identify.go | 2 +- syft/distro/identify_test.go | 7 ++- syft/event/event.go | 8 +-- syft/event/parsers/parsers.go | 11 ++-- syft/file/digest.go | 6 ++ syft/file/digest_cataloger.go | 98 +++++++++++++++++++++++++++++++++ syft/file/metadata_cataloger.go | 28 ++++++++++ syft/lib.go | 60 +++++--------------- 12 files changed, 201 insertions(+), 75 deletions(-) create mode 100644 syft/file/digest.go create mode 100644 syft/file/digest_cataloger.go create mode 100644 syft/file/metadata_cataloger.go diff --git a/internal/constants.go b/internal/constants.go index 5cb49659a..b027f8502 100644 --- a/internal/constants.go +++ b/internal/constants.go @@ -6,5 +6,5 @@ const ( // JSONSchemaVersion is the current schema version output by the JSON presenter // This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment. - JSONSchemaVersion = "1.0.3" + JSONSchemaVersion = "1.0.4" ) diff --git a/schema/json/README.md b/schema/json/README.md index 957bb2bec..e9fe920db 100644 --- a/schema/json/README.md +++ b/schema/json/README.md @@ -1,10 +1,10 @@ # JSON Schema -This is the JSON schema for output from the JSON presenter (`syft -o json`). The required inputs for defining the JSON schema are as follows: +This is the JSON schema for output from the JSON presenters (`syft packages -o json` and `syft power-user `). The required inputs for defining the JSON schema are as follows: - the value of `internal.JSONSchemaVersion` that governs the schema filename -- the `Document` struct definition within `syft/presenters/json/document.go` that governs the overall document shape -- the `metadataContainer` struct definition within `schema/json/generate.go` that governs the allowable shapes of `pkg.Package.Metadata` +- the `Document` struct definition within `internal/presenters/poweruser/json_document.go` that governs the overall document shape +- the `artifactMetadataContainer` struct definition within `schema/json/generate.go` that governs the allowable shapes of `pkg.Package.Metadata` With regard to testing the JSON schema, integration test cases provided by the developer are used as examples to validate that JSON output from Syft is always valid relative to the `schema/json/schema-$VERSION.json` file. @@ -26,7 +26,7 @@ When adding a new `pkg.*Metadata` that is assigned to the `pkg.Package.Metadata` are done: - a new integration test case is added to `test/integration/pkg_cases_test.go` that exercises the new package type with the new metadata -- the new metadata struct is added to the `metadataContainer` struct within `schema/json/generate.go` +- the new metadata struct is added to the `artifactMetadataContainer` struct within `schema/json/generate.go` ## Generating a New Schema diff --git a/schema/json/generate.go b/schema/json/generate.go index 4896e1924..dd65c45e6 100644 --- a/schema/json/generate.go +++ b/schema/json/generate.go @@ -6,13 +6,14 @@ import ( "fmt" "io/ioutil" "os" + "reflect" "sort" "strings" "github.com/alecthomas/jsonschema" "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/presenter/poweruser" "github.com/anchore/syft/syft/pkg" - jsonPresenter "github.com/anchore/syft/syft/presenter/json" ) /* @@ -25,7 +26,7 @@ can be extended to include specific package metadata struct shapes in the future // This should represent all possible metadatas represented in the pkg.Package.Metadata field (an interface{}). // When a new package metadata definition is created it will need to be manually added here. The variable name does // not matter as long as it is exported. -type metadataContainer struct { +type artifactMetadataContainer struct { Apk pkg.ApkMetadata Dpkg pkg.DpkgMetadata Gem pkg.GemMetadata @@ -36,10 +37,23 @@ type metadataContainer struct { Cargo pkg.CargoPackageMetadata } -// nolint:funlen func main() { - metadataSchema := jsonschema.Reflect(&metadataContainer{}) - documentSchema := jsonschema.Reflect(&jsonPresenter.Document{}) + write(encode(build())) +} + +func build() *jsonschema.Schema { + reflector := &jsonschema.Reflector{ + AllowAdditionalProperties: true, + TypeNamer: func(r reflect.Type) string { + name := r.Name() + if strings.HasPrefix(name, "JSON") { + name = strings.TrimPrefix(name, "JSON") + } + return name + }, + } + documentSchema := reflector.ReflectFromType(reflect.TypeOf(&poweruser.JSONDocument{})) + metadataSchema := reflector.ReflectFromType(reflect.TypeOf(&artifactMetadataContainer{})) // TODO: inject source definitions @@ -47,7 +61,7 @@ func main() { var metadataNames []string for name, definition := range metadataSchema.Definitions { - if name == "metadataContainer" { + if name == "artifactMetadataContainer" { // ignore the definition for the fake container continue } @@ -71,22 +85,30 @@ func main() { } // set the "anyOf" field for Package.Metadata to be a conjunction of several types - documentSchema.Definitions["Package"].Properties.Set("metadata", map[string][]map[string]string{ + documentSchema.Definitions["Document"].Properties.Set("artifacts.metadata", map[string][]map[string]string{ "anyOf": metadataTypes, }) - filename := fmt.Sprintf("schema-%s.json", internal.JSONSchemaVersion) + return documentSchema +} +func encode(schema *jsonschema.Schema) []byte { var newSchemaBuffer = new(bytes.Buffer) enc := json.NewEncoder(newSchemaBuffer) // prevent > and < from being escaped in the payload enc.SetEscapeHTML(false) enc.SetIndent("", " ") - err := enc.Encode(&documentSchema) + err := enc.Encode(&schema) if err != nil { panic(err) } + return newSchemaBuffer.Bytes() +} + +func write(schema []byte) { + filename := fmt.Sprintf("schema-%s.json", internal.JSONSchemaVersion) + if _, err := os.Stat(filename); !os.IsNotExist(err) { // check if the schema is the same... existingFh, err := os.Open(filename) @@ -99,7 +121,7 @@ func main() { panic(err) } - if bytes.Equal(existingSchemaBytes, newSchemaBuffer.Bytes()) { + if bytes.Equal(existingSchemaBytes, schema) { // the generated schema is the same, bail with no error :) fmt.Println("No change to the existing schema!") os.Exit(0) @@ -115,7 +137,7 @@ func main() { panic(err) } - _, err = fh.Write(newSchemaBuffer.Bytes()) + _, err = fh.Write(schema) if err != nil { panic(err) } diff --git a/schema/json/schema-1.0.3.json b/schema/json/schema-1.0.3.json index de3d7f933..108ba7479 100644 --- a/schema/json/schema-1.0.3.json +++ b/schema/json/schema-1.0.3.json @@ -749,4 +749,4 @@ "type": "object" } } -} +} \ No newline at end of file diff --git a/syft/distro/identify.go b/syft/distro/identify.go index fc6fe52bc..72be74b97 100644 --- a/syft/distro/identify.go +++ b/syft/distro/identify.go @@ -36,7 +36,7 @@ var identityFiles = []parseEntry{ } // Identify parses distro-specific files to determine distro metadata like version and release. -func Identify(resolver source.Resolver) *Distro { +func Identify(resolver source.FileResolver) *Distro { var distro *Distro identifyLoop: diff --git a/syft/distro/identify_test.go b/syft/distro/identify_test.go index 3e73aa2c6..d0d4470ee 100644 --- a/syft/distro/identify_test.go +++ b/syft/distro/identify_test.go @@ -99,7 +99,12 @@ func TestIdentifyDistro(t *testing.T) { t.Fatalf("unable to produce a new source for testing: %s", test.fixture) } - d := Identify(s.Resolver) + resolver, err := s.FileResolver(source.SquashedScope) + if err != nil { + t.Fatalf("unable to get resolver: %+v", err) + } + + d := Identify(resolver) if d == nil { if test.Type == UnknownDistroType { return diff --git a/syft/event/event.go b/syft/event/event.go index a88d38422..8c6faefc1 100644 --- a/syft/event/event.go +++ b/syft/event/event.go @@ -10,11 +10,11 @@ const ( // AppUpdateAvailable is a partybus event that occurs when an application update is available AppUpdateAvailable partybus.EventType = "syft-app-update-available" - // CatalogerStarted is a partybus event that occurs when the package cataloging has begun - CatalogerStarted partybus.EventType = "syft-cataloger-started-event" + // PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun + PackageCatalogerStarted partybus.EventType = "syft-cataloger-started-event" - // CatalogerFinished is a partybus event that occurs when the package cataloging has completed - CatalogerFinished partybus.EventType = "syft-cataloger-finished-event" + // PresenterReady is a partybus event that occurs when an analysis result is ready for final presentation + PresenterReady partybus.EventType = "syft-presenter-ready-event" // ImportStarted is a partybus event that occurs when an SBOM upload process has begun ImportStarted partybus.EventType = "syft-import-started-event" diff --git a/syft/event/parsers/parsers.go b/syft/event/parsers/parsers.go index 1eddcf245..a5d02a2f0 100644 --- a/syft/event/parsers/parsers.go +++ b/syft/event/parsers/parsers.go @@ -6,11 +6,12 @@ package parsers import ( "fmt" + "github.com/anchore/syft/internal/presenter" + "github.com/wagoodman/go-progress" - "github.com/anchore/syft/syft/cataloger" "github.com/anchore/syft/syft/event" - "github.com/anchore/syft/syft/presenter" + "github.com/anchore/syft/syft/pkg/cataloger" "github.com/wagoodman/go-partybus" ) @@ -40,7 +41,7 @@ func checkEventType(actual, expected partybus.EventType) error { } func ParseCatalogerStarted(e partybus.Event) (*cataloger.Monitor, error) { - if err := checkEventType(e.Type, event.CatalogerStarted); err != nil { + if err := checkEventType(e.Type, event.PackageCatalogerStarted); err != nil { return nil, err } @@ -52,8 +53,8 @@ func ParseCatalogerStarted(e partybus.Event) (*cataloger.Monitor, error) { return &monitor, nil } -func ParseCatalogerFinished(e partybus.Event) (presenter.Presenter, error) { - if err := checkEventType(e.Type, event.CatalogerFinished); err != nil { +func ParsePresenterReady(e partybus.Event) (presenter.Presenter, error) { + if err := checkEventType(e.Type, event.PresenterReady); err != nil { return nil, err } diff --git a/syft/file/digest.go b/syft/file/digest.go new file mode 100644 index 000000000..87b53dbb8 --- /dev/null +++ b/syft/file/digest.go @@ -0,0 +1,6 @@ +package file + +type Digest struct { + Algorithm string `json:"algorithm"` + Value string `json:"value"` +} diff --git a/syft/file/digest_cataloger.go b/syft/file/digest_cataloger.go new file mode 100644 index 000000000..37a8ff1b9 --- /dev/null +++ b/syft/file/digest_cataloger.go @@ -0,0 +1,98 @@ +package file + +import ( + "crypto" + "fmt" + "hash" + "io" + "strings" + + "github.com/anchore/syft/syft/source" +) + +var supportedHashAlgorithms = make(map[string]crypto.Hash) + +type DigestsCataloger struct { + resolver source.FileResolver + hashes []crypto.Hash +} + +func init() { + for _, h := range []crypto.Hash{ + crypto.MD5, + crypto.SHA1, + crypto.SHA256, + } { + supportedHashAlgorithms[cleanAlgorithmName(h.String())] = h + } +} + +func NewDigestsCataloger(resolver source.FileResolver, hashAlgorithms []string) (*DigestsCataloger, error) { + var hashes []crypto.Hash + for _, hashStr := range hashAlgorithms { + name := cleanAlgorithmName(hashStr) + hashObj, ok := supportedHashAlgorithms[name] + if !ok { + return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr) + } + hashes = append(hashes, hashObj) + } + + return &DigestsCataloger{ + resolver: resolver, + hashes: hashes, + }, nil +} + +func (i *DigestsCataloger) Catalog() (map[source.Location][]Digest, error) { + results := make(map[source.Location][]Digest) + for location := range i.resolver.AllLocations() { + result, err := i.catalogLocation(location) + if err != nil { + return nil, err + } + results[location] = result + } + return results, nil +} + +func (i *DigestsCataloger) catalogLocation(location source.Location) ([]Digest, error) { + contentReader, err := i.resolver.FileContentsByLocation(location) + if err != nil { + return nil, err + } + defer contentReader.Close() + + // create a set of hasher objects tied together with a single writer to feed content into + hashers := make([]hash.Hash, len(i.hashes)) + writers := make([]io.Writer, len(i.hashes)) + for idx, hashObj := range i.hashes { + hashers[idx] = hashObj.New() + writers[idx] = hashers[idx] + } + + size, err := io.Copy(io.MultiWriter(writers...), contentReader) + if err != nil { + return nil, fmt.Errorf("unable to observe contents of %+v: %+v", location.RealPath, err) + } + + result := make([]Digest, len(i.hashes)) + if size > 0 { + // only capture digests when there is content. It is important to do this based on SIZE and not + // FILE TYPE. The reasoning is that it is possible for a tar to be crafted with a header-only + // file type but a body is still allowed. + for idx, hasher := range hashers { + result[idx] = Digest{ + Algorithm: cleanAlgorithmName(i.hashes[idx].String()), + Value: fmt.Sprintf("%+x", hasher.Sum(nil)), + } + } + } + + return result, nil +} + +func cleanAlgorithmName(name string) string { + lower := strings.ToLower(name) + return strings.Replace(lower, "-", "", -1) +} diff --git a/syft/file/metadata_cataloger.go b/syft/file/metadata_cataloger.go new file mode 100644 index 000000000..8f0565902 --- /dev/null +++ b/syft/file/metadata_cataloger.go @@ -0,0 +1,28 @@ +package file + +import ( + "github.com/anchore/syft/syft/source" +) + +type MetadataCataloger struct { + resolver source.FileResolver +} + +func NewMetadataCataloger(resolver source.FileResolver) *MetadataCataloger { + return &MetadataCataloger{ + resolver: resolver, + } +} + +func (i *MetadataCataloger) Catalog() (map[source.Location]source.FileMetadata, error) { + results := make(map[source.Location]source.FileMetadata) + for location := range i.resolver.AllLocations() { + metadata, err := i.resolver.FileMetadataByLocation(location) + if err != nil { + return nil, err + } + + results[location] = metadata + } + return results, nil +} diff --git a/syft/lib.go b/syft/lib.go index 7f63e2210..9b9bfd965 100644 --- a/syft/lib.go +++ b/syft/lib.go @@ -17,32 +17,29 @@ Similar to the cataloging process, Linux distribution identification is also per package syft import ( - "encoding/json" "fmt" - "io" "github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/log" - "github.com/anchore/syft/syft/cataloger" "github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/logger" "github.com/anchore/syft/syft/pkg" - jsonPresenter "github.com/anchore/syft/syft/presenter/json" + "github.com/anchore/syft/syft/pkg/cataloger" "github.com/anchore/syft/syft/source" "github.com/wagoodman/go-partybus" ) -// Catalog the given image from a particular perspective (e.g. squashed source, all-layers source). Returns the discovered -// set of packages, the identified Linux distribution, and the source object used to wrap the data source. -func Catalog(userInput string, scope source.Scope) (source.Source, *pkg.Catalog, *distro.Distro, error) { - theSource, cleanup, err := source.New(userInput, scope) - defer cleanup() +// CatalogPackages takes an inventory of packages from the given image from a particular perspective +// (e.g. squashed source, all-layers source). Returns the discovered set of packages, the identified Linux +// distribution, and the source object used to wrap the data source. +func CatalogPackages(src source.Source, scope source.Scope) (*pkg.Catalog, *distro.Distro, error) { + resolver, err := src.FileResolver(scope) if err != nil { - return source.Source{}, nil, nil, err + return nil, nil, fmt.Errorf("unable to determine FileResolver while cataloging packages: %w", err) } // find the distro - theDistro := distro.Identify(theSource.Resolver) + theDistro := distro.Identify(resolver) if theDistro != nil { log.Infof("identified distro: %s", theDistro.String()) } else { @@ -51,7 +48,7 @@ func Catalog(userInput string, scope source.Scope) (source.Source, *pkg.Catalog, // conditionally use the correct set of loggers based on the input type (container image or directory) var catalogers []cataloger.Cataloger - switch theSource.Metadata.Scheme { + switch src.Metadata.Scheme { case source.ImageScheme: log.Info("cataloging image") catalogers = cataloger.ImageCatalogers() @@ -59,46 +56,15 @@ func Catalog(userInput string, scope source.Scope) (source.Source, *pkg.Catalog, log.Info("cataloging directory") catalogers = cataloger.DirectoryCatalogers() default: - return source.Source{}, nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", theSource.Metadata.Scheme) + return nil, nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", src.Metadata.Scheme) } - catalog, err := cataloger.Catalog(theSource.Resolver, theDistro, catalogers...) + catalog, err := cataloger.Catalog(resolver, theDistro, catalogers...) if err != nil { - return source.Source{}, nil, nil, err + return nil, nil, err } - return theSource, catalog, theDistro, nil -} - -// CatalogFromJSON takes an existing syft report and generates native syft objects. -func CatalogFromJSON(reader io.Reader) (source.Metadata, *pkg.Catalog, *distro.Distro, error) { - var doc jsonPresenter.Document - var err error - decoder := json.NewDecoder(reader) - if err := decoder.Decode(&doc); err != nil { - return source.Metadata{}, nil, nil, err - } - - var pkgs = make([]pkg.Package, len(doc.Artifacts)) - for i, a := range doc.Artifacts { - pkgs[i], err = a.ToPackage() - if err != nil { - return source.Metadata{}, nil, nil, err - } - } - - catalog := pkg.NewCatalog(pkgs...) - - var theDistro *distro.Distro - if doc.Distro.Name != "" { - d, err := distro.NewDistro(distro.Type(doc.Distro.Name), doc.Distro.Version, doc.Distro.IDLike) - if err != nil { - return source.Metadata{}, nil, nil, err - } - theDistro = &d - } - - return doc.Source.ToSourceMetadata(), catalog, theDistro, nil + return catalog, theDistro, nil } // SetLogger sets the logger object used for all syft logging calls. From 18dd2950ac5bfda56a47899ae77dbf546f2faed9 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:57:18 -0400 Subject: [PATCH 07/29] update event handlers relative to new command structure Signed-off-by: Alex Goodman --- internal/ui/common/event_handlers.go | 6 +++--- internal/ui/etui/ephemeral_tui.go | 4 ++-- internal/ui/logger_output.go | 4 ++-- ui/event_handlers.go | 4 ++-- ui/handler.go | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/ui/common/event_handlers.go b/internal/ui/common/event_handlers.go index 756f74012..b601e6ac7 100644 --- a/internal/ui/common/event_handlers.go +++ b/internal/ui/common/event_handlers.go @@ -8,11 +8,11 @@ import ( "github.com/wagoodman/go-partybus" ) -// CatalogerFinishedHandler is a UI function for processing the CatalogerFinished bus event, displaying the catalog +// CatalogerPresenterReady is a UI function for processing the CatalogerFinished bus event, displaying the catalog // via the given presenter to stdout. -func CatalogerFinishedHandler(event partybus.Event) error { +func CatalogerPresenterReady(event partybus.Event) error { // show the report to stdout - pres, err := syftEventParsers.ParseCatalogerFinished(event) + pres, err := syftEventParsers.ParsePresenterReady(event) if err != nil { return fmt.Errorf("bad CatalogerFinished event: %w", err) } diff --git a/internal/ui/etui/ephemeral_tui.go b/internal/ui/etui/ephemeral_tui.go index 8aa9dec81..fa5a0a61b 100644 --- a/internal/ui/etui/ephemeral_tui.go +++ b/internal/ui/etui/ephemeral_tui.go @@ -129,7 +129,7 @@ eventLoop: log.Errorf("unable to show %s event: %+v", e.Type, err) } - case e.Type == syftEvent.CatalogerFinished: + case e.Type == syftEvent.PresenterReady: // we may have other background processes still displaying progress, wait for them to // finish before discontinuing dynamic content and showing the final report wg.Wait() @@ -146,7 +146,7 @@ eventLoop: fmt.Fprint(output, logBuffer.String()) } - if err := common.CatalogerFinishedHandler(e); err != nil { + if err := common.CatalogerPresenterReady(e); err != nil { log.Errorf("unable to show %s event: %+v", e.Type, err) } diff --git a/internal/ui/logger_output.go b/internal/ui/logger_output.go index 511300edf..d402958fe 100644 --- a/internal/ui/logger_output.go +++ b/internal/ui/logger_output.go @@ -24,8 +24,8 @@ eventLoop: } // ignore all events except for the final event - if e.Type == syftEvent.CatalogerFinished { - err := common.CatalogerFinishedHandler(e) + if e.Type == syftEvent.PresenterReady { + err := common.CatalogerPresenterReady(e) if err != nil { log.Errorf("unable to show catalog image finished event: %+v", err) } diff --git a/ui/event_handlers.go b/ui/event_handlers.go index 6f56ac697..103a4dd95 100644 --- a/ui/event_handlers.go +++ b/ui/event_handlers.go @@ -268,8 +268,8 @@ func ReadImageHandler(ctx context.Context, fr *frame.Frame, event partybus.Event return nil } -// CatalogerStartedHandler periodically writes catalog statistics to a single line. -func CatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error { +// PackageCatalogerStartedHandler periodically writes catalog statistics to a single line. +func PackageCatalogerStartedHandler(ctx context.Context, fr *frame.Frame, event partybus.Event, wg *sync.WaitGroup) error { monitor, err := syftEventParsers.ParseCatalogerStarted(event) if err != nil { return fmt.Errorf("bad %s event: %w", event.Type, err) diff --git a/ui/handler.go b/ui/handler.go index 7149ffd46..edf2e5ead 100644 --- a/ui/handler.go +++ b/ui/handler.go @@ -15,7 +15,7 @@ import ( "github.com/wagoodman/jotframe/pkg/frame" ) -// Handler is an aggregated event handler for the set of supported events (PullDockerImage, ReadImage, FetchImage, CatalogerStarted) +// Handler is an aggregated event handler for the set of supported events (PullDockerImage, ReadImage, FetchImage, PackageCatalogerStarted) type Handler struct { } @@ -27,7 +27,7 @@ func NewHandler() *Handler { // RespondsTo indicates if the handler is capable of handling the given event. func (r *Handler) RespondsTo(event partybus.Event) bool { switch event.Type { - case stereoscopeEvent.PullDockerImage, stereoscopeEvent.ReadImage, stereoscopeEvent.FetchImage, syftEvent.CatalogerStarted, syftEvent.ImportStarted: + case stereoscopeEvent.PullDockerImage, stereoscopeEvent.ReadImage, stereoscopeEvent.FetchImage, syftEvent.PackageCatalogerStarted, syftEvent.ImportStarted: return true default: return false @@ -46,8 +46,8 @@ func (r *Handler) Handle(ctx context.Context, fr *frame.Frame, event partybus.Ev case stereoscopeEvent.FetchImage: return FetchImageHandler(ctx, fr, event, wg) - case syftEvent.CatalogerStarted: - return CatalogerStartedHandler(ctx, fr, event, wg) + case syftEvent.PackageCatalogerStarted: + return PackageCatalogerStartedHandler(ctx, fr, event, wg) case syftEvent.ImportStarted: return ImportStartedHandler(ctx, fr, event, wg) From ae32942a180a7cf0d4304012e82719e20474c052 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:58:29 -0400 Subject: [PATCH 08/29] update import to require patching image metadata source field Signed-off-by: Alex Goodman --- internal/anchore/import.go | 3 ++- internal/anchore/import_package_sbom.go | 12 ++++++------ internal/anchore/import_package_sbom_test.go | 20 +++++++++----------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/internal/anchore/import.go b/internal/anchore/import.go index f6f62b861..17a679879 100644 --- a/internal/anchore/import.go +++ b/internal/anchore/import.go @@ -26,6 +26,7 @@ type ImportConfig struct { Distro *distro.Distro Dockerfile []byte OverwriteExistingUpload bool + Scope source.Scope } func importProgress(source string) (*progress.Stage, *progress.Manual) { @@ -71,7 +72,7 @@ func (c *Client) Import(ctx context.Context, cfg ImportConfig) error { prog.N++ sessionID := startOperation.Uuid - packageDigest, err := importPackageSBOM(authedCtx, c.client.ImportsApi, sessionID, cfg.SourceMetadata, cfg.Catalog, cfg.Distro, stage) + packageDigest, err := importPackageSBOM(authedCtx, c.client.ImportsApi, sessionID, cfg.SourceMetadata, cfg.Catalog, cfg.Distro, cfg.Scope, stage) if err != nil { return fmt.Errorf("failed to import Package SBOM: %w", err) } diff --git a/internal/anchore/import_package_sbom.go b/internal/anchore/import_package_sbom.go index f70a27e3d..02b832e7e 100644 --- a/internal/anchore/import_package_sbom.go +++ b/internal/anchore/import_package_sbom.go @@ -8,9 +8,9 @@ import ( "fmt" "net/http" - "github.com/wagoodman/go-progress" + "github.com/anchore/syft/internal/presenter/packages" - jsonPresenter "github.com/anchore/syft/syft/presenter/json" + "github.com/wagoodman/go-progress" "github.com/anchore/syft/syft/distro" "github.com/anchore/syft/syft/source" @@ -24,9 +24,9 @@ type packageSBOMImportAPI interface { ImportImagePackages(context.Context, string, external.ImagePackageManifest) (external.ImageImportContentResponse, *http.Response, error) } -func packageSbomModel(s source.Metadata, catalog *pkg.Catalog, d *distro.Distro) (*external.ImagePackageManifest, error) { +func packageSbomModel(s source.Metadata, catalog *pkg.Catalog, d *distro.Distro, scope source.Scope) (*external.ImagePackageManifest, error) { var buf bytes.Buffer - pres := jsonPresenter.NewPresenter(catalog, s, d) + pres := packages.NewJSONPresenter(catalog, s, d, scope) err := pres.Present(&buf) if err != nil { return nil, fmt.Errorf("unable to serialize results: %w", err) @@ -41,11 +41,11 @@ func packageSbomModel(s source.Metadata, catalog *pkg.Catalog, d *distro.Distro) return &model, nil } -func importPackageSBOM(ctx context.Context, api packageSBOMImportAPI, sessionID string, s source.Metadata, catalog *pkg.Catalog, d *distro.Distro, stage *progress.Stage) (string, error) { +func importPackageSBOM(ctx context.Context, api packageSBOMImportAPI, sessionID string, s source.Metadata, catalog *pkg.Catalog, d *distro.Distro, scope source.Scope, stage *progress.Stage) (string, error) { log.Debug("importing package SBOM") stage.Current = "package SBOM" - model, err := packageSbomModel(s, catalog, d) + model, err := packageSbomModel(s, catalog, d, scope) if err != nil { return "", fmt.Errorf("unable to create PackageSBOM model: %w", err) } diff --git a/internal/anchore/import_package_sbom_test.go b/internal/anchore/import_package_sbom_test.go index becb74bec..cf97899ea 100644 --- a/internal/anchore/import_package_sbom_test.go +++ b/internal/anchore/import_package_sbom_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/wagoodman/go-progress" + "github.com/anchore/syft/internal/presenter/packages" - jsonPresenter "github.com/anchore/syft/syft/presenter/json" + "github.com/wagoodman/go-progress" "github.com/anchore/syft/syft/distro" @@ -38,7 +38,6 @@ func TestPackageSbomToModel(t *testing.T) { Scheme: source.ImageScheme, ImageMetadata: source.ImageMetadata{ UserInput: "user-in", - Scope: "scope!", Layers: []source.LayerMetadata{ { MediaType: "layer-metadata-type!", @@ -76,7 +75,7 @@ func TestPackageSbomToModel(t *testing.T) { c := pkg.NewCatalog(p) - model, err := packageSbomModel(m, c, &d) + model, err := packageSbomModel(m, c, &d, source.AllLayersScope) if err != nil { t.Fatalf("unable to generate model from source material: %+v", err) } @@ -89,19 +88,19 @@ func TestPackageSbomToModel(t *testing.T) { } var buf bytes.Buffer - pres := jsonPresenter.NewPresenter(c, m, &d) + pres := packages.NewJSONPresenter(c, m, &d, source.AllLayersScope) if err := pres.Present(&buf); err != nil { t.Fatalf("unable to get expected json: %+v", err) } // unmarshal expected result - var expectedDoc jsonPresenter.Document + var expectedDoc packages.JSONDocument if err := json.Unmarshal(buf.Bytes(), &expectedDoc); err != nil { t.Fatalf("unable to parse json doc: %+v", err) } // unmarshal actual result - var actualDoc jsonPresenter.Document + var actualDoc packages.JSONDocument if err := json.Unmarshal(modelJSON, &actualDoc); err != nil { t.Fatalf("unable to parse json doc: %+v", err) } @@ -178,10 +177,9 @@ func TestPackageSbomImport(t *testing.T) { }) m := source.Metadata{ - Scheme: "a-schema", + Scheme: source.ImageScheme, ImageMetadata: source.ImageMetadata{ UserInput: "user-in", - Scope: "scope!", Layers: nil, Size: 10, ManifestDigest: "sha256:digest!", @@ -192,7 +190,7 @@ func TestPackageSbomImport(t *testing.T) { d, _ := distro.NewDistro(distro.CentOS, "8.0", "") - theModel, err := packageSbomModel(m, catalog, &d) + theModel, err := packageSbomModel(m, catalog, &d, source.AllLayersScope) if err != nil { t.Fatalf("could not get sbom model: %+v", err) } @@ -231,7 +229,7 @@ func TestPackageSbomImport(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - digest, err := importPackageSBOM(context.TODO(), test.api, sessionID, m, catalog, &d, &progress.Stage{}) + digest, err := importPackageSBOM(context.TODO(), test.api, sessionID, m, catalog, &d, source.AllLayersScope, &progress.Stage{}) // validate error handling if err != nil && !test.expectsError { From efcd8a8b9a1e5264ebb1d5bd87381124677e9d0a Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 08:59:28 -0400 Subject: [PATCH 09/29] update integration and acceptance tests for new resolvers Signed-off-by: Alex Goodman --- test/acceptance/deb.sh | 2 +- test/acceptance/mac.sh | 2 +- test/acceptance/rpm.sh | 2 +- ...test.go => catalog_packages_cases_test.go} | 0 ...erage_test.go => catalog_packages_test.go} | 53 +++++--- test/integration/distro_test.go | 13 +- test/integration/document_import_test.go | 101 ---------------- test/integration/java_no_main_package_test.go | 20 ---- test/integration/json_schema_test.go | 113 ------------------ .../package_ownership_relationship_test.go | 25 ++-- ...egression_apk_scanner_buffer_size_test.go} | 15 +-- .../regression_java_no_main_package_test.go | 9 ++ test/integration/utils_test.go | 44 +++++++ 13 files changed, 106 insertions(+), 293 deletions(-) rename test/integration/{pkg_cases_test.go => catalog_packages_cases_test.go} (100%) rename test/integration/{pkg_coverage_test.go => catalog_packages_test.go} (79%) delete mode 100644 test/integration/document_import_test.go delete mode 100644 test/integration/java_no_main_package_test.go delete mode 100644 test/integration/json_schema_test.go rename test/integration/{regression_test.go => regression_apk_scanner_buffer_size_test.go} (52%) create mode 100644 test/integration/regression_java_no_main_package_test.go create mode 100644 test/integration/utils_test.go diff --git a/test/acceptance/deb.sh b/test/acceptance/deb.sh index afe7eadcc..46793472d 100755 --- a/test/acceptance/deb.sh +++ b/test/acceptance/deb.sh @@ -42,7 +42,7 @@ docker run --rm \ /bin/bash -x -c "\ DEBIAN_FRONTEND=noninteractive apt install ${DISTDIR}/syft_*_linux_amd64.deb -y && \ syft version && \ - syft ${TEST_IMAGE} -vv -o json > ${REPORT} \ + syft packages ${TEST_IMAGE} -vv -o json > ${REPORT} \ " # keep the generated report around diff --git a/test/acceptance/mac.sh b/test/acceptance/mac.sh index fade10d76..e6c955bc7 100755 --- a/test/acceptance/mac.sh +++ b/test/acceptance/mac.sh @@ -40,7 +40,7 @@ ls -alh ${TEST_IMAGE_TAR} SYFT_PATH="${DISTDIR}/syft-macos_darwin_amd64/syft" chmod 755 "${SYFT_PATH}" "${SYFT_PATH}" version -SYFT_CHECK_FOR_APP_UPDATE=0 "${SYFT_PATH}" docker-archive://${TEST_IMAGE_TAR} -vv -o json > "${REPORT}" +SYFT_CHECK_FOR_APP_UPDATE=0 "${SYFT_PATH}" packages docker-archive://${TEST_IMAGE_TAR} -vv -o json > "${REPORT}" # keep the generated report around mkdir -p ${RESULTSDIR} diff --git a/test/acceptance/rpm.sh b/test/acceptance/rpm.sh index 062375cb0..53d6800c0 100755 --- a/test/acceptance/rpm.sh +++ b/test/acceptance/rpm.sh @@ -41,7 +41,7 @@ docker run --rm \ /bin/bash -x -c "\ rpm -ivh ${DISTDIR}/syft_*_linux_amd64.rpm && \ syft version && \ - syft ${TEST_IMAGE} -vv -o json > ${REPORT} \ + syft packages ${TEST_IMAGE} -vv -o json > ${REPORT} \ " # keep the generated report around diff --git a/test/integration/pkg_cases_test.go b/test/integration/catalog_packages_cases_test.go similarity index 100% rename from test/integration/pkg_cases_test.go rename to test/integration/catalog_packages_cases_test.go diff --git a/test/integration/pkg_coverage_test.go b/test/integration/catalog_packages_test.go similarity index 79% rename from test/integration/pkg_coverage_test.go rename to test/integration/catalog_packages_test.go index d676c7644..33df9c172 100644 --- a/test/integration/pkg_coverage_test.go +++ b/test/integration/catalog_packages_test.go @@ -3,25 +3,54 @@ package integration import ( "testing" + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/pkg/cataloger" + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/anchore/syft/syft/source" + "github.com/go-test/deep" "github.com/anchore/syft/internal" - "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/source" ) -func TestPkgCoverageImage(t *testing.T) { +func BenchmarkImagePackageCatalogers(b *testing.B) { fixtureImageName := "image-pkg-coverage" - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() + imagetest.GetFixtureImage(b, "docker-archive", fixtureImageName) + tarPath := imagetest.GetFixtureImageTarPath(b, fixtureImageName) - _, catalog, _, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) + var pc *pkg.Catalog + for _, c := range cataloger.ImageCatalogers() { + // in case of future alteration where state is persisted, assume no dependency is safe to reuse + theSource, cleanupSource, err := source.New("docker-archive:" + tarPath) + b.Cleanup(cleanupSource) + if err != nil { + b.Fatalf("unable to get source: %+v", err) + } + + resolver, err := theSource.FileResolver(source.SquashedScope) + if err != nil { + b.Fatalf("unable to get resolver: %+v", err) + } + + theDistro := distro.Identify(resolver) + + b.Run(c.Name(), func(b *testing.B) { + for i := 0; i < b.N; i++ { + pc, err = cataloger.Catalog(resolver, theDistro, c) + if err != nil { + b.Fatalf("failure during benchmark: %+v", err) + } + } + }) + + b.Logf("catalog for %q number of packages: %d", c.Name(), pc.PackageCount()) } +} + +func TestPkgCoverageImage(t *testing.T) { + catalog, _, _ := catalogFixtureImage(t, "image-pkg-coverage") observedLanguages := internal.NewStringSet() definedLanguages := internal.NewStringSet() @@ -100,11 +129,7 @@ func TestPkgCoverageImage(t *testing.T) { } func TestPkgCoverageDirectory(t *testing.T) { - _, catalog, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", source.SquashedScope) - - if err != nil { - t.Errorf("unable to create source from dir: %+v", err) - } + catalog, _, _ := catalogDirectory(t, "test-fixtures/image-pkg-coverage") observedLanguages := internal.NewStringSet() definedLanguages := internal.NewStringSet() diff --git a/test/integration/distro_test.go b/test/integration/distro_test.go index 51d888e75..a54c472f3 100644 --- a/test/integration/distro_test.go +++ b/test/integration/distro_test.go @@ -3,23 +3,12 @@ package integration import ( "testing" - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/distro" - "github.com/anchore/syft/syft/source" "github.com/go-test/deep" ) func TestDistroImage(t *testing.T) { - fixtureImageName := "image-distro-id" - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() - - _, _, actualDistro, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } + _, actualDistro, _ := catalogFixtureImage(t, "image-distro-id") expected, err := distro.NewDistro(distro.Busybox, "1.31.1", "") if err != nil { diff --git a/test/integration/document_import_test.go b/test/integration/document_import_test.go deleted file mode 100644 index cd80d1ca0..000000000 --- a/test/integration/document_import_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package integration - -import ( - "bytes" - "strings" - "testing" - - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/pkg" - "github.com/anchore/syft/syft/presenter/json" - "github.com/anchore/syft/syft/source" - "github.com/go-test/deep" -) - -func TestCatalogFromJSON(t *testing.T) { - - // ensure each of our fixture images results in roughly the same shape when: - // generate json -> import json -> assert packages and distro are the same (except for select fields) - - tests := []struct { - fixture string - }{ - { - fixture: "image-pkg-coverage", - }, - } - - for _, test := range tests { - t.Run(test.fixture, func(t *testing.T) { - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", test.fixture) - tarPath := imagetest.GetFixtureImageTarPath(t, test.fixture) - defer cleanup() - - expectedSource, expectedCatalog, expectedDistro, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } - - var buf bytes.Buffer - jsonPres := json.NewPresenter(expectedCatalog, expectedSource.Metadata, expectedDistro) - if err = jsonPres.Present(&buf); err != nil { - t.Fatalf("failed to write to presenter: %+v", err) - } - - sourceMetadata, actualCatalog, actualDistro, err := syft.CatalogFromJSON(&buf) - if err != nil { - t.Fatalf("failed to import document: %+v", err) - } - - for _, d := range deep.Equal(sourceMetadata, expectedSource.Metadata) { - t.Errorf(" image metadata diff: %+v", d) - } - - for _, d := range deep.Equal(actualDistro, expectedDistro) { - t.Errorf(" distro diff: %+v", d) - } - - var actualPackages, expectedPackages []*pkg.Package - - for _, p := range expectedCatalog.Sorted() { - expectedPackages = append(expectedPackages, p) - } - - for _, p := range actualCatalog.Sorted() { - actualPackages = append(actualPackages, p) - } - - if len(actualPackages) != len(expectedPackages) { - t.Fatalf("mismatched package length: %d != %d", len(actualPackages), len(expectedPackages)) - } - - for i, e := range expectedPackages { - a := actualPackages[i] - - // omit fields that should be missing - if e.MetadataType == pkg.JavaMetadataType { - metadata := e.Metadata.(pkg.JavaMetadata) - metadata.Parent = nil - e.Metadata = metadata - } - - // ignore the virtual path on the location for now - for l := range a.Locations { - a.Locations[l].VirtualPath = "" - e.Locations[l].VirtualPath = "" - } - - for _, d := range deep.Equal(a, e) { - // ignore errors for empty collections vs nil for select fields - if strings.Contains(d, "[] != ") { - continue - } - t.Errorf(" package %d (name=%s) diff: %+v", i, e.Name, d) - } - } - - }) - } - -} diff --git a/test/integration/java_no_main_package_test.go b/test/integration/java_no_main_package_test.go deleted file mode 100644 index e330a78fb..000000000 --- a/test/integration/java_no_main_package_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package integration - -import ( - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/source" - "testing" -) - -func TestJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252 - fixtureImageName := "image-java-no-main-package" - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() - - _, _, _, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - 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 deleted file mode 100644 index 022c9db54..000000000 --- a/test/integration/json_schema_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package integration - -import ( - "bytes" - "fmt" - "os/exec" - "path" - "path/filepath" - "strings" - "testing" - - "github.com/anchore/syft/internal" - - "github.com/anchore/syft/syft/distro" - "github.com/anchore/syft/syft/presenter" - - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/source" - "github.com/xeipuuv/gojsonschema" -) - -const jsonSchemaPath = "schema/json" - -func repoRoot(t *testing.T) string { - t.Helper() - repoRoot, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() - if err != nil { - t.Fatalf("unable to find repo root dir: %+v", err) - } - absRepoRoot, err := filepath.Abs(strings.TrimSpace(string(repoRoot))) - if err != nil { - t.Fatal("unable to get abs path to repo root:", err) - } - return absRepoRoot -} - -func validateAgainstV1Schema(t *testing.T, json string) { - fullSchemaPath := path.Join(repoRoot(t), jsonSchemaPath, fmt.Sprintf("schema-%s.json", internal.JSONSchemaVersion)) - schemaLoader := gojsonschema.NewReferenceLoader(fmt.Sprintf("file://%s", fullSchemaPath)) - documentLoader := gojsonschema.NewStringLoader(json) - - result, err := gojsonschema.Validate(schemaLoader, documentLoader) - if err != nil { - t.Fatal("unable to validate json schema:", err.Error()) - } - - if !result.Valid() { - t.Errorf("failed json schema validation:") - t.Errorf("JSON:\n%s\n", json) - for _, desc := range result.Errors() { - t.Errorf(" - %s\n", desc) - } - } -} - -func TestJsonSchemaImg(t *testing.T) { - fixtureImageName := "image-pkg-coverage" - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() - - src, catalog, _, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } - - output := bytes.NewBufferString("") - - d, err := distro.NewDistro(distro.CentOS, "5", "rhel fedora") - if err != nil { - t.Fatalf("bad distro: %+v", err) - } - - p := presenter.GetPresenter(presenter.JSONPresenter, src.Metadata, catalog, &d) - if p == nil { - t.Fatal("unable to get presenter") - } - - err = p.Present(output) - if err != nil { - t.Fatalf("unable to present: %+v", err) - } - - validateAgainstV1Schema(t, output.String()) - -} - -func TestJsonSchemaDirs(t *testing.T) { - src, catalog, _, err := syft.Catalog("dir:test-fixtures/image-pkg-coverage", source.SquashedScope) - if err != nil { - t.Errorf("unable to create source from dir: %+v", err) - } - - output := bytes.NewBufferString("") - - d, err := distro.NewDistro(distro.CentOS, "5", "rhel fedora") - if err != nil { - t.Fatalf("bad distro: %+v", err) - } - - p := presenter.GetPresenter(presenter.JSONPresenter, src.Metadata, catalog, &d) - if p == nil { - t.Fatal("unable to get presenter") - } - - err = p.Present(output) - if err != nil { - t.Fatalf("unable to present: %+v", err) - } - - validateAgainstV1Schema(t, output.String()) -} diff --git a/test/integration/package_ownership_relationship_test.go b/test/integration/package_ownership_relationship_test.go index 490408ccc..dee87a6d2 100644 --- a/test/integration/package_ownership_relationship_test.go +++ b/test/integration/package_ownership_relationship_test.go @@ -5,11 +5,7 @@ import ( "encoding/json" "testing" - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/presenter" - jsonPresenter "github.com/anchore/syft/syft/presenter/json" - "github.com/anchore/syft/syft/source" + "github.com/anchore/syft/internal/presenter/packages" ) func TestPackageOwnershipRelationships(t *testing.T) { @@ -25,27 +21,24 @@ func TestPackageOwnershipRelationships(t *testing.T) { for _, test := range tests { t.Run(test.fixture, func(t *testing.T) { - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", test.fixture) - tarPath := imagetest.GetFixtureImageTarPath(t, test.fixture) - defer cleanup() + catalog, d, src := catalogFixtureImage(t, test.fixture) - src, catalog, d, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } - - p := presenter.GetPresenter(presenter.JSONPresenter, src.Metadata, catalog, d) + p := packages.Presenter(packages.JSONPresenterOption, packages.PresenterConfig{ + SourceMetadata: src.Metadata, + Catalog: catalog, + Distro: d, + }) if p == nil { t.Fatal("unable to get presenter") } output := bytes.NewBufferString("") - err = p.Present(output) + err := p.Present(output) if err != nil { t.Fatalf("unable to present: %+v", err) } - var doc jsonPresenter.Document + var doc packages.JSONDocument decoder := json.NewDecoder(output) if err := decoder.Decode(&doc); err != nil { t.Fatalf("unable to decode json doc: %+v", err) diff --git a/test/integration/regression_test.go b/test/integration/regression_apk_scanner_buffer_size_test.go similarity index 52% rename from test/integration/regression_test.go rename to test/integration/regression_apk_scanner_buffer_size_test.go index 34f8f2ff8..5aaa4f24d 100644 --- a/test/integration/regression_test.go +++ b/test/integration/regression_apk_scanner_buffer_size_test.go @@ -4,25 +4,12 @@ import ( "testing" "github.com/anchore/syft/syft/pkg" - - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/anchore/syft/syft" - "github.com/anchore/syft/syft/source" ) func TestRegression212ApkBufferSize(t *testing.T) { // This is a regression test for issue #212 (https://github.com/anchore/syft/issues/212) in which the apk db could // not be processed due to a scanner buffer that was too small - - fixtureImageName := "image-large-apk-data" - _, cleanup := imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() - - _, catalog, _, err := syft.Catalog("docker-archive:"+tarPath, source.SquashedScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } + catalog, _, _ := catalogFixtureImage(t, "image-large-apk-data") expectedPkgs := 58 actualPkgs := 0 diff --git a/test/integration/regression_java_no_main_package_test.go b/test/integration/regression_java_no_main_package_test.go new file mode 100644 index 000000000..a5f41ddaf --- /dev/null +++ b/test/integration/regression_java_no_main_package_test.go @@ -0,0 +1,9 @@ +package integration + +import ( + "testing" +) + +func TestRegressionJavaNoMainPackage(t *testing.T) { // Regression: https://github.com/anchore/syft/issues/252 + catalogFixtureImage(t, "image-java-no-main-package") +} diff --git a/test/integration/utils_test.go b/test/integration/utils_test.go new file mode 100644 index 000000000..ad194b273 --- /dev/null +++ b/test/integration/utils_test.go @@ -0,0 +1,44 @@ +package integration + +import ( + "testing" + + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/anchore/syft/syft" + "github.com/anchore/syft/syft/distro" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +func catalogFixtureImage(t *testing.T, fixtureImageName string) (*pkg.Catalog, *distro.Distro, source.Source) { + imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) + tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) + + theSource, cleanupSource, err := source.New("docker-archive:" + tarPath) + t.Cleanup(cleanupSource) + if err != nil { + t.Fatalf("unable to get source: %+v", err) + } + + pkgCatalog, actualDistro, err := syft.CatalogPackages(theSource, source.SquashedScope) + if err != nil { + t.Fatalf("failed to catalog image: %+v", err) + } + + return pkgCatalog, actualDistro, theSource +} + +func catalogDirectory(t *testing.T, dir string) (*pkg.Catalog, *distro.Distro, source.Source) { + theSource, cleanupSource, err := source.New("dir:" + dir) + t.Cleanup(cleanupSource) + if err != nil { + t.Fatalf("unable to get source: %+v", err) + } + + pkgCatalog, actualDistro, err := syft.CatalogPackages(theSource, source.AllLayersScope) + if err != nil { + t.Fatalf("failed to catalog image: %+v", err) + } + + return pkgCatalog, actualDistro, theSource +} From 68d698e9f21fe5038d3e83867d063e028242a660 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 09:00:05 -0400 Subject: [PATCH 10/29] remove inline-compare testing Signed-off-by: Alex Goodman --- test/inline-compare/.gitignore | 3 - test/inline-compare/Makefile | 49 ------ test/inline-compare/compare-all.sh | 16 -- test/inline-compare/compare.py | 234 -------------------------- test/inline-compare/utils/__init__.py | 0 test/inline-compare/utils/format.py | 46 ----- test/inline-compare/utils/image.py | 5 - test/inline-compare/utils/inline.py | 142 ---------------- test/inline-compare/utils/package.py | 146 ---------------- test/inline-compare/utils/syft.py | 68 -------- 10 files changed, 709 deletions(-) delete mode 100644 test/inline-compare/.gitignore delete mode 100644 test/inline-compare/Makefile delete mode 100755 test/inline-compare/compare-all.sh delete mode 100755 test/inline-compare/compare.py delete mode 100644 test/inline-compare/utils/__init__.py delete mode 100644 test/inline-compare/utils/format.py delete mode 100644 test/inline-compare/utils/image.py delete mode 100644 test/inline-compare/utils/inline.py delete mode 100644 test/inline-compare/utils/package.py delete mode 100644 test/inline-compare/utils/syft.py diff --git a/test/inline-compare/.gitignore b/test/inline-compare/.gitignore deleted file mode 100644 index 1bdfd8fd4..000000000 --- a/test/inline-compare/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.json -*.pyc -inline-reports \ No newline at end of file diff --git a/test/inline-compare/Makefile b/test/inline-compare/Makefile deleted file mode 100644 index 945b01698..000000000 --- a/test/inline-compare/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -ifndef SYFT_CMD - SYFT_CMD = go run ../../main.go -endif - -IMAGE_CLEAN = $(shell basename $(COMPARE_IMAGE) | tr ":" "_" ) -SYFT_DIR = syft-reports -SYFT_REPORT = $(SYFT_DIR)/$(IMAGE_CLEAN).json -INLINE_DIR = inline-reports -INLINE_REPORT = $(INLINE_DIR)/$(IMAGE_CLEAN)-content-os.json - -ifndef SYFT_DIR - $(error SYFT_DIR is not set) -endif - -ifndef INLINE_DIR - $(error INLINE_DIR is not set) -endif - -.PHONY: all -.DEFAULT_GOAL := -all: clean-syft - ./compare-all.sh - -.PHONY: compare-image -compare-image: $(SYFT_REPORT) $(INLINE_REPORT) - ./compare.py $(COMPARE_IMAGE) - -.PHONY: gather-image -gather-image: $(SYFT_REPORT) $(INLINE_REPORT) - -$(INLINE_REPORT): - echo "Creating $(INLINE_REPORT)..." - mkdir -p $(INLINE_DIR) - curl -s https://ci-tools.anchore.io/inline_scan-v0.7.0 | bash -s -- -p -r $(COMPARE_IMAGE) - mv anchore-reports/* $(INLINE_DIR)/ - rmdir anchore-reports - -$(SYFT_REPORT): - echo "Creating $(SYFT_REPORT)..." - mkdir -p $(SYFT_DIR) - $(SYFT_CMD) $(COMPARE_IMAGE) -o json > $(SYFT_REPORT) - -.PHONY: clean -clean: clean-syft - rm -f $(INLINE_DIR)/* - -.PHONY: clean-syft -clean-syft: - rm -f $(SYFT_DIR)/* \ No newline at end of file diff --git a/test/inline-compare/compare-all.sh b/test/inline-compare/compare-all.sh deleted file mode 100755 index 146afe9b2..000000000 --- a/test/inline-compare/compare-all.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -eu - -images=("debian:10.5" "centos:8.2.2004" "rails:5.0.1" "alpine:3.12.0" "anchore/test_images:java" "anchore/test_images:py38" "anchore/anchore-engine:v0.8.2" "jenkins/jenkins:2.249.2-lts-jdk11" ) - -# gather all image analyses -for img in "${images[@]}"; do - echo "Gathering facts for $img" - COMPARE_IMAGE=${img} make gather-image -done - -# compare all results -for img in "${images[@]}"; do - echo "Comparing results for $img" - COMPARE_IMAGE=${img} make compare-image -done diff --git a/test/inline-compare/compare.py b/test/inline-compare/compare.py deleted file mode 100755 index 6dc5bb655..000000000 --- a/test/inline-compare/compare.py +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import difflib -import collections - -import utils.package -from utils.format import Colors, print_rows -from utils.inline import InlineScan -from utils.syft import Syft - -DEFAULT_QUALITY_GATE_THRESHOLD = 0.95 -INDENT = " " - -PACKAGE_QUALITY_GATE = collections.defaultdict(lambda: DEFAULT_QUALITY_GATE_THRESHOLD, **{}) -METADATA_QUALITY_GATE = collections.defaultdict(lambda: DEFAULT_QUALITY_GATE_THRESHOLD, **{ - # syft is better at detecting package versions in specific cases, leading to a drop in matching metadata - "anchore/test_images:java": 0.61, - "jenkins/jenkins:2.249.2-lts-jdk11": 0.85, -}) - -# We additionally fail if an image is above a particular threshold. Why? We expect the lower threshold to be 90%, -# however additional functionality in grype is still being implemented, so this threshold may not be able to be met. -# In these cases the IMAGE_QUALITY_GATE is set to a lower value to allow the test to pass for known issues. Once these -# issues/enhancements are done we want to ensure that the lower threshold is bumped up to catch regression. The only way -# to do this is to select an upper threshold for images with known threshold values, so we have a failure that -# loudly indicates the lower threshold should be bumped. -PACKAGE_UPPER_THRESHOLD = collections.defaultdict(lambda: 1, **{}) -METADATA_UPPER_THRESHOLD = collections.defaultdict(lambda: 1, **{ - # syft is better at detecting package versions in specific cases, leading to a drop in matching metadata - "anchore/test_images:java": 0.65, - "jenkins/jenkins:2.249.2-lts-jdk11": 0.9, -}) - - -def report(image, analysis): - if analysis.extra_packages: - rows = [] - print( - Colors.bold + "Syft found extra packages:", - Colors.reset, - "Syft discovered packages that Inline did not", - ) - for package in sorted(list(analysis.extra_packages)): - rows.append([INDENT, repr(package)]) - print_rows(rows) - print() - - if analysis.missing_packages: - rows = [] - print( - Colors.bold + "Syft missed packages:", - Colors.reset, - "Inline discovered packages that Syft did not", - ) - for package in sorted(list(analysis.missing_packages)): - rows.append([INDENT, repr(package)]) - print_rows(rows) - print() - - if analysis.missing_metadata: - print( - Colors.bold + "Syft mismatched metadata:", - Colors.reset, - "the packages between Syft and Inline are the same, the metadata is not", - ) - for inline_metadata_pair in sorted(list(analysis.missing_metadata)): - pkg, metadata = inline_metadata_pair - if pkg not in analysis.syft_data.metadata[pkg.type]: - continue - syft_metadata_item = analysis.syft_data.metadata[pkg.type][pkg] - - diffs = difflib.ndiff([repr(syft_metadata_item)], [repr(metadata)]) - - print(INDENT + "for: " + repr(pkg), "(top is syft, bottom is inline)") - print(INDENT+INDENT+("\n"+INDENT+INDENT).join(list(diffs))) - - if not analysis.missing_metadata: - print( - INDENT, - "There are mismatches, but only due to packages Syft did not find (but inline did).\n", - ) - - if analysis.similar_missing_packages: - rows = [] - print( - Colors.bold + "Probably pairings of missing/extra packages:", - Colors.reset, - "to aid in troubleshooting missed/extra packages", - ) - for similar_packages in analysis.similar_missing_packages: - rows.append( - [ - INDENT, - repr(similar_packages.pkg), - "--->", - repr(similar_packages.missed), - ] - ) - print_rows(rows) - print() - - show_probable_mismatches = analysis.unmatched_missing_packages and analysis.extra_packages and len(analysis.unmatched_missing_packages) != len(analysis.missing_packages) - - if show_probable_mismatches: - rows = [] - print( - Colors.bold + "Probably missed packages:", - Colors.reset, - "a probable pair was not found", - ) - for p in analysis.unmatched_missing_packages: - rows.append([INDENT, repr(p)]) - print_rows(rows) - print() - - print(Colors.bold + "Summary:", Colors.reset, image) - print(" Inline Packages : %d" % len(analysis.inline_data.packages)) - print(" Syft Packages : %d" % len(analysis.syft_data.packages)) - print( - " (extra) : %d (note: this is ignored by the quality gate!)" - % len(analysis.extra_packages) - ) - print(" (missing) : %d" % len(analysis.missing_packages)) - print() - - if show_probable_mismatches: - print( - " Probable Package Matches : %d (matches not made, but were probably found by both Inline and Syft)" - % len(analysis.similar_missing_packages) - ) - print( - " Probable Packages Matched : %2.3f %% (%d/%d packages)" - % ( - analysis.percent_probable_overlapping_packages, - len(analysis.overlapping_packages) - + len(analysis.similar_missing_packages), - len(analysis.inline_data.packages), - ) - ) - print( - " Probable Packages Missing : %d " - % len(analysis.unmatched_missing_packages) - ) - print() - print( - " Baseline Packages Matched : %2.3f %% (%d/%d packages)" - % ( - analysis.percent_overlapping_packages, - len(analysis.overlapping_packages), - len(analysis.inline_data.packages), - ) - ) - print( - " Baseline Metadata Matched : %2.3f %% (%d/%d metadata)" - % ( - analysis.percent_overlapping_metadata, - len(analysis.overlapping_metadata), - len(analysis.inline_metadata), - ) - ) - - -def enforce_quality_gate(title, actual_value, lower_gate_value, upper_gate_value): - - if actual_value < lower_gate_value: - print( - Colors.bold - + " %s Quality Gate:\t" % title - + Colors.FG.red - + "FAIL (is not >= %d %%)" % lower_gate_value, - Colors.reset, - ) - return False - elif actual_value > upper_gate_value: - print( - Colors.bold - + " %s Quality Gate:\t" % title - + Colors.FG.orange - + "FAIL (lower threshold is artificially low and should be updated)", - Colors.reset, - ) - return False - - print( - Colors.bold - + " %s Quality Gate:\t" % title - + Colors.FG.green - + "Pass (>= %d %%)" % lower_gate_value, - Colors.reset, - ) - - return True - -def main(image): - cwd = os.path.dirname(os.path.abspath(__file__)) - - # parse the inline-scan and syft reports on disk - inline = InlineScan(image=image, report_dir=os.path.join(cwd, "inline-reports")) - syft = Syft(image=image, report_dir=os.path.join(cwd, "syft-reports")) - - # analyze the raw data to generate all derivative data for the report and quality gate - analysis = utils.package.Analysis( - syft_data=syft.packages(), inline_data=inline.packages() - ) - - # show some useful report data for debugging / warm fuzzies - report(image, analysis) - - # enforce a quality gate based on the comparison of package values and metadata values - success = True - success &= enforce_quality_gate( - title="Package", - actual_value=analysis.percent_overlapping_packages, - lower_gate_value=PACKAGE_QUALITY_GATE[image] * 100, - upper_gate_value=PACKAGE_UPPER_THRESHOLD[image] * 100 - ) - success &= enforce_quality_gate( - title="Metadata", - actual_value=analysis.percent_overlapping_metadata, - lower_gate_value=METADATA_QUALITY_GATE[image] * 100, - upper_gate_value=METADATA_UPPER_THRESHOLD[image] * 100 - ) - - if not success: - return 1 - return 0 - -if __name__ == "__main__": - if len(sys.argv) != 2: - sys.exit("provide an image") - - rc = main(sys.argv[1]) - sys.exit(rc) diff --git a/test/inline-compare/utils/__init__.py b/test/inline-compare/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/inline-compare/utils/format.py b/test/inline-compare/utils/format.py deleted file mode 100644 index e376bf820..000000000 --- a/test/inline-compare/utils/format.py +++ /dev/null @@ -1,46 +0,0 @@ -class Colors: - reset = "\033[0m" - bold = "\033[01m" - disable = "\033[02m" - underline = "\033[04m" - reverse = "\033[07m" - strikethrough = "\033[09m" - invisible = "\033[08m" - - class FG: - black = "\033[30m" - red = "\033[31m" - green = "\033[32m" - orange = "\033[33m" - blue = "\033[34m" - purple = "\033[35m" - cyan = "\033[36m" - lightgrey = "\033[37m" - darkgrey = "\033[90m" - lightred = "\033[91m" - lightgreen = "\033[92m" - yellow = "\033[93m" - lightblue = "\033[94m" - pink = "\033[95m" - lightcyan = "\033[96m" - - class BG: - black = "\033[40m" - red = "\033[41m" - green = "\033[42m" - orange = "\033[43m" - blue = "\033[44m" - purple = "\033[45m" - cyan = "\033[46m" - lightgrey = "\033[47m" - - -def print_rows(rows): - if not rows: - return - widths = [] - for col, _ in enumerate(rows[0]): - width = max(len(row[col]) for row in rows) + 2 # padding - widths.append(width) - for row in rows: - print("".join(word.ljust(widths[col_idx]) for col_idx, word in enumerate(row))) diff --git a/test/inline-compare/utils/image.py b/test/inline-compare/utils/image.py deleted file mode 100644 index 8b2d3818a..000000000 --- a/test/inline-compare/utils/image.py +++ /dev/null @@ -1,5 +0,0 @@ -import os - - -def clean(image: str) -> str: - return os.path.basename(image.replace(":", "_")) diff --git a/test/inline-compare/utils/inline.py b/test/inline-compare/utils/inline.py deleted file mode 100644 index 781d6a72a..000000000 --- a/test/inline-compare/utils/inline.py +++ /dev/null @@ -1,142 +0,0 @@ -import os -import re -import json -import collections - -import utils.package -import utils.image - - -class InlineScan: - """ - Class for parsing inlnie-scan output files into a set of packages and package metadata. - """ - report_tmpl = "{image}-{report}.json" - - def __init__(self, image, report_dir): - self.report_dir = report_dir - self.image = image - - def packages(self): - python_packages, python_metadata = self._python_packages() - gem_packages, gem_metadata = self._gem_packages() - java_packages, java_metadata = self._java_packages() - npm_packages, npm_metadata = self._npm_packages() - os_packages, os_metadata = self._os_packages() - - packages = ( - python_packages | os_packages | gem_packages | java_packages | npm_packages - ) - metadata = { - **python_metadata, - **os_metadata, - **gem_metadata, - **java_metadata, - **npm_metadata, - } - - return utils.package.Info(packages=frozenset(packages), metadata=metadata) - - def _report_path(self, report): - return os.path.join( - self.report_dir, - self.report_tmpl.format(image=utils.image.clean(self.image), report=report), - ) - - def _enumerate_section(self, report, section): - report_path = self._report_path(report=report) - os_report_path = self._report_path(report="content-os") - - if os.path.exists(os_report_path) and not os.path.exists(report_path): - # if the OS report is there but the target report is not, that is engine's way of saying "no findings" - return - - with open(report_path) as json_file: - data = json.load(json_file) - for entry in data[section]: - yield entry - - def _java_packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section(report="content-java", section="content"): - # normalize to pseudo-inline - pkg_type = entry["type"].lower() - if pkg_type in ("java-jar", "java-war", "java-ear"): - pkg_type = "java-?ar" - elif pkg_type in ("java-jpi", "java-hpi"): - pkg_type = "java-?pi" - - # this would usually be "package" but this would not be able to account for duplicate dependencies in - # nested jars of the same name. Fallback to the package name if there is no given location - name = entry["location"] - - # replace fields with "N/A" with None - for k, v in dict(entry).items(): - if v in ("", "N/A"): - entry[k] = None - - pkg = utils.package.Package( - name=name, - type=pkg_type, - ) - packages.add(pkg) - - metadata[pkg.type][pkg] = utils.package.Metadata( - version=entry["maven-version"], - ) - - return packages, metadata - - def _npm_packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section(report="content-npm", section="content"): - pkg = utils.package.Package( - name=entry["package"], - type=entry["type"].lower(), - ) - packages.add(pkg) - metadata[pkg.type][pkg] = utils.package.Metadata(version=entry["version"]) - - return packages, metadata - - def _python_packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section( - report="content-python", section="content" - ): - pkg = utils.package.Package( - name=entry["package"], - type=entry["type"].lower(), - ) - packages.add(pkg) - metadata[pkg.type][pkg] = utils.package.Metadata(version=entry["version"]) - - return packages, metadata - - def _gem_packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section(report="content-gem", section="content"): - pkg = utils.package.Package( - name=entry["package"], - type=entry["type"].lower(), - ) - packages.add(pkg) - metadata[pkg.type][pkg] = utils.package.Metadata(version=entry["version"]) - - return packages, metadata - - def _os_packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section(report="content-os", section="content"): - pkg = utils.package.Package( - name=entry["package"], type=entry["type"].lower() - ) - packages.add(pkg) - metadata[pkg.type][pkg] = utils.package.Metadata(version=entry["version"]) - - return packages, metadata diff --git a/test/inline-compare/utils/package.py b/test/inline-compare/utils/package.py deleted file mode 100644 index 13118a4b5..000000000 --- a/test/inline-compare/utils/package.py +++ /dev/null @@ -1,146 +0,0 @@ -import difflib -import collections -import dataclasses -from typing import Set, FrozenSet, Tuple, Any, List - -Metadata = collections.namedtuple("Metadata", "version") -Package = collections.namedtuple("Package", "name type") -Info = collections.namedtuple("Info", "packages metadata") - -SimilarPackages = collections.namedtuple("SimilarPackages", "pkg missed") -ProbableMatch = collections.namedtuple("ProbableMatch", "pkg ratio") - - -@dataclasses.dataclass() -class Analysis: - """ - A package metadata analysis class. When given the raw syft and inline data, all necessary derivative information - needed to do a comparison of package and metadata is performed, allowing callers to interpret the results - """ - - # all raw data from the inline scan and syft reports - syft_data: Info - inline_data: Info - - # all derivative information (derived from the raw data above) - overlapping_packages: FrozenSet[Package] = dataclasses.field(init=False) - extra_packages: FrozenSet[Package] = dataclasses.field(init=False) - missing_packages: FrozenSet[Package] = dataclasses.field(init=False) - - inline_metadata: Set[Tuple[Any, Any]] = dataclasses.field(init=False) - missing_metadata: Set[Tuple[Any, Any]] = dataclasses.field(init=False) - overlapping_metadata: Set[Tuple[Any, Any]] = dataclasses.field(init=False) - - similar_missing_packages: List[Package] = dataclasses.field(init=False) - unmatched_missing_packages: List[Package] = dataclasses.field(init=False) - - def __post_init__(self): - if not self.valid(): - raise RuntimeError("invalid data given") - - # basic sets derived from package information - self.overlapping_packages = self.syft_data.packages & self.inline_data.packages - self.extra_packages = self.syft_data.packages - self.inline_data.packages - self.missing_packages = self.inline_data.packages - self.syft_data.packages - - # basic sets derived from metadata information - self.inline_metadata = self._inline_metadata() - self.overlapping_metadata = self._overlapping_metadata() - self.missing_metadata = self.inline_metadata - self.overlapping_metadata - - # try to account for potential false negatives by pairing extra packages discovered only by syft with missing - # packages discovered only by inline scan. - ( - similar_missing_packages, - unmatched_missing_packages, - ) = self._pair_similar_packages(self.extra_packages, self.missing_packages) - self.similar_missing_packages = similar_missing_packages - self.unmatched_missing_packages = unmatched_missing_packages - - def valid(self) -> bool: - # we are purposefully selecting test images that are guaranteed to have packages (this should never happen). - # ... if it does, then this analysis is not valid! - return bool(self.inline_data.packages) - - def _inline_metadata(self): - """ - Returns the set of inline scan metadata paired with the corresponding package info. - """ - inline_metadata_set = set() - for package in self.inline_data.packages: - metadata = self.inline_data.metadata[package.type][package] - inline_metadata_set.add((package, metadata)) - return inline_metadata_set - - def _overlapping_metadata(self): - """ - Returns the metadata which has been found similar between both syft and inline scan. - """ - syft_overlap_metadata_set = set() - for package in self.syft_data.packages: - metadata = self.syft_data.metadata[package.type][package] - # we only want to really count mismatched metadata for packages that are at least found by inline - if package in self.inline_data.metadata.get(package.type, []): - syft_overlap_metadata_set.add((package, metadata)) - - return syft_overlap_metadata_set & self.inline_metadata - - @staticmethod - def _pair_similar_packages(extra_packages, missing_packages, similar_threshold=0.7): - """ - Try to account for potential false negatives by pairing extra packages discovered only by syft with missing - packages discovered only by inline scan. - """ - matches = collections.defaultdict(set) - found = {} - for s in extra_packages: - for i in missing_packages: - ratio = difflib.SequenceMatcher(None, s.name, i.name).ratio() - if ratio >= similar_threshold: - if i in found: - # only allow for an inline package to be paired once - if ratio < found[i]: - continue - else: - matches[s].discard(i) - - # persist the result - found[i] = ratio - matches[s].add(i) - - results = [] - for s, i_set in matches.items(): - missed = tuple([ProbableMatch(pkg=i, ratio=found[i]) for i in i_set]) - results.append(SimilarPackages(pkg=s, missed=missed)) - - not_found = [i for i in missing_packages if i not in found] - - return sorted(results, key=lambda x: x.pkg), sorted( - not_found, key=lambda x: x.name - ) - - @property - def percent_overlapping_packages(self): - """Returns a percentage representing how many packages that were found relative to the number of expected""" - return ( - float(len(self.overlapping_packages)) - / float(len(self.inline_data.packages)) - ) * 100.0 - - @property - def percent_overlapping_metadata(self): - """Returns a percentage representing how many matching metdata that were found relative to the number of expected""" - return ( - float(len(self.overlapping_metadata)) / float(len(self.inline_metadata)) - ) * 100.0 - - @property - def percent_probable_overlapping_packages(self): - """ - Returns a percentage representing how many packages that were found relative to the number of expected after - considering pairing of missing packages with extra packages in a fuzzy match. - """ - return ( - float(len(self.overlapping_packages) + len(self.similar_missing_packages)) - / float(len(self.inline_data.packages)) - ) * 100.0 diff --git a/test/inline-compare/utils/syft.py b/test/inline-compare/utils/syft.py deleted file mode 100644 index 51c7e0ba0..000000000 --- a/test/inline-compare/utils/syft.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -import json -import collections - -import utils.package -import utils.image - - -class Syft: - """ - Class for parsing syft output into a set of packages and package metadata. - """ - report_tmpl = "{image}.json" - - def __init__(self, image, report_dir): - self.report_path = os.path.join( - report_dir, self.report_tmpl.format(image=utils.image.clean(image)) - ) - - def _enumerate_section(self, section): - with open(self.report_path) as json_file: - data = json.load(json_file) - for entry in data[section]: - yield entry - - def packages(self): - packages = set() - metadata = collections.defaultdict(dict) - for entry in self._enumerate_section(section="artifacts"): - - # normalize to inline - pkg_type = entry["type"].lower() - if pkg_type in ("wheel", "egg", "python"): - pkg_type = "python" - elif pkg_type in ("deb",): - pkg_type = "dpkg" - elif pkg_type in ("java-archive",): - # normalize to pseudo-inline - pkg_type = "java-?ar" - elif pkg_type in ("jenkins-plugin",): - # normalize to pseudo-inline - pkg_type = "java-?pi" - elif pkg_type in ("apk",): - pkg_type = "apkg" - - name = entry["name"] - version = entry["version"] - - if "java" in pkg_type: - # we need to use the virtual path instead of the name to account for nested dependencies with the same - # package name (but potentially different metadata) - name = entry.get("metadata", {}).get("virtualPath") - - elif pkg_type == "apkg": - # inline scan strips off the release from the version, which should be normalized here - fields = entry["version"].split("-") - version = "-".join(fields[:-1]) - - pkg = utils.package.Package( - name=name, - type=pkg_type, - ) - - packages.add(pkg) - - metadata[pkg.type][pkg] = utils.package.Metadata(version=version) - - return utils.package.Info(packages=frozenset(packages), metadata=metadata) From cf516add959581396860696bb3cd8a34d49e5c7c Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 09:00:28 -0400 Subject: [PATCH 11/29] add cli testing Signed-off-by: Alex Goodman --- test/cli/json_schema_test.go | 91 ++++++++++++++ test/cli/packages_cmd_test.go | 139 ++++++++++++++++++++++ test/cli/power_user_cmd_test.go | 49 ++++++++ test/cli/root_cmd_test.go | 91 ++++++++++++++ test/cli/test-fixtures/image-pkg-coverage | 1 + test/cli/trait_assertions_test.go | 82 +++++++++++++ test/cli/utils_test.go | 73 ++++++++++++ 7 files changed, 526 insertions(+) create mode 100644 test/cli/json_schema_test.go create mode 100644 test/cli/packages_cmd_test.go create mode 100644 test/cli/power_user_cmd_test.go create mode 100644 test/cli/root_cmd_test.go create mode 120000 test/cli/test-fixtures/image-pkg-coverage create mode 100644 test/cli/trait_assertions_test.go create mode 100644 test/cli/utils_test.go diff --git a/test/cli/json_schema_test.go b/test/cli/json_schema_test.go new file mode 100644 index 000000000..669123639 --- /dev/null +++ b/test/cli/json_schema_test.go @@ -0,0 +1,91 @@ +package cli + +import ( + "fmt" + "path" + "strings" + "testing" + + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/anchore/syft/internal" + "github.com/xeipuuv/gojsonschema" +) + +// this is the path to the json schema directory relative to the root of the repo +const jsonSchemaPath = "schema/json" + +func TestJSONSchema(t *testing.T) { + + imageFixture := func(t *testing.T) string { + fixtureImageName := "image-pkg-coverage" + imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) + tarPath := imagetest.GetFixtureImageTarPath(t, fixtureImageName) + return "docker-archive:" + tarPath + } + + tests := []struct { + name string + subcommand string + args []string + fixture func(*testing.T) string + }{ + { + name: "packages:image:docker-archive:pkg-coverage", + subcommand: "packages", + args: []string{"-o", "json"}, + fixture: imageFixture, + }, + { + name: "power-user:image:docker-archive:pkg-coverage", + subcommand: "power-user", + fixture: imageFixture, + }, + { + name: "packages:dir:pkg-coverage", + subcommand: "packages", + args: []string{"-o", "json"}, + fixture: func(t *testing.T) string { + return "dir:test-fixtures/image-pkg-coverage" + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fixtureRef := test.fixture(t) + args := []string{ + test.subcommand, fixtureRef, "-q", + } + for _, a := range test.args { + args = append(args, a) + } + + _, stdout, _ := runSyftCommand(t, nil, args...) + + if len(strings.Trim(stdout, "\n ")) < 100 { + t.Fatalf("bad syft output: %q", stdout) + } + + validateAgainstV1Schema(t, stdout) + }) + } +} + +func validateAgainstV1Schema(t testing.TB, json string) { + fullSchemaPath := path.Join(repoRoot(t), jsonSchemaPath, fmt.Sprintf("schema-%s.json", internal.JSONSchemaVersion)) + schemaLoader := gojsonschema.NewReferenceLoader(fmt.Sprintf("file://%s", fullSchemaPath)) + documentLoader := gojsonschema.NewStringLoader(json) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + if err != nil { + t.Fatal("unable to validate json schema:", err.Error()) + } + + if !result.Valid() { + t.Errorf("failed json schema validation:") + t.Errorf("JSON:\n%s\n", json) + for _, desc := range result.Errors() { + t.Errorf(" - %s\n", desc) + } + } +} diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go new file mode 100644 index 000000000..f5732330e --- /dev/null +++ b/test/cli/packages_cmd_test.go @@ -0,0 +1,139 @@ +package cli + +import ( + "strings" + "testing" + + "github.com/anchore/syft/syft/source" +) + +func TestPackagesCmdFlags(t *testing.T) { + request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") + + tests := []struct { + name string + args []string + env map[string]string + assertions []traitAssertion + }{ + { + name: "json-output-flag", + args: []string{"packages", "-o", "json", request}, + assertions: []traitAssertion{ + assertJsonReport, + assertSource(source.SquashedScope), + assertSuccessfulReturnCode, + }, + }, + { + name: "output-env-binding", + env: map[string]string{ + "SYFT_OUTPUT": "json", + }, + args: []string{"packages", request}, + assertions: []traitAssertion{ + assertJsonReport, + assertSuccessfulReturnCode, + }, + }, + { + name: "table-output-flag", + args: []string{"packages", "-o", "table", request}, + assertions: []traitAssertion{ + assertTableReport, + assertSuccessfulReturnCode, + }, + }, + { + name: "default-output-flag", + args: []string{"packages", request}, + assertions: []traitAssertion{ + assertTableReport, + assertSuccessfulReturnCode, + }, + }, + { + name: "squashed-scope-flag", + args: []string{"packages", "-o", "json", "-s", "squashed", request}, + assertions: []traitAssertion{ + assertSource(source.SquashedScope), + assertSuccessfulReturnCode, + }, + }, + { + name: "all-layers-scope-flag", + args: []string{"packages", "-o", "json", "-s", "all-layers", request}, + assertions: []traitAssertion{ + assertSource(source.AllLayersScope), + assertSuccessfulReturnCode, + }, + }, + { + name: "packages-scope-env-binding", + env: map[string]string{ + "SYFT_PACKAGES_SCOPE": "all-layers", + }, + args: []string{"packages", "-o", "json", request}, + assertions: []traitAssertion{ + assertSource(source.AllLayersScope), + assertSuccessfulReturnCode, + }, + }, + { + name: "attempt-upload-on-cli-switches", + args: []string{"packages", "-vv", "-H", "localhost:8080", "-u", "the-username", "-d", "test-fixtures/image-pkg-coverage/Dockerfile", "--overwrite-existing-image", request}, + env: map[string]string{ + "SYFT_ANCHORE_PATH": "path/to/api", + "SYFT_ANCHORE_PASSWORD": "the-password", + }, + assertions: []traitAssertion{ + // we cannot easily assert a successful upload behavior, so instead we are doing the next best thing + // and asserting that the parsed configuration has the expected values and we see log entries + // indicating an upload attempt. + assertNotInOutput("the-username"), + assertNotInOutput("the-password"), + assertInOutput("uploading results to localhost:8080"), + assertInOutput(`dockerfile: test-fixtures/image-pkg-coverage/Dockerfile`), + assertInOutput(`overwrite-existing-image: true`), + assertInOutput(`path: path/to/api`), + assertInOutput(`host: localhost:8080`), + assertFailingReturnCode, // upload can't go anywhere, so if this passes that would be surprising + }, + }, + { + name: "dockerfile-without-upload-is-invalid", + args: []string{"packages", "-vv", "-d", "test-fixtures/image-pkg-coverage/Dockerfile", request}, + assertions: []traitAssertion{ + + assertNotInOutput("uploading results to localhost:8080"), + assertInOutput("invalid application config: cannot provide dockerfile option without enabling upload"), + assertFailingReturnCode, + }, + }, + { + name: "attempt-upload-with-env-host-set", + args: []string{"packages", "-vv", request}, + env: map[string]string{ + "SYFT_ANCHORE_HOST": "localhost:8080", + }, + assertions: []traitAssertion{ + assertInOutput("uploading results to localhost:8080"), + assertFailingReturnCode, // upload can't go anywhere, so if this passes that would be surprising + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...) + for _, traitFn := range test.assertions { + traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) + } + if t.Failed() { + t.Log("STDOUT:\n", stdout) + t.Log("STDERR:\n", stderr) + t.Log("COMMAND:", strings.Join(cmd.Args, " ")) + } + }) + } +} diff --git a/test/cli/power_user_cmd_test.go b/test/cli/power_user_cmd_test.go new file mode 100644 index 000000000..5bc6aa982 --- /dev/null +++ b/test/cli/power_user_cmd_test.go @@ -0,0 +1,49 @@ +package cli + +import ( + "strings" + "testing" +) + +func TestPowerUserCmdFlags(t *testing.T) { + request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") + + tests := []struct { + name string + args []string + env map[string]string + assertions []traitAssertion + }{ + { + name: "json-output-flag-fails", + args: []string{"power-user", "-o", "json", request}, + assertions: []traitAssertion{ + assertFailingReturnCode, + }, + }, + { + name: "default-results", + args: []string{"power-user", request}, + assertions: []traitAssertion{ + assertInOutput(`"type": "regularFile"`), // proof of file-metadata data + assertInOutput(`"algorithm": "sha256"`), // proof of file-metadata default digest algorithm of sha256 + assertInOutput(`"metadataType": "ApkMetadata"`), // proof of package artifacts data + assertSuccessfulReturnCode, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...) + for _, traitFn := range test.assertions { + traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) + } + if t.Failed() { + t.Log("STDOUT:\n", stdout) + t.Log("STDERR:\n", stderr) + t.Log("COMMAND:", strings.Join(cmd.Args, " ")) + } + }) + } +} diff --git a/test/cli/root_cmd_test.go b/test/cli/root_cmd_test.go new file mode 100644 index 000000000..9c58ec299 --- /dev/null +++ b/test/cli/root_cmd_test.go @@ -0,0 +1,91 @@ +package cli + +import ( + "strings" + "testing" + + "github.com/sergi/go-diff/diffmatchpatch" +) + +func TestRootCmdAliasesToPackagesSubcommand(t *testing.T) { + request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") + deprecationWarning := "The root command is deprecated" + + _, aliasStdout, aliasStderr := runSyftCommand(t, nil, request) + + if !strings.Contains(aliasStderr, deprecationWarning) { + t.Errorf("missing root-packages alias deprecation warning") + } + + _, pkgsStdout, pkgsStderr := runSyftCommand(t, nil, "packages", request) + + if strings.Contains(pkgsStderr, deprecationWarning) { + t.Errorf("packages command should not have deprecation warning") + } + + if aliasStdout != pkgsStdout { + t.Errorf("packages and root command should have same report output but do not!") + dmp := diffmatchpatch.New() + diffs := dmp.DiffMain(aliasStdout, pkgsStdout, true) + t.Error(dmp.DiffPrettyText(diffs)) + } +} + +func TestPersistentFlags(t *testing.T) { + request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") + + tests := []struct { + name string + args []string + env map[string]string + assertions []traitAssertion + }{ + { + name: "quiet-flag", + // note: the root command will always show the deprecation warning, so the packages command is used instead + args: []string{"packages", "-q", request}, + assertions: []traitAssertion{ + func(tb testing.TB, stdout, stderr string, rc int) { + // ensure there is no status + if len(stderr) != 0 { + tb.Errorf("should have seen no stderr output, got %d bytes", len(stderr)) + } + // ensure there is still a report + if len(stdout) == 0 { + tb.Errorf("should have seen a report on stdout, got nothing") + } + }, + }, + }, + { + name: "info-log-flag", + args: []string{"-v", request}, + assertions: []traitAssertion{ + assertLoggingLevel("info"), + assertSuccessfulReturnCode, + }, + }, + { + name: "debug-log-flag", + args: []string{"-vv", request}, + assertions: []traitAssertion{ + assertLoggingLevel("debug"), + assertSuccessfulReturnCode, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cmd, stdout, stderr := runSyftCommand(t, test.env, test.args...) + for _, traitFn := range test.assertions { + traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) + } + if t.Failed() { + t.Log("STDOUT:\n", stdout) + t.Log("STDERR:\n", stderr) + t.Log("COMMAND:", strings.Join(cmd.Args, " ")) + } + }) + } +} diff --git a/test/cli/test-fixtures/image-pkg-coverage b/test/cli/test-fixtures/image-pkg-coverage new file mode 120000 index 000000000..155332274 --- /dev/null +++ b/test/cli/test-fixtures/image-pkg-coverage @@ -0,0 +1 @@ +../../integration/test-fixtures/image-pkg-coverage \ No newline at end of file diff --git a/test/cli/trait_assertions_test.go b/test/cli/trait_assertions_test.go new file mode 100644 index 000000000..1eb1b807e --- /dev/null +++ b/test/cli/trait_assertions_test.go @@ -0,0 +1,82 @@ +package cli + +import ( + "encoding/json" + "fmt" + "regexp" + "strings" + "testing" + + "github.com/acarl005/stripansi" + "github.com/anchore/syft/syft/source" +) + +type traitAssertion func(tb testing.TB, stdout, stderr string, rc int) + +func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { + var data interface{} + + if err := json.Unmarshal([]byte(stdout), &data); err != nil { + tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) + } +} + +func assertTableReport(tb testing.TB, stdout, _ string, _ int) { + if !strings.Contains(stdout, "NAME") || !strings.Contains(stdout, "VERSION") || !strings.Contains(stdout, "TYPE") { + tb.Errorf("expected to find a table report, but did not") + } +} + +func assertSource(scope source.Scope) traitAssertion { + return func(tb testing.TB, stdout, stderr string, rc int) { + // we can only verify source with the json report + assertJsonReport(tb, stdout, stderr, rc) + + if !strings.Contains(stdout, fmt.Sprintf(`"scope": "%s"`, scope.String())) { + tb.Errorf("JSON report did not indicate the %q scope", scope) + } + } +} + +func assertLoggingLevel(level string) traitAssertion { + // match examples: + // "[0000] INFO" + // "[0012] DEBUG" + logPattern := regexp.MustCompile(`(?m)^\[\d\d\d\d\]\s+` + strings.ToUpper(level)) + return func(tb testing.TB, _, stderr string, _ int) { + if !logPattern.MatchString(stripansi.Strip(stderr)) { + tb.Errorf("output did not indicate the %q logging level", level) + } + } +} + +func assertNotInOutput(data string) traitAssertion { + return func(tb testing.TB, stdout, stderr string, _ int) { + if strings.Contains(stripansi.Strip(stderr), data) { + tb.Errorf("data=%q was found in stderr, but should not have been there", data) + } + if strings.Contains(stripansi.Strip(stdout), data) { + tb.Errorf("data=%q was found in stdout, but should not have been there", data) + } + } +} + +func assertInOutput(data string) traitAssertion { + return func(tb testing.TB, stdout, stderr string, _ int) { + if !strings.Contains(stripansi.Strip(stderr), data) && !strings.Contains(stripansi.Strip(stdout), data) { + tb.Errorf("data=%q was NOT found in any output, but should have been there", data) + } + } +} + +func assertFailingReturnCode(tb testing.TB, _, _ string, rc int) { + if rc == 0 { + tb.Errorf("expected a failure but got rc=%d", rc) + } +} + +func assertSuccessfulReturnCode(tb testing.TB, _, _ string, rc int) { + if rc != 0 { + tb.Errorf("expected no failure but got rc=%d", rc) + } +} diff --git a/test/cli/utils_test.go b/test/cli/utils_test.go new file mode 100644 index 000000000..a2b6bf0c7 --- /dev/null +++ b/test/cli/utils_test.go @@ -0,0 +1,73 @@ +package cli + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/anchore/stereoscope/pkg/imagetest" +) + +func getFixtureImage(t testing.TB, fixtureImageName string) string { + imagetest.GetFixtureImage(t, "docker-archive", fixtureImageName) + return imagetest.GetFixtureImageTarPath(t, fixtureImageName) +} + +func runSyftCommand(t testing.TB, env map[string]string, args ...string) (*exec.Cmd, string, string) { + cmd := getSyftCommand(t, args...) + if env != nil { + var envList []string + for key, val := range env { + if key == "" { + continue + } + envList = append(envList, fmt.Sprintf("%s=%s", key, val)) + } + cmd.Env = envList + } + var stdout, stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + // ignore errors since this may be what the test expects + cmd.Run() + + return cmd, stdout.String(), stderr.String() +} + +func getSyftCommand(t testing.TB, args ...string) *exec.Cmd { + + var binaryLocation string + if os.Getenv("SYFT_BINARY_LOCATION") != "" { + // SYFT_BINARY_LOCATION is relative to the repository root. (e.g., "snapshot/syft-linux_amd64/syft") + // This value is transformed due to the CLI tests' need for a path relative to the test directory. + binaryLocation = path.Join(repoRoot(t), os.Getenv("SYFT_BINARY_LOCATION")) + } else { + os := runtime.GOOS + if os == "darwin" { + os = "macos_darwin" + } + + binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-%s_%s/syft", os, runtime.GOARCH)) + } + return exec.Command(binaryLocation, args...) +} + +func repoRoot(t testing.TB) string { + t.Helper() + root, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() + if err != nil { + t.Fatalf("unable to find repo root dir: %+v", err) + } + absRepoRoot, err := filepath.Abs(strings.TrimSpace(string(root))) + if err != nil { + t.Fatal("unable to get abs path to repo root:", err) + } + return absRepoRoot +} From 1d87f07da1ff91f70ed7ef09bf3f26a8d91a181b Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 09:01:07 -0400 Subject: [PATCH 12/29] update pipeline with new levels of testing Signed-off-by: Alex Goodman --- .github/workflows/release.yaml | 42 +- .../workflows/static-unit-integration.yaml | 101 ----- .github/workflows/validations.yaml | 368 ++++++++++++++++++ .gitignore | 1 + Makefile | 85 +++- go.mod | 6 +- go.sum | 11 +- 7 files changed, 470 insertions(+), 144 deletions(-) delete mode 100644 .github/workflows/static-unit-integration.yaml create mode 100644 .github/workflows/validations.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6e9393c3a..1721d9152 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -9,7 +9,7 @@ on: - "v*" env: - GO_VERSION: "1.14.x" + GO_VERSION: "1.16.x" jobs: wait-for-checks: @@ -29,17 +29,26 @@ jobs: id: static-analysis with: token: ${{ secrets.GITHUB_TOKEN }} - # This check name is defined as the circle-ci workflow name (in .circleci/config.yaml) - checkName: "Static-Analysis (1.x, ubuntu-latest)" + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) + checkName: "Static-Analysis" ref: ${{ github.event.pull_request.head.sha || github.sha }} - - name: Check unit + integration results (latest go version) + - name: Check unit test results uses: fountainhead/action-wait-for-check@v1.0.0 - id: unit-integration + id: unit with: token: ${{ secrets.GITHUB_TOKEN }} - # This check name is defined as the circle-ci workflow name (in .circleci/config.yaml) - checkName: "Tests (1.x, ubuntu-latest)" + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) + checkName: "Unit-Test" + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Check integration test results + uses: fountainhead/action-wait-for-check@v1.0.0 + id: integration + with: + token: ${{ secrets.GITHUB_TOKEN }} + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) + checkName: "Integration-Test" ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Check acceptance test results (linux) @@ -47,7 +56,7 @@ jobs: id: acceptance-linux with: token: ${{ secrets.GITHUB_TOKEN }} - # This check name is defined as the github action job name (in .github/workflows/acceptance-test.yaml) + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) checkName: "Acceptance-Linux" ref: ${{ github.event.pull_request.head.sha || github.sha }} @@ -56,27 +65,28 @@ jobs: id: acceptance-mac with: token: ${{ secrets.GITHUB_TOKEN }} - # This check name is defined as the github action job name (in .github/workflows/acceptance-test.yaml) + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) checkName: "Acceptance-Mac" ref: ${{ github.event.pull_request.head.sha || github.sha }} - - name: Check inline comparison test results + - name: Check cli test results (linux) uses: fountainhead/action-wait-for-check@v1.0.0 - id: inline-compare + id: cli-linux with: token: ${{ secrets.GITHUB_TOKEN }} - # This check name is defined as the github action job name (in .github/workflows/acceptance-test.yaml) - checkName: "Inline-Compare" + # This check name is defined as the github action job name (in .github/workflows/testing.yaml) + checkName: "Cli-Linux" ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Quality gate - if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit-integration.outputs.conclusion != 'success' || steps.inline-compare.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success' + if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit.outputs.conclusion != 'success' || steps.integration.outputs.conclusion != 'success' || steps.cli-linux.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success' run: | echo "Static Analysis Status: ${{ steps.static-analysis.conclusion }}" - echo "Unit & Integration Test Status: ${{ steps.unit-integration.outputs.conclusion }}" + echo "Unit Test Status: ${{ steps.unit.outputs.conclusion }}" + echo "Integration Test Status: ${{ steps.integration.outputs.conclusion }}" echo "Acceptance Test (Linux) Status: ${{ steps.acceptance-linux.outputs.conclusion }}" echo "Acceptance Test (Mac) Status: ${{ steps.acceptance-mac.outputs.conclusion }}" - echo "Inline Compare Status: ${{ steps.inline-compare.outputs.conclusion }}" + echo "CLI Test (Linux) Status: ${{ steps.cli-linux.outputs.conclusion }}" false release: diff --git a/.github/workflows/static-unit-integration.yaml b/.github/workflows/static-unit-integration.yaml deleted file mode 100644 index eac581c30..000000000 --- a/.github/workflows/static-unit-integration.yaml +++ /dev/null @@ -1,101 +0,0 @@ -name: "Static Analysis + Unit + Integration" -on: - workflow_dispatch: - push: - pull_request: -jobs: - Static-Analysis: - strategy: - matrix: - go-version: [1.x] - platform: [ubuntu-latest] - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - - uses: actions/checkout@v2 - - - name: Restore bootstrap cache - id: bootstrap-cache - uses: actions/cache@v2.1.3 - with: - path: | - ~/go/pkg/mod - ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}-${{ hashFiles('Makefile') }} - restore-keys: | - ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-go-${{ matrix.go-version }}- - - - name: Bootstrap project dependencies - if: steps.bootstrap-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Bootstrap CI dependencies - run: make ci-bootstrap - - - name: Run static analysis - run: make static-analysis - - Tests: - strategy: - matrix: - # test the lower bounds of support, and the latest available - go-version: [1.13.x, 1.x] - platform: [ubuntu-latest] - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - - uses: actions/checkout@v2 - - - name: Restore bootstrap cache - id: bootstrap-cache - uses: actions/cache@v2.1.3 - with: - path: | - ~/go/pkg/mod - ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}-${{ hashFiles('Makefile') }} - restore-keys: | - ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-go-${{ matrix.go-version }}- - - - name: Bootstrap project dependencies - if: steps.bootstrap-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Bootstrap CI dependencies - run: make ci-bootstrap - - - name: Build cache key for java test-fixture blobs (for unit tests) - run: make java-packages-fingerprint - - - name: Restore Java test-fixture cache - id: unit-java-cache - uses: actions/cache@v2.1.3 - with: - path: syft/cataloger/java/test-fixtures/java-builds/packages - key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }} - - - name: Run unit tests - run: make unit - - - name: Validate syft output against the CycloneDX schema - run: make validate-cyclonedx-schema - - - name: Build key for tar cache - run: make integration-fingerprint - - - name: Restore integration test cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/integration/test-fixtures/cache - key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('integration/test-fixtures/cache.fingerprint') }} - - - name: Run integration tests - run: make integration diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml new file mode 100644 index 000000000..5b8560d09 --- /dev/null +++ b/.github/workflows/validations.yaml @@ -0,0 +1,368 @@ +name: "Validations" +on: + workflow_dispatch: + push: + pull_request: + +env: + GO_VERSION: "1.16.x" + +jobs: + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Static-Analysis: + name: "Static analysis" + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v2 + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap + + - name: Bootstrap CI environment dependencies + run: make ci-bootstrap + + - name: Run static analysis + run: make static-analysis + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Unit-Test: + name: "Unit tests" + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v2 + + - name: Restore docker cache + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap + + - name: Bootstrap CI environment dependencies + run: make ci-bootstrap + + - name: Build cache key for java test-fixture blobs (for unit tests) + run: make java-packages-fingerprint + + - name: Restore Java test-fixture cache + id: unit-java-cache + uses: actions/cache@v2.1.3 + with: + path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages + key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }} + + - name: Run unit tests + run: make unit + + - uses: actions/upload-artifact@v2 + with: + name: unit-test-results + path: test/results/**/* + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Integration-Test: + name: "Integration tests" + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v2 + + - name: Restore docker cache + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap + + - name: Bootstrap CI environment dependencies + run: make ci-bootstrap + + - name: Validate syft output against the CycloneDX schema + run: make validate-cyclonedx-schema + + - name: Build key for tar cache + run: make integration-fingerprint + + - name: Restore integration test cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/test/integration/test-fixtures/cache + key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/test-fixtures/cache.fingerprint') }} + + - name: Run integration tests + run: make integration + + Benchmark-Test: + name: "Benchmark tests" + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v2 + + - name: Restore docker cache + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap + + - name: Bootstrap CI environment dependencies + run: make ci-bootstrap + + - name: Restore base benchmark result + uses: actions/cache@v2 + with: + path: test/results/benchmark-main.txt + # use base sha for PR or new commit hash for main push in benchmark result key + key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }} + + - name: Run benchmark tests + id: benchmark + run: | + REF_NAME=${GITHUB_REF##*/} make benchmark + OUTPUT=$(make show-benchstat) + OUTPUT="${OUTPUT//'%'/'%25'}" + OUTPUT="${OUTPUT//$'\n'/'%0A'}" + OUTPUT="${OUTPUT//$'\r'/'%0D'}" + echo "::set-output name=result::$OUTPUT" + + - uses: actions/upload-artifact@v2 + with: + name: branchmark-test-results + path: test/results/**/* + + - name: Update PR benchmark results comment + uses: marocchino/sticky-pull-request-comment@v2 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + header: benchmark + message: | + ### Benchmark Test Results + +
+ Benchmark results from the latest changes vs base branch + + ``` + ${{ steps.benchmark.outputs.result }} + ``` + +
+ + Build-Snapshot-Artifacts: + name: "Build snapshot artifacts" + runs-on: macos-latest # We're creating these snapshot builds on macOS to be consistent with our release workflow's build process, which also takes place on macOS (due to code signing requirements). + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/setup-go@v2 + with: + go-version: ${{ env.GO_VERSION }} + + - uses: actions/checkout@v2 + + - name: Restore tool cache + id: tool-cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap + + - name: Build snapshot artifacts + run: make snapshot + + - uses: actions/upload-artifact@v2 + with: + name: artifacts + path: snapshot/**/* + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Acceptance-Linux: + name: "Acceptance tests (Linux)" + needs: [Build-Snapshot-Artifacts] + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/checkout@v2 + + - uses: actions/download-artifact@v2 + with: + name: artifacts + path: snapshot + + - name: Run Acceptance Tests (Linux) + run: make acceptance-linux + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Acceptance-Mac: + name: "Acceptance tests (Mac)" + needs: [Build-Snapshot-Artifacts] + runs-on: macos-latest + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/checkout@v2 + + - uses: actions/download-artifact@v2 + with: + name: artifacts + path: snapshot + + - name: Run Acceptance Tests (Mac) + run: make acceptance-mac + + # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline + Cli-Linux: + name: "CLI tests (Linux)" + needs: [Build-Snapshot-Artifacts] + runs-on: ubuntu-20.04 + # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) + # skip if this is a pull_request event on an internal PR (which is already covered by push events) + if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + steps: + - uses: actions/checkout@v2 + + - name: Restore docker cache + uses: satackey/action-docker-layer-caching@v0.0.11 + continue-on-error: true + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: (cache-miss) Bootstrap go dependencies + if: steps.go-cache.outputs.cache-hit != 'true' + run: make bootstrap-go + + - name: Build key for tar cache + run: make cli-fingerprint + + - name: Restore CLI test cache + uses: actions/cache@v2.1.3 + with: + path: ${{ github.workspace }}/test/cli/test-fixtures/cache + key: ${{ runner.os }}-cli-test-cache-${{ hashFiles('test/cli/test-fixtures/cache.fingerprint') }} + + - uses: actions/download-artifact@v2 + with: + name: artifacts + path: snapshot + + - name: Run CLI Tests (Linux) + run: make cli-linux diff --git a/.gitignore b/.gitignore index 3edd0085e..5e4ca2bee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ CHANGELOG.md +/test/results /dist /snapshot .server/ diff --git a/Makefile b/Makefile index b085a7b76..0caeb4cc0 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ BIN = syft TEMPDIR = ./.tmp -RESULTSDIR = $(TEMPDIR)/results -COVER_REPORT = $(RESULTSDIR)/cover.report -COVER_TOTAL = $(RESULTSDIR)/cover.total +RESULTSDIR = test/results +COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt +COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --config .golangci.yaml ACC_TEST_IMAGE = centos:8.2.2004 ACC_DIR = ./test/acceptance @@ -19,6 +19,7 @@ COVERAGE_THRESHOLD := 68 # CI cache busting values; change these if you want CI to not use previous stored cache COMPARE_CACHE_BUSTER="f7e689d76a9" INTEGRATION_CACHE_BUSTER="789bacdf" +CLI_CACHE_BUSTER="789bacdf" BOOTSTRAP_CACHE="789bacdf" ## Build variables @@ -57,6 +58,10 @@ ifndef SNAPSHOTDIR $(error SNAPSHOTDIR is not set) endif +ifndef REF_NAME + REF_NAME = $(VERSION) +endif + define title @printf '$(TITLE)$(1)$(RESET)\n' endef @@ -68,7 +73,7 @@ all: clean static-analysis test ## Run all linux-based checks (linting, license @printf '$(SUCCESS)All checks pass!$(RESET)\n' .PHONY: test -test: unit validate-cyclonedx-schema integration acceptance-linux ## Run all tests (currently unit, integration, and linux acceptance tests) +test: unit validate-cyclonedx-schema integration benchmark acceptance-linux ## Run all tests (currently unit, integration, and linux acceptance tests) .PHONY: help help: @@ -78,20 +83,31 @@ help: ci-bootstrap: DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils -.PHONY: bootstrap -bootstrap: ## Download and install all go dependencies (+ prep tooling in the ./tmp dir) - $(call title,Bootstrapping dependencies) - @pwd - # prep temp dirs - mkdir -p $(TEMPDIR) +.PHONY: +ci-bootstrap-mac: + github_changelog_generator --version || sudo gem install github_changelog_generator + +$(RESULTSDIR): mkdir -p $(RESULTSDIR) - # install go dependencies - go mod download - # install utilities + +$(TEMPDIR): + mkdir -p $(TEMPDIR) + +.PHONY: bootstrap-tools +bootstrap-tools: $(TEMPDIR) + [ -f "$(TEMPDIR)/benchstat" ] || GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat [ -f "$(TEMPDIR)/golangci" ] || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.26.0 [ -f "$(TEMPDIR)/bouncer" ] || curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.2.0 [ -f "$(TEMPDIR)/goreleaser" ] || curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh -s -- -b $(TEMPDIR)/ v0.140.0 +.PHONY: bootstrap-go +bootstrap-go: + go mod download + +.PHONY: bootstrap +bootstrap: $(RESULTSDIR) bootstrap-go bootstrap-tools ## Download and install all go dependencies (+ prep tooling in the ./tmp dir) + $(call title,Bootstrapping dependencies) + .PHONY: static-analysis static-analysis: lint check-licenses @@ -124,33 +140,45 @@ validate-cyclonedx-schema: cd schema/cyclonedx && make .PHONY: unit -unit: fixtures ## Run unit tests (with coverage) +unit: $(RESULTSDIR) fixtures ## Run unit tests (with coverage) $(call title,Running unit tests) go test -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/syft/test) @go tool cover -func $(COVER_REPORT) | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > $(COVER_TOTAL) @echo "Coverage: $$(cat $(COVER_TOTAL))" @if [ $$(echo "$$(cat $(COVER_TOTAL)) >= $(COVERAGE_THRESHOLD)" | bc -l) -ne 1 ]; then echo "$(RED)$(BOLD)Failed coverage quality gate (> $(COVERAGE_THRESHOLD)%)$(RESET)" && false; fi +.PHONY: benchmark +benchmark: $(RESULTSDIR) ## Run benchmark tests and compare against the baseline (if available) + $(call title,Running benchmark tests) + go test -p 1 -run=^Benchmark -bench=. -count=5 -benchmem ./... | tee $(RESULTSDIR)/benchmark-$(REF_NAME).txt + (test -s $(RESULTSDIR)/benchmark-main.txt && \ + $(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-main.txt $(RESULTSDIR)/benchmark-$(REF_NAME).txt || \ + $(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-$(REF_NAME).txt) \ + | tee $(RESULTSDIR)/benchstat.txt + +.PHONY: show-benchstat +show-benchstat: + @cat $(RESULTSDIR)/benchstat.txt + .PHONY: integration integration: ## Run integration tests $(call title,Running integration tests) go test -v ./test/integration - # 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/cache.fingerprint && echo "$(INTEGRATION_CACHE_BUSTER)" >> test/integration/test-fixtures/cache.fingerprint .PHONY: java-packages-fingerprint java-packages-fingerprint: - @cd syft/cataloger/java/test-fixtures/java-builds && \ + @cd syft/pkg/cataloger/java/test-fixtures/java-builds && \ make packages.fingerprint .PHONY: fixtures fixtures: $(call title,Generating test fixtures) - cd syft/cataloger/java/test-fixtures/java-builds && make + cd syft/pkg/cataloger/java/test-fixtures/java-builds && make .PHONY: generate-json-schema generate-json-schema: ## Generate a new json schema @@ -175,7 +203,7 @@ $(SNAPSHOTDIR): ## Build snapshot release binaries and packages # note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately .PHONY: acceptance-mac -acceptance-mac: $(SNAPSHOTDIR) ## Run acceptance tests on build snapshot binaries and packages (Mac) +acceptance-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run acceptance tests on build snapshot binaries and packages (Mac) $(call title,Running acceptance test: Run on Mac) $(ACC_DIR)/mac.sh \ $(SNAPSHOTDIR) \ @@ -202,7 +230,7 @@ compare: ## Compare the reports of a run of a main-branch build of syft against @cd test/inline-compare && make .PHONY: acceptance-test-deb-package-install -acceptance-test-deb-package-install: $(SNAPSHOTDIR) +acceptance-test-deb-package-install: $(RESULTSDIR) $(SNAPSHOTDIR) $(call title,Running acceptance test: DEB install) $(ACC_DIR)/deb.sh \ $(SNAPSHOTDIR) \ @@ -211,7 +239,7 @@ acceptance-test-deb-package-install: $(SNAPSHOTDIR) $(RESULTSDIR) .PHONY: acceptance-test-rpm-package-install -acceptance-test-rpm-package-install: $(SNAPSHOTDIR) +acceptance-test-rpm-package-install: $(RESULTSDIR) $(SNAPSHOTDIR) $(call title,Running acceptance test: RPM install) $(ACC_DIR)/rpm.sh \ $(SNAPSHOTDIR) \ @@ -219,6 +247,23 @@ acceptance-test-rpm-package-install: $(SNAPSHOTDIR) $(ACC_TEST_IMAGE) \ $(RESULTSDIR) +# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted +cli-fingerprint: + find test/cli/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/cli/test-fixtures/cache.fingerprint && echo "$(CLI_CACHE_BUSTER)" >> test/cli/test-fixtures/cache.fingerprint + +.PHONY: cli-linux +cli-linux: $(SNAPSHOTDIR) ## Run CLI tests for Linux executable + chmod 755 "$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)" + $(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version + SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)' \ + go test -count=1 -v ./test/cli + +.PHONY: cli-macos +cli-macos: $(SNAPSHOTDIR) ## Run CLI tests for macOS executable + $(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version + SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN)' \ + go test -count=1 -v ./test/cli + .PHONY: changlog-release changelog-release: @echo "Last tag: $(SECOND_TO_LAST_TAG)" diff --git a/go.mod b/go.mod index 038fe513e..f2138d29d 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,14 @@ module github.com/anchore/syft go 1.14 require ( + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/adrg/xdg v0.2.1 - github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 + github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074 github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf github.com/anchore/go-rpmdb v0.0.0-20201106153645-0043963c2e12 github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b - github.com/anchore/stereoscope v0.0.0-20210201165248-e94c52b4052d + github.com/anchore/stereoscope v0.0.0-20210317203852-f77bbcbede40 github.com/antihax/optional v1.0.0 github.com/bmatcuk/doublestar/v2 v2.0.4 github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible @@ -31,6 +32,7 @@ require ( 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/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240 diff --git a/go.sum b/go.sum index 625136e08..ba334d43d 100644 --- a/go.sum +++ b/go.sum @@ -96,10 +96,12 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/adrg/xdg v0.2.1 h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic= github.com/adrg/xdg v0.2.1/go.mod h1:ZuOshBmzV4Ta+s23hdfFZnBsdzmoR3US0d7ErpqSbTQ= -github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 h1:T3+cD5fYvuH36h7EZq+TDpm+d8a6FSD4pQsbmuGGQ8o= -github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= +github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074 h1:Lw9q+WyJLFOR+AULchS5/2GKfM+6gOh4szzizdfH3MU= +github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -113,8 +115,8 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= 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-20210201165248-e94c52b4052d h1:2hv5NOZ0fD8tPk1UdGiW9PHxmjBmBLL+sFlhLXjjKgo= -github.com/anchore/stereoscope v0.0.0-20210201165248-e94c52b4052d/go.mod h1:lhSEYyGLXTXMIFHAz7Ls/MNQ5EjYd5ziLxovKZp1xOs= +github.com/anchore/stereoscope v0.0.0-20210317203852-f77bbcbede40 h1:k3/JigkYl7NjMad9eDBBcsg9qiXJFreW6rKNgE0aMUI= +github.com/anchore/stereoscope v0.0.0-20210317203852-f77bbcbede40/go.mod h1:T/OUHXgngXFlo2vknQsDx+n/jErCLPt5o0H1ZXFBpig= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -737,7 +739,6 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g= github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d h1:KOxOL6qpmqwoPloNwi+CEgc1ayjHNOFNrvoOmeDOjDg= From 4bde850f0424bcad416d3d591508478d5fa26acf Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 10:58:47 -0400 Subject: [PATCH 13/29] add file-metadata config options to docs Signed-off-by: Alex Goodman --- Makefile | 2 +- README.md | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 0caeb4cc0..fbcd38382 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ SUCCESS := $(BOLD)$(GREEN) COVERAGE_THRESHOLD := 68 # CI cache busting values; change these if you want CI to not use previous stored cache COMPARE_CACHE_BUSTER="f7e689d76a9" -INTEGRATION_CACHE_BUSTER="789bacdf" +INTEGRATION_CACHE_BUSTER="23493ba738c3d2f" CLI_CACHE_BUSTER="789bacdf" BOOTSTRAP_CACHE="789bacdf" diff --git a/README.md b/README.md index 83d1f2f6e..6210b6228 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # syft -[![Static Analysis + Unit + Integration](https://github.com/anchore/syft/workflows/Static%20Analysis%20+%20Unit%20+%20Integration/badge.svg)](https://github.com/anchore/syft/actions?query=workflow%3A%22Static+Analysis+%2B+Unit+%2B+Integration%22) -[![Acceptance](https://github.com/anchore/syft/workflows/Acceptance/badge.svg)](https://github.com/anchore/syft/actions?query=workflow%3AAcceptance) +[![Validations](https://github.com/anchore/syft/workflows/validations.yaml/badge.svg)](https://github.com/anchore/syft/workflows/validations.yaml) [![Go Report Card](https://goreportcard.com/badge/github.com/anchore/syft)](https://goreportcard.com/report/github.com/anchore/syft) [![GitHub release](https://img.shields.io/github/release/anchore/syft.svg)](https://github.com/anchore/syft/releases/latest) [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/anchore/syft/blob/main/LICENSE) @@ -22,28 +21,28 @@ If you encounter an issue, please [let us know using the issue tracker](https:// To generate an SBOM for a Docker or OCI image: ``` -syft +syft packages ``` The above output includes only software that is visible in the container (i.e., the squashed representation of the image). To include software from all image layers in the SBOM, regardless of its presence in the final image, provide `--scope all-layers`: ``` -syft --scope all-layers +syft packages --scope all-layers ``` Syft can generate a SBOM from a variety of sources: ``` # catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands) -syft path/to/image.tar +syft packages path/to/image.tar # catalog a directory -syft path/to/dir +syft packages path/to/dir ``` The output format for Syft is configurable as well: ``` -syft -o +syft packages -o ``` Where the `format`s available are: @@ -93,19 +92,28 @@ quiet: false # same as SYFT_CHECK_FOR_APP_UPDATE env var check-for-app-update: true +# cataloging packages is exposed through the packages and power-user subcommands packages: + # enable/disable cataloging of packages + # SYFT_PACKAGES_CATALOGING_ENABLED env var + cataloging-enabled: true + # the search space to look for packages (options: all-layers, squashed) - # same as -s ; SYFT_SCOPE env var + # same as -s ; SYFT_PACKAGES_SCOPE env var scope: "squashed" +# cataloging file metadata is exposed through the power-user subcommand file-metadata: - # enable/disable cataloging if file metadata + # enable/disable cataloging of file metadata + # SYFT_FILE_METADATA_CATALOGING_ENABLED env var cataloging-enabled: true # the search space to look for file metadata (options: all-layers, squashed) + # SYFT_FILE_METADATA_SCOPE env var scope: "squashed" # the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1") + # SYFT_FILE_METADATA_DIGESTS env var digests: ["sha256"] log: @@ -121,6 +129,7 @@ log: # same as SYFT_LOG_FILE env var file: "" +# uploading package SBOM is exposed through the packages subcommand anchore: # (feature-preview) the Anchore Enterprise Host or URL to upload results to (supported on Enterprise 3.0+) # same as -H ; SYFT_ANCHORE_HOST env var From b1b57f6ba6bcd1720de0768751c3a9ab3efad07d Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Thu, 18 Mar 2021 15:43:05 -0400 Subject: [PATCH 14/29] remove benchmark test event filter in validations pipeline Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 5b8560d09..2c26ca5f9 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -167,9 +167,9 @@ jobs: Benchmark-Test: name: "Benchmark tests" runs-on: ubuntu-20.04 - # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) - # skip if this is a pull_request event on an internal PR (which is already covered by push events) - if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository + # note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and + # we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter + # the job by event. steps: - uses: actions/setup-go@v2 with: @@ -215,11 +215,7 @@ jobs: id: benchmark run: | REF_NAME=${GITHUB_REF##*/} make benchmark - OUTPUT=$(make show-benchstat) - OUTPUT="${OUTPUT//'%'/'%25'}" - OUTPUT="${OUTPUT//$'\n'/'%0A'}" - OUTPUT="${OUTPUT//$'\r'/'%0D'}" - echo "::set-output name=result::$OUTPUT" + echo "::set-output name=result::$(make show-benchstat)" - uses: actions/upload-artifact@v2 with: From f180d1c537ef29df1d0dd661ef01826716df8536 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Sat, 20 Mar 2021 07:33:13 -0400 Subject: [PATCH 15/29] improve config parsing + fix command deprecation warning Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 2 +- Makefile | 41 ++++++----------- README.md | 26 ++++++----- cmd/cmd.go | 45 ++++++++++++------- cmd/packages.go | 8 ++-- cmd/power_user.go | 18 ++++++-- cmd/power_user_tasks.go | 12 ++--- internal/config/application.go | 39 +++++++++++----- internal/config/cataloger_options.go | 23 ++++++++++ internal/config/file_metadata.go | 20 ++------- internal/config/packages.go | 18 +------- internal/presenter/packages/json_package.go | 3 ++ internal/presenter/poweruser/json_document.go | 2 +- internal/version/build.go | 8 ++++ internal/version/update.go | 12 ++--- internal/version/update_test.go | 9 ++++ syft/pkg/ownership_by_files_relationship.go | 4 ++ test/cli/packages_cmd_test.go | 2 +- test/cli/power_user_cmd_test.go | 1 + test/cli/utils_test.go | 17 ++++--- 20 files changed, 179 insertions(+), 131 deletions(-) create mode 100644 internal/config/cataloger_options.go diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 2c26ca5f9..76b4f0cc7 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -361,4 +361,4 @@ jobs: path: snapshot - name: Run CLI Tests (Linux) - run: make cli-linux + run: make cli diff --git a/Makefile b/Makefile index fbcd38382..35d4cb09e 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,6 @@ SUCCESS := $(BOLD)$(GREEN) # the quality gate lower threshold for unit test total % coverage (by function statements) COVERAGE_THRESHOLD := 68 # CI cache busting values; change these if you want CI to not use previous stored cache -COMPARE_CACHE_BUSTER="f7e689d76a9" INTEGRATION_CACHE_BUSTER="23493ba738c3d2f" CLI_CACHE_BUSTER="789bacdf" BOOTSTRAP_CACHE="789bacdf" @@ -26,7 +25,13 @@ BOOTSTRAP_CACHE="789bacdf" DISTDIR=./dist SNAPSHOTDIR=./snapshot GITTREESTATE=$(if $(shell git status --porcelain),dirty,clean) -SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/syft_linux_amd64/syft) +OS := $(shell uname) + +ifeq ($(OS),Darwin) + SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN)) +else + SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)) +endif ifeq "$(strip $(VERSION))" "" override VERSION = $(shell git describe --always --tags --dirty) @@ -73,7 +78,7 @@ all: clean static-analysis test ## Run all linux-based checks (linting, license @printf '$(SUCCESS)All checks pass!$(RESET)\n' .PHONY: test -test: unit validate-cyclonedx-schema integration benchmark acceptance-linux ## Run all tests (currently unit, integration, and linux acceptance tests) +test: unit validate-cyclonedx-schema integration benchmark acceptance-linux cli ## Run all tests (currently unit, integration, linux acceptance, and mac cli tests) .PHONY: help help: @@ -215,20 +220,6 @@ acceptance-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run acceptance tests on build sn .PHONY: acceptance-linux acceptance-linux: acceptance-test-deb-package-install acceptance-test-rpm-package-install ## Run acceptance tests on build snapshot binaries and packages (Linux) -# note: this is used by CI to determine if the inline-scan report cache should be busted for the inline-compare tests -.PHONY: compare-fingerprint -compare-fingerprint: - find test/inline-compare/* -type f -exec md5sum {} + | grep -v '\-reports' | grep -v 'fingerprint' | awk '{print $1}' | sort | md5sum | tee test/inline-compare/inline-compare.fingerprint && echo "$(COMPARE_CACHE_BUSTER)" >> test/inline-compare/inline-compare.fingerprint - -.PHONY: compare-snapshot -compare-snapshot: $(SNAPSHOTDIR) ## Compare the reports of a run of a snapshot build of syft against inline-scan - chmod 755 $(SNAPSHOT_CMD) - @cd test/inline-compare && SYFT_CMD=$(SNAPSHOT_CMD) make - -.PHONY: compare -compare: ## Compare the reports of a run of a main-branch build of syft against inline-scan - @cd test/inline-compare && make - .PHONY: acceptance-test-deb-package-install acceptance-test-deb-package-install: $(RESULTSDIR) $(SNAPSHOTDIR) $(call title,Running acceptance test: DEB install) @@ -251,17 +242,11 @@ acceptance-test-rpm-package-install: $(RESULTSDIR) $(SNAPSHOTDIR) cli-fingerprint: find test/cli/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/cli/test-fixtures/cache.fingerprint && echo "$(CLI_CACHE_BUSTER)" >> test/cli/test-fixtures/cache.fingerprint -.PHONY: cli-linux -cli-linux: $(SNAPSHOTDIR) ## Run CLI tests for Linux executable - chmod 755 "$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)" - $(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version - SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)' \ - go test -count=1 -v ./test/cli - -.PHONY: cli-macos -cli-macos: $(SNAPSHOTDIR) ## Run CLI tests for macOS executable - $(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version - SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN)' \ +.PHONY: cli +cli: $(SNAPSHOTDIR) ## Run CLI tests + chmod 755 "$(SNAPSHOT_CMD)" + $(SNAPSHOT_CMD) version + SYFT_BINARY_LOCATION='$(SNAPSHOT_CMD)' \ go test -count=1 -v ./test/cli .PHONY: changlog-release diff --git a/README.md b/README.md index 6210b6228..62123c14b 100644 --- a/README.md +++ b/README.md @@ -93,24 +93,26 @@ quiet: false check-for-app-update: true # cataloging packages is exposed through the packages and power-user subcommands -packages: +package: + cataloger: # enable/disable cataloging of packages - # SYFT_PACKAGES_CATALOGING_ENABLED env var - cataloging-enabled: true - + # SYFT_PACKAGE_CATALOGER_ENABLED env var + enabled: true + # the search space to look for packages (options: all-layers, squashed) - # same as -s ; SYFT_PACKAGES_SCOPE env var + # same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var scope: "squashed" # cataloging file metadata is exposed through the power-user subcommand file-metadata: - # enable/disable cataloging of file metadata - # SYFT_FILE_METADATA_CATALOGING_ENABLED env var - cataloging-enabled: true - - # the search space to look for file metadata (options: all-layers, squashed) - # SYFT_FILE_METADATA_SCOPE env var - scope: "squashed" + cataloger: + # enable/disable cataloging of file metadata + # SYFT_FILE_METADATA_CATALOGER_ENABLED env var + enabled: true + + # the search space to look for file metadata (options: all-layers, squashed) + # SYFT_FILE_METADATA_CATALOGER_SCOPE env var + scope: "squashed" # the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1") # SYFT_FILE_METADATA_DIGESTS env var diff --git a/cmd/cmd.go b/cmd/cmd.go index 450d3e469..9e0bda837 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -34,7 +34,7 @@ func init() { } // provided to disambiguate the root vs packages command, whichever is indicated by the cli args will be set here. -// TODO: when the root alias command is removed, this function (hack) can be removed +// TODO: when the root alias command is removed, this variable can be removed var activeCmd *cobra.Command func Execute() { @@ -44,23 +44,28 @@ func Execute() { } } +// we must setup the config-cli bindings first before the application configuration is parsed. However, this cannot +// be done without determining what the primary command that the config options should be bound to since there are +// shared concerns (the root-packages alias). func initCmdAliasBindings() { // TODO: when the root alias command is removed, this function (hack) can be removed + // map of all commands except for root + commands := make(map[string]*cobra.Command) + for _, c := range rootCmd.Commands() { + name := strings.Split(c.Use, " ")[0] + commands[name] = c + } + activeCmd = rootCmd for i, a := range os.Args { if i == 0 { // don't consider the bin continue } - if a == "packages" { - // this is positively the first subcommand directive, and is "packages" - activeCmd = packagesCmd - break - } - if !strings.HasPrefix("-", a) { - // this is the first non-switch provided and was not "packages" - break + // check to see if this argument may be a command + if c, exists := commands[a]; exists { + activeCmd = c } } @@ -69,14 +74,20 @@ func initCmdAliasBindings() { fmt.Fprintln(os.Stderr, color.New(color.Bold, color.Red).Sprintf("The root command is deprecated, please use the 'packages' subcommand")) } - // note: we need to lazily bind config options since they are shared between both the root command - // and the packages command. Otherwise there will be global viper state that is in contention. - // See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE - // reading the application configuration, which implies that it must be an initializer (or rewrite the command - // initialization structure against typical patterns used with cobra, which is somewhat extreme for a - // temporary alias) - if err := bindConfigOptions(activeCmd.Flags()); err != nil { - panic(err) + if activeCmd == packagesCmd || activeCmd == rootCmd { + // note: we need to lazily bind config options since they are shared between both the root command + // and the packages command. Otherwise there will be global viper state that is in contention. + // See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE + // reading the application configuration, which implies that it must be an initializer (or rewrite the command + // initialization structure against typical patterns used with cobra, which is somewhat extreme for a + // temporary alias) + if err := bindConfigOptions(activeCmd.Flags()); err != nil { + panic(err) + } + } else { + if err := bindConfigOptions(packagesCmd.Flags()); err != nil { + panic(err) + } } } diff --git a/cmd/packages.go b/cmd/packages.go index 1e95adec5..d0d205919 100644 --- a/cmd/packages.go +++ b/cmd/packages.go @@ -141,7 +141,7 @@ func setPackageFlags(flags *pflag.FlagSet) { func bindConfigOptions(flags *pflag.FlagSet) error { ///////// Formatting & Input options ////////////////////////////////////////////// - if err := viper.BindPFlag("packages.scope", flags.Lookup("scope")); err != nil { + if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil { return err } @@ -194,14 +194,14 @@ func packagesExecWorker(userInput string) <-chan error { } defer cleanup() - catalog, d, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt) + catalog, d, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt) if err != nil { errs <- fmt.Errorf("failed to catalog input: %+v", err) return } if appConfig.Anchore.Host != "" { - if err := runPackageSbomUpload(src, src.Metadata, catalog, d, appConfig.Packages.ScopeOpt); err != nil { + if err := runPackageSbomUpload(src, src.Metadata, catalog, d, appConfig.Package.Cataloger.ScopeOpt); err != nil { errs <- err return } @@ -213,7 +213,7 @@ func packagesExecWorker(userInput string) <-chan error { SourceMetadata: src.Metadata, Catalog: catalog, Distro: d, - Scope: appConfig.Packages.ScopeOpt, + Scope: appConfig.Package.Cataloger.ScopeOpt, }), }) }() diff --git a/cmd/power_user.go b/cmd/power_user.go index 1f48459a6..2a15f5180 100644 --- a/cmd/power_user.go +++ b/cmd/power_user.go @@ -3,6 +3,8 @@ package cmd import ( "fmt" + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/bus" "github.com/anchore/syft/internal/presenter/poweruser" "github.com/anchore/syft/internal/ui" @@ -13,14 +15,24 @@ import ( "github.com/wagoodman/go-partybus" ) +const powerUserExample = ` {{.appName}} {{.command}} + + Only image sources are supported (e.g. docker: , docker-archive: , oci: , etc.), the directory source (dir:) is not supported. + + All behavior is controlled via application configuration and environment variables (see https://github.com/anchore/syft#configuration) +` + var powerUserOpts = struct { configPath string }{} var powerUserCmd = &cobra.Command{ - Use: "power-user [SOURCE]", - Short: "Run bulk operations on container images", - Example: ` {{.appName}} power-user `, + Use: "power-user [IMAGE]", + Short: "Run bulk operations on container images", + Example: internal.Tprintf(powerUserExample, map[string]interface{}{ + "appName": internal.ApplicationName, + "command": "power-user", + }), Args: cobra.ExactArgs(1), Hidden: true, SilenceUsage: true, diff --git a/cmd/power_user_tasks.go b/cmd/power_user_tasks.go index 0d5c21746..2800202f6 100644 --- a/cmd/power_user_tasks.go +++ b/cmd/power_user_tasks.go @@ -37,12 +37,12 @@ func powerUserTasks(src source.Source) ([]powerUserTask, error) { } func catalogPackagesTask(src source.Source) powerUserTask { - if !appConfig.Packages.CatalogingEnabled { + if !appConfig.Package.Cataloger.Enabled { return nil } task := func(results *poweruser.JSONDocumentConfig) error { - packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt) + packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt) if err != nil { return err } @@ -57,11 +57,11 @@ func catalogPackagesTask(src source.Source) powerUserTask { } func catalogFileMetadataTask(src source.Source) (powerUserTask, error) { - if !appConfig.FileMetadata.CatalogingEnabled { + if !appConfig.FileMetadata.Cataloger.Enabled { return nil, nil } - resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt) + resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } @@ -79,11 +79,11 @@ func catalogFileMetadataTask(src source.Source) (powerUserTask, error) { } func catalogFileDigestTask(src source.Source) (powerUserTask, error) { - if !appConfig.FileMetadata.CatalogingEnabled { + if !appConfig.FileMetadata.Cataloger.Enabled { return nil, nil } - resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt) + resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) if err != nil { return nil, err } diff --git a/internal/config/application.go b/internal/config/application.go index 7ec137331..24c97d1a8 100644 --- a/internal/config/application.go +++ b/internal/config/application.go @@ -1,6 +1,7 @@ package config import ( + "errors" "fmt" "path" "strings" @@ -15,6 +16,8 @@ import ( "gopkg.in/yaml.v2" ) +var ErrApplicationConfigNotFound = fmt.Errorf("application config not found") + // Application is the main syft application configuration. type Application struct { ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading) @@ -25,7 +28,7 @@ type Application struct { Dev Development `yaml:"dev" json:"dev" mapstructure:"dev"` CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise - Packages Packages `yaml:"packages" json:"packages" mapstructure:"packages"` + Package Packages `yaml:"package" json:"package" mapstructure:"package"` FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"` } @@ -33,7 +36,9 @@ type Application struct { func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) (*Application, error) { // the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead setNonCliDefaultAppConfigValues(v) - _ = readConfig(v, cliOpts.ConfigPath) + if err := readConfig(v, cliOpts.ConfigPath); err != nil && !errors.Is(err, ErrApplicationConfigNotFound) { + return nil, err + } config := &Application{ CliOptions: cliOpts, @@ -88,7 +93,7 @@ func (cfg *Application) build() error { } for _, builder := range []func() error{ - cfg.Packages.build, + cfg.Package.build, cfg.FileMetadata.build, } { if err := builder(); err != nil { @@ -111,7 +116,9 @@ func (cfg Application) String() string { } // readConfig attempts to read the given config path from disk or discover an alternate store location +// nolint:funlen func readConfig(v *viper.Viper, configPath string) error { + var err error v.AutomaticEnv() v.SetEnvPrefix(internal.ApplicationName) // allow for nested options to be specified via environment variables @@ -132,16 +139,20 @@ func readConfig(v *viper.Viper, configPath string) error { // 1. look for ..yaml (in the current directory) v.AddConfigPath(".") - v.SetConfigName(internal.ApplicationName) - if err := v.ReadInConfig(); err == nil { + v.SetConfigName("." + internal.ApplicationName) + if err = v.ReadInConfig(); err == nil { return nil + } else if !errors.As(err, &viper.ConfigFileNotFoundError{}) { + return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err) } // 2. look for ./config.yaml (in the current directory) v.AddConfigPath("." + internal.ApplicationName) v.SetConfigName("config") - if err := v.ReadInConfig(); err == nil { + if err = v.ReadInConfig(); err == nil { return nil + } else if !errors.As(err, &viper.ConfigFileNotFoundError{}) { + return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err) } // 3. look for ~/..yaml @@ -149,8 +160,10 @@ func readConfig(v *viper.Viper, configPath string) error { if err == nil { v.AddConfigPath(home) v.SetConfigName("." + internal.ApplicationName) - if err := v.ReadInConfig(); err == nil { + if err = v.ReadInConfig(); err == nil { return nil + } else if !errors.As(err, &viper.ConfigFileNotFoundError{}) { + return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err) } } @@ -160,11 +173,13 @@ func readConfig(v *viper.Viper, configPath string) error { v.AddConfigPath(path.Join(dir, internal.ApplicationName)) } v.SetConfigName("config") - if err := v.ReadInConfig(); err == nil { + if err = v.ReadInConfig(); err == nil { return nil + } else if !errors.As(err, &viper.ConfigFileNotFoundError{}) { + return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err) } - return fmt.Errorf("application config not found") + return ErrApplicationConfigNotFound } // setNonCliDefaultAppConfigValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value) @@ -174,8 +189,8 @@ func setNonCliDefaultAppConfigValues(v *viper.Viper) { v.SetDefault("check-for-app-update", true) v.SetDefault("dev.profile-cpu", false) v.SetDefault("dev.profile-mem", false) - v.SetDefault("packages.cataloging-enabled", true) - v.SetDefault("file-metadata.cataloging-enabled", true) - v.SetDefault("file-metadata.scope", source.SquashedScope) + v.SetDefault("package.cataloger.enabled", true) + v.SetDefault("file-metadata.cataloger.enabled", true) + v.SetDefault("file-metadata.cataloger.scope", source.SquashedScope) v.SetDefault("file-metadata.digests", []string{"sha256"}) } diff --git a/internal/config/cataloger_options.go b/internal/config/cataloger_options.go new file mode 100644 index 000000000..72e4c0977 --- /dev/null +++ b/internal/config/cataloger_options.go @@ -0,0 +1,23 @@ +package config + +import ( + "fmt" + + "github.com/anchore/syft/syft/source" +) + +type catalogerOptions struct { + Enabled bool `yaml:"enabled" json:"enabled" mapstructure:"enabled"` + Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` + ScopeOpt source.Scope `yaml:"-" json:"-"` +} + +func (cfg *catalogerOptions) build() error { + scopeOption := source.ParseScope(cfg.Scope) + if scopeOption == source.UnknownScope { + return fmt.Errorf("bad scope value %q", cfg.Scope) + } + cfg.ScopeOpt = scopeOption + + return nil +} diff --git a/internal/config/file_metadata.go b/internal/config/file_metadata.go index a58f6410c..274fce24b 100644 --- a/internal/config/file_metadata.go +++ b/internal/config/file_metadata.go @@ -1,24 +1,10 @@ package config -import ( - "fmt" - - "github.com/anchore/syft/syft/source" -) - type FileMetadata struct { - CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"` - Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` - ScopeOpt source.Scope `yaml:"-" json:"-"` - Digests []string `yaml:"digests" json:"digests" mapstructure:"digests"` + Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"` + Digests []string `yaml:"digests" json:"digests" mapstructure:"digests"` } func (cfg *FileMetadata) build() error { - scopeOption := source.ParseScope(cfg.Scope) - if scopeOption == source.UnknownScope { - return fmt.Errorf("bad scope value %q", cfg.Scope) - } - cfg.ScopeOpt = scopeOption - - return nil + return cfg.Cataloger.build() } diff --git a/internal/config/packages.go b/internal/config/packages.go index 63a1245f6..8193ab04c 100644 --- a/internal/config/packages.go +++ b/internal/config/packages.go @@ -1,23 +1,9 @@ package config -import ( - "fmt" - - "github.com/anchore/syft/syft/source" -) - type Packages struct { - CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"` - Scope string `yaml:"scope" json:"scope" mapstructure:"scope"` - ScopeOpt source.Scope `yaml:"-" json:"-"` + Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"` } func (cfg *Packages) build() error { - scopeOption := source.ParseScope(cfg.Scope) - if scopeOption == source.UnknownScope { - return fmt.Errorf("bad scope value %q", cfg.Scope) - } - cfg.ScopeOpt = scopeOption - - return nil + return cfg.Cataloger.build() } diff --git a/internal/presenter/packages/json_package.go b/internal/presenter/packages/json_package.go index c3be8ff1f..a2ea899dd 100644 --- a/internal/presenter/packages/json_package.go +++ b/internal/presenter/packages/json_package.go @@ -23,6 +23,9 @@ type JSONPackage struct { func NewJSONPackages(catalog *pkg.Catalog) ([]JSONPackage, error) { artifacts := make([]JSONPackage, 0) + if catalog == nil { + return artifacts, nil + } for _, p := range catalog.Sorted() { art, err := NewJSONPackage(p) if err != nil { diff --git a/internal/presenter/poweruser/json_document.go b/internal/presenter/poweruser/json_document.go index d59b38c93..856090a80 100644 --- a/internal/presenter/poweruser/json_document.go +++ b/internal/presenter/poweruser/json_document.go @@ -15,7 +15,7 @@ type JSONDocument struct { // NewJSONDocument creates and populates a new JSON document struct from the given cataloging results. func NewJSONDocument(config JSONDocumentConfig) (JSONDocument, error) { - pkgsDoc, err := packages.NewJSONDocument(config.PackageCatalog, config.SourceMetadata, config.Distro, config.ApplicationConfig.Packages.ScopeOpt, config.ApplicationConfig) + pkgsDoc, err := packages.NewJSONDocument(config.PackageCatalog, config.SourceMetadata, config.Distro, config.ApplicationConfig.Package.Cataloger.ScopeOpt, config.ApplicationConfig) if err != nil { return JSONDocument{}, err } diff --git a/internal/version/build.go b/internal/version/build.go index 3d6702c0c..1313fa9a3 100644 --- a/internal/version/build.go +++ b/internal/version/build.go @@ -6,6 +6,7 @@ package version import ( "fmt" "runtime" + "strings" ) const valueNotProvided = "[not provided]" @@ -28,6 +29,13 @@ type Version struct { Platform string `json:"platform"` // GOOS and GOARCH at build-time } +func (v Version) IsProductionBuild() bool { + if strings.Contains(v.Version, "SNAPSHOT") || strings.Contains(v.Version, valueNotProvided) { + return false + } + return true +} + // FromBuild provides all version details func FromBuild() Version { return Version{ diff --git a/internal/version/update.go b/internal/version/update.go index 3aa13ef3a..7fd791e1c 100644 --- a/internal/version/update.go +++ b/internal/version/update.go @@ -20,13 +20,13 @@ var latestAppVersionURL = struct { // IsUpdateAvailable indicates if there is a newer application version available, and if so, what the new version is. func IsUpdateAvailable() (bool, string, error) { - currentVersionStr := FromBuild().Version - currentVersion, err := hashiVersion.NewVersion(currentVersionStr) + currentBuildInfo := FromBuild() + if !currentBuildInfo.IsProductionBuild() { + // don't allow for non-production builds to check for a version. + return false, "", nil + } + currentVersion, err := hashiVersion.NewVersion(currentBuildInfo.Version) if err != nil { - if currentVersionStr == valueNotProvided { - // this is the default build arg and should be ignored (this is not an error case) - return false, "", nil - } return false, "", fmt.Errorf("failed to parse current application version: %w", err) } diff --git a/internal/version/update_test.go b/internal/version/update_test.go index 10c34b738..c79750540 100644 --- a/internal/version/update_test.go +++ b/internal/version/update_test.go @@ -81,6 +81,15 @@ func TestIsUpdateAvailable(t *testing.T) { newVersion: "", err: false, }, + { + name: "SnapshotBuildVersion", + buildVersion: "2.0.0-SHAPSHOT-a78bf9c", + latestVersion: "1.0.0", + code: 200, + isAvailable: false, + newVersion: "", + err: false, + }, { name: "BadUpdateValidVersion", buildVersion: "1.0.0", diff --git a/syft/pkg/ownership_by_files_relationship.go b/syft/pkg/ownership_by_files_relationship.go index 0151ee2b4..f235557a4 100644 --- a/syft/pkg/ownership_by_files_relationship.go +++ b/syft/pkg/ownership_by_files_relationship.go @@ -45,6 +45,10 @@ func ownershipByFilesRelationships(catalog *Catalog) []Relationship { func findOwnershipByFilesRelationships(catalog *Catalog) map[ID]map[ID]*strset.Set { var relationships = make(map[ID]map[ID]*strset.Set) + if catalog == nil { + return relationships + } + for _, candidateOwnerPkg := range catalog.Sorted() { if candidateOwnerPkg.Metadata == nil { continue diff --git a/test/cli/packages_cmd_test.go b/test/cli/packages_cmd_test.go index f5732330e..e5c28dfbb 100644 --- a/test/cli/packages_cmd_test.go +++ b/test/cli/packages_cmd_test.go @@ -71,7 +71,7 @@ func TestPackagesCmdFlags(t *testing.T) { { name: "packages-scope-env-binding", env: map[string]string{ - "SYFT_PACKAGES_SCOPE": "all-layers", + "SYFT_PACKAGE_CATALOGER_SCOPE": "all-layers", }, args: []string{"packages", "-o", "json", request}, assertions: []traitAssertion{ diff --git a/test/cli/power_user_cmd_test.go b/test/cli/power_user_cmd_test.go index 5bc6aa982..603c1a18d 100644 --- a/test/cli/power_user_cmd_test.go +++ b/test/cli/power_user_cmd_test.go @@ -25,6 +25,7 @@ func TestPowerUserCmdFlags(t *testing.T) { name: "default-results", args: []string{"power-user", request}, assertions: []traitAssertion{ + assertNotInOutput(" command is deprecated"), // only the root command should be deprecated assertInOutput(`"type": "regularFile"`), // proof of file-metadata data assertInOutput(`"algorithm": "sha256"`), // proof of file-metadata default digest algorithm of sha256 assertInOutput(`"metadataType": "ApkMetadata"`), // proof of package artifacts data diff --git a/test/cli/utils_test.go b/test/cli/utils_test.go index a2b6bf0c7..a12525d47 100644 --- a/test/cli/utils_test.go +++ b/test/cli/utils_test.go @@ -45,16 +45,19 @@ func getSyftCommand(t testing.TB, args ...string) *exec.Cmd { var binaryLocation string if os.Getenv("SYFT_BINARY_LOCATION") != "" { - // SYFT_BINARY_LOCATION is relative to the repository root. (e.g., "snapshot/syft-linux_amd64/syft") - // This value is transformed due to the CLI tests' need for a path relative to the test directory. - binaryLocation = path.Join(repoRoot(t), os.Getenv("SYFT_BINARY_LOCATION")) + // SYFT_BINARY_LOCATION is the absolute path to the snapshot binary + binaryLocation = os.Getenv("SYFT_BINARY_LOCATION") } else { - os := runtime.GOOS - if os == "darwin" { - os = "macos_darwin" + // note: there is a subtle - vs _ difference between these versions + switch runtime.GOOS { + case "darwin": + binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-macos_darwin_%s/syft", runtime.GOARCH)) + case "linux": + binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft_linux_%s/syft", runtime.GOARCH)) + default: + t.Fatalf("unsupported OS: %s", runtime.GOOS) } - binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-%s_%s/syft", os, runtime.GOARCH)) } return exec.Command(binaryLocation, args...) } From abca2c5f0b1fb2225d504b0b4ab26fce174245bf Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 22 Mar 2021 10:20:44 -0400 Subject: [PATCH 16/29] remove token usage from benchmark sticky comment action Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 76b4f0cc7..bb0707069 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -225,7 +225,6 @@ jobs: - name: Update PR benchmark results comment uses: marocchino/sticky-pull-request-comment@v2 with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} header: benchmark message: | ### Benchmark Test Results From 36e4af1953a81036251be9a1b582657e821dc43d Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 22 Mar 2021 11:27:01 -0400 Subject: [PATCH 17/29] adjust jsom schema version + adopt java pom properies test fixtures Signed-off-by: Alex Goodman --- .github/workflows/acceptance-test.yaml | 142 --- .../snapshot/TestJSONDirsPresenter.golden | 81 ++ .../snapshot/TestJSONImgsPresenter.golden | 107 +++ .../stereoscope-fixture-image-simple.golden | Bin 0 -> 16896 bytes schema/json/schema-1.0.4.json | 830 ++++++++++++++++++ ...colon-delimited-with-equals.pom.properties | 5 + .../pom/colon-delimited.pom.properties | 5 + ...quals-delimited-with-colons.pom.properties | 5 + syft/pkg/cataloger/rust/parse_cargo_lock.go | 2 +- 9 files changed, 1034 insertions(+), 143 deletions(-) delete mode 100644 .github/workflows/acceptance-test.yaml create mode 100644 internal/presenter/packages/test-fixtures/snapshot/TestJSONDirsPresenter.golden create mode 100644 internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden create mode 100644 internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden create mode 100644 schema/json/schema-1.0.4.json create mode 100644 syft/pkg/cataloger/java/test-fixtures/pom/colon-delimited-with-equals.pom.properties create mode 100644 syft/pkg/cataloger/java/test-fixtures/pom/colon-delimited.pom.properties create mode 100644 syft/pkg/cataloger/java/test-fixtures/pom/equals-delimited-with-colons.pom.properties diff --git a/.github/workflows/acceptance-test.yaml b/.github/workflows/acceptance-test.yaml deleted file mode 100644 index 2fd79cad7..000000000 --- a/.github/workflows/acceptance-test.yaml +++ /dev/null @@ -1,142 +0,0 @@ -name: "Acceptance" -on: - workflow_dispatch: - push: - # ... only act on pushes to main - branches: - - main - # ... do not act on release tags - tags-ignore: - - v* - -env: - GO_VERSION: "1.14.x" - -jobs: - Build-Snapshot-Artifacts: - # though the release pipeline is running on mac for the signing step, we are skipping the signing step here and - # require a system with docker installed, which ubuntu-20.04 has by default (and mac does not for licensing reasons). - runs-on: ubuntu-20.04 - steps: - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.GO_VERSION }} - - - uses: actions/checkout@v2 - - - name: Restore bootstrap cache - id: cache - uses: actions/cache@v2.1.3 - with: - path: | - ~/go/pkg/mod - ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}-${{ hashFiles('Makefile') }} - restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}- - ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - - name: Bootstrap project dependencies - if: steps.bootstrap-cache.outputs.cache-hit != 'true' - run: make bootstrap - - - name: Build snapshot artifacts - run: make snapshot - - - uses: actions/upload-artifact@v2 - with: - name: artifacts - path: snapshot/**/* - - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,workflow,job,commit,message,author - text: The syft acceptance tests have failed tragically! - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} - if: ${{ failure() }} - - # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline - Acceptance-Linux: - needs: [Build-Snapshot-Artifacts] - # come Nov 30 2020 ubuntu-latest will be ubuntu-20.04, until then it needs to be explicitly referenced due to python 3.7 specific features being used - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: artifacts - path: snapshot - - - name: Run Acceptance Tests (Linux) - run: make acceptance-linux - - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,workflow,job,commit,message,author - text: The syft acceptance tests have failed tragically! - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} - if: ${{ failure() }} - - # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline - Acceptance-Mac: - needs: [Build-Snapshot-Artifacts] - runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: artifacts - path: snapshot - - - name: Run Acceptance Tests (Mac) - run: make acceptance-mac - - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,workflow,job,commit,message,author - text: The syft acceptance tests have failed tragically! - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} - if: ${{ failure() }} - - # Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline - Inline-Compare: - needs: [Build-Snapshot-Artifacts] - # come Nov 30 2020 ubuntu-latest will be ubuntu-20.04, until then it needs to be explicitly referenced due to python 3.7 specific features being used - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v2 - - - name: Fingerprint inline-compare sources - run: make compare-fingerprint - - - name: Restore inline reports cache - id: cache - uses: actions/cache@v2.1.3 - with: - path: ${{ github.workspace }}/test/inline-compare/inline-reports - key: inline-reports-${{ hashFiles('**/inline-compare.fingerprint') }} - - - uses: actions/download-artifact@v2 - with: - name: artifacts - path: snapshot - - - name: Compare Anchore inline-scan results against snapshot build output - run: make compare-snapshot - - - uses: 8398a7/action-slack@v3 - with: - status: ${{ job.status }} - fields: repo,workflow,job,commit,message,author - text: The syft acceptance tests have failed tragically! - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }} - if: ${{ failure() }} diff --git a/internal/presenter/packages/test-fixtures/snapshot/TestJSONDirsPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestJSONDirsPresenter.golden new file mode 100644 index 000000000..b43c0e029 --- /dev/null +++ b/internal/presenter/packages/test-fixtures/snapshot/TestJSONDirsPresenter.golden @@ -0,0 +1,81 @@ +{ + "artifacts": [ + { + "id": "package-1-id", + "name": "package-1", + "version": "1.0.1", + "type": "python", + "foundBy": "the-cataloger-1", + "locations": [ + { + "path": "/some/path/pkg1" + } + ], + "licenses": [ + "MIT" + ], + "language": "python", + "cpes": [ + "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" + ], + "purl": "a-purl-2", + "metadataType": "PythonPackageMetadata", + "metadata": { + "name": "package-1", + "version": "1.0.1", + "license": "", + "author": "", + "authorEmail": "", + "platform": "", + "sitePackagesRootPath": "" + } + }, + { + "id": "package-2-id", + "name": "package-2", + "version": "2.0.1", + "type": "deb", + "foundBy": "the-cataloger-2", + "locations": [ + { + "path": "/some/path/pkg1" + } + ], + "licenses": [], + "language": "", + "cpes": [ + "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" + ], + "purl": "a-purl-2", + "metadataType": "DpkgMetadata", + "metadata": { + "package": "package-2", + "source": "", + "version": "2.0.1", + "sourceVersion": "", + "architecture": "", + "maintainer": "", + "installedSize": 0, + "files": null + } + } + ], + "artifactRelationships": [], + "source": { + "type": "directory", + "target": "/some/path" + }, + "distro": { + "name": "", + "version": "", + "idLike": "" + }, + "descriptor": { + "name": "syft", + "version": "[not provided]" + }, + "schema": { + "version": "1.0.4", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.0.4.json" + } +} diff --git a/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden new file mode 100644 index 000000000..dbb11f32c --- /dev/null +++ b/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden @@ -0,0 +1,107 @@ +{ + "artifacts": [ + { + "id": "package-1-id", + "name": "package-1", + "version": "1.0.1", + "type": "python", + "foundBy": "the-cataloger-1", + "locations": [ + { + "path": "/somefile-1.txt", + "layerID": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b" + } + ], + "licenses": [ + "MIT" + ], + "language": "python", + "cpes": [ + "cpe:2.3:*:some:package:1:*:*:*:*:*:*:*" + ], + "purl": "a-purl-1", + "metadataType": "PythonPackageMetadata", + "metadata": { + "name": "package-1", + "version": "1.0.1", + "license": "", + "author": "", + "authorEmail": "", + "platform": "", + "sitePackagesRootPath": "" + } + }, + { + "id": "package-2-id", + "name": "package-2", + "version": "2.0.1", + "type": "deb", + "foundBy": "the-cataloger-2", + "locations": [ + { + "path": "/somefile-2.txt", + "layerID": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf" + } + ], + "licenses": [], + "language": "", + "cpes": [ + "cpe:2.3:*:some:package:2:*:*:*:*:*:*:*" + ], + "purl": "a-purl-2", + "metadataType": "DpkgMetadata", + "metadata": { + "package": "package-2", + "source": "", + "version": "2.0.1", + "sourceVersion": "", + "architecture": "", + "maintainer": "", + "installedSize": 0, + "files": null + } + } + ], + "artifactRelationships": [], + "source": { + "type": "image", + "target": { + "userInput": "user-image-input", + "imageID": "sha256:92fbdd71302c666029f11ef5ea49caba6e97daa86cb4dce7874377b26c731d65", + "manifestDigest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368", + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "tags": [ + "stereoscope-fixture-image-simple:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ], + "imageSize": 38, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "digest": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b", + "size": 22 + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "digest": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf", + "size": 16 + } + ], + "manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjoxNTg2LCJkaWdlc3QiOiJzaGEyNTY6OTJmYmRkNzEzMDJjNjY2MDI5ZjExZWY1ZWE0OWNhYmE2ZTk3ZGFhODZjYjRkY2U3ODc0Mzc3YjI2YzczMWQ2NSJ9LCJsYXllcnMiOlt7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLCJzaXplIjoyMDQ4LCJkaWdlc3QiOiJzaGEyNTY6ZTE1OGI1N2Q2ZjVhOTZlZjVmZDIyZjJmZTc2YzcwYjViYTZmZjViMjYxOWY5ZDgzMTI1YjJhYWQwNDkyYWM3YiJ9LHsibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1NjpkYTIxMDU2ZTdiZjQzMDhlY2VhMGMwODM2ODQ4YTdmZTkyZjM4ZmRjZjM1YmMwOWVlNmQ5OGU3YWI3YmVlZWJmIn1dfQ==", + "config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJIb3N0bmFtZSI6IiIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpudWxsLCJJbWFnZSI6InNoYTI1Njo3MDRjZGI0ZDViYmNlMDhjNzI1N2I0OTUxMWM5YzBlYTc2N2UwNzdmZDhiOGIzNDUxOGMzNjg3YTdmZjFlNTlkIiwiVm9sdW1lcyI6bnVsbCwiV29ya2luZ0RpciI6IiIsIkVudHJ5cG9pbnQiOm51bGwsIk9uQnVpbGQiOm51bGwsIkxhYmVscyI6bnVsbH0sImNvbnRhaW5lcl9jb25maWciOnsiSG9zdG5hbWUiOiIiLCJEb21haW5uYW1lIjoiIiwiVXNlciI6IiIsIkF0dGFjaFN0ZGluIjpmYWxzZSwiQXR0YWNoU3Rkb3V0IjpmYWxzZSwiQXR0YWNoU3RkZXJyIjpmYWxzZSwiVHR5IjpmYWxzZSwiT3BlblN0ZGluIjpmYWxzZSwiU3RkaW5PbmNlIjpmYWxzZSwiRW52IjpbIlBBVEg9L3Vzci9sb2NhbC9zYmluOi91c3IvbG9jYWwvYmluOi91c3Ivc2JpbjovdXNyL2Jpbjovc2JpbjovYmluIl0sIkNtZCI6WyIvYmluL3NoIiwiLWMiLCIjKG5vcCkgQUREIGZpbGU6ZGYzYjc0NGY1NGE5YjE2YjliOWFlZDQwZTNlOThkOWNhMmI0OWY1YTc3ZDlmYThhOTc2OTBkN2JhZjU4ODgyMCBpbiAvc29tZWZpbGUtMi50eHQgIl0sIkltYWdlIjoic2hhMjU2OjcwNGNkYjRkNWJiY2UwOGM3MjU3YjQ5NTExYzljMGVhNzY3ZTA3N2ZkOGI4YjM0NTE4YzM2ODdhN2ZmMWU1OWQiLCJWb2x1bWVzIjpudWxsLCJXb3JraW5nRGlyIjoiIiwiRW50cnlwb2ludCI6bnVsbCwiT25CdWlsZCI6bnVsbCwiTGFiZWxzIjpudWxsfSwiY3JlYXRlZCI6IjIwMjEtMDMtMTNUMTY6MTU6NTAuMDM2MDAwNloiLCJkb2NrZXJfdmVyc2lvbiI6IjIwLjEwLjIiLCJoaXN0b3J5IjpbeyJjcmVhdGVkIjoiMjAyMS0wMy0xM1QxNjoxNTo0OS44NjA5MDgyWiIsImNyZWF0ZWRfYnkiOiIvYmluL3NoIC1jICMobm9wKSBBREQgZmlsZTphYzMyZGEyM2Q1MWU4MDFmMDJmOTI0MTIzZWQzMDk5MGViM2YwZmVjMWI5ZWQ0ZjBiMDZjMjRlODhiOWMzNjk1IGluIC9zb21lZmlsZS0xLnR4dCAifSx7ImNyZWF0ZWQiOiIyMDIxLTAzLTEzVDE2OjE1OjUwLjAzNjAwMDZaIiwiY3JlYXRlZF9ieSI6Ii9iaW4vc2ggLWMgIyhub3ApIEFERCBmaWxlOmRmM2I3NDRmNTRhOWIxNmI5YjlhZWQ0MGUzZTk4ZDljYTJiNDlmNWE3N2Q5ZmE4YTk3NjkwZDdiYWY1ODg4MjAgaW4gL3NvbWVmaWxlLTIudHh0ICJ9XSwib3MiOiJsaW51eCIsInJvb3RmcyI6eyJ0eXBlIjoibGF5ZXJzIiwiZGlmZl9pZHMiOlsic2hhMjU2OmUxNThiNTdkNmY1YTk2ZWY1ZmQyMmYyZmU3NmM3MGI1YmE2ZmY1YjI2MTlmOWQ4MzEyNWIyYWFkMDQ5MmFjN2IiLCJzaGEyNTY6ZGEyMTA1NmU3YmY0MzA4ZWNlYTBjMDgzNjg0OGE3ZmU5MmYzOGZkY2YzNWJjMDllZTZkOThlN2FiN2JlZWViZiJdfX0=", + "scope": "Squashed" + } + }, + "distro": { + "name": "", + "version": "", + "idLike": "" + }, + "descriptor": { + "name": "syft", + "version": "[not provided]" + }, + "schema": { + "version": "1.0.4", + "url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-1.0.4.json" + } +} diff --git a/internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden b/internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden new file mode 100644 index 0000000000000000000000000000000000000000..24d879f4948af2cdd6b512a7048d61847316ec24 GIT binary patch literal 16896 zcmeHOZExE)5ccQ&3Qzm80kO^Z7X$myH3eFrXofcHfCWXt*F>u=8IoKy2=d=|vYpg% z(YUQ_BV8#3u_#eT@;Oq+d+x+})LL=x5f8{nL!z=&aj6kQl2XqpHVVfe0$2D~rY-BA5KcDNKW8Yd|1GfY7W4 zi!tV7j)sT|uo>c?wqjW{CNDzu7S3XRo{g`vr)Av~W*XpWsBv6Qp~A=VUv;RKcOEs3 zaTl)|pBLFUnn@jwvfFFr9EP%aF;wvA>f&j0d3$~`3&mYIi_%HqpcAY5Pm1^1_$>SL z(dpCQNAtQGO-g4bquS=hc&&U}{CHz=X<3BR?9Ea3cnZ**Wg{q#>I)d;z`?&?el5z` zZ~aHd$NiX3!q`V@C1a5@qb(Lz1Gd346ll=OYiEdMI&veW*U>1WrO?PrYa&-l5!BC% z{-`dep_Miu!{$TNZ(DyhHRmn3^@Sl^jKNepZ<*)Tx`33Egi8?2F?QOaV5E=%Ng2Je zu(f0yD@TQrM#hK(*B*NQx}40Xq0Yv|d@?!8{w}L`d2xQ6uN3v9XsXLunYXiRS>vSm zW1dd{gk|x$v0<`${Q4;KrF#c6;(e&Wt@jdBM4SLZpXi8jh&&hu9-=iOXz7hn!hwtDf>e@GDJ>BW?6nts*q#5O zNNn;ym?Zx9Ftg+;`;6ki}f#eC^K)YwH{H)RE+=GoPK{43K# zB@pnpWWm2KiQ2aop1a{A`vceCR25s|0~!-NJ;k=7_!8c_@mTMZOt zL>380SWwDpU<)piS4ftfQBv@f&Iaui!IoM>ZqxK5?Xeb!t z5!1vtX+i3Ws|6Kc#6^%cGKy4i!61he@Uct*Asb*fKvncEQf?j6AqcNkkj6?ILa;G= zbDem&!x-iRwbC_MvzPo22>L*}K+69(z#QnT|GngYwC+gae-EJkUdsPC1j-M$jn3=8 zyZ;aFKiB_HFi`bGr5|5L)Da;l%%ZE8Ji8 z90YqFuQKPeo#X<5cl0vM%2RW`3}G~(3T5reSs29pLz~|_$lC<+L7h)$kfk1|MUF9| zRdm>4rcH$4gi~6JXdy;KqzMcMCK%+eQ|2HqfoqMeR2;rY Date: Mon, 22 Mar 2021 15:25:04 -0400 Subject: [PATCH 18/29] simplify command alias logic + remove deprecation warning for root command Signed-off-by: Alex Goodman --- README.md | 3 +++ cmd/cmd.go | 38 ++++++---------------------- cmd/packages.go | 2 +- test/cli/root_cmd_test.go | 53 ++++++++++++++++++++++++++++----------- 4 files changed, 50 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 62123c14b..47ba28c61 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ If you encounter an issue, please [let us know using the issue tracker](https:// To generate an SBOM for a Docker or OCI image: ``` syft packages + +# note: this is the same as not providing the "packages" subcommand +syft ``` The above output includes only software that is visible in the container (i.e., the squashed representation of the image). diff --git a/cmd/cmd.go b/cmd/cmd.go index 9e0bda837..ac95e2d0a 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -3,7 +3,6 @@ package cmd import ( "fmt" "os" - "strings" "github.com/spf13/cobra" @@ -33,10 +32,6 @@ func init() { ) } -// provided to disambiguate the root vs packages command, whichever is indicated by the cli args will be set here. -// TODO: when the root alias command is removed, this variable can be removed -var activeCmd *cobra.Command - func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, color.Red.Sprint(err.Error())) @@ -48,30 +43,9 @@ func Execute() { // be done without determining what the primary command that the config options should be bound to since there are // shared concerns (the root-packages alias). func initCmdAliasBindings() { - // TODO: when the root alias command is removed, this function (hack) can be removed - - // map of all commands except for root - commands := make(map[string]*cobra.Command) - for _, c := range rootCmd.Commands() { - name := strings.Split(c.Use, " ")[0] - commands[name] = c - } - - activeCmd = rootCmd - for i, a := range os.Args { - if i == 0 { - // don't consider the bin - continue - } - // check to see if this argument may be a command - if c, exists := commands[a]; exists { - activeCmd = c - } - } - - if activeCmd == rootCmd { - // note: cobra supports command deprecation, however the command name is empty and does not report to stderr - fmt.Fprintln(os.Stderr, color.New(color.Bold, color.Red).Sprintf("The root command is deprecated, please use the 'packages' subcommand")) + activeCmd, _, err := rootCmd.Find(os.Args[1:]) + if err != nil { + panic(err) } if activeCmd == packagesCmd || activeCmd == rootCmd { @@ -81,11 +55,13 @@ func initCmdAliasBindings() { // reading the application configuration, which implies that it must be an initializer (or rewrite the command // initialization structure against typical patterns used with cobra, which is somewhat extreme for a // temporary alias) - if err := bindConfigOptions(activeCmd.Flags()); err != nil { + if err = bindPackagesConfigOptions(activeCmd.Flags()); err != nil { panic(err) } } else { - if err := bindConfigOptions(packagesCmd.Flags()); err != nil { + // even though the root command or packages command is NOT being run, we still need default bindings + // such that application config parsing passes. + if err = bindPackagesConfigOptions(packagesCmd.Flags()); err != nil { panic(err) } } diff --git a/cmd/packages.go b/cmd/packages.go index d0d205919..e19bee44e 100644 --- a/cmd/packages.go +++ b/cmd/packages.go @@ -138,7 +138,7 @@ func setPackageFlags(flags *pflag.FlagSet) { ) } -func bindConfigOptions(flags *pflag.FlagSet) error { +func bindPackagesConfigOptions(flags *pflag.FlagSet) error { ///////// Formatting & Input options ////////////////////////////////////////////// if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil { diff --git a/test/cli/root_cmd_test.go b/test/cli/root_cmd_test.go index 9c58ec299..ec46ed132 100644 --- a/test/cli/root_cmd_test.go +++ b/test/cli/root_cmd_test.go @@ -9,25 +9,50 @@ import ( func TestRootCmdAliasesToPackagesSubcommand(t *testing.T) { request := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") - deprecationWarning := "The root command is deprecated" - _, aliasStdout, aliasStderr := runSyftCommand(t, nil, request) - - if !strings.Contains(aliasStderr, deprecationWarning) { - t.Errorf("missing root-packages alias deprecation warning") + tests := []struct { + name string + env map[string]string + assertions []traitAssertion + }{ + { + name: "go-case", + assertions: []traitAssertion{ + assertTableReport, + assertSuccessfulReturnCode, + }, + }, + { + name: "respond-to-output-binding", + env: map[string]string{ + "SYFT_OUTPUT": "text", + }, + assertions: []traitAssertion{ + assertInOutput("[Image]"), + assertSuccessfulReturnCode, + }, + }, } - _, pkgsStdout, pkgsStderr := runSyftCommand(t, nil, "packages", request) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + aliasCmd, aliasStdout, aliasStderr := runSyftCommand(t, test.env, request) + for _, traitFn := range test.assertions { + traitFn(t, aliasStdout, aliasStderr, aliasCmd.ProcessState.ExitCode()) + } - if strings.Contains(pkgsStderr, deprecationWarning) { - t.Errorf("packages command should not have deprecation warning") - } + pkgCmd, pkgsStdout, pkgsStderr := runSyftCommand(t, test.env, "packages", request) + for _, traitFn := range test.assertions { + traitFn(t, pkgsStdout, pkgsStderr, pkgCmd.ProcessState.ExitCode()) + } - if aliasStdout != pkgsStdout { - t.Errorf("packages and root command should have same report output but do not!") - dmp := diffmatchpatch.New() - diffs := dmp.DiffMain(aliasStdout, pkgsStdout, true) - t.Error(dmp.DiffPrettyText(diffs)) + if aliasStdout != pkgsStdout { + t.Errorf("packages and root command should have same report output but do not!") + dmp := diffmatchpatch.New() + diffs := dmp.DiffMain(aliasStdout, pkgsStdout, true) + t.Error(dmp.DiffPrettyText(diffs)) + } + }) } } From e3b1522394899227e1292f9da57887046567c57d Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 06:58:30 -0400 Subject: [PATCH 19/29] upgrade goreleaser + constrain pipeline tool cache Signed-off-by: Alex Goodman --- .github/workflows/release.yaml | 29 +++++++++++++++++++---------- .goreleaser.yaml | 7 ++----- Makefile | 10 +++++----- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1721d9152..16d2500d1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -103,23 +103,32 @@ jobs: with: fetch-depth: 0 - # We are expecting this cache to have been created during the "Build-Snapshot-Artifacts" job in the "Acceptance" workflow. - - name: Restore bootstrap cache - id: cache + - name: Restore tool cache + id: tool-cache uses: actions/cache@v2.1.3 with: - path: | - ~/go/pkg/mod - ${{ github.workspace }}/.tmp - key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}-${{ hashFiles('Makefile') }} + path: ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }} + + - name: Restore go cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }} restore-keys: | - ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-go-${{ env.GO_VERSION }}- - - name: Bootstrap project dependencies - if: steps.bootstrap-cache.outputs.cache-hit != 'true' + - name: (cache-miss) Bootstrap all project dependencies + if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true' run: make bootstrap + - name: Login to Docker Hub + uses: docker/login-action@v1 + with: + username: ${{ secrets.TOOLBOX_DOCKER_USER }} + password: ${{ secrets.TOOLBOX_DOCKER_PASS }} + - name: Import GPG key id: import_gpg uses: crazy-max/ghaction-import-gpg@v2 diff --git a/.goreleaser.yaml b/.goreleaser.yaml index bd8c7749e..2317d3bbf 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -92,18 +92,15 @@ brews: description: *description dockers: - - - binaries: - - syft - dockerfile: Dockerfile + - dockerfile: Dockerfile image_templates: - "anchore/syft:latest" - "anchore/syft:{{ .Tag }}" - "anchore/syft:v{{ .Major }}" - "anchore/syft:v{{ .Major }}.{{ .Minor }}" - build_flag_templates: - "--build-arg=BUILD_DATE={{.Date}}" - "--build-arg=BUILD_VERSION={{.Version}}" - "--build-arg=VCS_REF={{.FullCommit}}" - "--build-arg=VCS_URL={{.GitURL}}" + use_buildx: true diff --git a/Makefile b/Makefile index 35d4cb09e..fe74cc184 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ COVERAGE_THRESHOLD := 68 # CI cache busting values; change these if you want CI to not use previous stored cache INTEGRATION_CACHE_BUSTER="23493ba738c3d2f" CLI_CACHE_BUSTER="789bacdf" -BOOTSTRAP_CACHE="789bacdf" +BOOTSTRAP_CACHE="c7afb99ad" ## Build variables DISTDIR=./dist @@ -100,10 +100,10 @@ $(TEMPDIR): .PHONY: bootstrap-tools bootstrap-tools: $(TEMPDIR) - [ -f "$(TEMPDIR)/benchstat" ] || GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat - [ -f "$(TEMPDIR)/golangci" ] || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.26.0 - [ -f "$(TEMPDIR)/bouncer" ] || curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.2.0 - [ -f "$(TEMPDIR)/goreleaser" ] || curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh -s -- -b $(TEMPDIR)/ v0.140.0 + GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.26.0 + curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.2.0 + curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh -s -- -b $(TEMPDIR)/ v0.160.0 .PHONY: bootstrap-go bootstrap-go: From 77e4c89a5ad6f8e70ce15d462e6022f889ec545f Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 10:28:57 -0400 Subject: [PATCH 20/29] bump coverage threshold + use ubuntu for snapshot builds Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 2 +- Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index bb0707069..8befc2711 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -240,7 +240,7 @@ jobs: Build-Snapshot-Artifacts: name: "Build snapshot artifacts" - runs-on: macos-latest # We're creating these snapshot builds on macOS to be consistent with our release workflow's build process, which also takes place on macOS (due to code signing requirements). + runs-on: ubuntu-20.04 # run only on push event (internal PRs) or on a pull_request event that is from a fork (external PR) # skip if this is a pull_request event on an internal PR (which is already covered by push events) if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository diff --git a/Makefile b/Makefile index fe74cc184..ed2431803 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ RESET := $(shell tput -T linux sgr0) TITLE := $(BOLD)$(PURPLE) SUCCESS := $(BOLD)$(GREEN) # the quality gate lower threshold for unit test total % coverage (by function statements) -COVERAGE_THRESHOLD := 68 +COVERAGE_THRESHOLD := 70 # CI cache busting values; change these if you want CI to not use previous stored cache INTEGRATION_CACHE_BUSTER="23493ba738c3d2f" CLI_CACHE_BUSTER="789bacdf" From 0e9c1c1d8639bb79e1583cfb8c918e3b2788a057 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 10:29:38 -0400 Subject: [PATCH 21/29] arrange power-user tasks ahead of parsing the source image Signed-off-by: Alex Goodman --- cmd/power_user.go | 13 ++++---- cmd/power_user_tasks.go | 73 ++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/cmd/power_user.go b/cmd/power_user.go index 2a15f5180..962470eba 100644 --- a/cmd/power_user.go +++ b/cmd/power_user.go @@ -72,6 +72,12 @@ func powerUserExecWorker(userInput string) <-chan error { go func() { defer close(errs) + tasks, err := powerUserTasks() + if err != nil { + errs <- err + return + } + checkForApplicationUpdate() src, cleanup, err := source.New(userInput) @@ -90,14 +96,9 @@ func powerUserExecWorker(userInput string) <-chan error { SourceMetadata: src.Metadata, ApplicationConfig: *appConfig, } - tasks, err := powerUserTasks(src) - if err != nil { - errs <- err - return - } for _, task := range tasks { - if err = task(&analysisResults); err != nil { + if err = task(&analysisResults, src); err != nil { errs <- err return } diff --git a/cmd/power_user_tasks.go b/cmd/power_user_tasks.go index 2800202f6..10070e548 100644 --- a/cmd/power_user_tasks.go +++ b/cmd/power_user_tasks.go @@ -7,41 +7,36 @@ import ( "github.com/anchore/syft/syft/source" ) -type powerUserTask func(*poweruser.JSONDocumentConfig) error +type powerUserTask func(*poweruser.JSONDocumentConfig, source.Source) error -func powerUserTasks(src source.Source) ([]powerUserTask, error) { +func powerUserTasks() ([]powerUserTask, error) { var tasks []powerUserTask - var err error - var task powerUserTask - task = catalogPackagesTask(src) - if task != nil { - tasks = append(tasks, task) + generators := []func() (powerUserTask, error){ + catalogPackagesTask, + catalogFileMetadataTask, + catalogFileDigestTask, } - task, err = catalogFileMetadataTask(src) - if err != nil { - return nil, err - } else if task != nil { - tasks = append(tasks, task) - } - - task, err = catalogFileDigestTask(src) - if err != nil { - return nil, err - } else if task != nil { - tasks = append(tasks, task) + for _, generator := range generators { + task, err := generator() + if err != nil { + return nil, err + } + if task != nil { + tasks = append(tasks, task) + } } return tasks, nil } -func catalogPackagesTask(src source.Source) powerUserTask { +func catalogPackagesTask() (powerUserTask, error) { if !appConfig.Package.Cataloger.Enabled { - return nil + return nil, nil } - task := func(results *poweruser.JSONDocumentConfig) error { + task := func(results *poweruser.JSONDocumentConfig, src source.Source) error { packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt) if err != nil { return err @@ -53,21 +48,23 @@ func catalogPackagesTask(src source.Source) powerUserTask { return nil } - return task + return task, nil } -func catalogFileMetadataTask(src source.Source) (powerUserTask, error) { +func catalogFileMetadataTask() (powerUserTask, error) { if !appConfig.FileMetadata.Cataloger.Enabled { return nil, nil } - resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) - if err != nil { - return nil, err - } + metadataCataloger := file.NewMetadataCataloger() - task := func(results *poweruser.JSONDocumentConfig) error { - result, err := file.NewMetadataCataloger(resolver).Catalog() + task := func(results *poweruser.JSONDocumentConfig, src source.Source) error { + resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) + if err != nil { + return err + } + + result, err := metadataCataloger.Catalog(resolver) if err != nil { return err } @@ -78,23 +75,23 @@ func catalogFileMetadataTask(src source.Source) (powerUserTask, error) { return task, nil } -func catalogFileDigestTask(src source.Source) (powerUserTask, error) { +func catalogFileDigestTask() (powerUserTask, error) { if !appConfig.FileMetadata.Cataloger.Enabled { return nil, nil } - resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) + digestsCataloger, err := file.NewDigestsCataloger(appConfig.FileMetadata.Digests) if err != nil { return nil, err } - cataloger, err := file.NewDigestsCataloger(resolver, appConfig.FileMetadata.Digests) - if err != nil { - return nil, err - } + task := func(results *poweruser.JSONDocumentConfig, src source.Source) error { + resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt) + if err != nil { + return err + } - task := func(results *poweruser.JSONDocumentConfig) error { - result, err := cataloger.Catalog() + result, err := digestsCataloger.Catalog(resolver) if err != nil { return err } From 40199096e9d3c670057fd098ee26d7d11f983b66 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 11:00:36 -0400 Subject: [PATCH 22/29] stabilize json file metadata presenter order Signed-off-by: Alex Goodman --- internal/presenter/poweruser/json_file_metadata.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/presenter/poweruser/json_file_metadata.go b/internal/presenter/poweruser/json_file_metadata.go index 368525a91..1b0a8d08e 100644 --- a/internal/presenter/poweruser/json_file_metadata.go +++ b/internal/presenter/poweruser/json_file_metadata.go @@ -2,6 +2,7 @@ package poweruser import ( "fmt" + "sort" "strconv" "github.com/anchore/syft/syft/file" @@ -46,5 +47,13 @@ func NewJSONFileMetadata(data map[source.Location]source.FileMetadata, digests m }, }) } + + // sort by real path then virtual path to ensure the result is stable across multiple runs + sort.SliceStable(results, func(i, j int) bool { + if results[i].Location.RealPath != results[j].Location.RealPath { + return results[i].Location.VirtualPath < results[j].Location.VirtualPath + } + return false + }) return results, nil } From d420368ba9db3dda5d1f41b0348048ef95ff9fd3 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 11:00:59 -0400 Subject: [PATCH 23/29] add tests around new file metadata cataloger Signed-off-by: Alex Goodman --- go.mod | 3 +- go.sum | 4 +- syft/file/digest_cataloger.go | 18 ++- syft/file/digest_cataloger_test.go | 98 ++++++++++++++ syft/file/metadata_cataloger.go | 13 +- syft/file/metadata_cataloger_test.go | 125 ++++++++++++++++++ syft/file/test-fixtures/a-path.txt | 1 + syft/file/test-fixtures/another-path.txt | 1 + .../image-file-type-mix/Dockerfile | 10 ++ .../image-file-type-mix/file-1.txt | 1 + syft/file/test-fixtures/last/path.txt | 1 + syft/source/all_layers_resolver.go | 2 +- syft/source/file_metadata_test.go | 122 +++++++++++++++++ syft/source/image_squash_resolver.go | 2 +- syft/source/mock_resolver.go | 19 ++- .../image-file-type-mix/Dockerfile | 10 ++ .../image-file-type-mix/file-1.txt | 1 + 17 files changed, 407 insertions(+), 24 deletions(-) create mode 100644 syft/file/digest_cataloger_test.go create mode 100644 syft/file/metadata_cataloger_test.go create mode 100644 syft/file/test-fixtures/a-path.txt create mode 100644 syft/file/test-fixtures/another-path.txt create mode 100644 syft/file/test-fixtures/image-file-type-mix/Dockerfile create mode 100644 syft/file/test-fixtures/image-file-type-mix/file-1.txt create mode 100644 syft/file/test-fixtures/last/path.txt create mode 100644 syft/source/file_metadata_test.go create mode 100644 syft/source/test-fixtures/image-file-type-mix/Dockerfile create mode 100644 syft/source/test-fixtures/image-file-type-mix/file-1.txt diff --git a/go.mod b/go.mod index f2138d29d..95354b280 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/anchore/go-rpmdb v0.0.0-20201106153645-0043963c2e12 github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b - github.com/anchore/stereoscope v0.0.0-20210317203852-f77bbcbede40 + github.com/anchore/stereoscope v0.0.0-20210323145922-1f45cd8849b4 github.com/antihax/optional v1.0.0 github.com/bmatcuk/doublestar/v2 v2.0.4 github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible @@ -34,6 +34,7 @@ require ( github.com/spf13/cobra v1.0.1-0.20200909172742-8a63648dd905 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 + github.com/stretchr/testify v1.6.0 github.com/wagoodman/go-partybus v0.0.0-20200526224238-eb215533f07d github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240 github.com/wagoodman/jotframe v0.0.0-20200730190914-3517092dd163 diff --git a/go.sum b/go.sum index ba334d43d..eecc235eb 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,8 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= 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-20210317203852-f77bbcbede40 h1:k3/JigkYl7NjMad9eDBBcsg9qiXJFreW6rKNgE0aMUI= -github.com/anchore/stereoscope v0.0.0-20210317203852-f77bbcbede40/go.mod h1:T/OUHXgngXFlo2vknQsDx+n/jErCLPt5o0H1ZXFBpig= +github.com/anchore/stereoscope v0.0.0-20210323145922-1f45cd8849b4 h1:Uuvne+/Mgeyu3fR1JCxiFUQQo2Gp5vXTInum3GbhbwM= +github.com/anchore/stereoscope v0.0.0-20210323145922-1f45cd8849b4/go.mod h1:G7tFR0iI9r6AvibmXKA9v010pRS1IIJgd0t6fOMDxCw= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= diff --git a/syft/file/digest_cataloger.go b/syft/file/digest_cataloger.go index 37a8ff1b9..10a5bba42 100644 --- a/syft/file/digest_cataloger.go +++ b/syft/file/digest_cataloger.go @@ -13,8 +13,7 @@ import ( var supportedHashAlgorithms = make(map[string]crypto.Hash) type DigestsCataloger struct { - resolver source.FileResolver - hashes []crypto.Hash + hashes []crypto.Hash } func init() { @@ -27,7 +26,7 @@ func init() { } } -func NewDigestsCataloger(resolver source.FileResolver, hashAlgorithms []string) (*DigestsCataloger, error) { +func NewDigestsCataloger(hashAlgorithms []string) (*DigestsCataloger, error) { var hashes []crypto.Hash for _, hashStr := range hashAlgorithms { name := cleanAlgorithmName(hashStr) @@ -39,15 +38,14 @@ func NewDigestsCataloger(resolver source.FileResolver, hashAlgorithms []string) } return &DigestsCataloger{ - resolver: resolver, - hashes: hashes, + hashes: hashes, }, nil } -func (i *DigestsCataloger) Catalog() (map[source.Location][]Digest, error) { +func (i *DigestsCataloger) Catalog(resolver source.FileResolver) (map[source.Location][]Digest, error) { results := make(map[source.Location][]Digest) - for location := range i.resolver.AllLocations() { - result, err := i.catalogLocation(location) + for location := range resolver.AllLocations() { + result, err := i.catalogLocation(resolver, location) if err != nil { return nil, err } @@ -56,8 +54,8 @@ func (i *DigestsCataloger) Catalog() (map[source.Location][]Digest, error) { return results, nil } -func (i *DigestsCataloger) catalogLocation(location source.Location) ([]Digest, error) { - contentReader, err := i.resolver.FileContentsByLocation(location) +func (i *DigestsCataloger) catalogLocation(resolver source.FileResolver, location source.Location) ([]Digest, error) { + contentReader, err := resolver.FileContentsByLocation(location) if err != nil { return nil, err } diff --git a/syft/file/digest_cataloger_test.go b/syft/file/digest_cataloger_test.go new file mode 100644 index 000000000..ad21f9184 --- /dev/null +++ b/syft/file/digest_cataloger_test.go @@ -0,0 +1,98 @@ +package file + +import ( + "crypto" + "fmt" + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/anchore/syft/syft/source" +) + +func testDigests(t testing.TB, files []string, hashes ...crypto.Hash) map[source.Location][]Digest { + digests := make(map[source.Location][]Digest) + + for _, f := range files { + fh, err := os.Open(f) + if err != nil { + t.Fatalf("could not open %q : %+v", f, err) + } + b, err := ioutil.ReadAll(fh) + if err != nil { + t.Fatalf("could not read %q : %+v", f, err) + } + + for _, hash := range hashes { + h := hash.New() + h.Write(b) + digests[source.NewLocation(f)] = append(digests[source.NewLocation(f)], Digest{ + Algorithm: cleanAlgorithmName(hash.String()), + Value: fmt.Sprintf("%x", h.Sum(nil)), + }) + } + } + + return digests +} + +func TestDigestsCataloger(t *testing.T) { + files := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"} + + tests := []struct { + name string + algorithms []string + expected map[source.Location][]Digest + constructorErr bool + catalogErr bool + }{ + { + name: "bad algorithm", + algorithms: []string{"sha-nothing"}, + constructorErr: true, + }, + { + name: "unsupported algorithm", + algorithms: []string{"sha512"}, + constructorErr: true, + }, + { + name: "md5-sha1-sha256", + algorithms: []string{"md5"}, + expected: testDigests(t, files, crypto.MD5), + }, + { + name: "md5-sha1-sha256", + algorithms: []string{"md5", "sha1", "sha256"}, + expected: testDigests(t, files, crypto.MD5, crypto.SHA1, crypto.SHA256), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + c, err := NewDigestsCataloger(test.algorithms) + if err != nil && !test.constructorErr { + t.Fatalf("could not create cataloger (but should have been able to): %+v", err) + } else if err == nil && test.constructorErr { + t.Fatalf("expected constructor error but did not get one") + } else if test.constructorErr && err != nil { + return + } + + resolver := source.NewMockResolverForPaths(files...) + actual, err := c.Catalog(resolver) + if err != nil && !test.catalogErr { + t.Fatalf("could not catalog (but should have been able to): %+v", err) + } else if err == nil && test.catalogErr { + t.Fatalf("expected catalog error but did not get one") + } else if test.catalogErr && err != nil { + return + } + + assert.Equal(t, actual, test.expected, "mismatched digests") + + }) + } +} diff --git a/syft/file/metadata_cataloger.go b/syft/file/metadata_cataloger.go index 8f0565902..7ffd41168 100644 --- a/syft/file/metadata_cataloger.go +++ b/syft/file/metadata_cataloger.go @@ -5,19 +5,16 @@ import ( ) type MetadataCataloger struct { - resolver source.FileResolver } -func NewMetadataCataloger(resolver source.FileResolver) *MetadataCataloger { - return &MetadataCataloger{ - resolver: resolver, - } +func NewMetadataCataloger() *MetadataCataloger { + return &MetadataCataloger{} } -func (i *MetadataCataloger) Catalog() (map[source.Location]source.FileMetadata, error) { +func (i *MetadataCataloger) Catalog(resolver source.FileResolver) (map[source.Location]source.FileMetadata, error) { results := make(map[source.Location]source.FileMetadata) - for location := range i.resolver.AllLocations() { - metadata, err := i.resolver.FileMetadataByLocation(location) + for location := range resolver.AllLocations() { + metadata, err := resolver.FileMetadataByLocation(location) if err != nil { return nil, err } diff --git a/syft/file/metadata_cataloger_test.go b/syft/file/metadata_cataloger_test.go new file mode 100644 index 000000000..91c89e85e --- /dev/null +++ b/syft/file/metadata_cataloger_test.go @@ -0,0 +1,125 @@ +package file + +import ( + "os" + "testing" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/anchore/syft/syft/source" + "github.com/stretchr/testify/assert" +) + +func TestFileMetadataFetch(t *testing.T) { + img := imagetest.GetFixtureImage(t, "docker-archive", "image-file-type-mix") + + c := NewMetadataCataloger() + + src, err := source.NewFromImage(img, "---") + if err != nil { + t.Fatalf("could not create source: %+v", err) + } + + resolver, err := src.FileResolver(source.SquashedScope) + if err != nil { + t.Fatalf("could not create resolver: %+v", err) + } + + actual, err := c.Catalog(resolver) + if err != nil { + t.Fatalf("could not catalog: %+v", err) + } + + tests := []struct { + path string + exists bool + expected source.FileMetadata + err bool + }{ + { + path: "/file-1.txt", + exists: true, + expected: source.FileMetadata{ + Mode: 0644, + Type: "regularFile", + UserID: 1, + GroupID: 2, + }, + }, + { + path: "/hardlink-1", + exists: true, + expected: source.FileMetadata{ + Mode: 0644, + Type: "hardLink", + UserID: 1, + GroupID: 2, + }, + }, + { + path: "/symlink-1", + exists: true, + expected: source.FileMetadata{ + Mode: 0777 | os.ModeSymlink, + Type: "symbolicLink", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/char-device-1", + exists: true, + expected: source.FileMetadata{ + Mode: 0644 | os.ModeDevice | os.ModeCharDevice, + Type: "characterDevice", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/block-device-1", + exists: true, + expected: source.FileMetadata{ + Mode: 0644 | os.ModeDevice, + Type: "blockDevice", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/fifo-1", + exists: true, + expected: source.FileMetadata{ + Mode: 0644 | os.ModeNamedPipe, + Type: "fifoNode", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/bin", + exists: true, + expected: source.FileMetadata{ + Mode: 0755 | os.ModeDir, + Type: "directory", + UserID: 0, + GroupID: 0, + }, + }, + } + + for _, test := range tests { + t.Run(test.path, func(t *testing.T) { + _, ref, err := img.SquashedTree().File(file.Path(test.path)) + if err != nil { + t.Fatalf("unable to get file: %+v", err) + } + + l := source.NewLocationFromImage(test.path, *ref, img) + + assert.Equal(t, actual[l], test.expected, "mismatched metadata") + + }) + } + +} diff --git a/syft/file/test-fixtures/a-path.txt b/syft/file/test-fixtures/a-path.txt new file mode 100644 index 000000000..67e954034 --- /dev/null +++ b/syft/file/test-fixtures/a-path.txt @@ -0,0 +1 @@ +test-fixtures/a-path.txt file contents! \ No newline at end of file diff --git a/syft/file/test-fixtures/another-path.txt b/syft/file/test-fixtures/another-path.txt new file mode 100644 index 000000000..0d654f8fe --- /dev/null +++ b/syft/file/test-fixtures/another-path.txt @@ -0,0 +1 @@ +test-fixtures/another-path.txt file contents! \ No newline at end of file diff --git a/syft/file/test-fixtures/image-file-type-mix/Dockerfile b/syft/file/test-fixtures/image-file-type-mix/Dockerfile new file mode 100644 index 000000000..218e369d0 --- /dev/null +++ b/syft/file/test-fixtures/image-file-type-mix/Dockerfile @@ -0,0 +1,10 @@ +FROM busybox:latest + +ADD file-1.txt . +RUN chmod 644 file-1.txt +RUN chown 1:2 file-1.txt +RUN ln -s file-1.txt symlink-1 +RUN ln file-1.txt hardlink-1 +RUN mknod char-device-1 c 89 1 +RUN mknod block-device-1 b 0 1 +RUN mknod fifo-1 p \ No newline at end of file diff --git a/syft/file/test-fixtures/image-file-type-mix/file-1.txt b/syft/file/test-fixtures/image-file-type-mix/file-1.txt new file mode 100644 index 000000000..d86db8155 --- /dev/null +++ b/syft/file/test-fixtures/image-file-type-mix/file-1.txt @@ -0,0 +1 @@ +file 1! \ No newline at end of file diff --git a/syft/file/test-fixtures/last/path.txt b/syft/file/test-fixtures/last/path.txt new file mode 100644 index 000000000..3d4a165ab --- /dev/null +++ b/syft/file/test-fixtures/last/path.txt @@ -0,0 +1 @@ +test-fixtures/last/path.txt file contents! \ No newline at end of file diff --git a/syft/source/all_layers_resolver.go b/syft/source/all_layers_resolver.go index 6437fb4bc..b446eccbf 100644 --- a/syft/source/all_layers_resolver.go +++ b/syft/source/all_layers_resolver.go @@ -194,7 +194,7 @@ func (r *allLayersResolver) AllLocations() <-chan Location { defer close(results) for _, layerIdx := range r.layers { tree := r.img.Layers[layerIdx].Tree - for _, ref := range tree.AllFiles() { + for _, ref := range tree.AllFiles(file.AllTypes...) { results <- NewLocationFromImage(string(ref.RealPath), ref, r.img) } } diff --git a/syft/source/file_metadata_test.go b/syft/source/file_metadata_test.go new file mode 100644 index 000000000..4092e4374 --- /dev/null +++ b/syft/source/file_metadata_test.go @@ -0,0 +1,122 @@ +package source + +import ( + "os" + "testing" + + "github.com/anchore/stereoscope/pkg/file" + "github.com/anchore/stereoscope/pkg/imagetest" + "github.com/stretchr/testify/assert" +) + +func TestFileMetadataFetch(t *testing.T) { + img := imagetest.GetFixtureImage(t, "docker-archive", "image-file-type-mix") + + tests := []struct { + path string + exists bool + expected FileMetadata + err bool + }{ + { + path: "/file-1.txt", + exists: true, + expected: FileMetadata{ + Mode: 0644, + Type: "regularFile", + UserID: 1, + GroupID: 2, + }, + }, + { + path: "/hardlink-1", + exists: true, + expected: FileMetadata{ + Mode: 0644, + Type: "hardLink", + UserID: 1, + GroupID: 2, + }, + }, + { + path: "/symlink-1", + exists: true, + expected: FileMetadata{ + Mode: 0777 | os.ModeSymlink, + Type: "symbolicLink", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/char-device-1", + exists: true, + expected: FileMetadata{ + Mode: 0644 | os.ModeDevice | os.ModeCharDevice, + Type: "characterDevice", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/block-device-1", + exists: true, + expected: FileMetadata{ + Mode: 0644 | os.ModeDevice, + Type: "blockDevice", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/fifo-1", + exists: true, + expected: FileMetadata{ + Mode: 0644 | os.ModeNamedPipe, + Type: "fifoNode", + UserID: 0, + GroupID: 0, + }, + }, + { + path: "/bin", + exists: true, + expected: FileMetadata{ + Mode: 0755 | os.ModeDir, + Type: "directory", + UserID: 0, + GroupID: 0, + }, + }, + } + + for _, test := range tests { + t.Run(test.path, func(t *testing.T) { + exists, ref, err := img.SquashedTree().File(file.Path(test.path)) + if err != nil { + t.Fatalf("unable to get file: %+v", err) + } + + if exists && !test.exists { + t.Fatalf("file=%q exists but shouldn't", test.path) + } else if !exists && test.exists { + t.Fatalf("file=%q does not exist but should", test.path) + } else if !exists && !test.exists { + return + } + + actual, err := fileMetadataByLocation(img, NewLocationFromImage(test.path, *ref, img)) + if err != nil && !test.err { + t.Fatalf("could not fetch (but should have been able to): %+v", err) + } else if err == nil && test.err { + t.Fatalf("expected fetch error but did not get one") + } else if test.err && err != nil { + return + } + + assert.Equal(t, test.expected, actual, "file metadata mismatch") + + }) + } + +} diff --git a/syft/source/image_squash_resolver.go b/syft/source/image_squash_resolver.go index 3500a80a2..de51edf11 100644 --- a/syft/source/image_squash_resolver.go +++ b/syft/source/image_squash_resolver.go @@ -144,7 +144,7 @@ func (r *imageSquashResolver) AllLocations() <-chan Location { results := make(chan Location) go func() { defer close(results) - for _, ref := range r.img.SquashedTree().AllFiles() { + for _, ref := range r.img.SquashedTree().AllFiles(file.AllTypes...) { results <- NewLocationFromImage(string(ref.RealPath), ref, r.img) } }() diff --git a/syft/source/mock_resolver.go b/syft/source/mock_resolver.go index 31d129449..b574ccd14 100644 --- a/syft/source/mock_resolver.go +++ b/syft/source/mock_resolver.go @@ -15,6 +15,7 @@ var _ FileResolver = (*MockResolver)(nil) // paths, which are typically paths to test fixtures. type MockResolver struct { Locations []Location + Metadata map[Location]FileMetadata } // NewMockResolverForPaths creates a new MockResolver, where the only resolvable @@ -28,6 +29,15 @@ func NewMockResolverForPaths(paths ...string) *MockResolver { return &MockResolver{Locations: locations} } +func NewMockResolverForPathsWithMetadata(metadata map[Location]FileMetadata) *MockResolver { + var locations []Location + for p := range metadata { + locations = append(locations, p) + } + + return &MockResolver{Locations: locations, Metadata: metadata} +} + // HasPath indicates if the given path exists in the underlying source. func (r MockResolver) HasPath(path string) bool { for _, l := range r.Locations { @@ -98,7 +108,14 @@ func (r MockResolver) RelativeFileByPath(_ Location, path string) *Location { } func (r MockResolver) AllLocations() <-chan Location { - panic("not implemented") + results := make(chan Location) + go func() { + defer close(results) + for _, l := range r.Locations { + results <- l + } + }() + return results } func (r MockResolver) FileMetadataByLocation(Location) (FileMetadata, error) { diff --git a/syft/source/test-fixtures/image-file-type-mix/Dockerfile b/syft/source/test-fixtures/image-file-type-mix/Dockerfile new file mode 100644 index 000000000..218e369d0 --- /dev/null +++ b/syft/source/test-fixtures/image-file-type-mix/Dockerfile @@ -0,0 +1,10 @@ +FROM busybox:latest + +ADD file-1.txt . +RUN chmod 644 file-1.txt +RUN chown 1:2 file-1.txt +RUN ln -s file-1.txt symlink-1 +RUN ln file-1.txt hardlink-1 +RUN mknod char-device-1 c 89 1 +RUN mknod block-device-1 b 0 1 +RUN mknod fifo-1 p \ No newline at end of file diff --git a/syft/source/test-fixtures/image-file-type-mix/file-1.txt b/syft/source/test-fixtures/image-file-type-mix/file-1.txt new file mode 100644 index 000000000..d86db8155 --- /dev/null +++ b/syft/source/test-fixtures/image-file-type-mix/file-1.txt @@ -0,0 +1 @@ +file 1! \ No newline at end of file From 929b78efbfd7ec4d7e22c2eb12f1a5e3c972f7c3 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 12:56:00 -0400 Subject: [PATCH 24/29] remove prealloc nolint rule in catalogers Signed-off-by: Alex Goodman --- internal/presenter/packages/table_presenter.go | 1 - syft/pkg/cataloger/python/package_cataloger.go | 1 - syft/pkg/cataloger/ruby/parse_gemspec.go | 1 - 3 files changed, 3 deletions(-) diff --git a/internal/presenter/packages/table_presenter.go b/internal/presenter/packages/table_presenter.go index c3313996e..aefaa7286 100644 --- a/internal/presenter/packages/table_presenter.go +++ b/internal/presenter/packages/table_presenter.go @@ -73,7 +73,6 @@ func (pres *TablePresenter) Present(output io.Writer) error { func removeDuplicateRows(items [][]string) [][]string { seen := map[string][]string{} - // nolint:prealloc var result [][]string for _, v := range items { diff --git a/syft/pkg/cataloger/python/package_cataloger.go b/syft/pkg/cataloger/python/package_cataloger.go index 64540ad7b..980c4b699 100644 --- a/syft/pkg/cataloger/python/package_cataloger.go +++ b/syft/pkg/cataloger/python/package_cataloger.go @@ -30,7 +30,6 @@ func (c *PackageCataloger) Name() string { // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing python egg and wheel installations. func (c *PackageCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, error) { - // nolint:prealloc var fileMatches []source.Location for _, glob := range []string{eggMetadataGlob, wheelMetadataGlob, eggFileMetadataGlob} { diff --git a/syft/pkg/cataloger/ruby/parse_gemspec.go b/syft/pkg/cataloger/ruby/parse_gemspec.go index d2fd0ba60..fc99f6710 100644 --- a/syft/pkg/cataloger/ruby/parse_gemspec.go +++ b/syft/pkg/cataloger/ruby/parse_gemspec.go @@ -53,7 +53,6 @@ var postProcessors = map[string]postProcessor{ } func processList(s string) []string { - // nolint:prealloc var results []string for _, item := range strings.Split(s, ",") { results = append(results, strings.Trim(item, "\" ")) From 68c4bf8bbe3d8556cfec4849b5b9d14cdead7b34 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 13:00:25 -0400 Subject: [PATCH 25/29] update documentation to reflect root vs packages subcommand Signed-off-by: Alex Goodman --- Makefile | 2 +- README.md | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ed2431803..ce2cd9843 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ all: clean static-analysis test ## Run all linux-based checks (linting, license @printf '$(SUCCESS)All checks pass!$(RESET)\n' .PHONY: test -test: unit validate-cyclonedx-schema integration benchmark acceptance-linux cli ## Run all tests (currently unit, integration, linux acceptance, and mac cli tests) +test: unit validate-cyclonedx-schema integration benchmark acceptance-linux cli ## Run all tests (currently unit, integration, linux acceptance, and cli tests) .PHONY: help help: diff --git a/README.md b/README.md index 47ba28c61..a16433c2d 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,14 @@ If you encounter an issue, please [let us know using the issue tracker](https:// To generate an SBOM for a Docker or OCI image: ``` -syft packages - -# note: this is the same as not providing the "packages" subcommand syft ``` +**Note**: This is equivalent to specifying the `packages` subcommand: +``` +syft packages +``` + The above output includes only software that is visible in the container (i.e., the squashed representation of the image). To include software from all image layers in the SBOM, regardless of its presence in the final image, provide `--scope all-layers`: From 12f419111ee5dcfc688527d38cae82bf7681df07 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 13:04:13 -0400 Subject: [PATCH 26/29] remove docker layer cache from validation pipeline Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 16 ---------------- Makefile | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 8befc2711..83ed6f1c5 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -63,10 +63,6 @@ jobs: - uses: actions/checkout@v2 - - name: Restore docker cache - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true - - name: Restore tool cache id: tool-cache uses: actions/cache@v2.1.3 @@ -122,10 +118,6 @@ jobs: - uses: actions/checkout@v2 - - name: Restore docker cache - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true - - name: Restore tool cache id: tool-cache uses: actions/cache@v2.1.3 @@ -177,10 +169,6 @@ jobs: - uses: actions/checkout@v2 - - name: Restore docker cache - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true - - name: Restore tool cache id: tool-cache uses: actions/cache@v2.1.3 @@ -328,10 +316,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Restore docker cache - uses: satackey/action-docker-layer-caching@v0.0.11 - continue-on-error: true - - name: Restore go cache id: go-cache uses: actions/cache@v2.1.3 diff --git a/Makefile b/Makefile index ce2cd9843..6f4632476 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ SUCCESS := $(BOLD)$(GREEN) # the quality gate lower threshold for unit test total % coverage (by function statements) COVERAGE_THRESHOLD := 70 # CI cache busting values; change these if you want CI to not use previous stored cache -INTEGRATION_CACHE_BUSTER="23493ba738c3d2f" +INTEGRATION_CACHE_BUSTER="88738d2f" CLI_CACHE_BUSTER="789bacdf" BOOTSTRAP_CACHE="c7afb99ad" From 3ef30f99bea3717744477d64a75a9b0f5bf73a06 Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 14:31:59 -0400 Subject: [PATCH 27/29] pull in stereoscope cache fix + add test cache makefile target helpers Signed-off-by: Alex Goodman --- Makefile | 31 ++- go.mod | 2 +- go.sum | 4 +- .../snapshot/TestJSONImgsPresenter.golden | 16 +- .../stereoscope-fixture-image-simple.golden | Bin 16896 -> 16896 bytes ...scope-fixture-packages-image-simple.golden | Bin 0 -> 16896 bytes syft/presenter/json/package.go | 181 ------------------ 7 files changed, 36 insertions(+), 198 deletions(-) create mode 100644 internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-packages-image-simple.golden delete mode 100644 syft/presenter/json/package.go diff --git a/Makefile b/Makefile index 6f4632476..fa3c5879e 100644 --- a/Makefile +++ b/Makefile @@ -147,7 +147,7 @@ validate-cyclonedx-schema: .PHONY: unit unit: $(RESULTSDIR) fixtures ## Run unit tests (with coverage) $(call title,Running unit tests) - go test -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/syft/test) + go test -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/syft/test) @go tool cover -func $(COVER_REPORT) | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > $(COVER_TOTAL) @echo "Coverage: $$(cat $(COVER_TOTAL))" @if [ $$(echo "$$(cat $(COVER_TOTAL)) >= $(COVERAGE_THRESHOLD)" | bc -l) -ne 1 ]; then echo "$(RED)$(BOLD)Failed coverage quality gate (> $(COVERAGE_THRESHOLD)%)$(RESET)" && false; fi @@ -189,10 +189,6 @@ fixtures: generate-json-schema: ## Generate a new json schema cd schema/json && go run generate.go -.PHONY: clear-test-cache -clear-test-cache: ## Delete all test cache (built docker image tars) - find . -type f -wholename "**/test-fixtures/cache/*.tar" -delete - .PHONY: build build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages @@ -313,7 +309,7 @@ release: clean-dist changelog-release ## Build and publish final binaries and pa .PHONY: clean -clean: clean-dist clean-snapshot ## Remove previous builds and result reports +clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache rm -rf $(RESULTSDIR)/* .PHONY: clean-snapshot @@ -323,3 +319,26 @@ clean-snapshot: .PHONY: clean-dist clean-dist: rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml + +clean-test-image-cache: clean-test-image-tar-cache clean-test-image-docker-cache + +.PHONY: clear-test-image-tar-cache +clean-test-image-tar-cache: ## Delete all test cache (built docker image tars) + find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete + +.PHONY: clear-test-image-docker-cache +clean-test-image-docker-cache: ## Purge all test docker images + docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs docker rmi --force + +.PHONY: show-test-image-cache +show-test-image-cache: ## Show all docker and image tar cache + $(call title,Docker daemon cache) + @docker images --format '{{.ID}} {{.Repository}}:{{.Tag}}' | grep stereoscope-fixture- | sort + + $(call title,Tar cache) + @find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" | sort + +.PHONY: show-test-snapshots +show-test-snapshots: ## Show all test snapshots + $(call title,Test snapshots) + @find . -type f -wholename "**/test-fixtures/snapshot/*" | sort \ No newline at end of file diff --git a/go.mod b/go.mod index 95354b280..5a9ded037 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/anchore/go-rpmdb v0.0.0-20201106153645-0043963c2e12 github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b - github.com/anchore/stereoscope v0.0.0-20210323145922-1f45cd8849b4 + github.com/anchore/stereoscope v0.0.0-20210323182342-47b72675ff65 github.com/antihax/optional v1.0.0 github.com/bmatcuk/doublestar/v2 v2.0.4 github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible diff --git a/go.sum b/go.sum index eecc235eb..3ec96d0c7 100644 --- a/go.sum +++ b/go.sum @@ -115,8 +115,8 @@ github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0v github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= 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-20210323145922-1f45cd8849b4 h1:Uuvne+/Mgeyu3fR1JCxiFUQQo2Gp5vXTInum3GbhbwM= -github.com/anchore/stereoscope v0.0.0-20210323145922-1f45cd8849b4/go.mod h1:G7tFR0iI9r6AvibmXKA9v010pRS1IIJgd0t6fOMDxCw= +github.com/anchore/stereoscope v0.0.0-20210323182342-47b72675ff65 h1:r3tiir6UCgj/YeTqy4s2bfhZ9SuJYNlXx1Z9e/eLrbI= +github.com/anchore/stereoscope v0.0.0-20210323182342-47b72675ff65/go.mod h1:G7tFR0iI9r6AvibmXKA9v010pRS1IIJgd0t6fOMDxCw= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= diff --git a/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden b/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden index dbb11f32c..0c27b16d9 100644 --- a/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden +++ b/internal/presenter/packages/test-fixtures/snapshot/TestJSONImgsPresenter.golden @@ -9,7 +9,7 @@ "locations": [ { "path": "/somefile-1.txt", - "layerID": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b" + "layerID": "sha256:3de16c5b8659a2e8d888b8ded8427be7a5686a3c8c4e4dd30de20f362827285b" } ], "licenses": [ @@ -40,7 +40,7 @@ "locations": [ { "path": "/somefile-2.txt", - "layerID": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf" + "layerID": "sha256:366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703" } ], "licenses": [], @@ -67,27 +67,27 @@ "type": "image", "target": { "userInput": "user-image-input", - "imageID": "sha256:92fbdd71302c666029f11ef5ea49caba6e97daa86cb4dce7874377b26c731d65", + "imageID": "sha256:c2b46b4eb06296933b7cf0722683964e9ecbd93265b9ef6ae9642e3952afbba0", "manifestDigest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368", "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "tags": [ - "stereoscope-fixture-image-simple:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + "stereoscope-fixture-image-simple:85066c51088bdd274f7a89e99e00490f666c49e72ffc955707cd6e18f0e22c5b" ], "imageSize": 38, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b", + "digest": "sha256:3de16c5b8659a2e8d888b8ded8427be7a5686a3c8c4e4dd30de20f362827285b", "size": 22 }, { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "digest": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf", + "digest": "sha256:366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703", "size": 16 } ], - "manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjoxNTg2LCJkaWdlc3QiOiJzaGEyNTY6OTJmYmRkNzEzMDJjNjY2MDI5ZjExZWY1ZWE0OWNhYmE2ZTk3ZGFhODZjYjRkY2U3ODc0Mzc3YjI2YzczMWQ2NSJ9LCJsYXllcnMiOlt7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLCJzaXplIjoyMDQ4LCJkaWdlc3QiOiJzaGEyNTY6ZTE1OGI1N2Q2ZjVhOTZlZjVmZDIyZjJmZTc2YzcwYjViYTZmZjViMjYxOWY5ZDgzMTI1YjJhYWQwNDkyYWM3YiJ9LHsibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1NjpkYTIxMDU2ZTdiZjQzMDhlY2VhMGMwODM2ODQ4YTdmZTkyZjM4ZmRjZjM1YmMwOWVlNmQ5OGU3YWI3YmVlZWJmIn1dfQ==", - "config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJIb3N0bmFtZSI6IiIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpudWxsLCJJbWFnZSI6InNoYTI1Njo3MDRjZGI0ZDViYmNlMDhjNzI1N2I0OTUxMWM5YzBlYTc2N2UwNzdmZDhiOGIzNDUxOGMzNjg3YTdmZjFlNTlkIiwiVm9sdW1lcyI6bnVsbCwiV29ya2luZ0RpciI6IiIsIkVudHJ5cG9pbnQiOm51bGwsIk9uQnVpbGQiOm51bGwsIkxhYmVscyI6bnVsbH0sImNvbnRhaW5lcl9jb25maWciOnsiSG9zdG5hbWUiOiIiLCJEb21haW5uYW1lIjoiIiwiVXNlciI6IiIsIkF0dGFjaFN0ZGluIjpmYWxzZSwiQXR0YWNoU3Rkb3V0IjpmYWxzZSwiQXR0YWNoU3RkZXJyIjpmYWxzZSwiVHR5IjpmYWxzZSwiT3BlblN0ZGluIjpmYWxzZSwiU3RkaW5PbmNlIjpmYWxzZSwiRW52IjpbIlBBVEg9L3Vzci9sb2NhbC9zYmluOi91c3IvbG9jYWwvYmluOi91c3Ivc2JpbjovdXNyL2Jpbjovc2JpbjovYmluIl0sIkNtZCI6WyIvYmluL3NoIiwiLWMiLCIjKG5vcCkgQUREIGZpbGU6ZGYzYjc0NGY1NGE5YjE2YjliOWFlZDQwZTNlOThkOWNhMmI0OWY1YTc3ZDlmYThhOTc2OTBkN2JhZjU4ODgyMCBpbiAvc29tZWZpbGUtMi50eHQgIl0sIkltYWdlIjoic2hhMjU2OjcwNGNkYjRkNWJiY2UwOGM3MjU3YjQ5NTExYzljMGVhNzY3ZTA3N2ZkOGI4YjM0NTE4YzM2ODdhN2ZmMWU1OWQiLCJWb2x1bWVzIjpudWxsLCJXb3JraW5nRGlyIjoiIiwiRW50cnlwb2ludCI6bnVsbCwiT25CdWlsZCI6bnVsbCwiTGFiZWxzIjpudWxsfSwiY3JlYXRlZCI6IjIwMjEtMDMtMTNUMTY6MTU6NTAuMDM2MDAwNloiLCJkb2NrZXJfdmVyc2lvbiI6IjIwLjEwLjIiLCJoaXN0b3J5IjpbeyJjcmVhdGVkIjoiMjAyMS0wMy0xM1QxNjoxNTo0OS44NjA5MDgyWiIsImNyZWF0ZWRfYnkiOiIvYmluL3NoIC1jICMobm9wKSBBREQgZmlsZTphYzMyZGEyM2Q1MWU4MDFmMDJmOTI0MTIzZWQzMDk5MGViM2YwZmVjMWI5ZWQ0ZjBiMDZjMjRlODhiOWMzNjk1IGluIC9zb21lZmlsZS0xLnR4dCAifSx7ImNyZWF0ZWQiOiIyMDIxLTAzLTEzVDE2OjE1OjUwLjAzNjAwMDZaIiwiY3JlYXRlZF9ieSI6Ii9iaW4vc2ggLWMgIyhub3ApIEFERCBmaWxlOmRmM2I3NDRmNTRhOWIxNmI5YjlhZWQ0MGUzZTk4ZDljYTJiNDlmNWE3N2Q5ZmE4YTk3NjkwZDdiYWY1ODg4MjAgaW4gL3NvbWVmaWxlLTIudHh0ICJ9XSwib3MiOiJsaW51eCIsInJvb3RmcyI6eyJ0eXBlIjoibGF5ZXJzIiwiZGlmZl9pZHMiOlsic2hhMjU2OmUxNThiNTdkNmY1YTk2ZWY1ZmQyMmYyZmU3NmM3MGI1YmE2ZmY1YjI2MTlmOWQ4MzEyNWIyYWFkMDQ5MmFjN2IiLCJzaGEyNTY6ZGEyMTA1NmU3YmY0MzA4ZWNlYTBjMDgzNjg0OGE3ZmU5MmYzOGZkY2YzNWJjMDllZTZkOThlN2FiN2JlZWViZiJdfX0=", + "manifest": "eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiY29uZmlnIjp7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuY29udGFpbmVyLmltYWdlLnYxK2pzb24iLCJzaXplIjoxNTg2LCJkaWdlc3QiOiJzaGEyNTY6YzJiNDZiNGViMDYyOTY5MzNiN2NmMDcyMjY4Mzk2NGU5ZWNiZDkzMjY1YjllZjZhZTk2NDJlMzk1MmFmYmJhMCJ9LCJsYXllcnMiOlt7Im1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuaW1hZ2Uucm9vdGZzLmRpZmYudGFyLmd6aXAiLCJzaXplIjoyMDQ4LCJkaWdlc3QiOiJzaGEyNTY6M2RlMTZjNWI4NjU5YTJlOGQ4ODhiOGRlZDg0MjdiZTdhNTY4NmEzYzhjNGU0ZGQzMGRlMjBmMzYyODI3Mjg1YiJ9LHsibWVkaWFUeXBlIjoiYXBwbGljYXRpb24vdm5kLmRvY2tlci5pbWFnZS5yb290ZnMuZGlmZi50YXIuZ3ppcCIsInNpemUiOjIwNDgsImRpZ2VzdCI6InNoYTI1NjozNjZhM2Y1NjUzZTM0NjczYjg3NTg5MWIwMjE2NDc0NDBkMDEyN2MyZWYwNDFlM2IxYTIyZGEyYTdkNGYzNzAzIn1dfQ==", + "config": "eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZpZyI6eyJIb3N0bmFtZSI6IiIsIkRvbWFpbm5hbWUiOiIiLCJVc2VyIjoiIiwiQXR0YWNoU3RkaW4iOmZhbHNlLCJBdHRhY2hTdGRvdXQiOmZhbHNlLCJBdHRhY2hTdGRlcnIiOmZhbHNlLCJUdHkiOmZhbHNlLCJPcGVuU3RkaW4iOmZhbHNlLCJTdGRpbk9uY2UiOmZhbHNlLCJFbnYiOlsiUEFUSD0vdXNyL2xvY2FsL3NiaW46L3Vzci9sb2NhbC9iaW46L3Vzci9zYmluOi91c3IvYmluOi9zYmluOi9iaW4iXSwiQ21kIjpudWxsLCJJbWFnZSI6InNoYTI1NjpkYWMyMTUwMzhjMDUwZTM1NzMwNTVlZmU4YTkwM2NkMWY5YmJkZmU0ZjlhZTlkODk5OTFjNTljY2M2OTA1MmU1IiwiVm9sdW1lcyI6bnVsbCwiV29ya2luZ0RpciI6IiIsIkVudHJ5cG9pbnQiOm51bGwsIk9uQnVpbGQiOm51bGwsIkxhYmVscyI6bnVsbH0sImNvbnRhaW5lcl9jb25maWciOnsiSG9zdG5hbWUiOiIiLCJEb21haW5uYW1lIjoiIiwiVXNlciI6IiIsIkF0dGFjaFN0ZGluIjpmYWxzZSwiQXR0YWNoU3Rkb3V0IjpmYWxzZSwiQXR0YWNoU3RkZXJyIjpmYWxzZSwiVHR5IjpmYWxzZSwiT3BlblN0ZGluIjpmYWxzZSwiU3RkaW5PbmNlIjpmYWxzZSwiRW52IjpbIlBBVEg9L3Vzci9sb2NhbC9zYmluOi91c3IvbG9jYWwvYmluOi91c3Ivc2JpbjovdXNyL2Jpbjovc2JpbjovYmluIl0sIkNtZCI6WyIvYmluL3NoIiwiLWMiLCIjKG5vcCkgQUREIGZpbGU6ZGYzYjc0NGY1NGE5YjE2YjliOWFlZDQwZTNlOThkOWNhMmI0OWY1YTc3ZDlmYThhOTc2OTBkN2JhZjU4ODgyMCBpbiAvc29tZWZpbGUtMi50eHQgIl0sIkltYWdlIjoic2hhMjU2OmRhYzIxNTAzOGMwNTBlMzU3MzA1NWVmZThhOTAzY2QxZjliYmRmZTRmOWFlOWQ4OTk5MWM1OWNjYzY5MDUyZTUiLCJWb2x1bWVzIjpudWxsLCJXb3JraW5nRGlyIjoiIiwiRW50cnlwb2ludCI6bnVsbCwiT25CdWlsZCI6bnVsbCwiTGFiZWxzIjpudWxsfSwiY3JlYXRlZCI6IjIwMjEtMDMtMjNUMTg6MTU6NTguODcyMjg5OFoiLCJkb2NrZXJfdmVyc2lvbiI6IjIwLjEwLjIiLCJoaXN0b3J5IjpbeyJjcmVhdGVkIjoiMjAyMS0wMy0yM1QxODoxNTo1OC42MTc3OTU2WiIsImNyZWF0ZWRfYnkiOiIvYmluL3NoIC1jICMobm9wKSBBREQgZmlsZTphYzMyZGEyM2Q1MWU4MDFmMDJmOTI0MTIzZWQzMDk5MGViM2YwZmVjMWI5ZWQ0ZjBiMDZjMjRlODhiOWMzNjk1IGluIC9zb21lZmlsZS0xLnR4dCAifSx7ImNyZWF0ZWQiOiIyMDIxLTAzLTIzVDE4OjE1OjU4Ljg3MjI4OThaIiwiY3JlYXRlZF9ieSI6Ii9iaW4vc2ggLWMgIyhub3ApIEFERCBmaWxlOmRmM2I3NDRmNTRhOWIxNmI5YjlhZWQ0MGUzZTk4ZDljYTJiNDlmNWE3N2Q5ZmE4YTk3NjkwZDdiYWY1ODg4MjAgaW4gL3NvbWVmaWxlLTIudHh0ICJ9XSwib3MiOiJsaW51eCIsInJvb3RmcyI6eyJ0eXBlIjoibGF5ZXJzIiwiZGlmZl9pZHMiOlsic2hhMjU2OjNkZTE2YzViODY1OWEyZThkODg4YjhkZWQ4NDI3YmU3YTU2ODZhM2M4YzRlNGRkMzBkZTIwZjM2MjgyNzI4NWIiLCJzaGEyNTY6MzY2YTNmNTY1M2UzNDY3M2I4NzU4OTFiMDIxNjQ3NDQwZDAxMjdjMmVmMDQxZTNiMWEyMmRhMmE3ZDRmMzcwMyJdfX0=", "scope": "Squashed" } }, diff --git a/internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden b/internal/presenter/packages/test-fixtures/snapshot/stereoscope-fixture-image-simple.golden index 24d879f4948af2cdd6b512a7048d61847316ec24..10739912e2dde8dde068e7331a59d19f8a62b18d 100644 GIT binary patch literal 16896 zcmeI3S#R4$5Pw?mmcPo4_x8TXFLC_wALg$*i5FT9bON2_EK#yUa-Na-Xu z0N@$nT8{_oKbVbZDF@{8v-;oO9Z*4-5}Z)3280o!#9%1bi|(FcUN^47Ds`2#`fy$4 z?I^$OYX4VHU%dSF;J1%em(bRpV%6?fVbmO7u|K7Z4Tha<^07)?#eL)Ur~5n6@|Cvx z{|Bal&i()Ix-8Z_)4Kkz7+vZAI9=fQzmt~vjrafaERWeF>)H&my)0DV8fb-4tI3E^ z{2mfAS$zL$6O={c@&c+ic$MEf1UKP7YN#$_9yN^%Coh|r z7uh7aX$^bX^}TZ5e0UQo%(_f@*qmKoADlvQSI#1IPz0>RGX2xyT{bD^)9GIJc!p1O zdHL(i9WN{Ts+`VeP+!ITSypfJ;`m9vtnJgHsm@Nzyuf;0<~=BWndj4MQO})+=`#Dp zURL5|HqDFq`|M&(U)pqZSHq8|?hLB^b`5p!XHEYXAFltX(z@^e_bPOQ5p_9(luuzq z_nY_41_j>|wZ{GgSN@mdKV?dDJs^~}+l7Aozoo-%T{b6qJ!~7m@Wj=_c8G?eskc>H zFSpk~uYq0zy#^kN2Aq<{5FUe}F7POnR3=8HZFE*4w(~kL6Szr4X$68tt-&UmbYzKZ z1_Wk@jpa@{rYeF<{$L@ZwE?#z(sWK|K0f?W0HNq|8N`F_x~NV zn&xE(r}I!@L-dulW#b`OvT} z{fdLuCyq%qi7qfI2{(aAl#S=bL`q120tpY1ChL7nAQF~tqp{Y~AZ-W%OOp&F)_lV_ zHJ0HmQs#G1)p?1$IAdg=l6}@TtgnGQZ?cu#Mb{73WUdM)c>|%DS1n?9v#11`>pukJ zI~aQ(LJ?gD{%!GpMf&-F7wzNj_`aPI*Yp3S|Icmy-`jsX##oWMIQwDO;Q#xT=swtM zpw~dJfnEduQw;>%1S&7U6UD5u9Jh=i5!_%a!|?zBECe4dXG(etN#Pbw2?pFs=92f0 z?04rs9E)DzKa`-mXwQFk(B{swd$wNvPWfTNjn+luEApb-B+KZD*L@CzH@=r^cGO@pd{;bjI10m67KvxeEIP)cq+ke5geA)a zWgH?W))K(CP)LG6ah8c95uA7H*U^BCnXI^d^rOca$x09gjfUw{eV;)-f;<@vJuyq7h7c z&<@Y+mE*w#0V1M8BQTPs$u_bVz`^DPoR){~_;Ltqpn|dv`1 m*YwbKku=8IoKy2=d=|vYpg% z(YUQ_BV8#3u_#eT@;Oq+d+x+})LL=x5f8{nL!z=&aj6kQl2XqpHVVfe0$2D~rY-BA5KcDNKW8Yd|1GfY7W4 zi!tV7j)sT|uo>c?wqjW{CNDzu7S3XRo{g`vr)Av~W*XpWsBv6Qp~A=VUv;RKcOEs3 zaTl)|pBLFUnn@jwvfFFr9EP%aF;wvA>f&j0d3$~`3&mYIi_%HqpcAY5Pm1^1_$>SL z(dpCQNAtQGO-g4bquS=hc&&U}{CHz=X<3BR?9Ea3cnZ**Wg{q#>I)d;z`?&?el5z` zZ~aHd$NiX3!q`V@C1a5@qb(Lz1Gd346ll=OYiEdMI&veW*U>1WrO?PrYa&-l5!BC% z{-`dep_Miu!{$TNZ(DyhHRmn3^@Sl^jKNepZ<*)Tx`33Egi8?2F?QOaV5E=%Ng2Je zu(f0yD@TQrM#hK(*B*NQx}40Xq0Yv|d@?!8{w}L`d2xQ6uN3v9XsXLunYXiRS>vSm zW1dd{gk|x$v0<`${Q4;KrF#c6;(e&Wt@jdBM4SLZpXi8jh&&hu9-=iOXz7hn!hwtDf>e@GDJ>BW?6nts*q#5O zNNn;ym?Zx9Ftg+;`;6ki}f#eC^K)YwH{H)RE+=GoPK{43K# zB@pnpWWm2KiQ2aop1a{A`vceCR25s|0~!-NJ;k=7_!8c_@mTMZOt zL>380SWwDpU<)piS4ftfQBv@f&Iaui!IoM>ZqxK5?Xeb!t z5!1vtX+i3Ws|6Kc#6^%cGKy4i!61he@Uct*Asb*fKvncEQf?j6AqcNkkj6?ILa;G= zbDem&!x-iRwbC_MvzPo22>L*}K+69(z#QnT|GngYwC+gae-EJkUdsPC1j-M$jn3=8 zyZ;aFKiB_HFi`bGr5|5L)Da;l%%ZE8Ji8 z90YqFuQKPeo#X<5cl0vM%2RW`3}G~(3T5reSs29pLz~|_$lC<+L7h)$kfk1|MUF9| zRdm>4rcH$4gi~6JXdy;KqzMcMCK%+eQ|2HqfoqMeR2;rY=I zmJ>>{Q&SLZlDnK;esgeUG=sg35=CNJbVM`lB}bkGZW)P&N#?w^0%KyW4oZ3IwICcb zDPfifGW7o~^Q?3G2VsN+V;!{ktpBG-kPc>u2nJuwJBVP!QKyS;C%c`|X<3;9w$zl` z`olG)x2O9r6H~aevHM!U z6pN83Rb|}So64tIGK^+ahJ$2vEuU6jUJM1?x}14jU966eCL#Nr&iw2sbFhi!{Abz6 zWO$PN`Q-Td?}KSs3`V&#qd{rYYRU7^pRT0SmexTi-pxzo8TD=G-&0uGhpU)TQCMG;IDKx7gE#NySy;fP4ogkeI1r$}oQER86FF2QTYvxqDbjxc!RSna6L{BzFW z1!raln|6Bb$?v+;oygD(geV6cPDW`qJqNIhJg*{LxJ;^xNo{XN<^p(9b104Red=NC z4A>z#&`z|29mwHHQ0*BcE+; zrKNKZ2sGCJ=J7v-|9DORkrZJ6_ad2(-2PuCX&p8+6$5ZFKgA4KOVmRUhTvm_hVyS7 zdqBMUBSo%@VEiko0eF-x$Mn}igMGW#O&LF!2QK|Ohj!yHlGgSgZdx0=mV4 zRkmXuQ*V**HBuY+k0A5Au>Y7qOe#B&S*yc^*8X3^a94*FqWTY|wca#4kxb^?{!TwI0|Jw`94|b8p`rkbNM+k50f9^{_mifP? zVgNa@i76m-+;%Q;Lp{R}mQ&njy;55Zb5n`bEk!Pmu4d{7scO5S2=N{h3Q8`)|(jj0lKWpURpO>^~!WSf#w~>k${?WjG(!} zdm>qsM(Ln+fckNbqJUARgCsFJ&ACLUE>e%S9Ijv`%cVt_dD!dqEO3 zP`vx;+c>n_*#+>bOrh~74Lhs)*rfkNh^yX!EBzN>659B0x2&I2zf8)zYG~c9)L2P} ajg={x%^s8n?SV<{5-kEP0xbeNK;S Date: Tue, 23 Mar 2021 15:03:25 -0400 Subject: [PATCH 28/29] cache mac acceptance image Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 16 +++++++++++++++- test/acceptance/mac.sh | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 83ed6f1c5..4f04003f4 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -99,6 +99,13 @@ jobs: - name: Run unit tests run: make unit + # TODO: remove me + - uses: actions/upload-artifact@v2 + if: failure() + with: + name: unit-test-cache + path: syft/file/test-fixtures/cache + - uses: actions/upload-artifact@v2 with: name: unit-test-results @@ -207,7 +214,7 @@ jobs: - uses: actions/upload-artifact@v2 with: - name: branchmark-test-results + name: benchmark-test-results path: test/results/**/* - name: Update PR benchmark results comment @@ -302,6 +309,13 @@ jobs: name: artifacts path: snapshot + - name: Restore docker image cache + id: go-cache + uses: actions/cache@v2.1.3 + with: + path: /tmp/image.tar + key: ${{ runner.os }}-${{ hashFiles('test/acceptance/mac.sh') }} + - name: Run Acceptance Tests (Mac) run: make acceptance-mac diff --git a/test/acceptance/mac.sh b/test/acceptance/mac.sh index e6c955bc7..b55a488f7 100755 --- a/test/acceptance/mac.sh +++ b/test/acceptance/mac.sh @@ -33,7 +33,7 @@ trap cleanup EXIT skopeo --version || brew install skopeo # fetch test image -skopeo --override-os linux copy docker://docker.io/${TEST_IMAGE} docker-archive:${TEST_IMAGE_TAR} +[[ -f ${TEST_IMAGE_TAR} ]] || skopeo --override-os linux copy "docker://docker.io/${TEST_IMAGE}" "docker-archive:${TEST_IMAGE_TAR}" ls -alh ${TEST_IMAGE_TAR} # run syft From 1b7c7555366171cd2a890d453d69fbfdc2aba21d Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Tue, 23 Mar 2021 16:50:57 -0400 Subject: [PATCH 29/29] add file-type mix as golden image Signed-off-by: Alex Goodman --- .github/workflows/validations.yaml | 7 - syft/file/metadata_cataloger_test.go | 13 +- .../image-file-type-mix/Dockerfile | 3 +- ...eoscope-fixture-image-file-type-mix.golden | Bin 0 -> 1498624 bytes syft/source/file_metadata_test.go | 122 ------------------ .../image-file-type-mix/Dockerfile | 10 -- .../image-file-type-mix/file-1.txt | 1 - 7 files changed, 13 insertions(+), 143 deletions(-) create mode 100644 syft/file/test-fixtures/snapshot/stereoscope-fixture-image-file-type-mix.golden delete mode 100644 syft/source/file_metadata_test.go delete mode 100644 syft/source/test-fixtures/image-file-type-mix/Dockerfile delete mode 100644 syft/source/test-fixtures/image-file-type-mix/file-1.txt diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index 4f04003f4..73305c489 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -99,13 +99,6 @@ jobs: - name: Run unit tests run: make unit - # TODO: remove me - - uses: actions/upload-artifact@v2 - if: failure() - with: - name: unit-test-cache - path: syft/file/test-fixtures/cache - - uses: actions/upload-artifact@v2 with: name: unit-test-results diff --git a/syft/file/metadata_cataloger_test.go b/syft/file/metadata_cataloger_test.go index 91c89e85e..a6971d6b3 100644 --- a/syft/file/metadata_cataloger_test.go +++ b/syft/file/metadata_cataloger_test.go @@ -1,6 +1,7 @@ package file import ( + "flag" "os" "testing" @@ -10,8 +11,16 @@ import ( "github.com/stretchr/testify/assert" ) -func TestFileMetadataFetch(t *testing.T) { - img := imagetest.GetFixtureImage(t, "docker-archive", "image-file-type-mix") +var updateImageGoldenFiles = flag.Bool("update-image", false, "update the golden fixture images used for testing") + +func TestFileMetadataCataloger(t *testing.T) { + testImage := "image-file-type-mix" + + if *updateImageGoldenFiles { + imagetest.UpdateGoldenFixtureImage(t, testImage) + } + + img := imagetest.GetGoldenFixtureImage(t, testImage) c := NewMetadataCataloger() diff --git a/syft/file/test-fixtures/image-file-type-mix/Dockerfile b/syft/file/test-fixtures/image-file-type-mix/Dockerfile index 218e369d0..d8f728587 100644 --- a/syft/file/test-fixtures/image-file-type-mix/Dockerfile +++ b/syft/file/test-fixtures/image-file-type-mix/Dockerfile @@ -4,7 +4,8 @@ ADD file-1.txt . RUN chmod 644 file-1.txt RUN chown 1:2 file-1.txt RUN ln -s file-1.txt symlink-1 +# note: hard links may behave inconsistently, this should be a golden image RUN ln file-1.txt hardlink-1 RUN mknod char-device-1 c 89 1 RUN mknod block-device-1 b 0 1 -RUN mknod fifo-1 p \ No newline at end of file +RUN mknod fifo-1 p diff --git a/syft/file/test-fixtures/snapshot/stereoscope-fixture-image-file-type-mix.golden b/syft/file/test-fixtures/snapshot/stereoscope-fixture-image-file-type-mix.golden new file mode 100644 index 0000000000000000000000000000000000000000..8acd4584ca27acb08fee66270b3a47b15959ef7e GIT binary patch literal 1498624 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

e51~(8xM>%QwDVQKs^u? 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

  • =FxSV<4a`jNojm(lw^oCJt~lyMB6lfJBo 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

    $H1iY(y_)eXKh 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 OU#GC~$lo*_07^D+0B^usN4Okki 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%0A8iM@lT}SFS_5}f}P4Y)d+N~@RF0K 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 z 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�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�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

    d$En-|mmR1ypVQF$O^f2n`oX0rhl_1A#Sd~g;^ z`;2#8XZYE~85;$q1=c6G#Z$iaeaiLo}#T)>ipFvHvjbQAGqI zjvXI55BI(-rET?YN8C#h*Om5xD{b;}lqLFJ#bR1xVoZVUQ|+a$Kw%>t^oh#X#iAeF z7aAlB)-B)BZ!poj)mTV8P{8y;S)XU3^=>q#i%HD-M*cKN_e#Qh*eA_iqdF%EL&sla zas_N)6^kuWw+i;YKOgn>9Y2?!@it5fETaEzH2A}_b|~@W$u7Ue1g>_Y;^B7v6NT2{0l6i;d5k%G`A$nYsIVr zi@AeT?UK@jwPzuU^0%?BdQ((<%;nn+3fRHJ8o|Isd`0X)$5|i(ASd501Qwx)oTd3# zncFWyR+tGvEBj(6^oymK9HL@FI-9;>%-SoT^!cBJw?XXnt)sbvpI+Z1%mtG7`W|4; zIC8c{oUuiS=2GS_RqweB+c4kb2*LKB9U|CEAdYW7Lj8@2N5ipq`);QVQ>G5OBAPQ} zP>aC4M-WBbrn~o!FbL{&>=#@(On(ql0`Zv0f$e0H`d36^BiOe!lb!r^V0ZCv^d9E* z_)=s;-H(z|!zC#nP&o~H-m|EjJK%Qta|ST}`yk9OMR^dmm*C?fJ>rLF#jH15t_2BW zyFZ2A1QT@pTm%Ldo`Z;xBwpv(2f8BQ-hHMZsTl01x?;>77@nZ#Ua(70-Z+wF8h4}U z7coMPVT2qt$Wu@%PAYndDf$aBMDmiQIjzYUZLdPFBh6W9k-y4Em*!Jf&M{ttJiJR? zeuoL=i5M!#Vxr40BB2cl?a6YlG{FzjZ@{6-5adctWVnx&MXfAc`;d1n}0 z3D~Ds5mP{!b)z;O35WR2`y0hv3;G*`W_R217%#ZRygBexe+iy|nfMcm;J2Y&N6(^~ zkB&45P1oWm{&#Sw$G^rd;BpZS4UPIOJVXQdaj%$m{Zka0oJ>U0yHkA+doS>RQx<9h`j+>NyuN`#++UU&M-mO~fY%AC8NZ9h)(ZD*P z3(1#-JhEK-<;H!wl^S-eeI<0M64s=xW5F4Tl`>$u?ga$zR>38 zutW*nJH$!Mdm%UlIt(y}OYEDhfQU7*89Un(eHg~HZ?T34S77|{L)0Q{F6gv0fm#%p zw;O(HKh_DCe^d;PMd0;yEIts4PjwsQvH2Z4%^iP-dO*zswSrH=Q4EeG-U5?4lF>&s2izWCz(mBB4??I2-+m6L3 zJ?8d<)abyxTvS?p9GpM610K@auc-|4{a>*Z2Vr{?h)W;^bIGgh>0gahJB&|BS%9kF0$xVrca#TN=VyIpZa;&}^8HI-2!%Ml_s)h};>CG` z+>oEON4_&Z>yW3)r5wsvj?WLoUE@kSE;06IyqXbpAEsLhxqLfm=ADkAdEAJ?8ZnU; zv8gj(88=b#^;&`-#Ssy&KSFW*^LFEtkM+@-uY46;j=_fHhgk9&OMcednA7kBxh9zm z!CxY!1M8C;3`yw@fCr-CUNqc)u^3q0M>9X`Epz+Vr04MGnp|0nO)Zy7zLyQItXoaZ zkUEPk+Lt)fP7WTRD9V}OUVM3L&G-EYWC-_~7-$47F~6Y0Y=@+R$p%jD2aER|KPzRu z-Xe?smFWC8U1=YRS$WCkj(3SmX4$c1kVzQykYEQ}Tmg#I3g&)pVoRdvy9KTI2ty5I zyd{ui)oD2DIBs2v%Bc77aVfQ+S}nSW77orP>~PKu(qI*p9l=@_N|WpEOd} zFI5Ko|LmY{W^3_lN3;4`Alk_3fjlSy934Wa*B6R0-%n~)|KBJcDXcNDPbdT3MU1C)XGhy?OTesnOkk=PJcNfPw2 zP`V6Vt~4AbpJt5~(de(Bx1AptX9XYs5{h7azQV_a#TdWI;Q@!8!1#Z|ALJ30-HbX| zVe=U+nm`0okPeqHbRR$@i7^4pdDLP7YJD7Q#$NM%Zp82#{{aS!GespX<&-f7kz>49 zU^1P?c{$Qa{co6m_%4ykSP7VAycPeO1Fy1C z5SJnaN}vT&UUN;-Bn(jBzu>RyQ!_#@TnVrd9fcOYqwa-dN&=L*{in>Q+jq?Dy>z2R z4;IsQiH5ym8iWaqkmO@PB=)h z=1lmAKFWlb+2;_rq%z?xa>tJEViCsg!-u@b?|_5GWUva12(wQFL9m+C!dvo}!NkrH zXBEK#@&mIbo-*DIZ-X~hOgjKeq!iaAl{hTwx^2xBr;H^maH{Ah6TMl zkFPXPr&o=IR7(m9rq4JNlILqLi)%46%tDLt-*nkm%KF&sdnHUSoq~*h5XK>WJ~*DI zC;B~sXuiqEz&_83fw)vGbRQB=H$Y^c_cmPY44xt}a(CeP3W1u4sV^yIn778~Df%2^ zCq6_7tkIqVo*29;zSNdX@=Ov|K*9f!^B zcN63FX<(!8^^sV|qU4#RUdKce-@Ke*_MGkL9{mgw1qVWoa+#fiyZV{x!<#<8<|7@GMg3!jP0LkL-}dih|VF zVe;mim-Z#x^3-1A1US$~wD#`WkKlhGAv@kze*r5w`2Lf8e*<5?@vAS8big2EhX+|Y zYv5FPWv^C2;`By#;1^gn8ugBdA}#8 zJg(RHGdQr`37gm8KQ#%J{8IadY->QIkqwJeV zPJ|lZc0igh%x>T+Fy)p}P+3yLcYq|AlrTppv=NAH?YW&1Yw*0;NR4wK>{)#uV}ymz z&H}eX<@(xKnyx^M)d9?Ttpzt=b<~_o z2u3|7=miDl{e}|y)74UpFqYx#f`%3Eq*{Q8(4^o3#3nY7eOqBEquXdw8ynSypc|~D zp*sEtXpe*cnyiB@hLU5^(?sLZ&@4aLkG6th+=&I{n)l*^u}$(nix9TS&4w)BupYc4EPubCX$!(p>A*c zONjb7Nr18^1`USEe;;*?A8cwZ1m<|beBZmQuSl&N6C|rnL^*8+;!lR|SPXOfD5OH27n3)mmbOU^|P4|AO~07v^fPk-2PeRl|kO zjYYFyRIv&ASNx!m`@p&RfXbu3dXq4EH6600Wn*{p?GtcTbCGM(F)?eO{0@fB#TYuf zb`KdkzQZ96I>M9ciRqCWy+BOs z313O@eI4?S2$dWWU_a?MzV|UAV2sC*wXgA2j*K`h3LT}Y>Q)TU>R}Clg(*zPF^o~{ zVp`&qQIAjph&8DELn(hl5NySvCWV<3RFYWE#lX02s5~Y$YVroIYz$hkh&S-3E z0wotiih^jgi5ZP=L>EAi17zG`|-*YDbt~v?SGKABXpcQ>oA-v7h_yjZJARqz+U6S z$P*=CGO4e`>-n&6);76Qdq|wqp0XIh@-tNGO1Q+V_LLg(`Bks+cBG{rorbK6&Ru}$ zwK=$+AYNn_UYbGSxS_zv3`@8#rvmqGDMA=|BPuKtx^U*NM_`@-<9)r51(nI~engV; z5m#Wc3=im&VF@U8pN-AW`oNoz6B_ra1bzSKbQ*aXhSmba!4bhN^hw)Bdg|_PaCQ=U zLpv^JY2F0fZh4!mb3X@l*I!~|^&F{g+YK`4&FJk~kRSGzF_O7A87-=P!02BQw(xP2 zN$jFsO(R1CY;|#@ti+}{CACsicm#cbz{YHxKH~i7I!xryUZqz{ReLsUrf#N^Y2d`+ zipSW#kjebemiGPf=bf-XLl>Hj>Ths_P zJaYQ%R{O1VSV^o_5Ed4*Q&ZukwE*nwn8&{L`#mmLV)of_CI)gn^#EL$#A|zGp?L2Q~j=`tL}b(-dBWbhU* zTj>^JdOm23S$I3tLHRd*2c0 z#_pqbRBuur4w0BqKQ_Elz!{Rv&Tnv-v<2c(ui+*n+HOxZuzdR=W+Urfb}~vGU zq$OT4-lJ0Htyb0k9vA_56^zSh{}BTQ8!kz?K~!)BC}2mLTvO+7k+s>_(d8m@Ox_G| z^^7kVCsENTtYyW>*JXIsrA#xCOPP221ZAjiThLpGg(>$sc@oDnKE_-|HzE^BlnLD| zzVRJ=h+MQ^oQR(3qNev6Pr}+K`g5 z(7gnb>Wf&g72MEXQt86%CQsLtydpNaku&()qQx%%@=RP8VU~ELfblO%$C~I;gzYwy zK}vgFz3v#DdmM)WBkoG|24}rXowo?bCTt`VN%_B?>35L(g2bZmz^4eXr6N;>9L+_+==N0RI;r~*0;3=ML~r{Y={Gw6$> zv5R%@>+q~T-U;CwnenNLiVeL<265ZUWFs--RPecJn5lFAWBi^@h%5ggzn)G=QU592 zZ#?%tE=_e-vuHg~KP&q?iA8*S9Vya(8^!nWN)iEzGWJ6gZ}VOy2HI2FkS%s=snp3( zY7`N1(ur}~$d&1vcO1J@NP4H_Nkj8rKAcP%1P>A$nC=A9g-LyM3XK)gl#ql$0vs6_ z56$L0YD0sMf=y}<606#v`2YJBs4{u$*4;x-bM7=^6_)6oOT)B{BGRIkx@F5VljK8A6t zrGuupx&rM{@wEu|k4pg!lU|}~p*ren#372srKtafa8wVKs_E&xi&Y17laxNTA%Q^n z04w0bZ*Q@Ft`0kd6F5FpmxFweo+%YJzI0TM@#CAfzmKvZ19yG!un{#lYQkfQjUJ2{ zYE`7f3yv8tjTy%6OVI6gY1B%%Xv`$@F=H8;&9{!3pCEB$%uug<5MBCt$e-f4yTBzwBso_iQ1IAQdfP8~mjS#z!O%ywJz}SJTch-<-z+?q+5>y6|43MAB zRQOu{Z5#y!@6WI3a#ieOJGMyS=hsjPb(a6~!NkDvGl#B z@MBt%9?Hs3`nVn{6>A}BGcUu};a?$yl}^1*T`_2(wbH*TS*;=_iimgM>%jLj8iwGA z;bU=Vxi&9Gk(i)gs5MxkNzjBCTP?2rnzoNG(SJ&+t}Zm^d?EJQtcZ@q$3|m=zO<%b z=r^XSE3PI17n6aO0;r!(Kt@sDJBoR52^}`1zmSNS8C_pIZO1sXVG3f2)^#$ZY>NzW zH8WM0PB9qtjp97P#`X%4jV;?{r{bbDbuF588{G+!S;|4$gt7 z0#Jon`*zykD%dF#JHCWnZ_#&HzfEC<wYW$$F#^}#t#@~t)r@@#ypf(#{ju5|%u z3uqB!l#a;IuUjPlYO55x+M+&=;YJE~8pL+HuOQVR!N^XE%{4(#MnJON-)u$fWXXTA zBkfa{;iPK9Xv&8Vb>?`;F_8%XqCF8Ocrttk@Z15kGTBpEy0_f-${;o1=? z^eXm^=Jo~112>Syv8H&FtmLW$s5=$V-mbFGpR{HU}Bu?mdR$n}YfQNQla5)6E;MBa**6 z0mF*gfD=jYrFQd%7LbL^e#c#^)7mJ7_Gl;2nAx#V?QV}3w2`nGj3*afgF(`%Or-#M zg|Zv{J(fMl6D$CA=3uO?GMhJkFwX4zBLw8&6`%s9L}t`^3F(WlV}tD@MzI_Zqcbor z3*;fXc}o8wYqsxvf!Lou@2zk#KMWw+A0f-s9tqbxa4iA11%n7iOv=zZ($2JFB5ucx zp_}U+=%jm7`ebPFcH-n5FNRzU%R!tUcZ;|rG1K8swEIr4X&wuanU*#1vl7Y-`_CT7 zIy1XSfph6N7q)bvo!ZOTj-r+@v*@Ksdod2au#_-OGsG_k?s_|+T(}84f$)n7xa>WZ zu?KXeZ{ELDWbPfso=h-zJc5C*CDOAA=8gy8<`(SWDRikFa>l!A5F?O`{eKYW3!Rgp z7>L|#hrK!7Y}btHU%*8=x@a>Va+t-VV(&J(mfxF04?*C0he%aQP2MT2DjB$nKP6HV z8P{s2^O}(RN>-CnlixV&1yTX}R$+)5Q{k4c7JHqHLHg!tBo}y-`a=0g0)rnxOJGit z`{>%bu++CBy;_MSdQ74B9gsF>DbnB+?AdVI`DnNXFQg^sQ8=snV+9*AJ-n`wc<9^f ze;3PxC`onRLYaV)P(Kp>ad%eOR?J}+ z>$cpxf_Ix9L)M^xDKVPT7- z!bF5&WM}LT9!FJZDL55=fnXDY=w}VqlsDM&*zpM%6ry1`(b1JzdV@w)Iu^#2T&yDw zolx0pAU(A<6^@Z`(3?5>GYSYz)W*}b^cN?A%Fs2NNOfk|uKj^eplaVpQ>7nlH4b9> zz)0D~R$af_BBpKeUMFUKB%1Ty$k=ILKMQvG>A1F>D92Nu8|0C&(5KZ2M-s=dyt3yM zDD$*WZgVLr6Q^)T1hY+fRo~V^Zgbm<){mImYN^{IM5dq1Ix-!fXv*gQfUIJO0ytJ$I%2*S442w5K-Lplr1Thml<1 zd$YP%5Fnm#ajw@!QXz?VOX;iKuN(-J8k|a9N*sw;U6ZzCZ83Lbp#S>cm~;d@HL+=? za-e$cdjcNbx|c`t^~K`Zu7n=DKQ0Ax&YI9uZC5T&S8zVLbR6^N+8#uT8?$f1Ex@;Pns-GB(q~sy=&w+ChR3QjZgjdz(Rpuvfxn>KlmH&2XVTZ+Yci? zgmq$JgW8p>Y?C)F!n+#YLmcoP^K&!x>8>R(=hN_ZDcKNV*z+Z!>^S6*#Pl=ySzm{;Qcgf4pW#O_-O128{&+bTivmnmN%@eaiMH#FnC zrapVfB-d(2`Ya3G5+~zoWH#rL+gOzNzEGlE2F-G!yd>%%Tnx+(bC87}4RV*+=sYQq z84j8g6;v@asAw=qyDuuY%qah#=z?MRp$^>6sqTl0-#dPZesF&qNtL8d3wFUyN%Y@? zbtM~A$^#F#1>-i8w2l~$GP zN_$V6fR|)&Yc~f(z#T=kLC?qBJ`)}phi`?Uhc0IHxXsVQIOyw+&*cfq-s-2?OgIFI zu!IEa?97C|Y9-zu`=nL=;K^9;ElSov^;^TUxi6C&QHxYKWg ziM12_JGYwmSt9L5V17O2>T<_8_iB~(VUF^ z5bx~$eU3meZix0caY!)29_n#s>{q@LyFaxmDqaWZhw6WyvJFbatCT*5mF*7Yfce=i zcJs6Q4coElTIZct9X8l<*PGZ*ZRR7wm*g+ijs~ z@H|JSbNtCiELAYjSo?7%2;_9Urk{I8c*h+%fQK#)gnemdYYPs3dT{6A;5}E%sYebTfn6zWldNQj*8Pzc ze7oI_dQzU#f;Yl-aHke?aOb<9H778?gGV*tVAp|Bm5qY%Zt$K0*>&VVuaovHtn798 zB80ggz!y6~0So2QmITqK*9=m!F&0r=0sT=b(V+VWNtJ~aFyo++a(IF2%3cFGX#BDP z(!ooxb`$KKlp*fbepV0gZ`yBZGY%Si5#fb+fP=;^7T3b!Vn7L-DIX*_x`Gmr|G_P^ zu)u|O?Xn+!#?VEcyAFTZY&p2=z|Mm&AO52G;v)ys_GzPmPapogY4nkU2X`6vX^BS; zAKazI9XW7t7p{<5_MH*urDOieoktEIIdJ&1rfK%WX`$|SPJ?7A2aU5)6G%6#4bipd z)do?;ieB6_r<17?+ACOz&ghfE^M*TMXB2N-adYCm%f+iK7KR# zBM%A@Gxkyjsqfaojg@}H0plwmkSo@eVtpr=ub^2O`=!t>ssAhAmUR2Ni*OIyk+whU ztu-o5m8=8ueMb%)IiPn`TU|=F)e)$++S|@9mq+5gqIg&bDX(eQDu>`zEngWJcd748 zXw_x>tikV(Oo!ZOfIqYieS&$eUDa8WR&E6FEn#5ZIjvEZv(`b|MObcBk!dX&` zxbGxxO=H8-n~v*WcJqT>POuXkAJ4F@Ux{nSI~;~y+(Wgsh0?vB;AUjVm36Y^eTQqoWwZ-h0oj9XW|mKcML+ZnnyScd+h5nC72AHfQ52PBIGj#hVh?i z=I&##2!vnr$BgpZZ3c`Fn}M~~>^pt--m9{9-8)fvE$wA3!J&M}nmkt7(Xq32jD5R3 zlrCW}6>r!RGAq@aqu-dxO}tu*l${4u5`<-FM7_mx;Cz z9q{e4C+w5Q0F(oCJKMXxSAp$KbOk0XMA1^OlhqV`g)=y3AGIi7xnsbtblXGS-iiHt zDF(HHVu%k*in9;39!*IV=KyY;;!fF?A-N!iq^ufn;zZc!#I}8^6I<+S9BI3u*oVw*P$!Row3Djz!NI`w!axJ`KcP z02V@Qfi~6)UL^j3op@-EJ=FEf{;x4NlX+nobh$XY>!C~cud=~V+7l}CcJZl zO9dq?orL#`{)T(&a>Axeve()4;%v z^6OF>!H4`+Sn%_4po6ypAf>|raTj~7&|aKE!*B>qH}ptZpR~LI11e27En2&kR=X$_ zNh#@}u)Fb2im0q$U8t+9XtJ}%gYF1^WW-}Zk?sAQ$g^^^y>}fz-Pjd*d9i#eU6IGP z7~A5dA?NKP-7TNvO!bV`b1hA#TK|jpS{TFT#9V4WB=wY$_{tt^B2pL zac3T%D{v4`Z^x~QT#WzeyAaIuEwc8r=zu4q0(R0Rf4lM-_M@*Y@ZUN7p8t>sChupZ z@_YUT{GNYq^gaJW4rRBxA5{kbf}&ygLz21SYU2gTYrgWevtIf+m{%N@Nr+5aYyiZ&QcIf?IIo2hRX6#sKk_H2RdV8d z=M3hKos7KO;Uk!Tyb1q9dqYnz4)$vn)HYXBm$tHu!y1oMn1Nx9$479J#zX4ePJ5P+ zGY*?ls540)b^~m&{0*7Pmg=>~)7z?jc(3Vuv?Dg=D|iYpAKT5$Q(LXxMD;g2aEcI% zYfo5Nv~8jMxM*$9H*e^TVk(|rP|>>9 zzIhv279;yYBh4LmQw}C_Er%;S@_VpvV|y<4_;;zBlx$-m$J1R6><92b3hm0Zn2b*b z_lNrK&XsjbbQcuz+OkcdmDQFx$HR%6NziQFipoK=bq{H_3V21sd$uv*iYA&n&QXD; z5L{nU9eTI0z6ozChZTF^bf2I0GQf(Z;v|1E5hYyK6D$dcf)aK_%A$=f zdJvn}S#0ylY})^U%%K)ExBngvsdpRgo$bC=*vidvWqFoHsrHIkreP)Hk0@KNWNd@m zrFiIlRz)2dTYbIFQ2mrGR-Q)wea9v7JfR*c+{SIm6X>D%pCH3XpVn zB=B-I-VJclgPTDI1Uq#b4vw@G(rL!qyqBvlJoBxk+y>2CSj{5_=7cxEvkymRXYfU2 z2F?=Eyj>9$c4k=E%&4%%P)0{(c}Y~zY8DjPiN6A!V_46(cWBVDsG!e=2K_uLXbjWx zMKXLkD(ISF3c#|cu*zX!o~W?DB8(qXVnxwUG0Z=F0_69{S5Nlgh0r#kITdDwPsVsN z@YJI3r~y~6EY(UWj(amwQxa2wVOc!v#@*$J}I;jihGQ!shQX`K|f zE_QCB7pENCH9U|18qD}Tzuz7!K*bmtdxO?<=852|XXt$oyuUHA|B!EsX}!soxf?Hq zVT|Lgs`l|T*6|X@F8M?0g{TKe-oyhWy9QrP7|e3;MGY4o95C!M`wpQuA`ferJ6;Av zkp6&&+4s+(q15N+XMsngqO%~GCz6Fnj$|(1IXtOn>0n^#V3O=XU)*cPtvB|dh+bjO zw86kD2a}j1zUKC1%zGU3u=iQWC{TYYq%?D%HwaqcxsY2j-|)Uex?Wu7#p57z5VA)P zNk_=m!H`J^`IjDYF+%=47!r?=Ujw3)HZ+&|34#T91}zpZSeeg>jIOg^h)-kFQvJYs zdaY#gx}>D_klc29zsFoLaE)QEShO(?uJ)bs8<+)WA0WKml$n&|orDzhy?DJCL*J3> z#aMjhBUBmv-`cHgiAviG)2sg{^=RkypfA;fzElr@fU-yIK4BFT_RuRk&0aiv zfIG$}DdWuiz^p`9#+$B$-B6u-iyfKv0dFn-KMjQw`UI{sc>D?PJCXBi=8PrhS>}u* z=Qqr0B$GnMXfj6G2{uxFVT8Bqj>6t7va2y(l zNAPxJLN~~psGS&WpF`PBJL2vS(ZExVgzaRHgugb>eF7~!2kRfH`>0h)0JZQS02;Xh z&p8axh|SN~fxi{(yB2^dOiX(VV}{y@*VNDm`AbMRXkv*QJg#W%dvuRM9=Rmr z6il>&^>-yuM%>IPWVRJ(-tFW&B912#w>)%4BORygd;O=3@Yv}iw!a!0i`aVD7pli}@ z7YG{Kj;1MlwKr_*n+6znq>YiS9dFCrPmc9Xrvbc11nI*AK4$>n(|!s`X_&z4>qsQ> ziY2eJLt@2|*Ed6A8OiJ15U&yB6(X+$s!PW*FeBs_AFX1Gk)9E2Fjo(%Z66&}$~27JS9h+Kh6Z2bb` zpZyidTPIwBRekDPq#wuo7w}>>61($svzNmoJ;ht*j6@&{m|`%Vunr+KE}WU3=w zsXlh@lq1n(kgsQ#rws?BtZgl6qQ41p#4T9$7beRi#HEh=QS9BDe)aboK-7hhHc&-eIKqBKS%}?oDaO}A3l0pM@nTIW&W0A^2%^-AFW%1^ z(L5OdM@I`GNtCAJn~p58k@hqz zamYisCO$??I0PX9l@)PY+<J@O{ru9Pl zWQ|{rj|V~t3x`g@qGiH-9HQ8P<{8vws(|sU|A8X!YnK!>eVYp5^#9D(+TF;h3nE8;5HfTe675EIaWO(o=tIs?5pa$Kar1=rV zWfE+Z^tWGNgB2M6XGkYBr`~*-O@Lnms$1cvLKknMdNO;sdqpr_dMDe%F4+@@^qnbe zPSRf`8vl1xcM0sW=_l$872+eX@60vLbK#rJL#^ER#%5R@*iyM~I`_?^KZaq;=*i-#LB@Dbx=sO&X*nKa@*m3>olDKWf zPFZ|M@%UpLD}yq_54)Cus~zInUaB7x>dnS*Hrnn^>J4a%VLYiAe~w-evwEAuW_xxB z+`Pl+K82`E6qN=XaxS;Hlm_UlTC6T*4UCdXX!I^h7iowpd6~fg8pmvA$#~R=0w8b^ zvxf!nw;O2=HJhbgzy^y_>1MNJ<#{R4w`YKhV9GZeDFw7fUu2vrqU~zz-_TRo@`&`L z6~;a+^RU&RQ#g7_5ypIe=jBSy<=BScR1SWr@T1*GI&Ew5&BT|n4}5LFBEBNN$ULVA z-^KVY#&;>cOYyD2w+7!vd>e7AtS4BFUcOMxYM=f8Tr=t%VnF|aqP}_8Vr>!R7;QhB z*mR&qe;&mG?WswPr`;`#j6q9yL61qs>FN_`FKnsll*FVuSQNOJEf$rCLHM6a9E{TA zoA;Lm^!XhHjh zW4pg19bR9U?8Ox44%eKj9iHhh1BIRb{D2q7gMna8s%;^i==gs;N%!wcZ>NDN(+D?v5|b@bv9DF~S8j!E?J2mlW90 z1kcbl!KtKY0QV#H;}CW5PK<@H3TOf&@t{Wd$Y7YZ`BZ$Id>c3bGp<^Iy+~`Kh=rH^ ztQj=f%W0(cfd`>|%13A##>YqMX*3D`Yb^2z7!|~6H98HKKqgmhoC-+7_(s``eD$ z=nvrJnQ+j6x6;KadC7*oWB^&QgXH_PJ)&|G-ZEMp(|-U5o}&j%Z7Vk*yy|DenRZrUJvHEw_rygeGME)>Z z>xfteJW7vO0F*EMYf$+c)H_fm@CHz9~|eXJD>eN8C~2q7A0I9#^49|t7m4rfaegQ z%7B<@!Zm20X3|d5-Di|xQZ4_5Tz$j;-X?1C-OqOv_>KbKQQ$iYd`E%rDDWKxzN5f* z6!?w;-%;TI2?a_$<;$yPTPJ(0w@quddK#-LYO8B2%DuG>^>(RVWlg#4@m5tP3Kb3Y z)gEtCqA+>-wVp&_hU{sY;c2Rvu}rS5t88j$@XlzEy^XS0_n0A9)YUGln3gd;efo7b z&XB#ebsk~bwC1WN4=N}uukuoU)~2fEO;sN9vU;mL-iUu{UO_3EmWJO%VP<-ImXOoX z*xFRPyvA!y%^`1VZc|m2)!k6-Z7FZ6vgS6(^_8sgQ>{{c#q`9Inp%$)|EejPhew-Z z^#FNm$VYCfsIpc!G+8T>%Tg2F@;&{SUUZJlGSZ}3{H znyczrx_oDGj%Y6^v1dyzsbq;2S>;M41x~lynp;?GwOfnq#U)Zssmoq$Eh;T8Ds(%i zCkn+4b>;Py*8GaRCUlChsHxWLMTW~-(Ix~>n^sd**C_DL4U>s_*j?nzxx>29UYuw} zQM0Yq^8<_UB4in2pyU!UF)^>o%i2nmu3avpJfd@Rd7Z2`JUmD!)2UQ_qDI6soLM6I z(g0$)f;3V!s|yilc`b-Bm3{PlL2tyaXjsu$TgQq^tg3IWZEC1rQC06{$)+bJ3b}~0 zOkR%OZ)|At676g2F|_0gM*XSQ#=5F<5BjL8YIfq>8n3r;_KX=VEiKcR*UQrznwHN9 zcjpWmVi<4BJ=1HvE9!0n{qme8IfVteWe%xWnAR-JsI00km+QR33=AN-uCo3bbl}RW z3fWu5hSs!lP+TZO-$;wg1ZpJ_i)K}#fB{uiU0Yv869VHOvm#L_t#7KTXjoofdrwv6 zAgPv4_FO~p@2YQTsUJEOtyfO=T$vay!6g;UFUz+t4r4gWa_j|#1<@W-K~ZT**rULn z?~G2tdL=4{BB{t(mR*`FxC?Vw*5u~xvAdTPpapg(7>N(=FZVWR5cKLR`wPs6;Gw+8t#MqDpB_NnvrB zRN^eg(M(~1I}$qIxnyW`cZr?IjTVM8(DTt_xfwkud+tI!w^*!`q@-j?S%fB~k(i~7 zWJpp9;v=b4xKJo%B%^%r+9@T6Yf)jbgHf@}zOYC{wOH$fvVx-G!W{6P!eVzB&48gk zg#|7eV^Q(-ArIoST%$*fSX@|8Sn7@%0Xd@Nazw|=r7;m6F1HkBQ;8+Tg|4tyzP+f( z=_t#UTuyhy&zbMS7##-7iqYxLD9^&;C1q$zi8F_~U@*Y#MlYhVZnspB7xpe-9j_Ce zH=(eI4=s+1BqJt%8n+X@Cl-QDM0_y2ks{xjPn}bkeG6g_2GV?r9veEThWKEx z(4ZPtbv|RlrSOSpFDWSoxiP)$4oC5~2C`YqyO^i^52T2Sfe|1&LC0Y^GoHuC-LRnI z!t7Fa2?ix`#S12mj&b2U_~a~eGg1yKz-`ZUmgRy0>r5xyDs)|Ogv=$kMtBAfUx-jP zLrO3l7V7j~%tn7s@sc96PY2Edu}sRy#7xq$%b91-SrSI!F)|#NMLI`MBsm~?4oVhf&Vq#)x-3j`6f%5PP7dYrMtjMT~ak?7E2RT&aAyfQalXb=tY99ET~VZ&-NEHJ7f z!$Z!m$A2C~QR&g1FwutketS)c1m9j&7JA{j>OtpMcCdp7t1{?!UPYpU&Z|ar*pNyL z3Aj)dsB)b1@R@NVM)#oa1*#Dhc!7#UhYqXCkf33eu{#z@*!3)dY?d3@>Sp7$W+_U1 zBH*;)W|_ORs0gd`g?-B+l4lNWTFTr^M2^~!tt7MCr8T#XN9JD5e0 zR4~-1*qH}eNr1S3Z$xO}EYdAH2e&-KH!el?MPbPaL@g|~JJ1TZvlxFAz9m$r zM41DB)iioU4D%lB5bEN>(!tG6$r9SuUU(x^ii+rph)CO`ypSiGB{R#4!fP9Imf3T1 z3QG%0sLuu?5W%2ciS{We#+E4BBOm>QEwSKUf_-(NE+N{nMR7@P>?4@KNRY%{`m*hd z!|5uqGcUO8OQ?Cp42p%2TO&IRXl>AG5tzTAEV8SHo8?5=@-E}Uc~H+pRgDZ*2FjcZ zozMtjG-7;&)9E3@cT|)X&Ce5xOVItSa@diU72rRvTmf2Wca`d5GvX{Lb#g$Xoi>Kh zM1|!Cy9=abIv-tILy|H^9@Jt5ImKm*bJ2cXAruKf%P#B>l3XZ0^Rv6K$7Wp-*6=}r zO%iiXWPo#zu)b*6?tyv{NggKj-1Cy(=y)~94{*GO;}FMf9IyPXjk*5DvGsR4evae6aQt_U(;wBt z>G}fw{F~!XbSPB)-o{*?a{M{RCpnfMvoTj6$3Op*jtR!#_b(3)#alUs^&<=a_b~hh z$CQ?ScMro)KBVUdQ(G4PE)NgmQyk+V92S0Z7#_jXlkqy`AL8L*Z06x)Jx}4^rI4n5&xO zKXSaB}JdMGAHga6Y zaojI#%tie{KihbCiw=c79Ixc~5XY??zt8bK9DmI54>&%>@x2@yczc{2U&L`P$0;1+ z=_2;C;*U1=rSU;O*YfZybSPXm4A0|uF%Qq>SmL;n<6AhEIVKZY`njKDmkxzrbBqUy z*v}IjH*)+b$9Hr5EXPe8-~X_Ux$ra*`|0H2%orLzpZ?Ou{AqmB&o&$ki<8d5+!*O^#Tln}6j~^?? z*Yo&OIA+(2;CC~}H}UW#9M9v}%W)RRK8|f1|AOP2IewaBJI9+izLDeI9N)n45sqhb z9OQTu$03f1ztPWSe0&kVqMw-@6ThOL9FFJcP*}k6c#bPLzL?`Sj>F^iryLW%rJp}= zJX(jsMvikh-pO%3#~*TBz;P@e?}Z#s=D3Js8^;SczK!F4j#qI!!13=mF6MX>#}1AU za!mZ4esVZJxk`t^2_7Dvf2TQ~z{5?yvN2aS$74CZontGfI8NbM__d9>CUbld$5(TF zHOJR*+{4pPGNQJPhyQcovU;l;f!! zf6noB91D-wn5&%QksMFw_{6aE6L>fU6VJVD7`~EY`a6XbK8@ob$5|ZH-=C)NY>qXK zi#Yz6<2yM1gyXw7{*>cpj!$xYAIEXLe)kW!Qj$KGV^?8Nke2zchxParY zIWFY*VlH2=X1NJM8plOEJe%VM9N*4yF~=T`-5mdf<25|LM>#Ix;m>ni%JCkK7jpbQ z$BQ^V$8j6aZ_ICP%(a+@U(4|ljvXA|%JFR+-^OtZ$A9Db1vtK)hd;&f9UO1x`1>3m z<+zOF5XVG&`W1d>qyL$k@I;QEW4?lL1IJ5wdN;@A9N*3HGLC=5aRtZEaQt_kUpL2< zJp65r=}&V}`2!qRb3Eoz8%w#I;~5(jFkH#;r@Xu$aNNk#Kg{vn9B<&biQ|17 zdpQ1#%OqYj009KXo%_$O`5wTa_Yj{nW^T#jGj*v;`~j;lEC z;&>&;-5mdz<1HLN%5e|J|KNBl$2&RR#_?f}w{!d{$GsfKJ!NAqjpGE4KjwJ&C$+v7 zf08VI)-6=LE{adG$+3?`N#9$Slx(O+DPF2E!hkt^lJhEtq?lH!GU zJq;q(H?CaVAXnB_=T5Z=I4p?W$`en9AzruvJY>F!!a9p+9c9q5`Jh zLSbVSw@fDMYJe4F5nU-1G*~@yMUAz(wyuhdlPhasdh3NzdL*Q=se$Dn)q7Eh+=x_G zPb;j|S6C~`>*@rlp3Kp8t8^=?MkHxvRda0x%eK6-k}S{#d((2687bG*dSEu)&|s}= zs9!EPVJu8G%`3`bI7}@Ovdb&=I#pJADw=8=Q6U)r#`^R%=5e8OEbX*xkblnsvm5LQ$3SMi8nIR}|3h+J*{m9Wxu( zD?9&7~b4-{F&YTH&R&QE)c)Ga#}+@D9%RD z@VZd5JwkRSo&Sb@VTI(xnV9QU&?}8q1owcUCjw%|4piY%n zaDl)V%&w@Z!P`*LP-m@d!qtH$mTkG$TV7FvJW%T#w`A3C0?4?2F-V|rHF#;^!CbYn z0(D0Rggt0V;2sGEMPzO|c^qpsI4hM=Uf)o8eu|1{PfuNg7dvj6=?%EIzy^`d1j2KT zOr{_|Gp#I7m#SeI2{ID61x#1rh5_Y#VZz9;=>JRlV-3BiJdG%Uw{H=ZZT_h zm?MJk(g469E=PJ|U2IhW%c`%c!UVK>YRYNsy)5eyqL^1*b$2w%oyR2B5SKWVOCEUPf+ZT;8xCQ>sljY7;9Z^ zJzb%xtDr}rXFdipXOoy82BDs)zR+|@#P5F^A#wcbDId0iwvR`Fbt3h ztcQ&Qo>?TAbyaN#}WkLxCLxu_ugZ`0>s>@fE75-3$B2ghTF(%0kU5>9+7e|4wqtxaahZ%F&wSl^K z$cSsILdB};A->Iqti}W(Pa_sE&~~srUNF&0T8^SUk&*}@hz(%#5dt?@n-C9I`x>k@ z2#69Y!_7k1pCYP*rHC2gt)g!Z;a=Iw^Tw@!`#8$G+L2}sd%gvxSv*! z*$*0%thCq(lXxpF^7xe`J$j&c?ISZuBhP#Ax$vurE}Jz5|>rKcnOhv#k(O6oP3Cadrj-CfuAO5!pj-@ckKxh0JCr2pKE!=PB!W zZfOmLR^fXY{Qqx$DPQ{CiTuWL_k+myIsD#_-xuLe;o&fH{|5d^{QD=k`*<9ROa6QL zm+}bzhRY!wb`SrC+p+C`5a&h2iTt9x_4uW9dwAM#Uc%Xty`wjn% zgTD#C^flvmJpYngjB*qHKkdB>fLv9XCtm4<5CduAV*oY&EgR5?NpoNIYH{q41QG~@ zM?evzxK(wlyGV6aQB|Fnpn%KpAjGoKeSda74!) znORs}AG`ji|G)2?@7CjX-K6XGJ-u-}7t(d_?|kPw=bqnre)l|j|50Ue7FjO(hxotU zPdFT~|G(t&i+k|RSWyCSHs_|>i+koRSWyi z_n#oMpuQ4`gUcuTlHuU-f#;I~&o2%zroi)D@Oe|B_c}PYx%V+~aLzYyOZed2 z&VYM9@cgE}=itNLBa?m5SB~p@o_zm_z0b)9KKK0Y^NPQC_=R^m{QQTXYP{kj|M`m_ zsPOYQKm6F-_80Ga@EiR6#Nq#b@Zt0R>>VHB_q+3Zzxu%c`Nv25SkWiLGO z_*HLP1~V)$`bKcWIdgNbCV@?(Yfs0Ifq(xA*h!E{oHM%ij*+dSrygFuX*7B3icO>I z4;^>zsIeYSWaZs*_T1dRuD}ia-a4{*&B|?eEx&Wc9mgGBx#iID%m01_f=W>Mx8Pp^ z$9N|3>tBS^H>B%;lkMKWC|-1R;`^NA*G}S@zL)$Avf?|*$!kXruH8a^PdsllLBGds z89lh{a(*w{_gji-{G8F`9V@nuu0MR-rcvY8m0L!$hmPMm zIyrLXXciGbA%Fk`W%yUaYYBQj3OzTi4ABE`x31hodd?rcd&Tnc<)a^2alz<)E4Jfz z6Co!rAEcY2MWy>8=>O^kb93UGG=e=maxUe$b48w$bc;Mk^2G7aAb;A9xw#1fMA<}g ziM-M7sBCNK#mTq@-Ipk2lz7=&dt#rfW(f`wRcjw+(GGbnCgIADP0b&JP##q z`6VkviXhu{QbcN+#Lpv$#|JK5NS>%eYTcTX@i&;S)*=qg1?gBXbo|dt`gNR+c&xxD zr{4#D6Gcs=2g>Xr${!=m(NnjKu0>%XxebteF|<6`FNYd$ot9XCl*8`toeTQY;vt#t)k)0wvksGOwx&d``& zheGA(#N!i*k3o(Ov`Cy!ZPqr*2dEvEe{7jg@TM<(iPTV9o(=g;SIx~;2*9-s|1Jjh z2f(IK4^vpZb;dcJIzyCoYLb>;uxfD0Cf?o;U7sw@&3yy+GGAUWI!X7qh_?seUMkJa zT| z@FBFF2bbL-${)Gk3-@1yxKnyO0{0hS7yc_y-}l7N4{!PQ5mAt2fDoaJ{H=IaB9Wb* zoBIv{R}t^$OWyBWwtaNf7ru1a=zYr$Ex&bS`zx_9i%3mF9c zknI0K=6=Y$g=F~JhTr!CKchM~x0>U07xgu{{he2qu3i4G%SN-v@qq>ydMLer3|&8% znVYMze#+;+2KK62e?F&v)$>k3z5sqP$%=fA1{I``9s_REa7&RJF4D6F*js=-mjJxu zB@h<*ANZZXMVLZQw=amoHga`Ob|gKAA^$k!lca|)!tVk8-2wOmz@Hp|KMwpU;3(#u zi}XAN{O^GK`HLLsomQNfNPG?W83f=W>{MVB=4k?v?Z^gTKLIA@wouU=`7|YqxTv1p z0ry+$IFX7FzkU$y=mC+}s1ri*XhZIUkn{bLxOjiy?-+pJ1N;#1Bnk3G@(%!iEAW>R zhFZvlev13!z~AHJcqUGN4D92;>bQq&W8^v+b<(q9O(OAcaO;f^<=1t<{}s3>N8){U zj^4d&&*<8%qpQgMY`DL$F*o-K+(ReQ<71ulAiY<^{bO+V(~!gnZv+3-0Q@lU&jY`L z1oN^%eRSoy-S@a&jw^4f~;r*kk@Y=*^V?B*)3}lSugH_%qh*exoatW zA+rND=*T6$48au78z8q6a_=WVgp2ac?Fq&6=AQO}IJ_6~e-3$rf$X4pdi+Tig+pQ}%Q~&$C(Z=$_BZKM@ zwEK_z<)e>Lx;tnXcg)Vsor`<$Zj7KNBYX$&1Hkdqxd<--xE?r-GyQ84H;*7*_reBA zdFjaGsyC9G%_& zz6%{EE=WgB==hHVbRn_(pUQx${N%ExxpB`EMuPX;ta1@BNgO#8!bMr#R<z9HiI zfq)L;X$vN&=78UZdl}F3eEY$yZ$FrX(*p=A^B)#cepf+i-I|93VUdmm!Wt!4x~I|~ zYKwd57Si$1038(HACc=(bsQ8rzBfR}o1x=#a6Nim^h%-QF9zs%1UlZiARRwHMDOy* z03B;jM!8y$j!z059~q!y7j$f1kdCU*acF>!cSFYu7Np~4LdUKFI=%}X&yed;dHI3J z&le8Rkvs)9>;>ugBcbE6fQ~G}ejY0Ju{Xh9!tG!0Sg>o~TYjmuwsadR@_RA-ZaX+P zcLLSPu<3;OeMYvPUBC3shvE0-i2KvH_sdaoS1*Bq+M`3#?hO(J-E6v zwjuANZx{UC4u7Xo`te2ebd~V8VC+a^=+JulJnDyHgd&W-1IM$ZlIooYps#)y$3PJv z;wQ$J+t79XXW!0-E<@r;$Zfl0ZthZ&!$sIHf&D(PD+MCsec}sX2L!f(G5R51P6z&i zJA22&mv+WM^uAl*em>lL$2k3B= zqW4+{tOP7a2nJ0R=%BQ5fd2>JW5lm$moHhf@|?StpGP0J&Of~J(D5U`rf*wxk)9Id z_r9(BeuPir-y?{}yMAvW<-I~uYYsz4Zy$(stcC76TtVki+JiHMj(-a1aNunPNd7L~ z$L8`b@;QIAqOR^~%X$W46b>%(cQ*W;2(42Dh%uMwpP*Mfaw*x(U=5ER)Kz}>Nx0t&_dkOBHRM6|uden5$p0hw^Y?Hc z>$qR*I}86$!TlfLPI*)MFLc}~51jZS*ofdR>O?{+aT3s^AUk#~LR6woQ4Q$VMHP63?)It6qJ=oHW?pi@AnfKGvbuPFfQl(_u& z3qJd}|4U}W-s{@6o5bT+_}70no;?`v^-K3jvT4xobESOpH2(FULw^16r0?$EVElZS zwFrlT>gcxv;rZbPe*O3G_4vP`;lLrx&G$RZZir48TM!izV9o6)54?d?@Z#Zd%X&`guf<$ zU(EQO0lW-+Syy=?7Kf>S4?<=jfm}dl>^#3ZL=Ps7No8|p15|$3{6Y|F=ejG^u zj|lv@#FI}?;;wsr8n+bg<%cG_AnqQ)zd`Bzw;}lVfs>wfCr{!I`^}2KiNrtQm+-3? z7wb2GJ%fMC5W*85oy1)t@ie~M()DxvBRt9Y=Ly91Yy2A&pC@3vAA}!|1R8|jgNkPm z{sPETJSR_`q~H?5u8rR_7{4-rmqYY>A-ENSzY_Se#Iq89`;x^oUFQoN2hKislLV6T z=Stv%;$I5E>%i%~-todop@8hwbRA&)6O8-sds~PeS`$KgzQXdtE)6{&V*Gd3O_JKg z4dO56RRSj-|DNkdnj%2g7a0FB<5X_xdJOoW_xf%K{x2c;{}+Ov1l}n=@BZAR2+uEf zFJ|0eoNVcIoyGV;#_`EmT(4$4$vA2>ab3*#TE@vvPgjBQL;#;<{94Az=198N~Hwga)ts5t z1?`C`x<9@&5!;D`U!0!h>D4w4S!5QjgE?Zq{=S<9>eL!}v7;{1(O!1oXU}@plIBKVRuL!|YA^7nj_1N!*$e$a6 z?+n2|9a1h{7=m9FqGvh;zdi)N0XUV5cOC5K@ixZ)3*&xyd1r{84}{~!2!6a60M3^`H3Z)fg110)O_%vl7z*`_fIUXR0+RB>lOlcQAg5A@Q}W=R=I|;&#m+Z@vfu z6zxLBzgQl- zM(TgxPKgUT;P!9NmiTq&NL;MJ1^#99uPB~Pw%gnTjIQ^=&h%`IvnJUN>FfC+zwZ_f z7uAutXpIEv`5K4&QpSHy^1%09HYt$3jMGqo_*!|E#BX8zEKaw_&Xo9rjIV+G81y{4 zRpS1*W{maReu>0SV|j=1uihYWR7c|4%=m_LC4M2}|B2(jwJq@)8>PIMYYIQ7GrxDTys!Uimfy$e=Erk}@zc3I{Wyoak8p(h`7KiacNo8kVJ&3OR7{8M7{Sr=mp7Fizq(JUw z{B0a=t}gMX8Q%-uDgOk^*SSa^;_;qWOL;&3--rH_QJ?sipZ|Z!`aif+%KPzul;d*+ z<6GI|w@A;(O4M2M@_%2)`7l^N{4?Xh{Cqihr*ykEU{Clb4);AbPl^D1esd>CzLs4l z@!Nzec1q{?yN1O7lJTFB9;8FCerPcs%nu3Zr}%t+lN?|B>ELpHyL(*fFSCAHBTe<& zKCVv~P9!OwD0jd23Muc~pB=`7@n6aL|GHD8e3BKtTIgSu_+`L;zJvAr8K;9-qX0i8 z#-DSV)bkeBGrdNp!~0nOhZwK3d@x@fV*KR|spkO8zY93!tG^1=52wQ*N$Gq6mkU4L z4sp6&mzH|Oeh|?0Z!qAH{J1G`zn^(8g$w+KNs0UQ*!_%uobzE4I_RRc-&Aj}JTxhu zcZ$D>#P>MA1?%lEL7wp;QHZQmbVzcc*CSX{+jXMW&HX}CH_Xn zX)QYG*?6%X8a|Lmw{6{-*%&v_tW`$mj55z?p(|AZ)AM! z8>IY|jK2r?vtgY3{O2V8I=nw!_pg{^vmZ z_$kgm!Fv8Uq(8;y$AS2q&+TKdJU+_(iog0@`Ci}Pcs`$aqpGI@eczdB1}3U_a+UF7FRAzkWV1u>86+Cxzadr251R<3W4fhef>& zQrAj(7Ek;U*AMSx{Ttcg1`hZ3v!wi&8NZSB2lMmoz@I&WaylV-{}wlW&mcW1pRAvi zdL~%UGo1dP*e~%p#{U64QoHH5bN=sppr7;v`%Cw6d`7q)+s%6ZjN>yI$X8!v+z8;b zhXL{1x>?5OrL5emAh5Q-M>tcsfunHn4oKzn2#B&%%6z{&IaT z%YXe68P6+N|7#e}ze(bLf3-k*kWZ4FPyGD6pX8CALHUC$|3qLMadn9NcSJrPNj!)9 z$$r1|y(Eux2w~6s!fB3&~z76&tE@b(~n6G!T{;L@e_5-is zau?+5IMf@I&cX3lhRQYYU_Cqy{gnP|Ii3A_<_6%TC)kg=o#XQ>ZkO>o;`$Kbkbl`Z zlj3=^_>16ie{WdcxalDSW+ARMu)_(@$k8$}5+6``oJf*{_oDP0Ie=F+=w(oz)_`h)f z&>t_{%lL|mCPj!z4)-&RZ+9g=&iI!J$NO$!`QsV?Cd&uwpYH=FeqS5l_opl$91r59 zg#6us@4};;Zu`%b@e%uHA?$A;D^PrbUC}f_!}pyimA7d(lqFuLUo`@!D0ar@;LIf6a1+^LenpeG17#f0Fwx^!<{qw{y5b z`_*-<|N8u-ko&3li}M><&(0kZuQ7fbaLPZc0{Q2?EdS&tDZiQJKg#-p{e+Kl`UmX~ z53qbHP`~|z-#6GF-otpXpZ_rH3HD1LXFS+X_&(#oe)4_PjvzgQ_2*M8AMB@Hh5A2< z`YJeo?^i5;-8nLSeEZu6s0*@4wIT!TR}!qMo1ME_{&W!Q05srE+$@qGHuVvJaMLImQQ-g6a9skf(MbI9~fD za7wqe+@JT`i)CatKsx&`$n5&OgEN)C|c}zU6u^ z#o-ymYOUe-~uwdKKeaFP{|8Vy`~j z{W-@o*e{ymbPn2EE@C|oaQeJOXiFrn1Wxrpu-z=P{7=~aX|Vie4mW65+{^MoJIpvT z5~Y8ze|{~s%fN&Es|_6gpq=Uz&JV%*`4$fM^ou4%43iwsGdZ3?d+9T*KWN{0JL`EN zr}LSt=N{lxF4hO?flso0FkgL^@nF4o3$w77&w)e zyP3yzj9*6b&>!UYvuKwI5039fsQ&;x!T!SqTyF&JBpX6_Oca~#RvRagjTaO7{N`Od zFU{}Re%Y>k9#32Pp0;kwpL^-13%BOa*?Qjgiy%gaWTg{hn_-ZTf&hAV2=jD~gowS`!kVC#w+DA{>M7fExx$>pinVJ2Gx;Q=&xRdpx zv-P4aA~rH`|EU`aojNN+snjZMoMTwQt4w)qoPtI#HB0Ag;`A(>qn4**XZN@`Ot01O za2zh38b`+iidV;RinV$kM}LYl^a$EPPrLJ0hHhtT;vsD$@~w8MQYQg%gTHjjB;LGS z+2@t=@>DlG?!`;vuv`f4DU0Am60=gp+=q$m8TY~CF9tWu9 zYc9^X-78|BFSsplJZCv6yqkxh={}vvHyY&@bck@}1DqQ;Hnl|xg)5E#?R$o6%cB&5 z1pVa8RTttpD`jANPw+_55YH*;-g!3Vvp9=X2v`yTyEATUH>t2Cf|J@hkdvTu(DHPo zXG`9;aAqk|tk7!Zi?gkEeI_pxEKku%lyOe5h`mn;Ub908-k;oyOpsT?O9&5rz}{x1 z?e!uctyY|A&>Q2f>eVQ9kZ&u6q9Byc63#aTxUVtQ56#M>lgG`B0T$sOXU*kt4jXdN zOiQG5rG?Wt_rrI)h>VDP(o}AGo=`X=4i(PB-^@5NX{(K+-5OY%CGlR7DxIl|bKyW} z$=jC@M+(AyWy5FK+@DI!}m{98KMRUCF#s&3@dA|Z!2MA0M< zl_{L8S*gpI(BYXlwl9xU7R9@gcAT0Db*#Hgfgn8^r~oL3$*0*0Wsy7)Rs<1wIu|+7 zDm1AUfbf)Xrc{)75Th7L$5NY4hGbn`73E^BP34t*N%i8?WFV*%ky^kJSv=-(+A~!M zco9l;QAQAH8D)~HR%DHVnmAt+rKCXKx=(pJ$(GdOki`m-O3{~hCWE{8_19Emj(3t}Mzk`4-1nT6^iX zT1P%a?McZ-&oX!P060gnJ>%|c;{-}kvdfL0r}7MCqlRhZ1;^q(&G%(cLzSZ+KeSoh z3MlO)$X(Fet(7u~a=AL&n(nQ0eD6+ggJK%J?`oQ&Zj-5(>3wfA+mo)jUJaJf^<&v+ zpE|Ly(r8>M?!B=Pk?jR=vN_I;#_QpxDesU#-8(=yI}YwB%5)k!?x^618`LZ=W#}0k zb}Y)>J_3--sOCY)beeT5?ckwICx25hk~aeDBuHeQ$mZSBb!ZRrjk-wQ zCQkhn?V@B|kcdjHjN`e<9i{3zQKeTYEC5vZkQTJewMrgsr@KE-M=19Jh%jo9yl6A~ zWYBI>JKBf!0KUI|F&{l|JIXpLU=NyQqvF?H0N{vohp(a!A2P^D+LKU{F*RPE^)o#i;30{4}N_XSWqH7)M*rD`6{5h5WPBXM|bKELb2&3V74 zNnukDq*G?3GEt6jD>}(6E8nEUO$mJ|DD3H!b-i}WWEblTqMr%Mcz#n(ZMSG8MRHOm zhl*0Gp6By$J22V+zhy18!4qB;#{u~jqt=hViZ5=go*^m$usey(w2BP_X(;?=rEyS&AW7ly`NX$x4&c6_1aZF z-Ne1n!L?J6P`8Rhprw4LGloa>kt#TuH<90p7P;dG?EwZYduV6^8Cjp?TdpX@A`7CO zm%2KwrhJqQQXq#Qo1qWE0+fSrOD`TM4@k;Jv9TYH+%Y6psNV1yk!4Y~uTmRzBXH+7 z8lq~$Eg=|!d2VgCfk%`yI?KEF5O;@ z1VmMjQA}T#9$i|Id1X5g)RZrI7;kjzGr)CwbE>hDy+P_r!l>sdhqDX z`aWq$K?g%mVFZl^Y!44!^EhF?NuxzSrac|VzIUB+8{9Y`=6%B)gn+nrDoXi?cC&A& z1ysIOx0yzAqf~K5rV-A7k!{DDXwOB28q*~z$TG;js*#%(QU3`6*~O>yq|QHg@8B14 z?KE#vQ1nUQGFucCL_c}Nm@J(fS?Y6{>IZqteLH@Tqd+`xLrHm42G5z(s|~7|VE~amc=(iK>z+vAt!YRDCz0+m zfx)0(6kz5+?x3XeZ69c?U{m7sr1FghOq4sJMhh>x zslH^&#qg~+RS_k>m)aqQ>HrK@YhKl(SW7C|#3Q4C(t%9XmwCGxQp$IF26#0;bOZ)( z-H{~*iDHZ=!hq37Dn~6s`A9wlh87IUidk5Ae3OrK0pqO(Rd^y9W#1i7#o4CpC?N)v z*klP4uiKce&Eg%q!y^cbVPtRSkS`>Lb3UQnGMa~Zr{y64t|_UoVPGt@!yG93+P<$& zno!Lz8R>5@WUmIV-rEd_1`hF}q?2O|dOr;3Nke|G3wDtu_E1AQpnl|0v8{Tw zf>cLzW%~IRF({S%h}bjhJmwTVRk+GAwMarKE=(P`B^u$SQx&ivy|5GnF=TqegUsN_ zVt!|xWx3Cb%AuQ;C`RxpJ>p)B!TOpfjEJbu)jJ@jFpxStNZ;%3_B!b!UJ(k5lt~if zt^G3?0pqvbl)uydo#1yIMW>w@7hV1FW?f{}ac?>=jJS#MHmbkGxG>2k#)bVCKV-5P zmkuzAf-bgsFXrck@Jye0dHN^5e@sesuyfOe&kcPS$@X3^!9%bAB>PXY|I1sw()5j` z|Dx|xz5ZtpO$ve8LsAZA_`Zu|d#{anAZ)}3-!>`l-X?zz`V&FeJ;}fRPYO4^{{4N1 z4t_&QOuxvNl)wJ>Js+j-l7ubi2?qW?OHa%VmiOl&`2M%zhQeRYK+u0My@KKI2>AE+ zb9$P?Kbrr`0{*+-zhp}9>m;mb?B%eT=?u``q~${r>6sQgW&n#C_0zz*#>AQUF%_v(Pxz8*x;20p0$iVH!pT)=@)V z!CyiXrh^UOGLDnRXDq|COnf6sniRRKd@YK8G3axfh|*%!2VZWn`j*H)^WWaDFuVx- zQp2;Wa$}W(xCV zb^Wi96JNFDe;;PGs~Z3e&%b43f}!T$CrRNi^N(4&>bigt__s2ee}$}fRSW(x(->d9 zm0c0|H?jIgmw#o9bQSyji>U@(IM%xe{Np>2=08>vLX-*q+wF$J;vZ%Fmr3jXe+Xmo z!h(NH5sX)BzqaAaKkR?n{@#0v2$H@i9XA$7C?ge~c7_s$%{z zXFXJ8(GF4g$0BT9{uiC{M_0i7i?sr@Mo7gqJpZaVRT0voSMpz~@5P!bRaXT5Og<%dPCx|ywf!%^ld4C_KUVfDyoTo=>p!&pM}s-6V@N=JWD%0G5w*6aUNQQoIl@{fJq)O`9AVMQtbdi>u%C;6{=l__;gKqByO>GeN@`HCBr{5P?IvpNG%1paLt zJf`daxXB)%kNKais-r(b{}20r>hb>ow&I5*|Lxftc8rf-yVMw={HJvPPZb;edWrwt z1sr;aQx5xG;(Lm~zhmn8U-1!e1Wkf}99MP(kwrTV&%c?{_Mb&3`+^ks{2ycAf31uz z{|n-8u|hrk(@_mduHnnSWn;T|-Tzm@M!!b~_HQKnA5H?${P#1Z=85>Px;Q~j z;Wd2u*YkfB($S|{@bBR;B!yQL{`LGHg@p8|7W~tRY6`C?{Oj`{6cW;-n)#pIhYv2Q zuHpH&%#`l`tD>V%Z-;-J%%|###J}$UtD>V%Z-@V;x(PrL__y`??>?H8JqZ34uKlKn z56?g5f9mqDjPqW_g8#Z(D%WEUKpUlHT|YMFnP+rLNX|5=va z|E-@VRZq-+Q{@pr!XulN5{MR}iI$v?LLRJa991paM({#zeS${qy&N>6`?H2!yV z|4$j^eTpUj*Y{y@KMY^~G5uHD|Kp}%pgzgJ!o|M`H4^{2{U69z+@RoJ>DT{A{9F3` zr?{COtWWaqw%ZD;fZ@wOzW-|b|6symMkW7BxBrS#|7UdhkD2HYb&~&jIm9^@c=+Pj$^UGt5Lv^~ zJr2*mnaSwyKSxj47$gM$2a2xB1pra_*Y^Jy$X$R6$^VSI0MW=I5%|~pKSxgO;XF$I z>&oW-P;8>`ujhXb$757!;(x~7?UlSe%B+CH^KUthp8pe-(xLqM{LfToj;Z}0Y;FG^ zipQwJl7E%6zarKDj;Z(mj7sTH{sjM}RBLu-C~rdvN2vb|z5nM>NgP>N^6%}5tY85i zhv#4K|FVE&jYUN8@3p34Q5K>^^B-zn6~x-KC1c=^s(-KN-FLZ%OD+i1NR?RBx4)nSUbiZ|U>DmWF=j-?J3b zABBHI@Bh3s89u%I-V- z&s1uaeQJVFD_%^SDw02>$D(N==~wAOioEKL0}n+w*lY|BYt7a7@krO6mE3^T|?xNdBA3xTh!& zU;eTFPq+UH*q*Oa@;|F?^Up~9TZZO;K36J`4*!jMMO7vkzWm!pTJQg&g6?@b1^Ar8+!_J7dxf97$e0ucPGT>KY_f78No1p53h6@&+L3jUSO{*6-p!N2bR1(;Iv zNc_|0uN8$mfJCYP4L$x-LwG=|?{mcDEOc8 z+Q-`YPqw!I3??jQRPbM)R(SeHB>P`R&;N^==n!?1|7v|o;R#^F*Z)}mr{{l#FcvQ? z_{Z!Yl|#Vc`8P9q{ZG6+hiMc1w_y5F*Z~-xe~kb1`LAJ=#fnS*tM&SBbzOi6{HILa z|BIF9FlB=Ow%P;0hUec*>-Im4v3PO8|LpE#&Hkh3f5uC5s5atX>Eb_x9HIPMdi_r* zWwAO4{u^FxkHR@%!}E{%e|r6QtUQM)BmNt1v#oLgNCf`Vj_&`5Q5GvM`B%C6H%k4F z^`CnEZ>&6rDP#VX&HbTphcExI|LFPuVU)#+Oa9x%=~%V)D~rOv-v6UN4OKk}{->Ir z!sXx5%D=Y%tD?M5ui(E@QhESnr1G!Z|302nJxKm*$J+kiX+xKPRh0MX_4!Ztq47RM zDF5lS9{;K}UIaF7N|F*g_fFtmqvNZppoW#U_{UBmLJpZPn*Z(Re zp4Bt|icWr#fkfaxt@r;}I{uq(rR2`G>&;m;y@28Qw=Mnse+l_7xyRi6Pd)!{Df#!5 z*?#CPhA;ov|6kkxmm~vF```53k~@t*ib5Qoe=DWee<&g&pw{QVTB+?0IK}oDfq%!= z^M7JX|05~#`N#CHa;2)q2rxYVw(02kKS!c1HaF(K+Hl*-mVgY;KeqqW?SE_>A4!qq zzo2aHAB7!(e^c9kj>KAgZj%3Uy*X2vQB(Uz;y-Qc`Ty~ed<0FB|C#z8Z)0oPQ!@>8 z`0{V-{U46NS)5Li|C-VrfQRSbGWGnAI9U$YCHZf8il+XHfQRQF>%aB>U*V+1=)(M0 z4ybDU5!d1Q*ZV)jNbwO>G5@p5I)735*WA6Fx&>q;{&o3ZEVT>r zFZi#|9%J)AaQ?gIe?j~$R!H#QP}>2BQ2rhL{eQ8{F3dmkZxtJr`oeq+FEu>>mYvb- z|A$ZL2tEY=?c!cn;TGUg_}BBlB9Ixui{O8@wy{#HC^G>^;NQ{q{|ID8@Z$4NdqAsN z1{i_=l&=3HkQu=X^I!G$c*?c_io(C4=YK_Db9gVze@mqWI0FBMrR_h%lNrHBhku18 zzzF=OEM5L1usOUJ!N1bge^I{wnwCEQb9gSJ_#pmU#b%|UtoI*wnwU=YK9BVPg;x{Clcae#r<9&%f!I+Wr>$O&0(elp-^Z#r^pZ`59lhNdv|FYX|H=}7dx~~Z3Kc(%zM^D!{Bz*qsHFXAn z2>jc6|ED-4hiPJTA!jWKpYz9>xjU=Vd?(= z{Df41F#nBaMco&`;rX|0J^oif_5hX4f6HrDTvZ032>hpQZT}mw94URu*0q{`LO9%IN4* zEctILodGsH|2Y3y&;Re^N!5eoe^%k?e^J_hGp*PEsbaieui(Fmum7&P2|&Y_f6V{W z{l9*q6g^4)J+GliKdBv_f7JiF|EG|Vu4=*mj5kws)#ZTU`N!~2xBp#|6y6E`>*aQ} zGNWt*fC&7jwf$Ei={>3?|4nt1zYx~&{F`Z8pa0&&lDb>Lf1|3b>{HAm@SoB9Kd9rp zSF_;1Rm~Tx6;IU^(Bb*F4MUgzUYeBM3;tmNZ*Oe1>y3>i*PE%weG2IC{5$&lpEAb# z6*K?GT>G!rfA;gF>Phn7tkk9yP5wp1hcEw@t?mD+81L6B`ERTH_!EhLGp+4^{XD69 z68z7q(k}H5U;eTGi|+raC55$1{;~X{5_hk!8~x$=w{QTMp8wHJL3MYMe|2;JDCWcS zZ#sJaA9bAfY8L#fTlyn{ion06=l}Gwr0!nwUsM+WG)Lgy(d$2yQqoZ_`A7SIjIICC z`~P<+QhFo#ukThFNQCmA*6aUOGSby8_}}X`>Sc9Pz=r4Fvi1D0E=MZwI{d2}{zYj2 zvHzzY|Er|Eqg(P{X&0yS&3awUXMo|$zipX%|Gy4LDsKe;`)f)E0K@ZdruF{cDp~L9 zmi)JhZB?5;AgJN_w@khNZDrxWNCjK$^zw@l(W_bRw|FiD@ zsi0z>PRYNzy`L$-2>hq?`497`QUXZ+m2Leg;v9j0$JXb+D&ae*RPx{2-SX6o{V2TQ z`N#KP&3}+8CC`F?watG7{;~g$=3fclL8X%aMr+Tp_Weh%{|r*4sQ2$$c|3|g7ceHo;SJwaxU;Zsyum9;#r1VDe-%{84N9>2^ zANGH3|53`juUzn7ZmV1TAC-T-{@95bfy4pWd`OoO@KT2uuC>Q)!W|R&9qSXI} z9{+bZQhDR^U!PUi1sI-xtpC&etE9c7Tkv03+Wbf9|2dA{|GUGH${Wf5th&wL5c%QD zznRhJKdEHBt6T7|_VZs9{`LM}U5b?6N&elU*F+CMQ7>@#@{jXB_4rRI@4oVW{?k4j z>u&`9O+$bGiIsyeWs?6{MI~Q`Iz0c{{ujnq+&J@JE4r#`|0w-G%hCIP#?AC#eS&{= zTmOhaBb0wDqsRY)35yvO{HxvmCrba{N$dSTVrF`lou-@Bb4!)dLkW|Few}48V%=!0`3IZR`D?2htTgDEKc;7aI!K01nT;Wt!Ul z8#~v76n6Pn^X-?yjKIHz1G)A2--8H?8SC(`Z~}M){!QKgkD2HYb&~&MZ~d=6|2c%P zm|?-cw@2C8UliRauXn0Y<3*9X z=ihSl`Hw1D@9LKPS1UDzCqP8t-*oi+zb;7%@0kAsGp@QoqVTWBf9m+?)hzjMO}ouw zYyPMH{@2Trx_in0z60t)h+_Z2_V3#Muac6EZpr_Fipm`TBGmteF8>{hl->yb8*QaK zz(nBR)ZhP=(%w-n_-}blWrIJ26oG%k(DVO09I3pK{8v3sVFM6>e;fdzzyGV`-PbMn zpDlUCdP&&;AOio6=HF*X?XTqDs~v0n>+}EA^6qOV{`VB?wQ^<3hhqPYQ2woqUjG?8 z4}%m6{wsrA;=_jL-?Y+t{%3py96^)dzgjOUH2+8F|6~6*&HoWti_b~$U#}{i0Wy5~ z$Nukn{1+d|N6&Nh98SaYZ|eE~aU}c#bO`?4snBRl6Y;;#ZB89?{Oj_si1B{4g8zNW zmi~#rhOhsz{6l~L?I%jnli*+J?C(h9KmGkj5#K?zl7F235Oj#~IYRl@?SG8vemRB7Yy0n!NQ=>p_&=bw_(!q-ruFy#7)d^YD#^dnLiV53Ky5LDv#qw{`~;@`0Z{}#r7nt%0~fcT%n*`ErR{|G+QIM69rMEKcoFxivJzmdrp4h(--{D~`( zTy&XSNb>!bm;YwH-k#VuVN9$px!z2@hI?~jHF^cOu_jix_P20jPpo!JGq`akR=3;x zag&04rL`M(>50|V27WUWt7qIw6?fT*)w^dr63N`(jy{RZ+K0& zU2oDO;xgNwp;$R^X;f#Y(9F>jB8%$2T*iG0uT1lv=@ze5^V(7-3)Qoi z+^wu1IDG%#Oqprj|67U-)XRURys=c@TN^LMoD+uU-?nM~x9wHyECOE0fmtKlS7z1gifVZmYFd z;S`XgjsH@X6SV(WwEu&)|ESLb9s7^8&rF;pfV1ecP;0u^CS*>qf#|H+R`aYDS%`#G z*{!y`j={*9@Ev+xeJheZL3d}7p{2)fYk#c>^NJ(PE#iS3r35{8?Mm4RVPZOKkBb;I z>hz2{KM8GtN%_tFrfTfrtbeAfwUN%h=15?)DX|{?Bjp_I55D! znE##D-+yByS*y}1pi@AnzS*lIO#r@*4i|8=c;?I@8t zTKUgl%}1d8r|A60CCQn;`2TezP_MP!O3iEL<=Hi36K@#XhPlghjsbi@VoMzcjav8la;)i+E}PnI zw>W)SyHu%-O^9hj8^$^q)}ze_y(YY}FD z+0uwk0i6QBEh&(73$9Zz3K`qUWz&Y6c8j)`&Y2~$1z8#Dt>I&w>!wUQYucV$HZpda zq-__QG&&ho_8&uk|6h_UxM=>>*niSCzW?g}pZYAI?LX?%_*f2M(dB>f_8-e~=GlK} z8z5c&mmuS?{b#Y+px6FW&e%oR@|~2Cv0S_8l`PlG87cHGvZ;arC(}r|W(r6A7-ctW zmc4@KIz_jbc2l-%yO}=wkA<0l8x4D-W$&_#2`7s^e8$mJNkLto9SBB`5|q0xG-ln5 znRA_tQ!Ztkl$%SJGlc>^Efvz4Y`ScE>8z1Uxkb;gOQx4e6;lX3lP><|nU$^@yLi*C zZLbn5^28=Sye^L>b;@V4kj|guIUxiE)LFkb_IkEUT{Xsw{*VkCDJ^Dp*XpHYxl*og zG?NXI^Nm(mFJ`6E6GgC>Dq5vdDO<90Wh-Tsa$YXunx5^YGEND_+A5nV5402t_{ArQ`+#9ouanl&LB(pf;`WQD8#>;1G`Zt0! zw^^L7w7p_`wn-LIcczqfK-iFW%q6HQ|6K;L*ot43{a3I5T$=1A>vy$b;ls`m_kWvb z|Ht(I6vqE)wb7E=wf%P~Qdx(gQ$VM{F_;2552Gp1@(O0o$zpM~X~7zdksCh8r_8Kv zmOr5ze+U7wU7yp*qJi1e*j$$f1f^lTJ(!$Q!nAddG8+xW*`TC69F3X&-(%4LU zJeAIv_}|J3p4_x$3(QAVZ=&GjsMSd2EXPQj*|O!9 zT(m3cl%4V1LJ?mP9XD0*%v8y+FlP*o>1+uN5OxhHnO4q8R%*$!l4Cb+I9lv7*f$b8 z$lJ~WVwc=};g;l8SC6%(uO53n>bW;2aVw41Zu;NW0~G%ebe+|G`hX(UH3 zvw*-lNs%h%%Gp91HZsg{F-mwWhkO zQZAP(J6TGK@vx-m+DNVOG``NJjvTk*^b8DqFw_c`yYAw03)uS}onZ9(?h&$up%E?*MY#fqvp}#xlC^_vmOLB75 zQMISWt&Ev+jMR~0FD3RkI8F6S#HxLt(;C#=U- zE^B8jEIdg&C=yvGV>wt;f|&*7a;}I82`K%TIBMpQkF%IIS}u9`h~QwhXvxeLN@f{a zS(EEpcEN%@-z;W}X**|Tu!y8&d!}ipt!&9F!rY%pXI;<8mdg$*9;<8@$_2aZx@M-F z$tlrfq|;?symO|T&ZSY!VUBCDSWf30MzY=~w`*;EemYqO4*LMoZ)kGm?3=wuDM zTy#yh=k0Q?Th0{AWv^@&(4ohP9K}M~L$-yEvY9naCzUl*sEG?jyHG?I-^+Qh!xUVs z#z>)-?#9V7iv+G+ZZFLMh6ovW98n4RHckNO;-=l`fr<6}95MVJ4@+yBt> znP>lVa15X>|4Wc@c>d2~vjO^Ho%LUsIE-Fj+D31}DcBjO=y_Qu>*Y+-wP_e@XVU27 zQ&+!$UMMWR=o#m12R#Y{lXn91fAsn_F{14s!tFHjM z<_>jX9cBF==*RhQHcp7e!Y^B%|AzSjntyeSbTt$IN%JLLK;P*U&?%r(K&QZOMGAOD z7q(g0ObvV-@v`YmDOXD2LtHssgiYP^Qg*q3ZaK{bDW=PADrXc51rML4GLGpL(>W#f zKST&eLhJpXmLLZ%ntvtsKN$D*{x3_wej=gme@l|g$7~>rF8@mGe>6ElkN=h;)3E(- zvDu*4{+OK<=4&;7tTFP&?E z{ZH@zumtQU659T^B*}ct2GX75s4j~A_WwcUAN7Bq{oleI-bB(|ipoi^|5Hc2)~r)N zr@%3t0%hCAa=&b}&h)(xmdS8_J@~zZ&~578hvy&r;+X zw*M|R8}!$6)^*wEsU=y6N)26y?8fHL9Wjv0iwH{hw0U|KCjE zNT{T(C_a5^cagk zntw(1A3Fa>um4#%k5MJ{{J*Fv_wU2sqRYP$`wxx_)8&6jGMI1wS^S>;o%O$qH7RKO z&r;fd7D>D+`;VdL|1C-R@82y9@hSorupBFn&|Xvjnn=^6Ir$Wr$2r5lTHDh z0>^9$%(%5m*=w~IvX6Jvm*}7W=~t1RUo(yUzdKXGsS3r3lcw(fM@{ab{9(u6&Gni% z8fh$+z2MP%ztn5gcezt?x6iiM^y;l*z2R*vSN72%KN~A__&J_%xHD}Ox^bqmZ=&pB z&-t>04Ii<4CytBG7OhOGY?|z(Ef48o^u^4uEiacYWy;t!nRfBShN%VYk(n;J1#Fp0XSbFM zw8bShSu%13Z0d+zNUZ{PRyNEcZ8zMfY_ZF>`jjnp4nUu>#SSR@mBlvT0h{rio`mg3 zU%z^&k{ge36J@nk!S3G`uN9BR`C5)r{~Oo>I9UIuY5l*p|ISa#xRE!EwH8)G)3(lw huB0axU1G*=yz&1=F^N0bwLYB!It6qJ{9jLj{~wLLVOjtH literal 0 HcmV?d00001 diff --git a/syft/source/file_metadata_test.go b/syft/source/file_metadata_test.go deleted file mode 100644 index 4092e4374..000000000 --- a/syft/source/file_metadata_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package source - -import ( - "os" - "testing" - - "github.com/anchore/stereoscope/pkg/file" - "github.com/anchore/stereoscope/pkg/imagetest" - "github.com/stretchr/testify/assert" -) - -func TestFileMetadataFetch(t *testing.T) { - img := imagetest.GetFixtureImage(t, "docker-archive", "image-file-type-mix") - - tests := []struct { - path string - exists bool - expected FileMetadata - err bool - }{ - { - path: "/file-1.txt", - exists: true, - expected: FileMetadata{ - Mode: 0644, - Type: "regularFile", - UserID: 1, - GroupID: 2, - }, - }, - { - path: "/hardlink-1", - exists: true, - expected: FileMetadata{ - Mode: 0644, - Type: "hardLink", - UserID: 1, - GroupID: 2, - }, - }, - { - path: "/symlink-1", - exists: true, - expected: FileMetadata{ - Mode: 0777 | os.ModeSymlink, - Type: "symbolicLink", - UserID: 0, - GroupID: 0, - }, - }, - { - path: "/char-device-1", - exists: true, - expected: FileMetadata{ - Mode: 0644 | os.ModeDevice | os.ModeCharDevice, - Type: "characterDevice", - UserID: 0, - GroupID: 0, - }, - }, - { - path: "/block-device-1", - exists: true, - expected: FileMetadata{ - Mode: 0644 | os.ModeDevice, - Type: "blockDevice", - UserID: 0, - GroupID: 0, - }, - }, - { - path: "/fifo-1", - exists: true, - expected: FileMetadata{ - Mode: 0644 | os.ModeNamedPipe, - Type: "fifoNode", - UserID: 0, - GroupID: 0, - }, - }, - { - path: "/bin", - exists: true, - expected: FileMetadata{ - Mode: 0755 | os.ModeDir, - Type: "directory", - UserID: 0, - GroupID: 0, - }, - }, - } - - for _, test := range tests { - t.Run(test.path, func(t *testing.T) { - exists, ref, err := img.SquashedTree().File(file.Path(test.path)) - if err != nil { - t.Fatalf("unable to get file: %+v", err) - } - - if exists && !test.exists { - t.Fatalf("file=%q exists but shouldn't", test.path) - } else if !exists && test.exists { - t.Fatalf("file=%q does not exist but should", test.path) - } else if !exists && !test.exists { - return - } - - actual, err := fileMetadataByLocation(img, NewLocationFromImage(test.path, *ref, img)) - if err != nil && !test.err { - t.Fatalf("could not fetch (but should have been able to): %+v", err) - } else if err == nil && test.err { - t.Fatalf("expected fetch error but did not get one") - } else if test.err && err != nil { - return - } - - assert.Equal(t, test.expected, actual, "file metadata mismatch") - - }) - } - -} diff --git a/syft/source/test-fixtures/image-file-type-mix/Dockerfile b/syft/source/test-fixtures/image-file-type-mix/Dockerfile deleted file mode 100644 index 218e369d0..000000000 --- a/syft/source/test-fixtures/image-file-type-mix/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM busybox:latest - -ADD file-1.txt . -RUN chmod 644 file-1.txt -RUN chown 1:2 file-1.txt -RUN ln -s file-1.txt symlink-1 -RUN ln file-1.txt hardlink-1 -RUN mknod char-device-1 c 89 1 -RUN mknod block-device-1 b 0 1 -RUN mknod fifo-1 p \ No newline at end of file diff --git a/syft/source/test-fixtures/image-file-type-mix/file-1.txt b/syft/source/test-fixtures/image-file-type-mix/file-1.txt deleted file mode 100644 index d86db8155..000000000 --- a/syft/source/test-fixtures/image-file-type-mix/file-1.txt +++ /dev/null @@ -1 +0,0 @@ -file 1! \ No newline at end of file

    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%0DWYjKLxFIKjmRK42UY0vuMHn?9t_0)ZP$w<4Pu=b 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