Skip to content

Instantly share code, notes, and snippets.

@bpholt
Last active May 19, 2023 16:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bpholt/15824aee2c5c7d9c78beea3f94c46f33 to your computer and use it in GitHub Desktop.
Save bpholt/15824aee2c5c7d9c78beea3f94c46f33 to your computer and use it in GitHub Desktop.
generate a GPG key pair for signing artifacts published by sbt, save it to a 1Password vault, and set the necessary secrets for GitHub Actions
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail
IFS=$'\n\t'
RED='\033[1;31m'
NC='\033[0m' # No Color
readonly RED NC
function log_error () {
echo -e "$1" > /dev/stderr
}
if ! op signin ; then
log_error "please log into the 1Password CLI"
exit 1
fi
if ! gh auth status; then
log_error "please log into GitHub CLI"
log_error "${RED}> gh auth login${NC}"
exit 1
fi
TEMP_HOME=$(mktemp -d)
readonly TEMP_HOME
export GNUPGHOME="${TEMP_HOME}/.gnupg"
# shellcheck disable=SC2174
mkdir -m 0700 -p "${GNUPGHOME}"
NAME="$1"
readonly NAME
if ! echo "${NAME}" | grep '^[-A-Za-z0-9]*$' > /dev/null; then
echo "Name must match regex ^[-A-Za-z0-9]*$" > /dev/stderr
exit 2
fi
PUBLISHING_USER="SET ME"
GITHUB_ORG="SET ME"
EMAIL_USER="SET ME"
EMAIL_DOMAIN="SET ME"
ONE_PASSWORD_VAULT="SET ME"
PASS_LENGTH=20
readonly PUBLISHING_USER GITHUB_ORG EMAIL_USER EMAIL_DOMAIN ONE_PASSWORD_VAULT PASS_LENGTH
EMAIL="${EMAIL_USER}+${NAME}@${EMAIL_DOMAIN}"
readonly EMAIL
PASSPHRASE=$(
jq --null-input "{
title: \"${NAME}\",
category: \"PASSWORD\",
urls: [
{
label: \"homepage\",
primary: false,
href: \"https://github.com/${GITHUB_ORG}/${NAME}\"
}
]
}" |
op item create \
--format=json \
--vault "${ONE_PASSWORD_VAULT}" \
--generate-password=letters,digits,symbols,${PASS_LENGTH} | \
jq -r '.fields | map(select(.id == "password"))[0].value'
)
readonly PASSPHRASE
set -x
cat << __EOF__ | gpg --batch --generate-key
Key-Type: RSA
Key-Length: 3072
Key-Usage: encrypt sign auth
Passphrase: ${PASSPHRASE}
Name-Real: ${NAME} release bot
Name-Email: ${EMAIL}
%commit
__EOF__
KEY_ID=$(gpg --list-keys --with-colons "${EMAIL}" | \
grep fpr | \
cut -d ':' -f 10) # 10th field is User ID
readonly KEY_ID
set +x
PUBLIC_KEY_FILE=$(mktemp)
gpg --batch --armor --export "${KEY_ID}" > "${PUBLIC_KEY_FILE}"
PRIVATE_KEY_FILE=$(mktemp)
gpg \
--batch \
--pinentry-mode loopback \
--passphrase "${PASSPHRASE}" \
--armor \
--export-secret-keys "${KEY_ID}" > "${PRIVATE_KEY_FILE}"
readonly PUBLIC_KEY_FILE PRIVATE_KEY_FILE
trap 'rm -f "${PRIVATE_KEY_FILE}"' EXIT
# this if block is experimental; I added it after having to upload a public key
# manually b/c automated submission wasn't working on any keyserver I tried 😩
if ! gpg --send-keys "${KEY_ID}"; then
pbcopy < "${PUBLIC_KEY_FILE}"
log_error "Created public key:"
log_error "$(cat "${PUBLIC_KEY_FILE}")\n\n"
log_error "${RED}Upload the public key to a keyserver, like https://keyserver.ubuntu.com.${NC}"
log_error "The public key has been copied to the clipboard for your convenience.\n\n"
fi
op item edit "${NAME}" \
--format=json \
--vault "${ONE_PASSWORD_VAULT}" \
--tags "GPG Keypair" \
"Key Materials.Public Key\.txt[file]=${PUBLIC_KEY_FILE}" \
"Key Materials.Private Key\.txt[file]=${PRIVATE_KEY_FILE}"
base64 < "${PRIVATE_KEY_FILE}" | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set PGP_SECRET
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set PGP_PASSPHRASE \
--body "${PASSPHRASE}"
set -x
op item get "${PUBLISHING_USER}" \
--vault "${ONE_PASSWORD_VAULT}" \
--fields "User Token.username" | \
tr -d '\n' | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set SONATYPE_USERNAME
op item get "${PUBLISHING_USER}" \
--vault "${ONE_PASSWORD_VAULT}" \
--fields "User Token.password" | \
tr -d '\n' | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set SONATYPE_PASSWORD
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail
IFS=$'\n\t'
RED='\033[1;31m'
NC='\033[0m' # No Color
readonly RED NC
function log_error () {
echo -e "$1" > /dev/stderr
}
if ! op signin ; then
log_error "please log into the 1Password CLI"
exit 1
fi
if ! gh auth status; then
log_error "please log into GitHub CLI"
log_error "${RED}> gh auth login${NC}"
exit 1
fi
NAME="$1"
readonly NAME
if ! echo "${NAME}" | grep '^[-A-Za-z0-9]*$' > /dev/null; then
echo "Name must match regex ^[-A-Za-z0-9]*$" > /dev/stderr
exit 2
fi
PUBLISHING_USER="SET ME"
GITHUB_ORG="SET ME"
EMAIL_USER="SET ME"
EMAIL_DOMAIN="SET ME"
ONE_PASSWORD_VAULT="SET ME"
readonly PUBLISHING_USER GITHUB_ORG EMAIL_USER EMAIL_DOMAIN ONE_PASSWORD_VAULT
EMAIL="${EMAIL_USER}+${NAME}@${EMAIL_DOMAIN}"
readonly EMAIL
PASSPHRASE=$(
op item get --vault "${ONE_PASSWORD_VAULT}" \
--fields password \
"${NAME}"
)
readonly PASSPHRASE
set -x
# there might be an easier way to do this, but I couldn't figure out how to
# get the file contents using "op item get" 🤷
op read "$(op item get --vault "${ONE_PASSWORD_VAULT}" \
--format json \
"${NAME}" | \
jq -r '"op://\(.vault.name)/\(.title)/\(.files | map(select(.name == "Private Key.txt")) | .[0].id)"')" | \
gpg \
--batch \
--pinentry-mode loopback \
--passphrase "${PASSPHRASE}" \
--import
# TODO detect if key is expired, and if so, pause so user can extend it using "gpg --edit-key"
# see https://unix.stackexchange.com/a/177310 for information about extending the expiration date
KEY_ID=$(gpg --list-keys --with-colons "${EMAIL}" | \
grep fpr | \
cut -d ':' -f 10 | \
head -n1) # 10th field is User ID, first key should be the main one
readonly KEY_ID
set +x
PUBLIC_KEY_FILE=$(mktemp)
gpg --batch --armor --export "${KEY_ID}" > "${PUBLIC_KEY_FILE}"
PRIVATE_KEY_FILE=$(mktemp)
gpg \
--batch \
--pinentry-mode loopback \
--passphrase "${PASSPHRASE}" \
--armor \
--export-secret-keys "${KEY_ID}" > "${PRIVATE_KEY_FILE}"
readonly PUBLIC_KEY_FILE PRIVATE_KEY_FILE
trap 'rm -f "${PRIVATE_KEY_FILE}"' EXIT
# this if block is experimental; I added it after having to upload a public key
# manually b/c automated submission wasn't working on any keyserver I tried 😩
if ! gpg --send-keys "${KEY_ID}"; then
pbcopy < "${PUBLIC_KEY_FILE}"
log_error "Created public key:"
log_error "$(cat "${PUBLIC_KEY_FILE}")\n\n"
log_error "${RED}Upload the public key to a keyserver, like https://keyserver.ubuntu.com.${NC}"
log_error "The public key has been copied to the clipboard for your convenience.\n\n"
fi
op item edit "${NAME}" \
--format=json \
--vault "${ONE_PASSWORD_VAULT}" \
--tags "GPG Keypair" \
"Key Materials.Public Key\.txt[file]=${PUBLIC_KEY_FILE}" \
"Key Materials.Private Key\.txt[file]=${PRIVATE_KEY_FILE}"
base64 < "${PRIVATE_KEY_FILE}" | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set PGP_SECRET
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set PGP_PASSPHRASE \
--body "${PASSPHRASE}"
set -x
op item get "${PUBLISHING_USER}" \
--vault "${ONE_PASSWORD_VAULT}" \
--fields "User Token.username" | \
tr -d '\n' | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set SONATYPE_USERNAME
op item get "${PUBLISHING_USER}" \
--vault "${ONE_PASSWORD_VAULT}" \
--fields "User Token.password" | \
tr -d '\n' | \
gh --repo "${GITHUB_ORG}/${NAME}" \
secret set SONATYPE_PASSWORD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment