mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Normalize snapshot and release artifacts (#789)
* refactor signing steps in release/snapshot workflows Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * show signing logs on snapshot or release failure Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update install.sh + tests to account for new goreleaser changes Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update cli tests to account for new goreleaser build names Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * fix acceptance test to use new snapshot bin path Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add notarization Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * address review comments Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
40423d8eee
commit
341288ba29
2
.github/scripts/apple-signing/.gitignore
vendored
Normal file
2
.github/scripts/apple-signing/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
dev-pki
|
||||
log
|
||||
10
.github/scripts/apple-signing/cleanup.sh
vendored
Executable file
10
.github/scripts/apple-signing/cleanup.sh
vendored
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
# grab utilities
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
. "$SCRIPT_DIR"/utils.sh
|
||||
|
||||
# cleanup any dev certs left behind
|
||||
. "$SCRIPT_DIR"/prep-signing-dev.sh
|
||||
cleanup_signing
|
||||
85
.github/scripts/apple-signing/notarize.sh
vendored
Executable file
85
.github/scripts/apple-signing/notarize.sh
vendored
Executable file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ue
|
||||
|
||||
set +xu
|
||||
if [ -z "$AC_USERNAME" ]; then
|
||||
exit_with_error "AC_USERNAME not set"
|
||||
fi
|
||||
|
||||
if [ -z "$AC_PASSWORD" ]; then
|
||||
exit_with_error "AC_PASSWORD not set"
|
||||
fi
|
||||
set -u
|
||||
|
||||
# repackage [archive-path]
|
||||
#
|
||||
# returns an archive compatible for Apple's notarization process, repackaging the input archive as needed
|
||||
#
|
||||
repackage() {
|
||||
archive=$1
|
||||
|
||||
case "$archive" in
|
||||
*.tar.gz)
|
||||
new_archive=${archive%.tar.gz}.zip
|
||||
(
|
||||
tmp_dir=$(mktemp -d)
|
||||
cd "$tmp_dir"
|
||||
# redirect stdout to stderr to preserve the return value
|
||||
tar xzf "$archive" && zip "$new_archive" $(tar tf "$archive") 1>&2
|
||||
rm -rf "$tmp_dir"
|
||||
)
|
||||
echo "$new_archive"
|
||||
;;
|
||||
*.zip)
|
||||
echo "$archive"
|
||||
;;
|
||||
*) return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# notarize [archive-path]
|
||||
#
|
||||
notarize() {
|
||||
archive_path=$1
|
||||
|
||||
title "notarizing binaries found in the release archive"
|
||||
|
||||
payload_archive_path=$(repackage "$archive_path")
|
||||
if [ "$?" != "0" ]; then
|
||||
exit_with_error "cannot prepare payload for notarization: $archive_path"
|
||||
fi
|
||||
|
||||
if [ ! -f "$payload_archive_path" ]; then
|
||||
exit_with_error "cannot find payload for notarization: $payload_archive_path"
|
||||
fi
|
||||
|
||||
# install gon
|
||||
which gon || (brew tap mitchellh/gon && brew install mitchellh/gon/gon)
|
||||
|
||||
# create config (note: json via stdin with gon is broken, can only use HCL from file)
|
||||
tmp_file=$(mktemp).hcl
|
||||
|
||||
cat <<EOF > "$tmp_file"
|
||||
notarize {
|
||||
path = "$archive_path"
|
||||
bundle_id = "com.anchore.toolbox.syft"
|
||||
}
|
||||
|
||||
apple_id {
|
||||
username = "$AC_USERNAME"
|
||||
password = "@env:AC_PASSWORD"
|
||||
}
|
||||
EOF
|
||||
|
||||
gon -log-level info "$tmp_file"
|
||||
|
||||
result="$?"
|
||||
|
||||
rm "$tmp_file"
|
||||
|
||||
if [ "$result" -ne "0" ]; then
|
||||
exit_with_error "notarization failed"
|
||||
fi
|
||||
}
|
||||
|
||||
172
.github/scripts/apple-signing/prep-signing-dev.sh
vendored
Executable file
172
.github/scripts/apple-signing/prep-signing-dev.sh
vendored
Executable file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
NAME=syft-dev
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
DIR=$SCRIPT_DIR/dev-pki
|
||||
FILE_PREFIX=$DIR/$NAME
|
||||
IDENTITY=${NAME}-id-415d8c69793
|
||||
|
||||
## OpenSSL material
|
||||
|
||||
KEY_PASSWORD="letthedevin"
|
||||
P12_PASSWORD="popeofnope"
|
||||
|
||||
KEY_FILE=$FILE_PREFIX-key.pem
|
||||
CSR_FILE=$FILE_PREFIX-csr.pem
|
||||
CERT_FILE=$FILE_PREFIX-cert.pem
|
||||
EXT_FILE=$FILE_PREFIX-ext.cnf
|
||||
P12_FILE=$FILE_PREFIX.p12
|
||||
|
||||
EXT_SECTION=codesign_reqext
|
||||
|
||||
## Keychain material
|
||||
|
||||
KEYCHAIN_NAME=$NAME
|
||||
KEYCHAIN_PATH=$HOME/Library/Keychains/$KEYCHAIN_NAME-db
|
||||
KEYCHAIN_PASSWORD="topsykretts"
|
||||
|
||||
# setup_signing
|
||||
#
|
||||
# preps the MAC_SIGNING_IDENTITY env var for use in the signing process, using ephemeral developer certificate material
|
||||
#
|
||||
function setup_signing() {
|
||||
# check to see if this has already been done... if so, bail!
|
||||
set +ue
|
||||
if security find-identity -p codesigning "$KEYCHAIN_PATH" | grep $IDENTITY ; then
|
||||
export MAC_SIGNING_IDENTITY=$IDENTITY
|
||||
commentary "skipping creating dev certificate material (already exists)"
|
||||
commentary "setting MAC_SIGNING_IDENTITY=${IDENTITY}"
|
||||
return 0
|
||||
fi
|
||||
set -ue
|
||||
|
||||
title "setting up developer certificate material"
|
||||
|
||||
mkdir -p "${DIR}"
|
||||
|
||||
# configure the openssl extensions
|
||||
cat << EOF > $EXT_FILE
|
||||
[ req ]
|
||||
default_bits = 2048 # RSA key size
|
||||
encrypt_key = yes # Protect private key
|
||||
default_md = sha256 # MD to use
|
||||
utf8 = yes # Input is UTF-8
|
||||
string_mask = utf8only # Emit UTF-8 strings
|
||||
prompt = yes # Prompt for DN
|
||||
distinguished_name = codesign_dn # DN template
|
||||
req_extensions = $EXT_SECTION # Desired extensions
|
||||
|
||||
[ codesign_dn ]
|
||||
commonName = $IDENTITY
|
||||
commonName_max = 64
|
||||
|
||||
[ $EXT_SECTION ]
|
||||
keyUsage = critical,digitalSignature
|
||||
extendedKeyUsage = critical,codeSigning
|
||||
subjectKeyIdentifier = hash
|
||||
EOF
|
||||
|
||||
title "create the private key"
|
||||
openssl genrsa \
|
||||
-des3 \
|
||||
-out "$KEY_FILE" \
|
||||
-passout "pass:$KEY_PASSWORD" \
|
||||
2048
|
||||
|
||||
title "create the csr"
|
||||
openssl req \
|
||||
-new \
|
||||
-key "$KEY_FILE" \
|
||||
-out "$CSR_FILE" \
|
||||
-passin "pass:$KEY_PASSWORD" \
|
||||
-config "$EXT_FILE" \
|
||||
-subj "/CN=$IDENTITY"
|
||||
|
||||
commentary "verify the csr: we should see X509 v3 extensions for codesigning in the CSR"
|
||||
openssl req -in "$CSR_FILE" -noout -text | grep -A1 "X509v3" || exit_with_error "could not find x509 extensions in CSR"
|
||||
|
||||
title "create the certificate"
|
||||
# note: Extensions in certificates are not transferred to certificate requests and vice versa. This means that
|
||||
# just because the CSR has x509 v3 extensions doesn't mean that you'll see these extensions in the cert output.
|
||||
# To prove this do:
|
||||
# openssl x509 -text -noout -in server.crt | grep -A10 "X509v3 extensions:"
|
||||
# ... and you will see no output (if -extensions is not used). (see https://www.openssl.org/docs/man1.1.0/man1/x509.html#BUGS)
|
||||
# To get the extensions, use "-extensions codesign_reqext" when creating the cert. The codesign_reqext value matches
|
||||
# the section name in the ext file used in CSR / cert creation (-extfile and -config).
|
||||
openssl x509 \
|
||||
-req \
|
||||
-days 10000 \
|
||||
-in "$CSR_FILE" \
|
||||
-signkey "$KEY_FILE" \
|
||||
-out "$CERT_FILE" \
|
||||
-extfile "$EXT_FILE" \
|
||||
-passin "pass:$KEY_PASSWORD" \
|
||||
-extensions $EXT_SECTION
|
||||
|
||||
commentary "verify the certificate: we should see our extensions"
|
||||
openssl x509 -text -noout -in $CERT_FILE | grep -A1 'X509v3' || exit_with_error "could not find x509 extensions in certificate"
|
||||
|
||||
title "export cert and private key to .p12 file"
|
||||
# note: this step may be entirely optional, however, I found it useful to follow the prod path which goes the route of using a p12
|
||||
openssl pkcs12 \
|
||||
-export \
|
||||
-out "$P12_FILE" \
|
||||
-inkey "$KEY_FILE" \
|
||||
-in "$CERT_FILE" \
|
||||
-passin "pass:$KEY_PASSWORD" \
|
||||
-passout "pass:$P12_PASSWORD"
|
||||
|
||||
|
||||
title "create the dev keychain"
|
||||
|
||||
# delete the keychain if it already exists
|
||||
if [ -f "$(KEYCHAIN_PATH)" ]; then
|
||||
security delete-keychain "$KEYCHAIN_NAME" &> /dev/null
|
||||
fi
|
||||
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_NAME"
|
||||
|
||||
set +e
|
||||
if ! security verify-cert -k "$KEYCHAIN_PATH" -c "$CERT_FILE" &> /dev/null; then
|
||||
set -e
|
||||
title "import the cert into the dev keychain if it is not already trusted by the system"
|
||||
|
||||
security import "$P12_FILE" -P $P12_PASSWORD -f pkcs12 -k "$KEYCHAIN_PATH" -T /usr/bin/codesign
|
||||
|
||||
# note: set the partition list for this certificate's private key to include "apple-tool:" and "apple:" allows the codesign command to access this keychain item without an interactive user prompt.
|
||||
security set-key-partition-list -S "apple-tool:,apple:,codesign:" -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
# note: add-trusted-cert requires user interaction
|
||||
commentary "adding the developer certificate as a trusted certificate... (requires user interaction)"
|
||||
security add-trusted-cert -d -r trustRoot -k "$KEYCHAIN_PATH" "$CERT_FILE"
|
||||
else
|
||||
set -e
|
||||
commentary "...dev cert has already been imported onto the dev keychain"
|
||||
fi
|
||||
|
||||
# remove any generated cert material since the keychain now has all of this material loaded
|
||||
rm -rf "${DIR}"
|
||||
|
||||
commentary "make certain there are identities that can be used for code signing"
|
||||
security find-identity -p codesigning "$KEYCHAIN_PATH" | grep -C 30 "$IDENTITY" || exit_with_error "could not find identity that can be used with codesign"
|
||||
|
||||
title "add the dev keychain to the search path for codesign"
|
||||
add_keychain $KEYCHAIN_NAME
|
||||
|
||||
commentary "verify the keychain actually shows up"
|
||||
security list-keychains | grep "$KEYCHAIN_NAME" || exit_with_error "could not find new keychain"
|
||||
|
||||
export MAC_SIGNING_IDENTITY=$IDENTITY
|
||||
commentary "setting MAC_SIGNING_IDENTITY=${IDENTITY}"
|
||||
|
||||
}
|
||||
|
||||
|
||||
function cleanup_signing() {
|
||||
title "delete the dev keychain and all certificate material"
|
||||
set -xue
|
||||
security delete-keychain "$KEYCHAIN_NAME"
|
||||
rm -f "$KEYCHAIN_PATH"
|
||||
rm -rf "${DIR}"
|
||||
}
|
||||
45
.github/scripts/apple-signing/prep-signing-prod.sh
vendored
Executable file
45
.github/scripts/apple-signing/prep-signing-prod.sh
vendored
Executable file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
assert_in_ci
|
||||
|
||||
set +xu
|
||||
if [ -z "$APPLE_DEVELOPER_ID_CERT" ]; then
|
||||
exit_with_error "APPLE_DEVELOPER_ID_CERT not set"
|
||||
fi
|
||||
|
||||
if [ -z "$APPLE_DEVELOPER_ID_CERT_PASS" ]; then
|
||||
exit_with_error "APPLE_DEVELOPER_ID_CERT_PASS not set"
|
||||
fi
|
||||
set -u
|
||||
|
||||
# setup_signing
|
||||
#
|
||||
# preps the MAC_SIGNING_IDENTITY env var for use in the signing process, using production certificate material
|
||||
#
|
||||
setup_signing() {
|
||||
title "setting up production certificate material"
|
||||
|
||||
# Write signing certificate to disk from environment variable.
|
||||
cert_file="$HOME/developer_id_certificate.p12"
|
||||
echo -n "$APPLE_DEVELOPER_ID_CERT" | base64 --decode > "$cert_file"
|
||||
|
||||
# In order to have all keychain interactions avoid an interactive user prompt, we need to control the password for the keychain in question, which means we need to create a new keychain into which we'll import the signing certificate and from which we'll later access this certificate during code signing.
|
||||
ephemeral_keychain="ci-ephemeral-keychain"
|
||||
ephemeral_keychain_password="$(openssl rand -base64 100)"
|
||||
security create-keychain -p "${ephemeral_keychain_password}" "${ephemeral_keychain}"
|
||||
|
||||
# Import signing certificate into the keychain. (This is a pre-requisite for gon, which is invoked via goreleaser.)
|
||||
ephemeral_keychain_full_path="$HOME/Library/Keychains/${ephemeral_keychain}-db"
|
||||
security import "${cert_file}" -k "${ephemeral_keychain_full_path}" -P "${APPLE_DEVELOPER_ID_CERT_PASS}" -T "$(command -v codesign)"
|
||||
|
||||
# Setting the partition list for this certificate's private key to include "apple-tool:" and "apple:" allows the codesign command to access this keychain item without an interactive user prompt. (codesign is invoked by gon.)
|
||||
security set-key-partition-list -S "apple-tool:,apple:" -s -k "${ephemeral_keychain_password}" "${ephemeral_keychain_full_path}"
|
||||
|
||||
# Make this new keychain the user's default keychain, so that codesign will be able to find this certificate when we specify it during signing.
|
||||
security default-keychain -d "user" -s "${ephemeral_keychain_full_path}"
|
||||
|
||||
# TODO: extract this from the certificate material itself
|
||||
export MAC_SIGNING_IDENTITY="Developer ID Application: ANCHORE, INC. (9MJHKYX5AT)"
|
||||
commentary "setting MAC_SIGNING_IDENTITY=${MAC_SIGNING_IDENTITY}"
|
||||
}
|
||||
65
.github/scripts/apple-signing/run.sh
vendored
Executable file
65
.github/scripts/apple-signing/run.sh
vendored
Executable file
@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
ARCHIVE_PATH="$1"
|
||||
IS_SNAPSHOT="$2"
|
||||
|
||||
## grab utilities
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
. "$SCRIPT_DIR"/utils.sh
|
||||
|
||||
main() {
|
||||
perform_notarization=false
|
||||
archive_abs_path=$(realpath "$ARCHIVE_PATH")
|
||||
|
||||
if [ ! -f "$archive_abs_path" ]; then
|
||||
echo "archive does not exist: $archive_abs_path"
|
||||
fi
|
||||
|
||||
case "$IS_SNAPSHOT" in
|
||||
|
||||
"1" | "true" | "yes")
|
||||
commentary "assuming development setup..."
|
||||
. "$SCRIPT_DIR"/prep-signing-dev.sh
|
||||
;;
|
||||
|
||||
"0" | "false" | "no")
|
||||
commentary "assuming production setup..."
|
||||
. "$SCRIPT_DIR"/prep-signing-prod.sh
|
||||
. "$SCRIPT_DIR"/notarize.sh
|
||||
perform_notarization=true
|
||||
;;
|
||||
|
||||
*)
|
||||
exit_with_error "could not determine if this was a production build (isSnapshot='$IS_SNAPSHOT')"
|
||||
;;
|
||||
esac
|
||||
|
||||
. "$SCRIPT_DIR"/sign.sh
|
||||
|
||||
# load up all signing material into a keychain (note: this should set the MAC_SIGNING_IDENTITY env var)
|
||||
setup_signing
|
||||
|
||||
# sign all of the binaries in the archive and recreate the input archive with the signed binaries
|
||||
sign_binaries_in_archive "$archive_abs_path" "$MAC_SIGNING_IDENTITY"
|
||||
|
||||
# send all of the binaries off to apple to bless
|
||||
if $perform_notarization ; then
|
||||
notarize "$archive_abs_path"
|
||||
else
|
||||
commentary "skipping notarization..."
|
||||
fi
|
||||
}
|
||||
|
||||
set +u
|
||||
if [ -z "$SCRIPT" ]
|
||||
then
|
||||
set -u
|
||||
# log all output
|
||||
mkdir -p "$SCRIPT_DIR/log"
|
||||
/usr/bin/script "$SCRIPT_DIR/log/signing-$(basename $ARCHIVE_PATH).txt" /bin/bash -c "$0 $*"
|
||||
exit $?
|
||||
else
|
||||
set -u
|
||||
main
|
||||
fi
|
||||
78
.github/scripts/apple-signing/sign.sh
vendored
Executable file
78
.github/scripts/apple-signing/sign.sh
vendored
Executable file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
# sign_binary [binary-path] [signing-identity]
|
||||
#
|
||||
# signs a single binary with cosign
|
||||
#
|
||||
sign_binary() {
|
||||
exe_path=$1
|
||||
identity=$2
|
||||
|
||||
if [ -x "$exe_path" ] && file -b "$exe_path" | grep -q "Mach-O"
|
||||
then
|
||||
echo "signing $exe_path ..."
|
||||
else
|
||||
echo "skip signing $exe_path ..."
|
||||
return 0
|
||||
fi
|
||||
|
||||
codesign \
|
||||
-s "$identity" \
|
||||
-f \
|
||||
--verbose=4 \
|
||||
--timestamp \
|
||||
--options runtime \
|
||||
$exe_path
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit_with_error "signing failed"
|
||||
fi
|
||||
|
||||
codesign --verify "$exe_path" --verbose=4
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
exit_with_error "signing verification failed"
|
||||
fi
|
||||
}
|
||||
|
||||
# sign_binaries_in_archive [archive-abs-path] [signing-identity]
|
||||
#
|
||||
# signs all binaries within an archive (there must be at least one)
|
||||
#
|
||||
sign_binaries_in_archive() {
|
||||
archive_abs_path=$1
|
||||
identity=$2
|
||||
|
||||
scratch_path=$(mktemp -d)
|
||||
trap "rm -rf -- $scratch_path" EXIT
|
||||
|
||||
title "getting contents from the release archive: $archive_abs_path"
|
||||
tar -C "$scratch_path" -xvf "$archive_abs_path"
|
||||
|
||||
# invalidate the current archive, we only want an asset with signed binaries from this point forward
|
||||
rm "$archive_abs_path"
|
||||
|
||||
title "signing binaries found in the release archive"
|
||||
|
||||
discovered_binaries=0
|
||||
tmp_pipe=$(mktemp -ut pipe.XXX)
|
||||
mkfifo "$tmp_pipe"
|
||||
|
||||
find "$scratch_path" -perm +111 -type f > "$tmp_pipe" &
|
||||
|
||||
while IFS= read -r binary; do
|
||||
sign_binary "$binary" "$identity"
|
||||
((discovered_binaries++))
|
||||
done < "$tmp_pipe"
|
||||
|
||||
rm "$tmp_pipe"
|
||||
|
||||
if [ "$discovered_binaries" = "0" ]; then
|
||||
exit_with_error "found no binaries to sign"
|
||||
fi
|
||||
|
||||
title "recreating the release archive: $archive_abs_path"
|
||||
(cd "$scratch_path" && tar -czvf "$archive_abs_path" .)
|
||||
}
|
||||
|
||||
76
.github/scripts/apple-signing/utils.sh
vendored
Normal file
76
.github/scripts/apple-signing/utils.sh
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
## terminal goodies
|
||||
PURPLE='\033[0;35m'
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
BOLD=$(tput bold)
|
||||
RESET='\033[0m'
|
||||
|
||||
function success() {
|
||||
echo -e "\n${GREEN}${BOLD}$@${RESET}"
|
||||
}
|
||||
|
||||
function title() {
|
||||
success "Task: $@"
|
||||
}
|
||||
|
||||
function commentary() {
|
||||
echo -e "\n${PURPLE}# $@${RESET}"
|
||||
}
|
||||
|
||||
function error() {
|
||||
echo -e "${RED}${BOLD}error: $@${RESET}"
|
||||
}
|
||||
|
||||
function exit_with_error() {
|
||||
error $@
|
||||
exit 1
|
||||
}
|
||||
|
||||
function exit_with_message() {
|
||||
success $@
|
||||
exit 0
|
||||
}
|
||||
|
||||
function realpath {
|
||||
echo "$(cd $(dirname $1); pwd)/$(basename $1)";
|
||||
}
|
||||
|
||||
|
||||
# this function adds all of the existing keychains plus the new one which is the same as going to Keychain Access
|
||||
# and selecting "Add Keychain" to make the keychain visible under "Custom Keychains". This is done with
|
||||
# "security list-keychains -s" for some reason. The downside is that this sets the search path, not appends
|
||||
# to it, so you will loose existing keychains in the search path... which is truly terrible.
|
||||
function add_keychain() {
|
||||
keychains=$(security list-keychains -d user)
|
||||
keychainNames=();
|
||||
for keychain in $keychains
|
||||
do
|
||||
basename=$(basename "$keychain")
|
||||
keychainName=${basename::${#basename}-4}
|
||||
keychainNames+=("$keychainName")
|
||||
done
|
||||
|
||||
echo "existing user keychains: ${keychainNames[@]}"
|
||||
|
||||
security -v list-keychains -s "${keychainNames[@]}" "$1"
|
||||
}
|
||||
|
||||
function exit_not_ci() {
|
||||
printf "WARNING! It looks like this isn't the CI environment. This script modifies the macOS Keychain setup in ways you probably wouldn't want for your own machine. It also requires an Apple Developer ID Certificate that you shouldn't have outside of the CI environment.\n\nExiting early to make sure nothing bad happens.\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
CI_HOME="/Users/runner"
|
||||
|
||||
function assert_in_ci() {
|
||||
|
||||
if [[ "${HOME}" != "${CI_HOME}" ]]; then
|
||||
exit_not_ci
|
||||
fi
|
||||
|
||||
set +u
|
||||
if [ -z "${GITHUB_ACTIONS}" ]; then
|
||||
exit_not_ci
|
||||
fi
|
||||
set -u
|
||||
}
|
||||
2
.github/scripts/goreleaser-install.sh
vendored
2
.github/scripts/goreleaser-install.sh
vendored
@ -338,7 +338,7 @@ hash_sha256_verify() {
|
||||
return 1
|
||||
fi
|
||||
BASENAME=${TARGET##*/}
|
||||
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
|
||||
want=$(grep "${BASENAME}$" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
|
||||
if [ -z "$want" ]; then
|
||||
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
|
||||
return 1
|
||||
|
||||
31
.github/scripts/mac-prepare-for-signing.sh
vendored
31
.github/scripts/mac-prepare-for-signing.sh
vendored
@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
CI_HOME="/Users/runner"
|
||||
if [[ "${HOME}" != "${CI_HOME}" ]]; then
|
||||
printf "WARNING! It looks like this isn't the CI environment. This script modifies the macOS Keychain setup in ways you probably wouldn't want for your own machine. It also requires an Apple Developer ID Certificate that you shouldn't have outside of the CI environment.\n\nExiting early to make sure nothing bad happens.\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install gon (see https://github.com/mitchellh/gon for details).
|
||||
brew tap mitchellh/gon
|
||||
brew install mitchellh/gon/gon
|
||||
|
||||
# Write signing certificate to disk from environment variable.
|
||||
CERT_FILE="$HOME/developer_id_certificate.p12"
|
||||
echo -n "$APPLE_DEVELOPER_ID_CERT" | base64 --decode > "$CERT_FILE"
|
||||
|
||||
# In order to have all keychain interactions avoid an interactive user prompt, we need to control the password for the keychain in question, which means we need to create a new keychain into which we'll import the signing certificate and from which we'll later access this certificate during code signing.
|
||||
EPHEMERAL_KEYCHAIN="ci-ephemeral-keychain"
|
||||
EPHEMERAL_KEYCHAIN_PASSWORD="$(openssl rand -base64 100)"
|
||||
security create-keychain -p "${EPHEMERAL_KEYCHAIN_PASSWORD}" "${EPHEMERAL_KEYCHAIN}"
|
||||
|
||||
# Import signing certificate into the keychain. (This is a pre-requisite for gon, which is invoked via goreleaser.)
|
||||
EPHEMERAL_KEYCHAIN_FULL_PATH="$HOME/Library/Keychains/${EPHEMERAL_KEYCHAIN}-db"
|
||||
security import "${CERT_FILE}" -k "${EPHEMERAL_KEYCHAIN_FULL_PATH}" -P "${APPLE_DEVELOPER_ID_CERT_PASS}" -T "$(command -v codesign)"
|
||||
|
||||
# Setting the partition list for this certificate's private key to include "apple-tool:" and "apple:" allows the codesign command to access this keychain item without an interactive user prompt. (codesign is invoked by gon.)
|
||||
security set-key-partition-list -S "apple-tool:,apple:" -s -k "${EPHEMERAL_KEYCHAIN_PASSWORD}" "${EPHEMERAL_KEYCHAIN_FULL_PATH}"
|
||||
|
||||
# Make this new keychain the user's default keychain, so that codesign will be able to find this certificate when we specify it during signing.
|
||||
security default-keychain -d "user" -s "${EPHEMERAL_KEYCHAIN_FULL_PATH}"
|
||||
19
.github/scripts/mac-sign-and-notarize.sh
vendored
19
.github/scripts/mac-sign-and-notarize.sh
vendored
@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eu
|
||||
|
||||
IS_SNAPSHOT="$1" # e.g. "true", "false"
|
||||
|
||||
if [[ "${IS_SNAPSHOT}" == "true" ]]; then
|
||||
# This is a snapshot build —— skipping signing and notarization...
|
||||
exit 0
|
||||
fi
|
||||
|
||||
GON_CONFIG="$2" # e.g. "gon.hcl"
|
||||
NEW_NAME_WITHOUT_EXTENSION="$3" # e.g. "./dist/syft-0.1.0"
|
||||
ORIGINAL_NAME_WITHOUT_EXTENSION="./dist/output" # This should match dmg and zip output_path in the gon config file, without the extension.
|
||||
|
||||
gon "${GON_CONFIG}"
|
||||
|
||||
# Rename outputs with specified desired name
|
||||
mv -v "${ORIGINAL_NAME_WITHOUT_EXTENSION}.dmg" "${NEW_NAME_WITHOUT_EXTENSION}.dmg"
|
||||
mv -v "${ORIGINAL_NAME_WITHOUT_EXTENSION}.zip" "${NEW_NAME_WITHOUT_EXTENSION}.zip"
|
||||
14
.github/scripts/verify-signature.sh
vendored
14
.github/scripts/verify-signature.sh
vendored
@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ue
|
||||
|
||||
DISTDIR=$1
|
||||
|
||||
export FINGERPRINT=$(gpg --verify ${DISTDIR}/*checksums.txt.sig ${DISTDIR}/*checksums.txt 2>&1 | grep 'using RSA key' | awk '{ print $NF }')
|
||||
|
||||
if [[ "${FINGERPRINT}" == "${SIGNING_FINGERPRINT}" ]]; then
|
||||
echo 'verified signature'
|
||||
else
|
||||
echo "signed with unknown fingerprint: ${FINGERPRINT}"
|
||||
echo " expected fingerprint: ${SIGNING_FINGERPRINT}"
|
||||
exit 1
|
||||
fi
|
||||
33
.github/workflows/release.yaml
vendored
33
.github/workflows/release.yaml
vendored
@ -14,7 +14,7 @@ env:
|
||||
jobs:
|
||||
quality-gate:
|
||||
environment: release
|
||||
runs-on: ubuntu-latest # This OS choice is arbitrary. None of the steps in this job are specific to either Linux or macOS.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@ -92,7 +92,8 @@ jobs:
|
||||
|
||||
release:
|
||||
needs: [quality-gate]
|
||||
runs-on: macos-latest # Due to our code signing process, it's vital that we run our release steps on macOS.
|
||||
# due to our code signing process, it's vital that we run our release steps on macOS
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: docker-practice/actions-setup-docker@v1
|
||||
|
||||
@ -124,35 +125,21 @@ jobs:
|
||||
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
|
||||
run: make bootstrap
|
||||
|
||||
- name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: crazy-max/ghaction-import-gpg@v2
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.SIGNING_GPG_PRIVATE_KEY }}
|
||||
PASSPHRASE: ${{ secrets.SIGNING_GPG_PASSPHRASE }}
|
||||
|
||||
- name: GPG signing info
|
||||
run: |
|
||||
echo "fingerprint: ${{ steps.import_gpg.outputs.fingerprint }}"
|
||||
echo "keyid: ${{ steps.import_gpg.outputs.keyid }}"
|
||||
echo "name: ${{ steps.import_gpg.outputs.name }}"
|
||||
echo "email: ${{ steps.import_gpg.outputs.email }}"
|
||||
|
||||
- name: Build & publish release artifacts
|
||||
run: make release
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.TOOLBOX_DOCKER_USER }}
|
||||
DOCKER_PASSWORD: ${{ secrets.TOOLBOX_DOCKER_PASS }}
|
||||
# we use a different token than GITHUB_SECRETS to additionally allow updating the homebrew repos
|
||||
GITHUB_TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }}
|
||||
GPG_PRIVATE_KEY: ${{ secrets.SIGNING_GPG_PRIVATE_KEY }}
|
||||
PASSPHRASE: ${{ secrets.SIGNING_GPG_PASSPHRASE }}
|
||||
SIGNING_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
APPLE_DEVELOPER_ID_CERT: ${{ secrets.APPLE_DEVELOPER_ID_CERT }} # Used during macOS code signing.
|
||||
APPLE_DEVELOPER_ID_CERT_PASS: ${{ secrets.APPLE_DEVELOPER_ID_CERT_PASS }} # Used during macOS code signing.
|
||||
AC_USERNAME: ${{ secrets.ENG_CI_APPLE_ID }} # Used during macOS notarization.
|
||||
AC_PASSWORD: ${{ secrets.ENG_CI_APPLE_ID_PASS }} # Used during macOS notarization.
|
||||
# used during macOS code signing
|
||||
APPLE_DEVELOPER_ID_CERT: ${{ secrets.APPLE_DEVELOPER_ID_CERT }}
|
||||
APPLE_DEVELOPER_ID_CERT_PASS: ${{ secrets.APPLE_DEVELOPER_ID_CERT_PASS }}
|
||||
# used during macOS notarization
|
||||
AC_USERNAME: ${{ secrets.ENG_CI_APPLE_ID }}
|
||||
AC_PASSWORD: ${{ secrets.ENG_CI_APPLE_ID_PASS }}
|
||||
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
|
||||
@ -1,84 +1,77 @@
|
||||
release:
|
||||
# If set to auto, will mark the release as not ready for production in case there is an indicator for this in the
|
||||
# tag e.g. v1.0.0-rc1 .If set to true, will mark the release as not ready for production.
|
||||
prerelease: auto
|
||||
|
||||
# If set to true, will not auto-publish the release. This is done to allow us to review the changelog before publishing.
|
||||
draft: true
|
||||
|
||||
env:
|
||||
# required to support multi architecture docker builds
|
||||
- DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
|
||||
builds:
|
||||
- binary: syft
|
||||
id: syft
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- id: linux-build
|
||||
binary: syft
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
# Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build)
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
ldflags: |
|
||||
# set the modified timestamp on the output binary to the git timestamp to ensure a reproducible build
|
||||
mod_timestamp: &build-timestamp '{{ .CommitTimestamp }}'
|
||||
env: &build-env
|
||||
- CGO_ENABLED=0
|
||||
ldflags: &build-ldflags |
|
||||
-w
|
||||
-s
|
||||
-extldflags '-static'
|
||||
-X github.com/anchore/syft/internal/version.version={{.Version}}
|
||||
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
|
||||
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
|
||||
-X github.com/anchore/syft/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}}
|
||||
-X github.com/anchore/syft/internal/version.gitDescription={{.Summary}}
|
||||
|
||||
# For more info on this macOS build, see: https://github.com/mitchellh/gon#usage-with-goreleaser
|
||||
- binary: syft
|
||||
id: syft-macos
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- id: darwin-build
|
||||
binary: syft
|
||||
goos:
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
# 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/syft/internal/version.version={{.Version}}
|
||||
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
|
||||
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
|
||||
-X github.com/anchore/syft/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}}
|
||||
mod_timestamp: *build-timestamp
|
||||
env: *build-env
|
||||
ldflags: *build-ldflags
|
||||
|
||||
- id: windows-build
|
||||
binary: syft
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
mod_timestamp: *build-timestamp
|
||||
env: *build-env
|
||||
ldflags: *build-ldflags
|
||||
|
||||
archives:
|
||||
- name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}'
|
||||
id: syft
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
- format: zip # This is a hack for syft-macos! We don't actually intend to use _this_ ZIP file, we just need goreleaser to consider the ZIP file produced by gon (which will have the same file name) to be an artifact so we can use it downstream in publishing (e.g. to a homebrew tap)
|
||||
id: syft-exception
|
||||
- id: linux-archives
|
||||
builds:
|
||||
- syft-macos
|
||||
- linux-build
|
||||
|
||||
# note: the signing process is depending on tar.gz archives. If this format changes then .github/scripts/apple-signing/*.sh will need to be adjusted
|
||||
- id: darwin-archives
|
||||
builds:
|
||||
- darwin-build
|
||||
|
||||
- id: windows-archives
|
||||
format: zip
|
||||
builds:
|
||||
- windows-build
|
||||
|
||||
signs:
|
||||
- artifacts: checksum
|
||||
cmd: sh
|
||||
args:
|
||||
- '-c'
|
||||
# we should not include the zip artifact, as the artifact is mutated throughout the next macOS notarization step
|
||||
# note: sed -i is not portable
|
||||
- 'sed "/.*_darwin_.*\.zip/d" ${artifact} > tmpfile && mv tmpfile ${artifact} && gpg --output ${signature} --detach-sign ${artifact}'
|
||||
- id: syft-macos-signing
|
||||
- artifacts: archive
|
||||
ids:
|
||||
- syft-macos
|
||||
cmd: ./.github/scripts/mac-sign-and-notarize.sh
|
||||
signature: "syft_${VERSION}_darwin_amd64.dmg" # This is somewhat unintuitive. This gets the DMG file recognized as an artifact. In fact, both a DMG and a ZIP file are being produced by this signing step.
|
||||
- darwin-archives
|
||||
signature: "${artifact}"
|
||||
cmd: ./.github/scripts/apple-signing/run.sh
|
||||
args:
|
||||
- "${artifact}"
|
||||
- "{{ .IsSnapshot }}"
|
||||
- "gon.hcl"
|
||||
- "./dist/syft_{{ .Version }}_darwin_amd64"
|
||||
artifacts: all
|
||||
|
||||
nfpms:
|
||||
- license: "Apache 2.0"
|
||||
@ -94,7 +87,8 @@ brews:
|
||||
owner: anchore
|
||||
name: homebrew-syft
|
||||
ids:
|
||||
- syft
|
||||
- darwin-archives
|
||||
- linux-archives
|
||||
homepage: *website
|
||||
description: *description
|
||||
license: "Apache License 2.0"
|
||||
|
||||
90
Makefile
90
Makefile
@ -4,8 +4,12 @@ RESULTSDIR = test/results
|
||||
COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt
|
||||
COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt
|
||||
LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --timeout=2m --config .golangci.yaml
|
||||
RELEASE_CMD=$(TEMPDIR)/goreleaser release --rm-dist
|
||||
SNAPSHOT_CMD=$(RELEASE_CMD) --skip-publish --snapshot
|
||||
COMPARE_TEST_IMAGE = centos:8.2.2004
|
||||
COMPARE_DIR = ./test/compare
|
||||
|
||||
# formatting variables
|
||||
BOLD := $(shell tput -T linux bold)
|
||||
PURPLE := $(shell tput -T linux setaf 5)
|
||||
GREEN := $(shell tput -T linux setaf 2)
|
||||
@ -14,8 +18,10 @@ RED := $(shell tput -T linux setaf 1)
|
||||
RESET := $(shell tput -T linux sgr0)
|
||||
TITLE := $(BOLD)$(PURPLE)
|
||||
SUCCESS := $(BOLD)$(GREEN)
|
||||
|
||||
# the quality gate lower threshold for unit test total % coverage (by function statements)
|
||||
COVERAGE_THRESHOLD := 62
|
||||
|
||||
# CI cache busting values; change these if you want CI to not use previous stored cache
|
||||
INTEGRATION_CACHE_BUSTER="894d8ca"
|
||||
CLI_CACHE_BUSTER="894d8ca"
|
||||
@ -24,18 +30,8 @@ BOOTSTRAP_CACHE="c7afb99ad"
|
||||
## Build variables
|
||||
DISTDIR=./dist
|
||||
SNAPSHOTDIR=./snapshot
|
||||
GITTREESTATE=$(if $(shell git status --porcelain),dirty,clean)
|
||||
OS := $(shell uname)
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN))
|
||||
else
|
||||
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN))
|
||||
endif
|
||||
|
||||
ifeq "$(strip $(VERSION))" ""
|
||||
override VERSION = $(shell git describe --always --tags --dirty)
|
||||
endif
|
||||
OS=$(shell uname | tr '[:upper:]' '[:lower:]')
|
||||
SNAPSHOT_BIN=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(OS)-build_$(OS)_amd64/$(BIN))
|
||||
|
||||
## Variable assertions
|
||||
|
||||
@ -67,6 +63,14 @@ define title
|
||||
@printf '$(TITLE)$(1)$(RESET)\n'
|
||||
endef
|
||||
|
||||
define safe_rm_rf
|
||||
bash -c 'test -z "$(1)" && false || rm -rf $(1)'
|
||||
endef
|
||||
|
||||
define safe_rm_rf_children
|
||||
bash -c 'test -z "$(1)" && false || rm -rf $(1)/*'
|
||||
endef
|
||||
|
||||
## Tasks
|
||||
|
||||
.PHONY: all
|
||||
@ -100,7 +104,7 @@ bootstrap-tools: $(TEMPDIR)
|
||||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.42.1
|
||||
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
|
||||
.github/scripts/goreleaser-install.sh -b $(TEMPDIR)/ v0.177.0
|
||||
.github/scripts/goreleaser-install.sh -d -b $(TEMPDIR)/ v1.3.1
|
||||
GOBIN="$(shell realpath $(TEMPDIR))" go install github.com/neilpa/yajsv@v1.4.0
|
||||
|
||||
.PHONY: bootstrap-go
|
||||
@ -223,15 +227,29 @@ build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages
|
||||
|
||||
$(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
|
||||
# DOCKER_CLI_EXPERIMENTAL needed to support multi architecture builds for goreleaser
|
||||
BUILD_GIT_TREE_STATE=$(GITTREESTATE) \
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled \
|
||||
$(TEMPDIR)/goreleaser release --skip-publish --skip-sign --rm-dist --snapshot --config $(TEMPDIR)/goreleaser.yaml
|
||||
$(SNAPSHOT_CMD) --skip-sign --config $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
.PHONY: snapshot-with-signing
|
||||
snapshot-with-signing: ## Build snapshot release binaries and packages (with dummy signing)
|
||||
$(call title,Building snapshot artifacts (+ signing))
|
||||
|
||||
# create a config with the dist dir overridden
|
||||
echo "dist: $(SNAPSHOTDIR)" > $(TEMPDIR)/goreleaser.yaml
|
||||
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
rm -f .github/scripts/apple-signing/log/signing-*
|
||||
|
||||
# build release snapshots
|
||||
bash -c "$(SNAPSHOT_CMD) --config $(TEMPDIR)/goreleaser.yaml || (cat .github/scripts/apple-signing/log/signing-* && false)"
|
||||
|
||||
# remove the keychain with the trusted self-signed cert automatically
|
||||
.github/scripts/apple-signing/cleanup.sh
|
||||
|
||||
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
|
||||
.PHONY: compare-mac
|
||||
@ -272,9 +290,9 @@ cli-fingerprint:
|
||||
|
||||
.PHONY: cli
|
||||
cli: $(SNAPSHOTDIR) ## Run CLI tests
|
||||
chmod 755 "$(SNAPSHOT_CMD)"
|
||||
$(SNAPSHOT_CMD) version
|
||||
SYFT_BINARY_LOCATION='$(SNAPSHOT_CMD)' \
|
||||
chmod 755 "$(SNAPSHOT_BIN)"
|
||||
$(SNAPSHOT_BIN) version
|
||||
SYFT_BINARY_LOCATION='$(SNAPSHOT_BIN)' \
|
||||
go test -count=1 -v ./test/cli
|
||||
|
||||
.PHONY: changelog
|
||||
@ -291,10 +309,6 @@ CHANGELOG.md:
|
||||
.PHONY: release
|
||||
release: clean-dist CHANGELOG.md ## Build and publish final binaries and packages. Intended to be run only on macOS.
|
||||
$(call title,Publishing release artifacts)
|
||||
|
||||
# Prepare for macOS-specific signing process
|
||||
.github/scripts/mac-prepare-for-signing.sh
|
||||
|
||||
# login to docker
|
||||
# note: the previous step creates a new keychain, so it is important to reauth into docker.io
|
||||
@echo $${DOCKER_PASSWORD} | docker login docker.io -u $${DOCKER_USERNAME} --password-stdin
|
||||
@ -303,19 +317,15 @@ release: clean-dist CHANGELOG.md ## Build and publish final binaries and packag
|
||||
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
|
||||
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
# release (note the version transformation from v0.7.0 --> 0.7.0)
|
||||
# DOCKER_CLI_EXPERIMENTAL needed to support multi architecture builds for goreleaser
|
||||
bash -c "\
|
||||
BUILD_GIT_TREE_STATE=$(GITTREESTATE) \
|
||||
VERSION=$(VERSION:v%=%) \
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled \
|
||||
$(TEMPDIR)/goreleaser \
|
||||
--rm-dist \
|
||||
--config $(TEMPDIR)/goreleaser.yaml \
|
||||
--release-notes <(cat CHANGELOG.md)"
|
||||
rm -f .github/scripts/apple-signing/log/signing-*
|
||||
|
||||
# verify checksum signatures
|
||||
.github/scripts/verify-signature.sh "$(DISTDIR)"
|
||||
bash -c "\
|
||||
$(RELEASE_CMD) \
|
||||
--config $(TEMPDIR)/goreleaser.yaml \
|
||||
--release-notes <(cat CHANGELOG.md)\
|
||||
|| cat .github/scripts/apple-signing/log/signing-* && false"
|
||||
|
||||
cat .github/scripts/apple-signing/log/signing-*
|
||||
|
||||
# upload the version file that supports the application version update check (excluding pre-releases)
|
||||
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
|
||||
@ -323,15 +333,17 @@ release: clean-dist CHANGELOG.md ## Build and publish final binaries and packag
|
||||
|
||||
.PHONY: clean
|
||||
clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache
|
||||
rm -rf $(RESULTSDIR)/*
|
||||
$(call safe_rm_rf_children,$(RESULTSDIR))
|
||||
|
||||
.PHONY: clean-snapshot
|
||||
clean-snapshot:
|
||||
rm -rf $(SNAPSHOTDIR) $(TEMPDIR)/goreleaser.yaml
|
||||
$(call safe_rm_rf,$(SNAPSHOTDIR))
|
||||
rm -f $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
.PHONY: clean-dist
|
||||
clean-dist: clean-changelog
|
||||
rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml
|
||||
$(call safe_rm_rf,$(DISTDIR))
|
||||
rm -f $(TEMPDIR)/goreleaser.yaml
|
||||
|
||||
.PHONY: clean-changelog
|
||||
clean-changelog:
|
||||
|
||||
@ -29,14 +29,14 @@ func printVersion(_ *cobra.Command, _ []string) {
|
||||
|
||||
switch outputFormat {
|
||||
case "text":
|
||||
fmt.Println("Application: ", internal.ApplicationName)
|
||||
fmt.Println("Version: ", versionInfo.Version)
|
||||
fmt.Println("BuildDate: ", versionInfo.BuildDate)
|
||||
fmt.Println("GitCommit: ", versionInfo.GitCommit)
|
||||
fmt.Println("GitTreeState: ", versionInfo.GitTreeState)
|
||||
fmt.Println("Platform: ", versionInfo.Platform)
|
||||
fmt.Println("GoVersion: ", versionInfo.GoVersion)
|
||||
fmt.Println("Compiler: ", versionInfo.Compiler)
|
||||
fmt.Println("Application: ", internal.ApplicationName)
|
||||
fmt.Println("Version: ", versionInfo.Version)
|
||||
fmt.Println("BuildDate: ", versionInfo.BuildDate)
|
||||
fmt.Println("GitCommit: ", versionInfo.GitCommit)
|
||||
fmt.Println("GitDescription: ", versionInfo.GitDescription)
|
||||
fmt.Println("Platform: ", versionInfo.Platform)
|
||||
fmt.Println("GoVersion: ", versionInfo.GoVersion)
|
||||
fmt.Println("Compiler: ", versionInfo.Compiler)
|
||||
|
||||
case "json":
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
|
||||
15
gon.hcl
15
gon.hcl
@ -1,15 +0,0 @@
|
||||
source = ["./dist/syft-macos_darwin_amd64/syft"] # The 'dist' directory path should ideally reference an env var, where the source of truth is the Makefile. I wasn't able to figure out how to solve this.
|
||||
bundle_id = "com.anchore.toolbox.syft"
|
||||
|
||||
sign {
|
||||
application_identity = "Developer ID Application: ANCHORE, INC. (9MJHKYX5AT)"
|
||||
}
|
||||
|
||||
dmg {
|
||||
output_path = "./dist/output.dmg"
|
||||
volume_name = "Syft"
|
||||
}
|
||||
|
||||
zip {
|
||||
output_path = "./dist/output.zip"
|
||||
}
|
||||
54
install.sh
54
install.sh
@ -507,15 +507,8 @@ get_format_name() (
|
||||
original_format="${format}"
|
||||
|
||||
case ${os} in
|
||||
# why override darwin to DMG? two reasons:
|
||||
# 1. the tar.gz does not contain a signed binary
|
||||
# 2. the zip is removed from the checksums file (since the signing process changes the content)
|
||||
darwin) format=dmg ;;
|
||||
windows) format=zip ;;
|
||||
esac
|
||||
case "${os}/${arch}" in
|
||||
darwin/arm64) format=zip ;;
|
||||
esac
|
||||
|
||||
log_trace "get_format_name(os=${os}, arch=${arch}, format=${original_format}) returned '${format}'"
|
||||
|
||||
@ -553,30 +546,6 @@ download_and_install_asset() (
|
||||
# outputs the path to the downloaded asset asset_filepath
|
||||
#
|
||||
download_asset() (
|
||||
download_url="$1"
|
||||
download_path="$2"
|
||||
name="$3"
|
||||
os="$4"
|
||||
arch="$5"
|
||||
version="$6"
|
||||
format="$7"
|
||||
|
||||
if [ "$format" = "dmg" ] || [ "$os/$arch/$format" = "darwin/arm64/zip" ]; then
|
||||
# the signing process outputs the zip/dmg and the checksum is not included in the checksums.txt file
|
||||
# TODO: remove this case in the future by upgrading the release process
|
||||
asset_filepath=$(download_asset_without_verification "${download_url}" "${download_path}" "${name}" "${os}" "${arch}" "${version}" "${format}")
|
||||
else
|
||||
asset_filepath=$(download_asset_by_checksums_file "${download_url}" "${download_path}" "${name}" "${os}" "${arch}" "${version}" "${format}")
|
||||
fi
|
||||
|
||||
echo "${asset_filepath}"
|
||||
)
|
||||
|
||||
# download_asset_without_verification [release-url-prefix] [destination] [name] [os] [arch] [version] [format]
|
||||
#
|
||||
# outputs the filepath to the raw asset (no verification against the checksums file is performed)
|
||||
#
|
||||
download_asset_without_verification() (
|
||||
download_url="$1"
|
||||
destination="$2"
|
||||
name="$3"
|
||||
@ -585,28 +554,7 @@ download_asset_without_verification() (
|
||||
version="$6"
|
||||
format="$7"
|
||||
|
||||
asset_filename="${name}_${version}_${os}_${arch}.${format}"
|
||||
asset_url="${download_url}/${asset_filename}"
|
||||
asset_filepath="${destination}/${asset_filename}"
|
||||
http_download "${asset_filepath}" "${asset_url}" ""
|
||||
|
||||
echo "${asset_filepath}"
|
||||
)
|
||||
|
||||
# download_asset_by_checksums_file [release-url-prefix] [destination] [name] [os] [arch] [version] [format]
|
||||
#
|
||||
# outputs the filepath to the raw asset (verified against the checksums file)
|
||||
#
|
||||
download_asset_by_checksums_file() (
|
||||
download_url="$1"
|
||||
destination="$2"
|
||||
name="$3"
|
||||
os="$4"
|
||||
arch="$5"
|
||||
version="$6"
|
||||
format="$7"
|
||||
|
||||
log_trace "download_asset_by_checksums_file(url=${download_url}, destination=${destination}, name=${name}, os=${os}, arch=${arch}, version=${version}, format=${format})"
|
||||
log_trace "download_asset(url=${download_url}, destination=${destination}, name=${name}, os=${os}, arch=${arch}, version=${version}, format=${format})"
|
||||
|
||||
checksums_filepath=$(download_github_release_checksums "${download_url}" "${name}" "${version}" "${destination}")
|
||||
|
||||
|
||||
@ -14,19 +14,19 @@ const valueNotProvided = "[not provided]"
|
||||
// all variables here are provided as build-time arguments, with clear default values
|
||||
var version = valueNotProvided
|
||||
var gitCommit = valueNotProvided
|
||||
var gitTreeState = valueNotProvided
|
||||
var gitDescription = valueNotProvided
|
||||
var buildDate = valueNotProvided
|
||||
var platform = fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
// Version defines the application version details (generally from build information)
|
||||
type Version struct {
|
||||
Version string `json:"version"` // application semantic version
|
||||
GitCommit string `json:"gitCommit"` // git SHA at build-time
|
||||
GitTreeState string `json:"gitTreeState"` // indication of git tree (either "clean" or "dirty") at build-time
|
||||
BuildDate string `json:"buildDate"` // date of the build
|
||||
GoVersion string `json:"goVersion"` // go runtime version at build-time
|
||||
Compiler string `json:"compiler"` // compiler used at build-time
|
||||
Platform string `json:"platform"` // GOOS and GOARCH at build-time
|
||||
Version string `json:"version"` // application semantic version
|
||||
GitCommit string `json:"gitCommit"` // git SHA at build-time
|
||||
GitDescription string `json:"gitDescription"` // output of 'git describe --dirty --always --tags'
|
||||
BuildDate string `json:"buildDate"` // date of the build
|
||||
GoVersion string `json:"goVersion"` // go runtime version at build-time
|
||||
Compiler string `json:"compiler"` // compiler used at build-time
|
||||
Platform string `json:"platform"` // GOOS and GOARCH at build-time
|
||||
}
|
||||
|
||||
func (v Version) IsProductionBuild() bool {
|
||||
@ -39,12 +39,12 @@ func (v Version) IsProductionBuild() bool {
|
||||
// FromBuild provides all version details
|
||||
func FromBuild() Version {
|
||||
return Version{
|
||||
Version: version,
|
||||
GitCommit: gitCommit,
|
||||
GitTreeState: gitTreeState,
|
||||
BuildDate: buildDate,
|
||||
GoVersion: runtime.Version(),
|
||||
Compiler: runtime.Compiler,
|
||||
Platform: platform,
|
||||
Version: version,
|
||||
GitCommit: gitCommit,
|
||||
GitDescription: gitDescription,
|
||||
BuildDate: buildDate,
|
||||
GoVersion: runtime.Version(),
|
||||
Compiler: runtime.Compiler,
|
||||
Platform: platform,
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,10 +101,8 @@ func getSyftBinaryLocation(t testing.TB) string {
|
||||
func getSyftBinaryLocationByOS(t testing.TB, goOS string) string {
|
||||
// note: there is a subtle - vs _ difference between these versions
|
||||
switch goOS {
|
||||
case "darwin":
|
||||
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-macos_darwin_%s/syft", runtime.GOARCH))
|
||||
case "linux":
|
||||
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft_linux_%s/syft", runtime.GOARCH))
|
||||
case "darwin", "linux":
|
||||
return path.Join(repoRoot(t), fmt.Sprintf("snapshot/%s-build_%s_%s/syft", goOS, goOS, runtime.GOARCH))
|
||||
default:
|
||||
t.Fatalf("unsupported OS: %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ else
|
||||
fi
|
||||
|
||||
# run syft
|
||||
SYFT_PATH="${DISTDIR}/syft-macos_darwin_amd64/syft"
|
||||
SYFT_PATH="${DISTDIR}/darwin-build_darwin_amd64/syft"
|
||||
chmod 755 "${SYFT_PATH}"
|
||||
"${SYFT_PATH}" version
|
||||
SYFT_CHECK_FOR_APP_UPDATE=0 "${SYFT_PATH}" packages docker-archive:${TEST_IMAGE_TAR} -vv -o json > "${REPORT}"
|
||||
|
||||
@ -72,9 +72,7 @@ run_test_case test_positive_snapshot_download_asset "linux" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "arm64" "rpm"
|
||||
run_test_case test_positive_snapshot_download_asset "linux" "arm64" "deb"
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "amd64" "zip"
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_download_asset "darwin" "arm64" "zip"
|
||||
run_test_case test_positive_snapshot_download_asset "windows" "amd64" "zip"
|
||||
# note: the mac signing process produces a dmg which is not part of the snapshot process (thus is not exercised here)
|
||||
|
||||
|
||||
@ -33,8 +33,6 @@ release=$(get_release_tag "${OWNER}" "${REPO}" "latest" )
|
||||
# exercise all possible assets against a real github release (based on asset listing from https://github.com/anchore/syft/releases/tag/v0.36.0)
|
||||
run_test_case test_download_release_asset "${release}" "darwin" "amd64" "tar.gz" "application/gzip"
|
||||
run_test_case test_download_release_asset "${release}" "darwin" "arm64" "tar.gz" "application/gzip"
|
||||
run_test_case test_download_release_asset "${release}" "darwin" "arm64" "zip" "application/zip"
|
||||
run_test_case test_download_release_asset "${release}" "darwin" "amd64" "dmg" "application/zlib"
|
||||
run_test_case test_download_release_asset "${release}" "linux" "amd64" "tar.gz" "application/gzip"
|
||||
run_test_case test_download_release_asset "${release}" "linux" "amd64" "rpm" "application/x-rpm"
|
||||
run_test_case test_download_release_asset "${release}" "linux" "amd64" "deb" "application/vnd.debian.binary-package"
|
||||
|
||||
@ -26,14 +26,8 @@ test_positive_snapshot_install_asset() {
|
||||
expected_path="${install_dir}/${binary}"
|
||||
assertFileExists "${expected_path}" "install_asset os=${os} arch=${arch} format=${format}"
|
||||
|
||||
build_dir_name="${name}"
|
||||
if [ "$os" == "darwin" ]; then
|
||||
# TODO: when we simplify the goreleaser build steps, this exception would not longer be expected
|
||||
build_dir_name="${name}-macos"
|
||||
fi
|
||||
|
||||
assertFilesEqual \
|
||||
"$(snapshot_dir)/${build_dir_name}_${os}_${arch}/${binary}" \
|
||||
"$(snapshot_dir)/${os}-build_${os}_${arch}/${binary}" \
|
||||
"${expected_path}" \
|
||||
"unable to verify installation of os=${os} arch=${arch} format=${format}"
|
||||
|
||||
@ -83,9 +77,7 @@ trap 'teardown_snapshot_server ${worker_pid}' EXIT
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "linux" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "amd64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "amd64" "zip"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "arm64" "tar.gz"
|
||||
run_test_case test_positive_snapshot_install_asset "darwin" "arm64" "zip"
|
||||
run_test_case test_positive_snapshot_install_asset "windows" "amd64" "zip"
|
||||
|
||||
# let's make certain we covered all assets that were expected
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user