#!/usr/bin/env bash
# Sign release artifacts with the Make Creative release key (minisign).
#
# Every Linux artifact we publish gets a detached `.minisig` beside it so a
# download can be checked against the public key in dist/makecreative.pub (also
# printed in README.md). Nothing in the app auto-applies an update, so a user
# running the verify command is the only thing between a compromised dist host
# and a bad binary on their machine.
#
#   dist/sign-artifacts.sh <artifact> [<artifact>...]
#
# Key material, present on every Linux build host (fw13, astra):
#
#   ~/.minisign/makecreative.key   encrypted secret key, mode 0600
#   ~/.minisign/password.env       exports MINISIGN_PASSWORD
#
# Neither is in git. Generation, storage, and rotation are in
# _private/docs/meta/ota-release-runbook.md.
#
# Signatures are verified against dist/makecreative.pub before this script
# exits, so a build host holding the wrong key fails the release rather than
# shipping artifacts nobody can verify.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

KEY="${MINISIGN_KEY:-$HOME/.minisign/makecreative.key}"
PASSWORD_ENV="${MINISIGN_PASSWORD_ENV:-$HOME/.minisign/password.env}"
PUBKEY="${MINISIGN_PUBKEY:-$SCRIPT_DIR/makecreative.pub}"

die() { echo "sign-artifacts: $*" >&2; exit 1; }

[ "$#" -gt 0 ] || die "usage: $0 <artifact> [<artifact>...]"

command -v minisign >/dev/null 2>&1 \
    || die "minisign is not on PATH (Debian/Ubuntu: apt install minisign)"

[ -f "$KEY" ] || die "no signing key at $KEY (see the OTA release runbook)"
[ -f "$PUBKEY" ] || die "no public key at $PUBKEY"
if grep -q '^PLACEHOLDER' "$PUBKEY"; then
    die "$PUBKEY is still a placeholder: install the real public key (see the OTA release runbook)"
fi

if [ -z "${MINISIGN_PASSWORD:-}" ]; then
    [ -f "$PASSWORD_ENV" ] \
        || die "MINISIGN_PASSWORD is unset and $PASSWORD_ENV does not exist"
    # shellcheck disable=SC1090
    . "$PASSWORD_ENV"
fi
[ -n "${MINISIGN_PASSWORD:-}" ] || die "MINISIGN_PASSWORD is empty"

for artifact in "$@"; do
    [ -f "$artifact" ] || die "no such artifact: $artifact"
done

# One invocation for the whole set: the password is read once, and minisign
# still writes a per-file trusted comment (timestamp, filename, prehashed), so
# a signature cannot be transplanted onto a different artifact.
printf '%s\n' "$MINISIGN_PASSWORD" | minisign -S \
    -s "$KEY" \
    -c "Make Creative, LLC release artifact" \
    -m "$@" >/dev/null

for artifact in "$@"; do
    if ! minisign -V -q -p "$PUBKEY" -m "$artifact" >/dev/null; then
        # Leave nothing behind that a later collect could mistake for a good
        # signature.
        rm -f "${artifact}.minisig"
        die "signature for $artifact does not verify against $PUBKEY"
    fi
    echo "signed: ${artifact}.minisig"
done
