qqq 1.0.0: the command-line client and the full-screen terminal UI (qqq ui) for QQQ applications over the UI API (/qqq/v1), with @qrun-io/qqq-cli 1.0.0, @qrun-io/qqq-core 1.0.0, @qrun-io/qqq-ui-api-client 1.8.0 and @qrun-io/qqq-ui-api-conformance 1.6.0 going final together. Squash of the release/1.0.0 branch at 79ba68e (the branch is kept with the full signed history; the tags v1.8.0 and cli-v1.0.0 point at that commit, which is what the released binaries were built from). See CHANGELOG.md [1.0.0] and docs/release-notes/1.0.0.md.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
65 lines
3.2 KiB
Bash
Executable File
65 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Copyright 2026 QRun.IO, Inc.
|
|
# Licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
#
|
|
# Authenticode-signs the Windows qqq binary with osslsigncode (runs on macOS and Linux) and recomputes
|
|
# SHA256SUMS. Run after scripts/build-binaries.mjs and before the GitHub release.
|
|
#
|
|
# scripts/sign-windows.sh [dist] [--dry-run]
|
|
#
|
|
# Environment (nothing set: prints what is missing and exits 0 without touching a file):
|
|
# QQQ_WINDOWS_PFX the code-signing certificate and key, a .pfx/.p12 file
|
|
# QQQ_WINDOWS_PFX_PASSWORD its password (or QQQ_WINDOWS_PFX_PASSWORD_FILE, a file holding it)
|
|
# QQQ_WINDOWS_TIMESTAMP_URL RFC 3161 timestamp server (default http://timestamp.digicert.com;
|
|
# "none" skips the timestamp, for tests only: the signature then expires
|
|
# with the certificate)
|
|
# Needs osslsigncode (brew install osslsigncode, apt install osslsigncode). Hardware-token (EV)
|
|
# certificates need osslsigncode's PKCS#11 options or signtool on Windows instead.
|
|
|
|
set -euo pipefail
|
|
|
|
dist="dist"; dry=0
|
|
for a in "$@"; do
|
|
case "$a" in
|
|
--dry-run) dry=1 ;;
|
|
-*) echo "sign-windows: unknown option $a" >&2; exit 2 ;;
|
|
*) dist="$a" ;;
|
|
esac
|
|
done
|
|
pfx="${QQQ_WINDOWS_PFX:-}"
|
|
password="${QQQ_WINDOWS_PFX_PASSWORD:-}"
|
|
[[ -z "$password" && -n "${QQQ_WINDOWS_PFX_PASSWORD_FILE:-}" ]] && password="$(cat "$QQQ_WINDOWS_PFX_PASSWORD_FILE")"
|
|
timestamp="${QQQ_WINDOWS_TIMESTAMP_URL:-http://timestamp.digicert.com}"
|
|
|
|
if [[ -z "$pfx" ]]; then
|
|
echo "sign-windows: not signing: set QQQ_WINDOWS_PFX (and QQQ_WINDOWS_PFX_PASSWORD or QQQ_WINDOWS_PFX_PASSWORD_FILE)."
|
|
echo " The .exe stays unsigned: SmartScreen warns on first run (More info, Run anyway)."
|
|
exit 0
|
|
fi
|
|
[[ -f "$pfx" ]] || { echo "sign-windows: $pfx does not exist" >&2; exit 1; }
|
|
if [[ $dry == 0 ]]; then command -v osslsigncode >/dev/null || { echo "sign-windows: needs osslsigncode" >&2; exit 1; }; fi
|
|
|
|
shopt -s nullglob
|
|
binaries=("$dist"/qqq-windows-*.exe)
|
|
[[ ${#binaries[@]} -gt 0 ]] || { echo "sign-windows: no $dist/qqq-windows-*.exe" >&2; exit 1; }
|
|
|
|
ts=(-ts "$timestamp"); [[ "$timestamp" == none ]] && ts=()
|
|
for bin in "${binaries[@]}"; do
|
|
echo "sign-windows: $bin"
|
|
if [[ $dry == 1 ]]; then
|
|
echo " would run: osslsigncode sign -pkcs12 $pfx -pass *** -h sha256 -n qqq -i https://github.com/QRun-IO/qqq-cli ${ts[*]} -in $bin -out $bin.signed"
|
|
echo " would run: osslsigncode verify -in $bin.signed, then replace $bin"
|
|
continue
|
|
fi
|
|
osslsigncode sign -pkcs12 "$pfx" -pass "$password" -h sha256 -n qqq -i https://github.com/QRun-IO/qqq-cli ${ts[@]+"${ts[@]}"} \
|
|
-in "$bin" -out "$bin.signed" >/dev/null
|
|
# verify the signature is there and well formed (a self-signed test certificate is untrusted: that is fine here)
|
|
osslsigncode verify -in "$bin.signed" 2>&1 | grep -E "Signature verification|Message digest|Number of signers" || true
|
|
mv "$bin.signed" "$bin"
|
|
done
|
|
|
|
if [[ $dry == 1 ]]; then echo " would recompute $dist/SHA256SUMS"; exit 0; fi
|
|
(cd "$dist" && if command -v sha256sum >/dev/null; then sha256sum qqq-*; else shasum -a 256 qqq-*; fi) > "$dist/SHA256SUMS.new"
|
|
mv "$dist/SHA256SUMS.new" "$dist/SHA256SUMS"
|
|
echo "sign-windows: recomputed $dist/SHA256SUMS"
|