mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Add release process (#89)
* add check for app update; fix ETUI error handling * validate user args * add goreleaser support * replace cgo dependencies (go-rpm) with go equivalents * add acceptance tests against build snapshot * add brew tap + acceptance test pipeline * add mac acceptance tests * fix compare makefile * fix mac acceptance tests * add release pipeline with wait checks * add token to release step * rm dir presenters int test * enforce dpkg to be non interactive Co-authored-by: Alfredo Deza <adeza@anchore.com> * pin brew formulae * pin skopeo to formulae url * only run acceptance tests Co-authored-by: Alfredo Deza <adeza@anchore.com>
This commit is contained in:
parent
3cb7c43dbc
commit
ba4f63099d
49 changed files with 952 additions and 57 deletions
|
@ -3,3 +3,4 @@ permit:
|
|||
- MIT.*
|
||||
- Apache.*
|
||||
- MPL.*
|
||||
- ISC
|
|
@ -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"
|
||||
|
|
83
.github/workflows/acceptance-test.yaml
vendored
Normal file
83
.github/workflows/acceptance-test.yaml
vendored
Normal file
|
@ -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
|
101
.github/workflows/release.yaml
vendored
Normal file
101
.github/workflows/release.yaml
vendored
Normal file
|
@ -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
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
/dist
|
||||
/snapshot
|
||||
.server/
|
||||
.vscode/
|
||||
*.tar
|
||||
|
|
44
.goreleaser.yaml
Normal file
44
.goreleaser.yaml
Normal file
|
@ -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
|
||||
|
162
Makefile
162
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)
|
||||
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
|
|
@ -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
|
||||
|
|
2
comparison/.gitignore
vendored
2
comparison/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
*.json
|
||||
*-reports
|
2
go.mod
2
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
|
||||
|
|
9
go.sum
9
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=
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"}
|
||||
{"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"}
|
|
@ -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":""}
|
||||
{"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":""}
|
Binary file not shown.
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
109
test/acceptance/compare.py
Executable file
109
test/acceptance/compare.py
Executable file
|
@ -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)
|
27
test/acceptance/compare.sh
Executable file
27
test/acceptance/compare.sh
Executable file
|
@ -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
|
45
test/acceptance/deb.sh
Executable file
45
test/acceptance/deb.sh
Executable file
|
@ -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}
|
42
test/acceptance/mac.sh
Executable file
42
test/acceptance/mac.sh
Executable file
|
@ -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}
|
45
test/acceptance/rpm.sh
Executable file
45
test/acceptance/rpm.sh
Executable file
|
@ -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}
|
File diff suppressed because one or more lines are too long
2
test/inline-compare/.gitignore
vendored
Normal file
2
test/inline-compare/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.json
|
||||
inline-reports
|
|
@ -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)/*
|
File diff suppressed because one or more lines are too long
|
@ -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
|
||||
|
Loading…
Reference in a new issue