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:
Alex Goodman
2020-07-23 10:52:44 -04:00
committed by GitHub
co-authored by Alfredo Deza
parent 3cb7c43dbc
commit ba4f63099d
49 changed files with 952 additions and 57 deletions
+109
View 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
View 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
View 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
View 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
View 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