Skip to content

Commit

Permalink
Normalize release assets and refactor install.sh (#630)
Browse files Browse the repository at this point in the history
* refactor release to keep snapshot assets in parity with release assets

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* refactor install.sh and put under test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* tidy go.sum

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add mac acceptance test to github actions workflow

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rm use of goreleaser in cli tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* go mod tidy with go 1.17

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
  • Loading branch information
wagoodman committed Feb 11, 2022
1 parent d2dba7d commit 5aa8533
Show file tree
Hide file tree
Showing 44 changed files with 1,928 additions and 1,082 deletions.
3 changes: 3 additions & 0 deletions .github/scripts/apple-signing/.gitignore
@@ -0,0 +1,3 @@
dev-pki
log
signing-identity.txt
10 changes: 10 additions & 0 deletions .github/scripts/apple-signing/cleanup.sh
@@ -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"/setup-dev.sh
cleanup_signing
53 changes: 53 additions & 0 deletions .github/scripts/apple-signing/notarize.sh
@@ -0,0 +1,53 @@
#!/usr/bin/env bash

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


# notarize [archive-path]
#
notarize() {
binary_path=$1
archive_path=${binary_path}-archive-for-notarization.zip

title "archiving release binary into ${archive_path}"

parent=$(dirname "$binary_path")
(
cd "${parent}" && zip "${archive_path}" "$(basename ${binary_path})"
)

if [ ! -f "$archive_path" ]; then
exit_with_error "cannot find payload for notarization: $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)
hcl_file=$(mktemp).hcl

cat <<EOF > "$hcl_file"
notarize {
path = "$archive_path"
bundle_id = "com.anchore.toolbox.grype"
}
apple_id {
username = "$AC_USERNAME"
password = "@env:AC_PASSWORD"
}
EOF

gon -log-level info "$hcl_file"

rm "${hcl_file}" "${archive_path}"
}

171 changes: 171 additions & 0 deletions .github/scripts/apple-signing/setup-dev.sh
@@ -0,0 +1,171 @@
#!/usr/bin/env bash
set -eu

NAME=grype-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}"
}
56 changes: 56 additions & 0 deletions .github/scripts/apple-signing/setup-prod.sh
@@ -0,0 +1,56 @@
#!/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

if [ -z "$DOCKER_USERNAME" ]; then
exit_with_error "DOCKER_USERNAME not set"
fi

if [ -z "$DOCKER_PASSWORD" ]; then
exit_with_error "DOCKER_PASSWORD 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}"

commentary "log into docker -- required for publishing (since the default keychain has now been replaced)"
echo "${DOCKER_PASSWORD}" | docker login docker.io -u "${DOCKER_USERNAME}" --password-stdin
}
46 changes: 46 additions & 0 deletions .github/scripts/apple-signing/setup.sh
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
set -eu

IS_SNAPSHOT="$1"

## grab utilities
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
. "$SCRIPT_DIR"/utils.sh
mkdir -p "$SCRIPT_DIR/log"

main() {

case "$IS_SNAPSHOT" in

"1" | "true" | "yes")
commentary "assuming development setup..."
. "$SCRIPT_DIR"/setup-dev.sh
;;

"0" | "false" | "no")
commentary "assuming production setup..."
. "$SCRIPT_DIR"/setup-prod.sh
;;

*)
exit_with_error "could not determine if this was a production build (isSnapshot='$IS_SNAPSHOT')"
;;
esac

# load up all signing material into a keychain (note: this should set the MAC_SIGNING_IDENTITY env var)
setup_signing

# write out identity to a file
echo -n "$MAC_SIGNING_IDENTITY" > "$SCRIPT_DIR/$SIGNING_IDENTITY_FILENAME"
}

# capture all output from a subshell to log output additionally to a file (as well as the terminal)
( (
set +u
if [ -n "$SKIP_SIGNING" ]; then
commentary "skipping signing setup..."
else
set -u
main
fi
) 2>&1) | tee "$SCRIPT_DIR/log/setup.txt"

0 comments on commit 5aa8533

Please sign in to comment.