mirror of
https://github.com/unpoller/unpoller.git
synced 2026-09-30 03:21:28 +02:00
ci: Authenticode-sign Windows and notarize the macOS universal binary.
Release tags now fail closed without signing secrets, ship a signed Windows PE via house signerd, and replace per-arch Darwin tarballs with one stapled universal archive. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
3a595a6896
commit
eeda665b7e
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fail closed when a publishing secret is empty. GitHub maps missing secrets
|
||||
# to "" so `if: secrets.FOO != ''` is not a substitute.
|
||||
set -euo pipefail
|
||||
|
||||
missing=0
|
||||
need() {
|
||||
local name=$1
|
||||
local val=${!name-}
|
||||
if [ -z "${val}" ]; then
|
||||
echo "missing secret: ${name}" >&2
|
||||
missing=1
|
||||
fi
|
||||
}
|
||||
|
||||
need GORELEASER_KEY
|
||||
need GPG_SIGNING_KEY
|
||||
need DOCKER_USERNAME
|
||||
need DOCKER_PASSWORD
|
||||
need CODESIGN_URL
|
||||
need CODESIGN_CLIENT_CERT
|
||||
need CODESIGN_CLIENT_KEY
|
||||
need MACOS_SIGN_P12
|
||||
need MACOS_SIGN_PASSWORD
|
||||
need MACOS_NOTARY_KEY
|
||||
need MACOS_NOTARY_KEY_ID
|
||||
need MACOS_NOTARY_ISSUER_ID
|
||||
need PACKAGECLOUD_TOKEN
|
||||
need HOMEBREW_TAP_GITHUB_TOKEN
|
||||
|
||||
if [ "${missing}" -ne 0 ]; then
|
||||
echo "refusing to publish with empty secrets" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "required secrets are present"
|
||||
@@ -15,6 +15,10 @@ permissions:
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
id-token: write
|
||||
env:
|
||||
DOCKER_CLI_EXPERIMENTAL: "enabled"
|
||||
DOCKER_REGISTRY: "ghcr.io"
|
||||
@@ -24,6 +28,23 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- run: git fetch --force --tags
|
||||
- name: Fail if publishing secrets are missing
|
||||
env:
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
CODESIGN_URL: ${{ secrets.CODESIGN_URL }}
|
||||
CODESIGN_CLIENT_CERT: ${{ secrets.CODESIGN_CLIENT_CERT }}
|
||||
CODESIGN_CLIENT_KEY: ${{ secrets.CODESIGN_CLIENT_KEY }}
|
||||
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
|
||||
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
|
||||
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
|
||||
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
|
||||
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
|
||||
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
|
||||
run: bash .github/scripts/require_secrets.sh
|
||||
- name: Install RPM tooling
|
||||
run: sudo apt-get install -y rpm
|
||||
- name: Set up QEMU
|
||||
@@ -62,12 +83,21 @@ jobs:
|
||||
# on your needs.
|
||||
- name: "make key file"
|
||||
run: "echo '${{ secrets.GPG_SIGNING_KEY }}' > /tmp/key.gpg"
|
||||
- name: Install golift codesign
|
||||
env:
|
||||
GOBIN: ${{ runner.temp }}/codesign-bin
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "${GOBIN}"
|
||||
go install golift.io/codesign/cmd/codesign@v1.0.3
|
||||
echo "${GOBIN}" >> "${GITHUB_PATH}"
|
||||
echo "CODESIGN_BIN=${GOBIN}/codesign" >> "${GITHUB_ENV}"
|
||||
- uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
# either 'goreleaser' (default) or 'goreleaser-pro':
|
||||
distribution: goreleaser-pro
|
||||
version: latest
|
||||
args: release --clean
|
||||
args: release --clean --timeout 60m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro'
|
||||
@@ -78,6 +108,16 @@ jobs:
|
||||
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
GPG_SIGNING_KEY: /tmp/key.gpg
|
||||
GPG_SIGNING_KEY_ID: ${{ steps.import_gpg.outputs.keyid }}
|
||||
CODESIGN_URL: ${{ secrets.CODESIGN_URL }}
|
||||
CODESIGN_CLIENT_CERT: ${{ secrets.CODESIGN_CLIENT_CERT }}
|
||||
CODESIGN_CLIENT_KEY: ${{ secrets.CODESIGN_CLIENT_KEY }}
|
||||
CODESIGN_NAME: unpoller
|
||||
CODESIGN_WEBSITE: https://unpoller.com
|
||||
MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }}
|
||||
MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }}
|
||||
MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }}
|
||||
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
|
||||
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
|
||||
- name: Update Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v5
|
||||
with:
|
||||
|
||||
@@ -74,6 +74,32 @@ builds:
|
||||
- amd64
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser -X "golift.io/version.Version={{.Version}}" -X "golift.io/version.Branch={{.Branch}} ({{.Commit}})" -X "golift.io/version.BuildDate={{.Date}}" -X "golift.io/version.BuildUser=goreleaser" -X "golift.io/version.Revision=1"
|
||||
hooks:
|
||||
post:
|
||||
- cmd: bash init/windows/signexe.sh "{{ .Path }}"
|
||||
if: '{{ eq .Os "windows" }}'
|
||||
|
||||
universal_binaries:
|
||||
- id: unpoller-mac
|
||||
ids: [unpoller-mac]
|
||||
replace: true
|
||||
|
||||
# Sign + notarize the macOS universal binary (quill; works on Linux CI).
|
||||
# Enabled only when MACOS_SIGN_P12 is set so local snapshots still work.
|
||||
notarize:
|
||||
macos:
|
||||
- enabled: '{{ isEnvSet "MACOS_SIGN_P12" }}'
|
||||
ids:
|
||||
- unpoller-mac
|
||||
sign:
|
||||
certificate: "{{ .Env.MACOS_SIGN_P12 }}"
|
||||
password: "{{ .Env.MACOS_SIGN_PASSWORD }}"
|
||||
notarize:
|
||||
issuer_id: "{{ .Env.MACOS_NOTARY_ISSUER_ID }}"
|
||||
key_id: "{{ .Env.MACOS_NOTARY_KEY_ID }}"
|
||||
key: "{{ .Env.MACOS_NOTARY_KEY }}"
|
||||
wait: true
|
||||
timeout: 20m
|
||||
|
||||
archives:
|
||||
- id: unpoller
|
||||
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
# Authenticode-sign a Windows PE via golift/codesign (YubiKey-backed signerd).
|
||||
# GoReleaser calls this from builds.hooks.post on windows binaries, after the
|
||||
# CLI is installed into a temp GOBIN (never /usr/bin/codesign).
|
||||
#
|
||||
# Local snapshots skip when CODESIGN_URL is unset. GitHub Actions must fail
|
||||
# closed — the release contract is an Authenticode-signed Windows binary.
|
||||
#
|
||||
# Prefer CODESIGN_BIN, then GOBIN/codesign, then GOPATH/bin, then PATH
|
||||
# entries that are not Apple's /usr/bin/codesign.
|
||||
|
||||
function pick_codesign() {
|
||||
if [ -n "${CODESIGN_BIN:-}" ]; then
|
||||
echo "${CODESIGN_BIN}"
|
||||
return
|
||||
fi
|
||||
if [ -n "${GOBIN:-}" ] && [ -x "${GOBIN}/codesign" ]; then
|
||||
echo "${GOBIN}/codesign"
|
||||
return
|
||||
fi
|
||||
gopath="$(go env GOPATH 2>/dev/null || true)"
|
||||
if [ -n "${gopath}" ] && [ -x "${gopath}/bin/codesign" ]; then
|
||||
echo "${gopath}/bin/codesign"
|
||||
return
|
||||
fi
|
||||
while IFS= read -r p; do
|
||||
case "$p" in
|
||||
/usr/bin/codesign|/bin/codesign) continue ;;
|
||||
esac
|
||||
echo "$p"
|
||||
return
|
||||
done < <(type -a -p codesign 2>/dev/null || true)
|
||||
return 1
|
||||
}
|
||||
|
||||
function sign() {
|
||||
if [ -z "${CODESIGN_URL:-}" ]; then
|
||||
if [ -n "${GITHUB_ACTIONS:-}" ]; then
|
||||
echo "CODESIGN_URL unset; refusing to ship an unsigned Windows binary in CI" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Skipped signing ${FILE} (CODESIGN_URL unset) .." >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bin="$(pick_codesign)" || {
|
||||
echo "CODESIGN_URL is set but golift codesign CLI not found (set CODESIGN_BIN)" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
CODESIGN_NAME="${CODESIGN_NAME:-unpoller}" \
|
||||
CODESIGN_WEBSITE="${CODESIGN_WEBSITE:-https://unpoller.com}" \
|
||||
"${bin}" -- "${FILE}"
|
||||
echo "Signed ${FILE} .." >&2
|
||||
}
|
||||
|
||||
[ -z "$1" ] || FILE="$1" sign
|
||||
Reference in New Issue
Block a user