diff --git a/.bouncer.yaml b/.bouncer.yaml index b9fd46b12..af6e762a5 100644 --- a/.bouncer.yaml +++ b/.bouncer.yaml @@ -2,4 +2,5 @@ permit: - BSD.* - MIT.* - Apache.* - - MPL.* \ No newline at end of file + - MPL.* + - ISC \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index 1029bd935..6c3406f20 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -102,18 +102,19 @@ jobs: - restore_cache: keys: - - integration-test-tar-cache-{{ checksum "integration/test-fixtures/tar-cache.fingerprint" }} + - integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }} - run: name: run integration tests command: make integration - save_cache: - key: integration-test-tar-cache-{{ checksum "integration/test-fixtures/tar-cache.fingerprint" }} + key: integration-test-tar-cache-{{ checksum "test/integration/test-fixtures/tar-cache.fingerprint" }} paths: - - "integration/test-fixtures/tar-cache" + - "test/integration/test-fixtures/tar-cache" workflows: - "Static Analysis & All Tests": + # Note: changing this workflow name requires making the same update in the .github/workflows/release.yaml pipeline + "Static Analysis + Unit + Integration": jobs: - run-static-analysis: name: "Static Analysis" diff --git a/.github/workflows/acceptance-test.yaml b/.github/workflows/acceptance-test.yaml new file mode 100644 index 000000000..796d85c4d --- /dev/null +++ b/.github/workflows/acceptance-test.yaml @@ -0,0 +1,83 @@ +name: 'Acceptance' +on: + push: + # ... only act on pushes to master + branches: + - master + # ... do not act on release tags + tags-ignore: + - v* +env: + GO_VERSION: "1.14.x" +jobs: + Build-Snapshot-Artifacts: + runs-on: ubuntu-latest + steps: + + # TODO: remove me after release + - name: Configure git for private modules + env: + TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }} + run: git config --global url."https://anchore:${TOKEN}@github.com".insteadOf "https://github.com" + + - 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 + with: + path: | + ~/go/pkg/mod + ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('Makefile') }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('Makefile') }}- + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: Bootstrap dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: make ci-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: + needs: [ Build-Snapshot-Artifacts ] + runs-on: ubuntu-latest + 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: + 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 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..9109c86e4 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,101 @@ +name: 'Release' +on: + push: + # take no actions on push... + branches-ignore: + - '**' + # ... only act on release tags + tags: + - 'v*' +env: + GO_VERSION: "1.14.x" +jobs: + wait-for-checks: + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v2 + + # we don't want to release commits that have been pushed and tagged, but not necessarily merged onto master + - name: Ensure tagged commit is on master + run: | + echo "Tag: ${GITHUB_REF##*/}" + git fetch origin master + git merge-base --is-ancestor ${GITHUB_REF##*/} origin/master && echo "${GITHUB_REF##*/} is a commit on master!" + + - name: Check static anaylysis, unit, and integration test results + uses: fountainhead/action-wait-for-check@v1 + id: sa-unit-int + with: + token: ${{ secrets.GITHUB_TOKEN }} + # This check name is defined as the circle-ci workflow name (in .circleci/config.yaml) + checkName: "Static Analysis + Unit + Integration" + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Check acceptance test results (linux) + uses: fountainhead/action-wait-for-check@v1 + 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) + checkName: "Acceptance-Linux" + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Check acceptance test results (mac) + uses: fountainhead/action-wait-for-check@v1 + 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) + checkName: "Acceptance-Mac" + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Quality gate + if: steps.sa-unit-int.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success' + run: | + echo "Static/Unit/Integration Status: ${{ steps.sa-unit-int.outputs.conclusion }}" + echo "Acceptance Test (Linux) Status: ${{ steps.acceptance-linux.outputs.conclusion }}" + echo "Acceptance Test (Mac) Status: ${{ steps.acceptance-mac.outputs.conclusion }}" + false + + release: + runs-on: ubuntu-latest + steps: + + # TODO: remove me after release + - name: Configure git for private modules + env: + TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }} + run: git config --global url."https://anchore:${TOKEN}@github.com".insteadOf "https://github.com" + + - 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 + with: + path: | + ~/go/pkg/mod + ${{ github.workspace }}/.tmp + key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('Makefile') }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('Makefile') }}- + ${{ runner.os }}-go-${{ env.GO_VERSION }}- + + - name: Bootstrap dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: make ci-bootstrap + + - name: Build snapshot artifacts + run: make release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/upload-artifact@v2 + with: + name: artifacts + path: dist \ No newline at end of file diff --git a/.gitignore b/.gitignore index bd5111c63..11203f625 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/dist +/snapshot .server/ .vscode/ *.tar diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 000000000..f8010cd7c --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,44 @@ +builds: + - binary: imgbom + env: + - CGO_ENABLED=0 + goos: + # windows not supported yet (due to jotframe) + # - windows + - linux + - darwin + goarch: + - amd64 + # Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build) + mod_timestamp: '{{ .CommitTimestamp }}' + ldflags: | + -w + -s + -extldflags '-static' + -X github.com/anchore/imgbom/internal/version.version={{.Version}} + -X github.com/anchore/imgbom/internal/version.gitCommit={{.Commit}} + -X github.com/anchore/imgbom/internal/version.buildDate={{.Date}} + -X github.com/anchore/imgbom/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}} + +nfpms: + - license: "Apache 2.0" + maintainer: "Anchore, Inc" + homepage: &website "https://github.com/anchore/imgbom" + description: &description "A tool that generates a Software Bill Of Materials (SBOM) from container images and filesystems" + formats: + - rpm + - deb + +brews: + - tap: + owner: anchore + name: homebrew-imgbom + homepage: *website + description: *description + +archives: + - format: tar.gz + format_overrides: + - goos: windows + format: zip + diff --git a/Makefile b/Makefile index 8faeb333a..1ce9b8f5f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,11 @@ +BIN = imgbom TEMPDIR = ./.tmp RESULTSDIR = $(TEMPDIR)/results COVER_REPORT = $(RESULTSDIR)/cover.report COVER_TOTAL = $(RESULTSDIR)/cover.total -LICENSES_REPORT = $(RESULTSDIR)/licenses.json LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --config .golangci.yaml +ACC_TEST_IMAGE = centos:8.2.2004 +ACC_DIR = ./test/acceptance BOLD := $(shell tput -T linux bold) PURPLE := $(shell tput -T linux setaf 5) GREEN := $(shell tput -T linux setaf 2) @@ -15,57 +17,94 @@ SUCCESS := $(BOLD)$(GREEN) # the quality gate lower threshold for unit test total % coverage (by function statements) COVERAGE_THRESHOLD := 72 +## Build variables +DISTDIR=./dist +SNAPSHOTDIR=./snapshot +GITTREESTATE=$(if $(shell git status --porcelain),dirty,clean) + +ifeq "$(strip $(VERSION))" "" + override VERSION = $(shell git describe --always --tags --dirty) +endif + +## Variable assertions + ifndef TEMPDIR - $(error TEMPDIR is not set) + $(error TEMPDIR is not set) +endif + +ifndef RESULTSDIR + $(error RESULTSDIR is not set) +endif + +ifndef ACC_DIR + $(error ACC_DIR is not set) +endif + +ifndef DISTDIR + $(error DISTDIR is not set) +endif + +ifndef SNAPSHOTDIR + $(error SNAPSHOTDIR is not set) endif define title @printf '$(TITLE)$(1)$(RESET)\n' endef -.PHONY: all bootstrap lint lint-fix unit coverage integration check-pipeline clear-cache help test compare +## Tasks -all: lint test ## Run all checks (linting, unit tests, and integration tests) +.PHONY: all +all: clean lint check-licenses test ## Run all linux-based checks (linting, license check, unit, integration, and linux acceptance tests) @printf '$(SUCCESS)All checks pass!$(RESET)\n' +.PHONY: compare compare: - @cd comparison && make + @cd test/inline-compare && make -test: unit integration ## Run all tests (currently unit & integration) +.PHONY: test +test: unit integration acceptance-linux ## Run all tests (currently unit, integration, and linux acceptance tests ) +.PHONY: help help: @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}' -ci-bootstrap: ci-lib-dependencies bootstrap +.PHONY: ci-bootstrap +ci-bootstrap: bootstrap sudo apt install -y bc -ci-lib-dependencies: - # libdb5.3-dev and libssl-dev are required for Berkeley DB C bindings for RPM DB support - sudo apt install -y libdb5.3-dev libssl-dev - -bootstrap: ## Download and install all project dependencies (+ prep tooling in the ./tmp dir) - $(call title,Downloading dependencies) +.PHONY: boostrap +bootstrap: ## Download and install all go dependencies (+ prep tooling in the ./tmp dir) + $(call title,Boostrapping dependencies) + @pwd # prep temp dirs mkdir -p $(TEMPDIR) mkdir -p $(RESULTSDIR) - # install project dependencies - go get ./... - # install golangci-lint - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .tmp/ v1.26.0 - # install bouncer - curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b .tmp/ v0.1.0 + # install go dependencies + go mod download + # install utilities + [ -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.1.0 + [ -f "$(TEMPDIR)/goreleaser" ] || curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh -s -- -b $(TEMPDIR)/ v0.140.0 +.PHONY: lint lint: ## Run gofmt + golangci lint checks $(call title,Running linters) @printf "files with gofmt issues: [$(shell gofmt -l -s .)]\n" @test -z "$(shell gofmt -l -s .)" $(LINTCMD) +.PHONY: lint-fix lint-fix: ## Auto-format all source code + run golangci lint fixers $(call title,Running lint fixers) gofmt -w -s . $(LINTCMD) --fix +.PHONY: check-licenses +check-licenses: + $(TEMPDIR)/bouncer check + +.PHONY: unit unit: ## Run unit tests (with coverage) $(call title,Running unit tests) go test --race -coverprofile $(COVER_REPORT) ./... @@ -73,20 +112,24 @@ unit: ## Run unit tests (with coverage) @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: integration integration: ## Run integration tests $(call title,Running integration tests) - go test -v -tags=integration ./integration + go test -v -tags=integration ./test/integration -integration/test-fixtures/tar-cache.key, integration-fingerprint: - find integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee integration/test-fixtures/tar-cache.fingerprint +test/integration/test-fixtures/tar-cache.key, integration-fingerprint: + find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/tar-cache.fingerprint +.PHONY: java-packages-fingerprint java-packages-fingerprint: @cd imgbom/cataloger/java/test-fixtures/java-builds && \ make packages.fingerprint +.PHONY: clear-test-cache clear-test-cache: ## Delete all test cache (built docker image tars) find . -type f -wholename "**/test-fixtures/tar-cache/*.tar" -delete +.PHONY: check-pipeline check-pipeline: ## Run local CircleCI pipeline locally (sanity check) $(call title,Check pipeline) # note: this is meant for local development & testing of the pipeline, NOT to be run in CI @@ -96,15 +139,70 @@ check-pipeline: ## Run local CircleCI pipeline locally (sanity check) circleci local execute -c .tmp/circleci.yml --job "Unit & Integration Tests (go-latest)" @printf '$(SUCCESS)Pipeline checks pass!$(RESET)\n' -# todo: replace this with goreleaser -build-release: ## Build final release binary - @mkdir -p dist - go build -s -w -X main.version="$(git describe --tags --dirty --always)" \ - -X main.commit="$(git describe --dirty --always)" \ - -X main.buildTime="$(date --rfc-3339=seconds --utc)" - -o dist/imgbom +.PHONY: build +build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages -# todo: this should by later used by goreleaser -check-licenses: - $(TEMPDIR)/bouncer list -o json | tee $(LICENSES_REPORT) - $(TEMPDIR)/bouncer check +$(SNAPSHOTDIR): ## Build snapshot release binaries and packages + $(call title,Building snapshot artifacts) + # create a config with the dist dir overridden + echo "dist: $(SNAPSHOTDIR)" > $(TEMPDIR)/goreleaser.yaml + cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml + + # build release snapshots + BUILD_GIT_TREE_STATE=$(GITTREESTATE) \ + $(TEMPDIR)/goreleaser release --skip-publish --rm-dist --snapshot --config $(TEMPDIR)/goreleaser.yaml + +.PHONY: acceptance-mac +acceptance-mac: $(SNAPSHOTDIR) ## Run acceptance tests on build snapshot binaries and packages (Mac) + $(call title,Running acceptance test: Run on Mac) + $(ACC_DIR)/mac.sh \ + $(SNAPSHOTDIR) \ + $(ACC_DIR)\ + $(ACC_TEST_IMAGE) + +.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) + +.PHONY: acceptance-test-deb-package-install +acceptance-test-deb-package-install: $(SNAPSHOTDIR) + $(call title,Running acceptance test: DEB install) + $(ACC_DIR)/deb.sh \ + $(SNAPSHOTDIR) \ + $(ACC_DIR)\ + $(ACC_TEST_IMAGE) + +.PHONY: acceptance-test-rpm-package-install +acceptance-test-rpm-package-install: $(SNAPSHOTDIR) + $(call title,Running acceptance test: RPM install) + $(ACC_DIR)/rpm.sh \ + $(SNAPSHOTDIR) \ + $(ACC_DIR)\ + $(ACC_TEST_IMAGE) + +# TODO: this is not releasing yet +.PHONY: release +release: clean-dist ## Build and publish final binaries and packages + $(call title,Publishing release artifacts) + # create a config with the dist dir overridden + echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml + cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml + + # release + BUILD_GIT_TREE_STATE=$(GITTREESTATE) \ + $(TEMPDIR)/goreleaser --skip-publish --rm-dist --config $(TEMPDIR)/goreleaser.yaml + + # create a version file for version-update checks + echo "$(VERSION)" > $(DISTDIR)/VERSION + # TODO: add upload to bucket + +.PHONY: clean +clean: clean-dist clean-shapshot ## Remove previous builds and result reports + rm -rf $(RESULTSDIR)/* + +.PHONY: clean-shapshot +clean-shapshot: + rm -rf $(SNAPSHOTDIR) $(TEMPDIR)/goreleaser.yaml + +.PHONY: clean-dist +clean-dist: + rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml \ No newline at end of file diff --git a/cmd/root.go b/cmd/root.go index 68bf56b05..07d921635 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,7 +18,7 @@ import ( var rootCmd = &cobra.Command{ Use: fmt.Sprintf("%s [SOURCE]", internal.ApplicationName), - Short: "A tool that generates a Software Build Of Materials (SBOM)", + Short: "A tool for generating a Software Bill Of Materials (SBOM) from container images and filesystems", Long: internal.Tprintf(`\ Supports the following image sources: {{.appName}} yourrepo/yourimage:tag defaults to using images from a docker daemon diff --git a/comparison/.gitignore b/comparison/.gitignore deleted file mode 100644 index 8795fb853..000000000 --- a/comparison/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.json -*-reports \ No newline at end of file diff --git a/go.mod b/go.mod index 891fe88e3..4e0d465e4 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-version v1.2.0 - github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.3.1 github.com/rogpeppe/go-internal v1.5.2 @@ -23,6 +22,7 @@ require ( 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-20200621153512-2778c704bf22 + github.com/wagoodman/go-rpmdb v0.0.0-20200719223757-ce54a4b0607b github.com/wagoodman/jotframe v0.0.0-20200622123948-2995cbd43525 go.uber.org/zap v1.15.0 golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 diff --git a/go.sum b/go.sum index 842c2c68a..51185319a 100644 --- a/go.sum +++ b/go.sum @@ -285,6 +285,8 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1 h1:LoN2wx/aN8JPGebG+2DaUyk4M+xRcqJXfuIbs8AWHdE= +github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -536,10 +538,6 @@ github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0 github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662 h1:UGS0RbPHwXJkq8tcba8OD0nvVUWLf2h7uUJznuHPPB0= -github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg= -github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc h1:pumO9pqmRAjvic6oove22RGh9wDZQnj96XQjJSbSEPs= -github.com/knqyf263/go-rpmdb v0.0.0-20190501070121-10a1c42a10dc/go.mod h1:MrSSvdMpTSymaQWk1yFr9sxFSyQmKMj6jkbvGrchBV8= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= @@ -823,6 +821,8 @@ github.com/wagoodman/go-progress v0.0.0-20200621122631-1a2120f0695a h1:lV3ioFpbq github.com/wagoodman/go-progress v0.0.0-20200621122631-1a2120f0695a/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= github.com/wagoodman/go-progress v0.0.0-20200621153512-2778c704bf22 h1:GYaiTP0ywrCjJ4qMxxCg+YKPSDMeFJg6i1X9X55LJCA= github.com/wagoodman/go-progress v0.0.0-20200621153512-2778c704bf22/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= +github.com/wagoodman/go-rpmdb v0.0.0-20200719223757-ce54a4b0607b h1:elYGLFZPymeTWJ6qA3tIzFet3LQ9D/Jl6HLWNyFjdQc= +github.com/wagoodman/go-rpmdb v0.0.0-20200719223757-ce54a4b0607b/go.mod h1:MjoIZzKmbYfcpbC6ARWMcHijAjtLBViDaHcayXKWQWI= github.com/wagoodman/jotframe v0.0.0-20200622123948-2995cbd43525 h1:fGlwSBQrl9/axciK2+gJ9q86SeQYJpbPx4vOrExvZXY= github.com/wagoodman/jotframe v0.0.0-20200622123948-2995cbd43525/go.mod h1:DzXZ1wfRedNhC3KQTick8Gf3CEPMFHsP5k4R/ldjKtw= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= @@ -1100,7 +1100,6 @@ golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200527183253-8e7acdbce89d h1:SR+e35rACZFBohNb4Om1ibX6N3iO0FtdbwqGSuD9dBU= golang.org/x/tools v0.0.0-20200527183253-8e7acdbce89d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= diff --git a/imgbom/cataloger/rpmdb/parse_rpmdb.go b/imgbom/cataloger/rpmdb/parse_rpmdb.go index 451bbd0b0..a524ce3a0 100644 --- a/imgbom/cataloger/rpmdb/parse_rpmdb.go +++ b/imgbom/cataloger/rpmdb/parse_rpmdb.go @@ -9,7 +9,7 @@ import ( "github.com/anchore/imgbom/imgbom/pkg" "github.com/anchore/imgbom/internal" "github.com/anchore/imgbom/internal/log" - rpmdb "github.com/knqyf263/go-rpmdb/pkg" + rpmdb "github.com/wagoodman/go-rpmdb/pkg" ) func parseRpmDB(_ string, reader io.Reader) ([]pkg.Package, error) { @@ -30,8 +30,7 @@ func parseRpmDB(_ string, reader io.Reader) ([]pkg.Package, error) { return nil, fmt.Errorf("failed to copy rpmdb contents to temp file: %w", err) } - db := rpmdb.DB{} - err = db.Open(f.Name()) + db, err := rpmdb.Open(f.Name()) if err != nil { return nil, err } diff --git a/imgbom/pkg/catalog.go b/imgbom/pkg/catalog.go index e43023f8f..09322d0e6 100644 --- a/imgbom/pkg/catalog.go +++ b/imgbom/pkg/catalog.go @@ -1,6 +1,7 @@ package pkg import ( + "sort" "sync" "github.com/anchore/imgbom/internal/log" @@ -94,3 +95,19 @@ func (c *Catalog) Enumerate(types ...Type) <-chan *Package { }() return channel } + +func (c *Catalog) Sorted(types ...Type) []*Package { + pkgs := make([]*Package, 0) + for p := range c.Enumerate(types...) { + pkgs = append(pkgs, p) + } + + sort.SliceStable(pkgs, func(i, j int) bool { + if pkgs[i].Name == pkgs[j].Name { + return pkgs[i].Version < pkgs[j].Version + } + return pkgs[i].Name < pkgs[j].Name + }) + + return pkgs +} diff --git a/imgbom/presenter/json/presenter.go b/imgbom/presenter/json/presenter.go index 2de343dbf..e9b549e39 100644 --- a/imgbom/presenter/json/presenter.go +++ b/imgbom/presenter/json/presenter.go @@ -53,7 +53,7 @@ type artifact struct { Type string `json:"type"` Cataloger string `json:"cataloger"` Sources []source `json:"sources"` - Metadata interface{} `json:"metadata"` + Metadata interface{} `json:"metadata,omitempty"` } func (pres *Presenter) Present(output io.Writer) error { @@ -82,7 +82,7 @@ func (pres *Presenter) Present(output io.Writer) error { return fmt.Errorf("unsupported source: %T", src) } - for p := range pres.catalog.Enumerate() { + for _, p := range pres.catalog.Sorted() { art := artifact{ Name: p.Name, Version: p.Version, diff --git a/imgbom/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden b/imgbom/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden index f8c261758..28bb0eb24 100644 --- a/imgbom/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden +++ b/imgbom/presenter/json/test-fixtures/snapshot/TestJsonDirsPresenter.golden @@ -1 +1 @@ -{"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}],"image":{"layers":null,"size":0,"digest":"","mediaType":"","tags":null},"Source":"/some/path"} \ No newline at end of file +{"artifacts":[{"name":"package-1","version":"1.0.1","type":"deb","cataloger":"","sources":[]},{"name":"package-2","version":"2.0.1","type":"deb","cataloger":"","sources":[]}],"image":{"layers":null,"size":0,"digest":"","mediaType":"","tags":null},"Source":"/some/path"} \ No newline at end of file diff --git a/imgbom/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden b/imgbom/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden index 2ef23aa84..76fd2d5b6 100644 --- a/imgbom/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden +++ b/imgbom/presenter/json/test-fixtures/snapshot/TestJsonImgsPresenter.golden @@ -1 +1 @@ -{"artifacts":[{"name":"package-1","version":"1.0.1","type":"deb","cataloger":"","sources":[{"foundBy":"","effects":[]}],"metadata":null},{"name":"package-2","version":"2.0.1","type":"deb","cataloger":"","sources":[{"foundBy":"","effects":[]}],"metadata":null}],"image":{"layers":[{"mediaType":"","digest":"","size":0},{"mediaType":"","digest":"","size":0},{"mediaType":"","digest":"","size":0}],"size":65,"digest":"sha256:26e4732b961662cd066976b6cadc25f2cedee52db90be26ee7c120d2ff468ef2","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tags":["anchore-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"]},"Source":""} \ No newline at end of file +{"artifacts":[{"name":"package-1","version":"1.0.1","type":"deb","cataloger":"","sources":[{"foundBy":"","effects":[]}]},{"name":"package-2","version":"2.0.1","type":"deb","cataloger":"","sources":[{"foundBy":"","effects":[]}]}],"image":{"layers":[{"mediaType":"","digest":"","size":0},{"mediaType":"","digest":"","size":0},{"mediaType":"","digest":"","size":0}],"size":65,"digest":"sha256:3c53d2d891940f8d8e95acb77b58752f54dc5de9d91d19dd90ced2db76256cea","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tags":["anchore-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"]},"Source":""} \ No newline at end of file diff --git a/imgbom/presenter/json/test-fixtures/snapshot/anchore-fixture-image-simple.golden b/imgbom/presenter/json/test-fixtures/snapshot/anchore-fixture-image-simple.golden index fff8311e4..739b61487 100644 Binary files a/imgbom/presenter/json/test-fixtures/snapshot/anchore-fixture-image-simple.golden and b/imgbom/presenter/json/test-fixtures/snapshot/anchore-fixture-image-simple.golden differ diff --git a/imgbom/presenter/text/presenter.go b/imgbom/presenter/text/presenter.go index 55624b522..b17e1b154 100644 --- a/imgbom/presenter/text/presenter.go +++ b/imgbom/presenter/text/presenter.go @@ -48,7 +48,7 @@ func (pres *Presenter) Present(output io.Writer) error { } // populate artifacts... - for p := range pres.catalog.Enumerate() { + for _, p := range pres.catalog.Sorted() { fmt.Fprintln(w, fmt.Sprintf("[%s]", p.Name)) fmt.Fprintln(w, " Version:\t", p.Version) fmt.Fprintln(w, " Type:\t", p.Type.String()) diff --git a/internal/version/update.go b/internal/version/update.go index 421ca228c..9c078a099 100644 --- a/internal/version/update.go +++ b/internal/version/update.go @@ -64,5 +64,9 @@ func fetchLatestApplicationVersion() (*hashiVersion.Version, error) { } versionStr := strings.TrimSuffix(string(versionBytes), "\n") + if len(versionStr) > 50 { + return nil, fmt.Errorf("version too long: %q", versionStr[:50]) + } + return hashiVersion.NewVersion(versionStr) } diff --git a/internal/version/update_test.go b/internal/version/update_test.go index 2484d69f6..10c34b738 100644 --- a/internal/version/update_test.go +++ b/internal/version/update_test.go @@ -168,6 +168,13 @@ func TestFetchLatestApplicationVersion(t *testing.T) { expected: nil, err: true, }, + { + name: "too long", + response: "this is really long this is really long this is really long this is really long this is really long this is really long this is really long this is really long ", + code: 200, + expected: nil, + err: true, + }, } for _, test := range tests { diff --git a/test/acceptance/compare.py b/test/acceptance/compare.py new file mode 100755 index 000000000..f4dcb5f13 --- /dev/null +++ b/test/acceptance/compare.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python3 +import sys +import json +import collections + +Metadata = collections.namedtuple("Metadata", "metadata sources") +Package = collections.namedtuple("Package", "name type version") +Vulnerability = collections.namedtuple("Vulnerability", "cve package") + + +class ImgBom: + def __init__(self, report_path): + self.report_path = report_path + + 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"): + package = Package( + name=entry["name"], type=entry["type"], version=entry["version"] + ) + + packages.add(package) + metadata[package.type][package] = Metadata( + metadata=repr(entry["metadata"]), sources=repr(entry["sources"]) + ) + return packages, metadata + + +def main(baseline_report, new_report): + report1_obj = ImgBom(report_path=baseline_report) + report1_packages, report1_metadata = report1_obj.packages() + + report2_obj = ImgBom(report_path=new_report) + report2_packages, report2_metadata = report2_obj.packages() + + if len(report2_packages) == 0 and len(report1_packages) == 0: + print("nobody found any packages") + return 0 + + same_packages = report2_packages & report1_packages + percent_overlap_packages = ( + float(len(same_packages)) / float(len(report1_packages)) + ) * 100.0 + + extra_packages = report2_packages - report1_packages + missing_pacakges = report1_packages - report2_packages + + report1_metadata_set = set() + for package in report1_packages: + metadata = report1_metadata[package.type][package] + report1_metadata_set.add((package, metadata)) + + report2_metadata_set = set() + for package in report2_packages: + metadata = report2_metadata[package.type][package] + report2_metadata_set.add((package, metadata)) + + same_metadata = report2_metadata_set & report1_metadata_set + percent_overlap_metadata = 0 + if len(report1_metadata_set) > 0: + percent_overlap_metadata = ( + float(len(same_metadata)) / float(len(report1_metadata_set)) + ) * 100.0 + + if len(extra_packages) > 0: + print("Extra packages:") + for package in sorted(list(extra_packages)): + print(" " + repr(package)) + print() + + if len(missing_pacakges) > 0: + print("Missing packages:") + for package in sorted(list(missing_pacakges)): + print(" " + repr(package)) + print() + + print("Baseline Packages: %d" % len(report1_packages)) + print("New Packages: %d" % len(report2_packages)) + print() + print( + "Baseline Packages Matched: %.2f %% (%d/%d packages)" + % (percent_overlap_packages, len(same_packages), len(report1_packages)) + ) + print( + "Baseline Metadata Matched: %.2f %% (%d/%d metadata)" + % (percent_overlap_metadata, len(same_metadata), len(report1_metadata_set)) + ) + + if len(report1_packages) != len(report2_packages): + print("failed quality gate: requires exact name & version match") + return 1 + + return 0 + + +if __name__ == "__main__": + print("\nComparing two imgbom reports...\n") + if len(sys.argv) != 3: + sys.exit("please provide two imgbom json files") + + rc = main(sys.argv[1], sys.argv[2]) + sys.exit(rc) diff --git a/test/acceptance/compare.sh b/test/acceptance/compare.sh new file mode 100755 index 000000000..28bef47d5 --- /dev/null +++ b/test/acceptance/compare.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -eu + +BOLD="$(tput -T linux bold)" +RED="$(tput -T linux setaf 1)" +RESET="$(tput -T linux sgr0)" +FAIL="${BOLD}${RED}" +SUCCESS="${BOLD}" +JQ_ARGS="-S .artifacts" + +if ! command -v jq &> /dev/null ;then + JQ_IMAGE="imega/jq:latest" + JQ_CMD="docker run --rm -i ${JQ_IMAGE} ${JQ_ARGS}" + docker pull "${JQ_IMAGE}" +else + JQ_CMD="jq ${JQ_ARGS}" +fi + +if [[ $(cat $1 | ${JQ_CMD}) ]]; then + set -x + # compare the output of both results + diff <(cat $1 | ${JQ_CMD}) <(cat $2 | ${JQ_CMD}) + set +x + echo "${SUCCESS}Comparison passed!${RESET}" +else + exit "${FAIL}Failing since one of the test files is empty ($1)${RESET}" +fi \ No newline at end of file diff --git a/test/acceptance/deb.sh b/test/acceptance/deb.sh new file mode 100755 index 000000000..f73b45b38 --- /dev/null +++ b/test/acceptance/deb.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -eux + +DISTDIR=$1 +ACC_DIR=$2 +TEST_IMAGE=$3 + +TEST_TYPE=deb +WORK_DIR=`mktemp -d -t "imgbom-acceptance-test-${TEST_TYPE}-XXXXXX"` +REPORT=${WORK_DIR}/acceptance-${TEST_TYPE}-${TEST_IMAGE}.json +GOLDEN_REPORT=${ACC_DIR}/test-fixtures/acceptance-${TEST_IMAGE}.json + +# check if tmp dir was created +if [[ ! "${WORK_DIR}" || ! -d "${WORK_DIR}" ]]; then + echo "Could not create temp dir" + exit 1 +fi + +function cleanup { + rm -rf "${WORK_DIR}" +} + +trap cleanup EXIT + +# fetch test image +docker pull ${TEST_IMAGE} + +# install and run imgbom +docker run --rm \ + -v /var/run/docker.sock://var/run/docker.sock \ + -v /${PWD}:/src \ + -v ${WORK_DIR}:${WORK_DIR} \ + -w /src \ + ubuntu:latest \ + /bin/bash -x -c "\ + DEBIAN_FRONTEND=noninteractive apt install ${DISTDIR}/imgbom_*_linux_amd64.deb -y && \ + imgbom version -v && \ + imgbom ${TEST_IMAGE} -vv -o json > ${REPORT} && \ + cat ${REPORT} \ + " + +# compare the results to a known good output +${ACC_DIR}/compare.py \ + ${GOLDEN_REPORT} \ + ${REPORT} diff --git a/test/acceptance/mac.sh b/test/acceptance/mac.sh new file mode 100755 index 000000000..ea0d52cd3 --- /dev/null +++ b/test/acceptance/mac.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -eux + +DISTDIR=$1 +ACC_DIR=$2 +TEST_IMAGE=$3 + +TEST_IMAGE_TAR=/tmp/image.tar +TEST_TYPE=mac +WORK_DIR=`mktemp -d -t "imgbom-acceptance-test-${TEST_TYPE}-XXXXXX"` +REPORT=${WORK_DIR}/acceptance-${TEST_TYPE}-${TEST_IMAGE}.json +GOLDEN_REPORT=${ACC_DIR}/test-fixtures/acceptance-${TEST_IMAGE}.json + +# check if tmp dir was created +if [[ ! "${WORK_DIR}" || ! -d "${WORK_DIR}" ]]; then + echo "Could not create temp dir" + exit 1 +fi + +function cleanup { + rm -rf "${WORK_DIR}" +} + +trap cleanup EXIT + +# install skopeo (pinned to 1.1.0) +skopeo --version || brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/75e8d7a40af77b48cc91f4bdb7d669f891a6de60/Formula/skopeo.rb + +# fetch test image +skopeo --override-os linux copy docker://docker.io/${TEST_IMAGE} docker-archive:${TEST_IMAGE_TAR} +ls -alh ${TEST_IMAGE_TAR} + +# run imgbom +chmod 755 ${DISTDIR}/imgbom_darwin_amd64/imgbom +${DISTDIR}/imgbom_darwin_amd64/imgbom version -v +${DISTDIR}/imgbom_darwin_amd64/imgbom docker-archive://${TEST_IMAGE_TAR} -vv -o json > ${REPORT} +cat ${REPORT} + +# compare the results to a known good output +${ACC_DIR}/compare.py \ + ${GOLDEN_REPORT} \ + ${REPORT} diff --git a/test/acceptance/rpm.sh b/test/acceptance/rpm.sh new file mode 100755 index 000000000..5c9e39034 --- /dev/null +++ b/test/acceptance/rpm.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -eux + +DISTDIR=$1 +ACC_DIR=$2 +TEST_IMAGE=$3 + +TEST_TYPE=rpm +WORK_DIR=`mktemp -d -t "imgbom-acceptance-test-${TEST_TYPE}-XXXXXX"` +REPORT=${WORK_DIR}/acceptance-${TEST_TYPE}-${TEST_IMAGE}.json +GOLDEN_REPORT=${ACC_DIR}/test-fixtures/acceptance-${TEST_IMAGE}.json + +# check if tmp dir was created +if [[ ! "${WORK_DIR}" || ! -d "${WORK_DIR}" ]]; then + echo "Could not create temp dir" + exit 1 +fi + +function cleanup { + rm -rf "${WORK_DIR}" +} + +trap cleanup EXIT + +# fetch test image +docker pull ${TEST_IMAGE} + +# install and run imgbom +docker run --rm \ + -v /var/run/docker.sock://var/run/docker.sock \ + -v /${PWD}:/src \ + -v ${WORK_DIR}:${WORK_DIR} \ + -w /src \ + centos:latest \ + /bin/bash -x -c "\ + rpm -ivh ${DISTDIR}/imgbom_*_linux_amd64.rpm && \ + imgbom version -v && \ + imgbom ${TEST_IMAGE} -vv -o json > ${REPORT} && \ + cat ${REPORT} \ + " + +# compare the results to a known good output +${ACC_DIR}/compare.py \ + ${GOLDEN_REPORT} \ + ${REPORT} diff --git a/test/acceptance/test-fixtures/acceptance-centos:8.2.2004.json b/test/acceptance/test-fixtures/acceptance-centos:8.2.2004.json new file mode 100644 index 000000000..8f42c5db5 --- /dev/null +++ b/test/acceptance/test-fixtures/acceptance-centos:8.2.2004.json @@ -0,0 +1,2 @@ + +{"artifacts":[{"name":"acl","version":"2.2.53","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"audit-libs","version":"3.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"0.17.20191104git1c2f876.el8"}},{"name":"basesystem","version":"11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"5.el8"}},{"name":"bash","version":"4.4.19","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"10.el8"}},{"name":"bind-export-libs","version":"9.11.13","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":32,"Arch":"x86_64","Release":"3.el8"}},{"name":"binutils","version":"2.30","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"73.el8"}},{"name":"bzip2-libs","version":"1.0.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"26.el8"}},{"name":"ca-certificates","version":"2019.2.32","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"80.0.el8_1"}},{"name":"centos-gpg-keys","version":"8.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"2.2004.0.1.el8"}},{"name":"centos-release","version":"8.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.2004.0.1.el8"}},{"name":"centos-repos","version":"8.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.2004.0.1.el8"}},{"name":"chkconfig","version":"1.11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"coreutils-single","version":"8.30","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8_2.1"}},{"name":"cpio","version":"2.12","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"8.el8"}},{"name":"cracklib","version":"2.9.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"15.el8"}},{"name":"crypto-policies","version":"20191128","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"2.git23e1bf1.el8"}},{"name":"cryptsetup-libs","version":"2.2.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"curl","version":"7.61.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"12.el8"}},{"name":"cyrus-sasl-lib","version":"2.1.27","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"dbus","version":"1.12.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"9.el8"}},{"name":"dbus-common","version":"1.12.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"noarch","Release":"9.el8"}},{"name":"dbus-daemon","version":"1.12.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"9.el8"}},{"name":"dbus-libs","version":"1.12.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"9.el8"}},{"name":"dbus-tools","version":"1.12.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"9.el8"}},{"name":"device-mapper","version":"1.02.169","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":8,"Arch":"x86_64","Release":"3.el8"}},{"name":"device-mapper-libs","version":"1.02.169","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":8,"Arch":"x86_64","Release":"3.el8"}},{"name":"dhcp-client","version":"4.3.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":12,"Arch":"x86_64","Release":"40.el8"}},{"name":"dhcp-common","version":"4.3.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":12,"Arch":"noarch","Release":"40.el8"}},{"name":"dhcp-libs","version":"4.3.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":12,"Arch":"x86_64","Release":"40.el8"}},{"name":"dnf","version":"4.2.17","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"6.el8"}},{"name":"dnf-data","version":"4.2.17","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"6.el8"}},{"name":"dracut","version":"049","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"70.git20200228.el8"}},{"name":"dracut-network","version":"049","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"70.git20200228.el8"}},{"name":"dracut-squash","version":"049","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"70.git20200228.el8"}},{"name":"elfutils-default-yama-scope","version":"0.178","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"7.el8"}},{"name":"elfutils-libelf","version":"0.178","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8"}},{"name":"elfutils-libs","version":"0.178","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8"}},{"name":"ethtool","version":"5.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":2,"Arch":"x86_64","Release":"2.el8"}},{"name":"expat","version":"2.2.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"file-libs","version":"5.33","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"13.el8"}},{"name":"filesystem","version":"3.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.el8"}},{"name":"findutils","version":"4.6.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"20.el8"}},{"name":"gawk","version":"4.2.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"gdbm","version":"1.18","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"1.el8"}},{"name":"gdbm-libs","version":"1.18","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"1.el8"}},{"name":"glib2","version":"2.56.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"8.el8"}},{"name":"glibc","version":"2.28","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"101.el8"}},{"name":"glibc-common","version":"2.28","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"101.el8"}},{"name":"glibc-minimal-langpack","version":"2.28","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"101.el8"}},{"name":"gmp","version":"6.1.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"10.el8"}},{"name":"gnupg2","version":"2.2.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"gnutls","version":"3.6.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"10.el8_2"}},{"name":"gpgme","version":"1.10.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8.0.1"}},{"name":"grep","version":"3.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"gzip","version":"1.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"9.el8"}},{"name":"hostname","version":"3.20","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"ima-evm-utils","version":"1.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"info","version":"6.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"ipcalc","version":"0.2.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"iproute","version":"5.3.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"iptables-libs","version":"1.8.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"10.el8"}},{"name":"iputils","version":"20180629","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.el8"}},{"name":"json-c","version":"0.13.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"0.2.el8"}},{"name":"kexec-tools","version":"2.0.20","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"14.el8"}},{"name":"keyutils-libs","version":"1.5.10","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"kmod","version":"25","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"16.el8"}},{"name":"kmod-libs","version":"25","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"16.el8"}},{"name":"krb5-libs","version":"1.17","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"18.el8"}},{"name":"langpacks-en","version":"1.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"12.el8"}},{"name":"less","version":"530","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libacl","version":"2.2.53","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libarchive","version":"3.3.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"8.el8_1"}},{"name":"libassuan","version":"2.5.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libattr","version":"2.4.48","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libblkid","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"libcap","version":"2.26","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libcap-ng","version":"0.7.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"libcom_err","version":"1.45.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libcomps","version":"0.1.11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"libcurl-minimal","version":"7.61.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"12.el8"}},{"name":"libdb","version":"5.3.28","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"libdb-utils","version":"5.3.28","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"libdnf","version":"0.39.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"libfdisk","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"libffi","version":"3.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"21.el8"}},{"name":"libgcc","version":"8.3.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8.0.2"}},{"name":"libgcrypt","version":"1.8.3","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"libgpg-error","version":"1.31","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libidn2","version":"2.2.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libkcapi","version":"1.1.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"16_1.el8"}},{"name":"libkcapi-hmaccalc","version":"1.1.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"16_1.el8"}},{"name":"libksba","version":"1.3.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8"}},{"name":"libmetalink","version":"0.1.3","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8"}},{"name":"libmnl","version":"1.0.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"libmodulemd1","version":"1.8.16","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"0.2.8.2.1"}},{"name":"libmount","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"libnghttp2","version":"1.33.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8_0.1"}},{"name":"libnsl2","version":"1.2.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.20180605git4a062cf.el8"}},{"name":"libpcap","version":"1.9.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":14,"Arch":"x86_64","Release":"3.el8"}},{"name":"libpwquality","version":"1.4.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"9.el8"}},{"name":"librepo","version":"1.11.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.el8"}},{"name":"libreport-filesystem","version":"2.9.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"10.el8"}},{"name":"libseccomp","version":"2.4.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libselinux","version":"2.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libsemanage","version":"2.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.el8"}},{"name":"libsepol","version":"2.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libsigsegv","version":"2.11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"libsmartcols","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"libsolv","version":"0.7.7","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libstdc++","version":"8.3.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8.0.2"}},{"name":"libtasn1","version":"4.13","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libtirpc","version":"1.1.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"libunistring","version":"0.9.9","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"libusbx","version":"1.0.22","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"libutempter","version":"1.1.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"14.el8"}},{"name":"libuuid","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"libverto","version":"0.3.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"libxcrypt","version":"4.1.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"libxml2","version":"2.9.7","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.el8"}},{"name":"libyaml","version":"0.1.7","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"libzstd","version":"1.4.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"2.el8"}},{"name":"lua-libs","version":"5.3.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"11.el8"}},{"name":"lz4-libs","version":"1.8.1.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"lzo","version":"2.08","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"14.el8"}},{"name":"mpfr","version":"3.1.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"ncurses-base","version":"6.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"7.20180224.el8"}},{"name":"ncurses-libs","version":"6.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"7.20180224.el8"}},{"name":"nettle","version":"3.4.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"npth","version":"1.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"openldap","version":"2.4.46","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"11.el8_1"}},{"name":"openssl-libs","version":"1.1.1c","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":1,"Arch":"x86_64","Release":"15.el8"}},{"name":"p11-kit","version":"0.23.14","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8_0"}},{"name":"p11-kit-trust","version":"0.23.14","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8_0"}},{"name":"pam","version":"1.3.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"8.el8"}},{"name":"pcre","version":"8.42","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"pcre2","version":"10.32","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"platform-python","version":"3.6.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"23.el8"}},{"name":"platform-python-setuptools","version":"39.2.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"5.el8"}},{"name":"popt","version":"1.16","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"14.el8"}},{"name":"procps-ng","version":"3.3.15","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"python3-dnf","version":"4.2.17","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"6.el8"}},{"name":"python3-gpg","version":"1.10.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8.0.1"}},{"name":"python3-hawkey","version":"0.39.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"python3-libcomps","version":"0.1.11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"4.el8"}},{"name":"python3-libdnf","version":"0.39.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"python3-libs","version":"3.6.8","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"23.el8"}},{"name":"python3-pip-wheel","version":"9.0.3","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"16.el8"}},{"name":"python3-rpm","version":"4.14.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"python3-setuptools-wheel","version":"39.2.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"5.el8"}},{"name":"readline","version":"7.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"10.el8"}},{"name":"rootfiles","version":"8.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"22.el8"}},{"name":"rpm","version":"4.14.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"rpm-build-libs","version":"4.14.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"rpm-libs","version":"4.14.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"37.el8"}},{"name":"sed","version":"4.5","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"1.el8"}},{"name":"setup","version":"2.12.2","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"5.el8"}},{"name":"shadow-utils","version":"4.6","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":2,"Arch":"x86_64","Release":"8.el8"}},{"name":"snappy","version":"1.1.7","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"5.el8"}},{"name":"sqlite-libs","version":"3.26.0","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"6.el8"}},{"name":"squashfs-tools","version":"4.3","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"19.el8"}},{"name":"systemd","version":"239","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"30.el8_2"}},{"name":"systemd-libs","version":"239","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"30.el8_2"}},{"name":"systemd-pam","version":"239","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"30.el8_2"}},{"name":"systemd-udev","version":"239","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"30.el8_2"}},{"name":"tar","version":"1.30","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":2,"Arch":"x86_64","Release":"4.el8"}},{"name":"tzdata","version":"2020a","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"1.el8"}},{"name":"util-linux","version":"2.32.1","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"22.el8"}},{"name":"vim-minimal","version":"8.0.1763","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":2,"Arch":"x86_64","Release":"13.el8"}},{"name":"xz","version":"5.2.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"xz-libs","version":"5.2.4","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"3.el8"}},{"name":"yum","version":"4.2.17","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"noarch","Release":"6.el8"}},{"name":"zlib","version":"1.2.11","type":"rpm","cataloger":"","sources":[{"foundBy":"rpmdb-cataloger","effects":[]}],"metadata":{"Epoch":0,"Arch":"x86_64","Release":"13.el8"}}],"image":{"layers":[{"mediaType":"","digest":"","size":0}],"size":215273207,"digest":"sha256:831691599b88ad6cc2a4abbd0e89661a121aff14cfa289ad840fd3946f274f1f","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tags":["centos:8.2.2004"]},"Source":""} \ No newline at end of file diff --git a/test/inline-compare/.gitignore b/test/inline-compare/.gitignore new file mode 100644 index 000000000..7d00abd7a --- /dev/null +++ b/test/inline-compare/.gitignore @@ -0,0 +1,2 @@ +*.json +inline-reports \ No newline at end of file diff --git a/comparison/Dockerfile b/test/inline-compare/Dockerfile similarity index 100% rename from comparison/Dockerfile rename to test/inline-compare/Dockerfile diff --git a/comparison/Makefile b/test/inline-compare/Makefile similarity index 73% rename from comparison/Makefile rename to test/inline-compare/Makefile index 400abb427..c01339def 100644 --- a/comparison/Makefile +++ b/test/inline-compare/Makefile @@ -5,10 +5,18 @@ IMGBOM_REPORT = $(IMGBOM_DIR)/$(IMAGE_CLEAN).json INLINE_DIR = inline-reports INLINE_REPORT = $(INLINE_DIR)/$(IMAGE_CLEAN)-content-os.json -.PHONY: bootstrap +ifndef IMGBOM_DIR + $(error IMGBOM_DIR is not set) +endif +ifndef INLINE_DIR + $(error INLINE_DIR is not set) +endif + +.PHONY: all all: compare +.PHONY: compare compare: $(INLINE_REPORT) $(IMGBOM_REPORT) docker build -t compare-imgbom:latest . docker run compare-imgbom:latest $(IMAGE) @@ -24,4 +32,8 @@ $(IMGBOM_REPORT): echo "Creating $(IMGBOM_REPORT)..." mkdir -p $(IMGBOM_DIR) docker pull $(IMAGE) - go run ../main.go centos:latest -o json > $(IMGBOM_REPORT) + go run ../../main.go $(IMAGE) -o json > $(IMGBOM_REPORT) + +.PHONY: clean +clean: + rm -f $(INLINE_DIR)/* $(IMGBOM_DIR)/* \ No newline at end of file diff --git a/comparison/compare.py b/test/inline-compare/compare.py similarity index 100% rename from comparison/compare.py rename to test/inline-compare/compare.py diff --git a/integration/fixture_image_distro_test.go b/test/integration/fixture_image_distro_test.go similarity index 100% rename from integration/fixture_image_distro_test.go rename to test/integration/fixture_image_distro_test.go diff --git a/integration/fixture_pkg_coverage_test.go b/test/integration/fixture_pkg_coverage_test.go similarity index 100% rename from integration/fixture_pkg_coverage_test.go rename to test/integration/fixture_pkg_coverage_test.go diff --git a/integration/test-fixtures/.gitignore b/test/integration/test-fixtures/.gitignore similarity index 100% rename from integration/test-fixtures/.gitignore rename to test/integration/test-fixtures/.gitignore diff --git a/integration/test-fixtures/image-distro-id/Dockerfile b/test/integration/test-fixtures/image-distro-id/Dockerfile similarity index 100% rename from integration/test-fixtures/image-distro-id/Dockerfile rename to test/integration/test-fixtures/image-distro-id/Dockerfile diff --git a/integration/test-fixtures/image-pkg-coverage/Dockerfile b/test/integration/test-fixtures/image-pkg-coverage/Dockerfile similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/Dockerfile rename to test/integration/test-fixtures/image-pkg-coverage/Dockerfile diff --git a/integration/test-fixtures/image-pkg-coverage/go/go.mod b/test/integration/test-fixtures/image-pkg-coverage/go/go.mod similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/go/go.mod rename to test/integration/test-fixtures/image-pkg-coverage/go/go.mod diff --git a/integration/test-fixtures/image-pkg-coverage/java/example-java-app-maven-0.1.0.jar b/test/integration/test-fixtures/image-pkg-coverage/java/example-java-app-maven-0.1.0.jar similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/java/example-java-app-maven-0.1.0.jar rename to test/integration/test-fixtures/image-pkg-coverage/java/example-java-app-maven-0.1.0.jar diff --git a/integration/test-fixtures/image-pkg-coverage/java/example-jenkins-plugin.hpi b/test/integration/test-fixtures/image-pkg-coverage/java/example-jenkins-plugin.hpi similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/java/example-jenkins-plugin.hpi rename to test/integration/test-fixtures/image-pkg-coverage/java/example-jenkins-plugin.hpi diff --git a/integration/test-fixtures/image-pkg-coverage/java/generate-fixtures.md b/test/integration/test-fixtures/image-pkg-coverage/java/generate-fixtures.md similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/java/generate-fixtures.md rename to test/integration/test-fixtures/image-pkg-coverage/java/generate-fixtures.md diff --git a/integration/test-fixtures/image-pkg-coverage/javascript/package-lock/package-lock.json b/test/integration/test-fixtures/image-pkg-coverage/javascript/package-lock/package-lock.json similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/javascript/package-lock/package-lock.json rename to test/integration/test-fixtures/image-pkg-coverage/javascript/package-lock/package-lock.json diff --git a/integration/test-fixtures/image-pkg-coverage/python/dist-info/METADATA b/test/integration/test-fixtures/image-pkg-coverage/python/dist-info/METADATA similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/python/dist-info/METADATA rename to test/integration/test-fixtures/image-pkg-coverage/python/dist-info/METADATA diff --git a/integration/test-fixtures/image-pkg-coverage/python/egg-info/PKG-INFO b/test/integration/test-fixtures/image-pkg-coverage/python/egg-info/PKG-INFO similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/python/egg-info/PKG-INFO rename to test/integration/test-fixtures/image-pkg-coverage/python/egg-info/PKG-INFO diff --git a/integration/test-fixtures/image-pkg-coverage/python/requires/requirements.txt b/test/integration/test-fixtures/image-pkg-coverage/python/requires/requirements.txt similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/python/requires/requirements.txt rename to test/integration/test-fixtures/image-pkg-coverage/python/requires/requirements.txt diff --git a/integration/test-fixtures/image-pkg-coverage/ruby/Gemfile.lock b/test/integration/test-fixtures/image-pkg-coverage/ruby/Gemfile.lock similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/ruby/Gemfile.lock rename to test/integration/test-fixtures/image-pkg-coverage/ruby/Gemfile.lock diff --git a/integration/test-fixtures/image-pkg-coverage/var/lib/dpkg/status b/test/integration/test-fixtures/image-pkg-coverage/var/lib/dpkg/status similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/var/lib/dpkg/status rename to test/integration/test-fixtures/image-pkg-coverage/var/lib/dpkg/status diff --git a/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/Packages b/test/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/Packages similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/var/lib/rpm/Packages rename to test/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/Packages diff --git a/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/generate-fixture.sh b/test/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/generate-fixture.sh similarity index 100% rename from integration/test-fixtures/image-pkg-coverage/var/lib/rpm/generate-fixture.sh rename to test/integration/test-fixtures/image-pkg-coverage/var/lib/rpm/generate-fixture.sh diff --git a/test/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden b/test/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden new file mode 100644 index 000000000..9406dbebc --- /dev/null +++ b/test/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden @@ -0,0 +1 @@ +{"artifacts":[{"name":"actionmailer","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"actionpack","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"actionview","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activemodel","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activerecord","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activesupport","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"arel","version":"5.0.1.20140414130214","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"bootstrap-sass","version":"3.1.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"builder","version":"3.2.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-rails","version":"4.0.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-script","version":"2.2.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-script-source","version":"1.7.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"erubis","version":"2.7.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"execjs","version":"2.0.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"hike","version":"1.2.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"i18n","version":"0.6.9","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"jbuilder","version":"2.0.7","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"jquery-rails","version":"3.1.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"json","version":"1.8.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"kgio","version":"2.9.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"libv8","version":"3.16.14.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mail","version":"2.5.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mime-types","version":"1.25.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"minitest","version":"5.3.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"multi_json","version":"1.10.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mysql2","version":"0.3.16","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"polyglot","version":"0.3.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rack","version":"1.5.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rack-test","version":"0.6.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rails","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"railties","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"raindrops","version":"0.13.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rake","version":"10.3.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rdoc","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"ref","version":"1.0.5","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sass","version":"3.2.19","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sass-rails","version":"4.0.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sdoc","version":"0.4.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"spring","version":"1.1.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sprockets","version":"2.11.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sprockets-rails","version":"2.1.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sqlite3","version":"1.3.9","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"therubyracer","version":"0.12.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"thor","version":"0.19.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"thread_safe","version":"0.3.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"tilt","version":"1.4.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"treetop","version":"1.4.15","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"turbolinks","version":"2.2.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"tzinfo","version":"1.2.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"uglifier","version":"2.5.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"unicorn","version":"4.8.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null}],"Source":"test-fixtures"} \ No newline at end of file diff --git a/test/integration/test-fixtures/snapshot/TestDirTextPresenter.golden b/test/integration/test-fixtures/snapshot/TestDirTextPresenter.golden new file mode 100644 index 000000000..de5364a32 --- /dev/null +++ b/test/integration/test-fixtures/snapshot/TestDirTextPresenter.golden @@ -0,0 +1,256 @@ +[Path: test-fixtures] +[actionmailer] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[actionpack] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[actionview] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[activemodel] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[activerecord] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[activesupport] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[arel] + Version: 5.0.1.20140414130214 + Type: bundle + Found by: bundler-cataloger + +[bootstrap-sass] + Version: 3.1.1.1 + Type: bundle + Found by: bundler-cataloger + +[builder] + Version: 3.2.2 + Type: bundle + Found by: bundler-cataloger + +[coffee-rails] + Version: 4.0.1 + Type: bundle + Found by: bundler-cataloger + +[coffee-script] + Version: 2.2.0 + Type: bundle + Found by: bundler-cataloger + +[coffee-script-source] + Version: 1.7.0 + Type: bundle + Found by: bundler-cataloger + +[erubis] + Version: 2.7.0 + Type: bundle + Found by: bundler-cataloger + +[execjs] + Version: 2.0.2 + Type: bundle + Found by: bundler-cataloger + +[hike] + Version: 1.2.3 + Type: bundle + Found by: bundler-cataloger + +[i18n] + Version: 0.6.9 + Type: bundle + Found by: bundler-cataloger + +[jbuilder] + Version: 2.0.7 + Type: bundle + Found by: bundler-cataloger + +[jquery-rails] + Version: 3.1.0 + Type: bundle + Found by: bundler-cataloger + +[json] + Version: 1.8.1 + Type: bundle + Found by: bundler-cataloger + +[kgio] + Version: 2.9.2 + Type: bundle + Found by: bundler-cataloger + +[libv8] + Version: 3.16.14.3 + Type: bundle + Found by: bundler-cataloger + +[mail] + Version: 2.5.4 + Type: bundle + Found by: bundler-cataloger + +[mime-types] + Version: 1.25.1 + Type: bundle + Found by: bundler-cataloger + +[minitest] + Version: 5.3.4 + Type: bundle + Found by: bundler-cataloger + +[multi_json] + Version: 1.10.1 + Type: bundle + Found by: bundler-cataloger + +[mysql2] + Version: 0.3.16 + Type: bundle + Found by: bundler-cataloger + +[polyglot] + Version: 0.3.4 + Type: bundle + Found by: bundler-cataloger + +[rack] + Version: 1.5.2 + Type: bundle + Found by: bundler-cataloger + +[rack-test] + Version: 0.6.2 + Type: bundle + Found by: bundler-cataloger + +[rails] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[railties] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[raindrops] + Version: 0.13.0 + Type: bundle + Found by: bundler-cataloger + +[rake] + Version: 10.3.2 + Type: bundle + Found by: bundler-cataloger + +[rdoc] + Version: 4.1.1 + Type: bundle + Found by: bundler-cataloger + +[ref] + Version: 1.0.5 + Type: bundle + Found by: bundler-cataloger + +[sass] + Version: 3.2.19 + Type: bundle + Found by: bundler-cataloger + +[sass-rails] + Version: 4.0.3 + Type: bundle + Found by: bundler-cataloger + +[sdoc] + Version: 0.4.0 + Type: bundle + Found by: bundler-cataloger + +[spring] + Version: 1.1.3 + Type: bundle + Found by: bundler-cataloger + +[sprockets] + Version: 2.11.0 + Type: bundle + Found by: bundler-cataloger + +[sprockets-rails] + Version: 2.1.3 + Type: bundle + Found by: bundler-cataloger + +[sqlite3] + Version: 1.3.9 + Type: bundle + Found by: bundler-cataloger + +[therubyracer] + Version: 0.12.1 + Type: bundle + Found by: bundler-cataloger + +[thor] + Version: 0.19.1 + Type: bundle + Found by: bundler-cataloger + +[thread_safe] + Version: 0.3.3 + Type: bundle + Found by: bundler-cataloger + +[tilt] + Version: 1.4.1 + Type: bundle + Found by: bundler-cataloger + +[treetop] + Version: 1.4.15 + Type: bundle + Found by: bundler-cataloger + +[turbolinks] + Version: 2.2.2 + Type: bundle + Found by: bundler-cataloger + +[tzinfo] + Version: 1.2.0 + Type: bundle + Found by: bundler-cataloger + +[uglifier] + Version: 2.5.0 + Type: bundle + Found by: bundler-cataloger + +[unicorn] + Version: 4.8.3 + Type: bundle + Found by: bundler-cataloger +