Last active
May 19, 2023 16:50
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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