-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit is an initial prototype based on the deployment workflow, using the Azure Code Signing service to sign Windows .exe and .msi files. These changes have been isolated as much as possible to not affect existing deployment workflows while also working around design issues with how GitHub CLI workflow works with GoReleaser and now with ACS support. The biggest smell was over whether to break from using GoReleaser or have GoReleaser control as much about the release process as it has been versus opening / signing / archiving the resulting GoReleaser artifacts; needless to say, the latter was chosen for expedience as well as leaning into officially supported solutions.
- Loading branch information
1 parent
3bb62d4
commit dea2cd5
Showing
3 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
name: HSM Testing | ||
run-name: ${{ inputs.tag_name }} / go ${{ inputs.go_version }} | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.ref_name }} | ||
cancel-in-progress: true | ||
|
||
permissions: | ||
contents: write | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
tag_name: | ||
required: true | ||
type: string | ||
go_version: | ||
default: "1.21" | ||
type: string | ||
|
||
jobs: | ||
windows: | ||
runs-on: windows-latest | ||
environment: production | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: ${{ inputs.go_version }} | ||
- name: Install GoReleaser | ||
uses: goreleaser/goreleaser-action@v5 | ||
with: | ||
version: "~1.17.1" | ||
install-only: true | ||
- name: Build release binaries | ||
shell: bash | ||
env: | ||
TAG_NAME: ${{ inputs.tag_name }} | ||
run: script/release-hsm --local "$TAG_NAME" --platform windows --config .goreleaser-hsm.yml | ||
|
||
# As official Azure HSM support for signing Windows .exe binaries is in the form of an action, | ||
# we must unzip the archives created by GoReleaser, sign the binaries, and then re-zip them. | ||
# This choice was due to the fact that GoReleaser produces | ||
- name: Expand goreleaser archives for signing | ||
shell: bash | ||
run: | | ||
for ZIP_FILE in dist/gh_*_windows_*.zip; do | ||
unzip -d "${ZIP_FILE%.zip}" "$ZIP_FILE" | ||
done | ||
- name: Sign .exe release binaries | ||
uses: azure/azure-code-signing-action@6c86237186b7eed50c9e8a3a6e42131bcc5e4601 | ||
with: | ||
azure-tenant-id: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO_TENANT_ID }} | ||
azure-client-id: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO_CLIENT_ID }} | ||
azure-client-secret: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO }} | ||
endpoint: https://wus.codesigning.azure.net/ | ||
code-signing-account-name: GitHubInc | ||
certificate-profile-name: GitHubInc | ||
files-folder: ${{ github.workspace }}/dist | ||
files-folder-filter: exe | ||
file-digest: SHA256 | ||
timestamp-rfc3161: http://timestamp.acs.microsoft.com | ||
timestamp-digest: SHA256 | ||
- name: Zip goreleaser directories | ||
shell: bash | ||
run: | | ||
for DIR in dist/gh_*_windows_*; do | ||
zip -r "$DIR.zip" "$DIR" | ||
done | ||
- name: Set up MSBuild | ||
id: setupmsbuild | ||
uses: microsoft/[email protected] | ||
- name: Build MSI | ||
shell: bash | ||
env: | ||
MSBUILD_PATH: ${{ steps.setupmsbuild.outputs.msbuildPath }} | ||
run: | | ||
for ZIP_FILE in dist/gh_*_windows_*.zip; do | ||
MSI_NAME="$(basename "$ZIP_FILE" ".zip")" | ||
MSI_VERSION="$(cut -d_ -f2 <<<"$MSI_NAME" | cut -d- -f1)" | ||
case "$MSI_NAME" in | ||
*_386 ) | ||
source_dir="$PWD/dist/windows_windows_386" | ||
platform="x86" | ||
;; | ||
*_amd64 ) | ||
source_dir="$PWD/dist/windows_windows_amd64_v1" | ||
platform="x64" | ||
;; | ||
*_arm64 ) | ||
echo "skipping building MSI for arm64 because WiX 3.11 doesn't support it: https://github.com/wixtoolset/issues/issues/6141" >&2 | ||
continue | ||
#source_dir="$PWD/dist/windows_windows_arm64" | ||
#platform="arm64" | ||
;; | ||
* ) | ||
printf "unsupported architecture: %s\n" "$MSI_NAME" >&2 | ||
exit 1 | ||
;; | ||
esac | ||
"${MSBUILD_PATH}\MSBuild.exe" ./build/windows/gh.wixproj -p:SourceDir="$source_dir" -p:OutputPath="$PWD/dist" -p:OutputName="$MSI_NAME" -p:ProductVersion="${MSI_VERSION#v}" -p:Platform="$platform" | ||
done | ||
- name: Sign .msi release binaries | ||
uses: azure/azure-code-signing-action@6c86237186b7eed50c9e8a3a6e42131bcc5e4601 | ||
with: | ||
azure-tenant-id: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO_TENANT_ID }} | ||
azure-client-id: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO_CLIENT_ID }} | ||
azure-client-secret: ${{ secrets.SPN_SPN_AZURE_CODE_SIGNING_DEMO }} | ||
endpoint: https://wus.codesigning.azure.net/ | ||
code-signing-account-name: GitHubInc | ||
certificate-profile-name: GitHubInc | ||
files-folder: ${{ github.workspace }}/dist | ||
files-folder-filter: msi | ||
file-digest: SHA256 | ||
timestamp-rfc3161: http://timestamp.acs.microsoft.com | ||
timestamp-digest: SHA256 | ||
- uses: actions/upload-artifact@v3 | ||
with: | ||
name: windows | ||
if-no-files-found: error | ||
retention-days: 7 | ||
path: | | ||
dist/*.zip | ||
dist/*.msi |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
project_name: gh | ||
|
||
release: | ||
prerelease: auto | ||
draft: true # we only publish after the Windows MSI gets uploaded | ||
name_template: "GitHub CLI {{.Version}}" | ||
|
||
before: | ||
hooks: | ||
- >- | ||
{{ if eq .Runtime.Goos "windows" }}echo{{ end }} make manpages GH_VERSION={{.Version}} | ||
- >- | ||
{{ if ne .Runtime.Goos "linux" }}echo{{ end }} make completions | ||
builds: | ||
- id: macos #build:macos | ||
goos: [darwin] | ||
goarch: [amd64, arm64] | ||
hooks: | ||
post: | ||
- cmd: ./script/sign '{{ .Path }}' | ||
output: true | ||
binary: bin/gh | ||
main: ./cmd/gh | ||
ldflags: | ||
- -s -w -X github.com/cli/cli/v2/internal/build.Version={{.Version}} -X github.com/cli/cli/v2/internal/build.Date={{time "2006-01-02"}} | ||
|
||
- id: linux #build:linux | ||
goos: [linux] | ||
goarch: [386, arm, amd64, arm64] | ||
env: | ||
- CGO_ENABLED=0 | ||
binary: bin/gh | ||
main: ./cmd/gh | ||
ldflags: | ||
- -s -w -X github.com/cli/cli/v2/internal/build.Version={{.Version}} -X github.com/cli/cli/v2/internal/build.Date={{time "2006-01-02"}} | ||
|
||
- id: windows #build:windows | ||
goos: [windows] | ||
goarch: [386, amd64, arm64] | ||
binary: bin/gh | ||
main: ./cmd/gh | ||
ldflags: | ||
- -s -w -X github.com/cli/cli/v2/internal/build.Version={{.Version}} -X github.com/cli/cli/v2/internal/build.Date={{time "2006-01-02"}} | ||
|
||
archives: | ||
- id: linux-archive | ||
builds: [linux] | ||
name_template: "gh_{{ .Version }}_linux_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" | ||
wrap_in_directory: true | ||
format: tar.gz | ||
rlcp: true | ||
files: | ||
- LICENSE | ||
- ./share/man/man1/gh*.1 | ||
- id: macos-archive | ||
builds: [macos] | ||
name_template: "gh_{{ .Version }}_macOS_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" | ||
wrap_in_directory: true | ||
format: zip | ||
rlcp: true | ||
files: | ||
- LICENSE | ||
- ./share/man/man1/gh*.1 | ||
- id: windows-archive | ||
builds: [windows] | ||
name_template: "gh_{{ .Version }}_windows_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" | ||
wrap_in_directory: false | ||
format: zip | ||
rlcp: true | ||
files: | ||
- LICENSE | ||
|
||
nfpms: #build:linux | ||
- license: MIT | ||
maintainer: GitHub | ||
homepage: https://github.com/cli/cli | ||
bindir: /usr | ||
dependencies: | ||
- git | ||
description: GitHub’s official command line tool. | ||
formats: | ||
- deb | ||
- rpm | ||
contents: | ||
- src: "./share/man/man1/gh*.1" | ||
dst: "/usr/share/man/man1" | ||
- src: "./share/bash-completion/completions/gh" | ||
dst: "/usr/share/bash-completion/completions/gh" | ||
- src: "./share/fish/vendor_completions.d/gh.fish" | ||
dst: "/usr/share/fish/vendor_completions.d/gh.fish" | ||
- src: "./share/zsh/site-functions/_gh" | ||
dst: "/usr/share/zsh/site-functions/_gh" |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
#!/bin/bash | ||
set -e | ||
|
||
print_help() { | ||
cat <<EOF | ||
To tag a new release: | ||
script/release [--staging] <tag-name> [--platform {linux|macos|windows}] [--branch <branch>] | ||
To build staging binaries from the current branch: | ||
script/release --current [--platform {linux|macos|windows}] | ||
To build binaries locally with goreleaser: | ||
script/release --local --platform {linux|macos|windows} | ||
EOF | ||
} | ||
|
||
if [ $# -eq 0 ]; then | ||
print_help >&2 | ||
exit 1 | ||
fi | ||
|
||
tag_name="" | ||
is_local="" | ||
do_push="" | ||
platform="" | ||
branch="trunk" | ||
deploy_env="production" | ||
goreleaser_config=".goreleaser.yml" | ||
|
||
while [ $# -gt 0 ]; do | ||
case "$1" in | ||
-h | --help ) | ||
print_help | ||
exit 0 | ||
;; | ||
-b | --branch ) | ||
branch="$2" | ||
shift 2 | ||
;; | ||
-c | --config ) | ||
goreleaser_config="$2" | ||
shift 2 | ||
;; | ||
-p | --platform ) | ||
platform="$2" | ||
shift 2 | ||
;; | ||
--local ) | ||
is_local=1 | ||
shift 1 | ||
;; | ||
--staging ) | ||
deploy_env="staging" | ||
shift 1 | ||
;; | ||
--current ) | ||
deploy_env="staging" | ||
tag_name="$(git describe --tags --abbrev=0)" | ||
branch="$(git rev-parse --symbolic-full-name '@{upstream}' 2>/dev/null || git branch --show-current)" | ||
branch="${branch#refs/remotes/*/}" | ||
do_push=1 | ||
shift 1 | ||
;; | ||
-* ) | ||
printf "unrecognized flag: %s\n" "$1" >&2 | ||
exit 1 | ||
;; | ||
* ) | ||
tag_name="$1" | ||
shift 1 | ||
;; | ||
esac | ||
done | ||
|
||
announce() { | ||
local tmpdir="${TMPDIR:-/tmp}" | ||
echo "$*" | sed "s:${tmpdir%/}:\$TMPDIR:" | ||
"$@" | ||
} | ||
|
||
trigger_deployment() { | ||
announce gh workflow -R cli/cli run deployment.yml --ref "$branch" -f tag_name="$tag_name" -f environment="$deploy_env" | ||
} | ||
|
||
build_local() { | ||
local config="$goreleaser_config" | ||
case "$platform" in | ||
linux ) | ||
sed '/#build:windows/,/^$/d; /#build:macos/,/^$/d' .goreleaser.yml >.goreleaser.generated.yml | ||
config=".goreleaser.generated.yml" | ||
;; | ||
macos ) | ||
sed '/#build:windows/,/^$/d; /#build:linux/,/^$/d' .goreleaser.yml >.goreleaser.generated.yml | ||
config=".goreleaser.generated.yml" | ||
;; | ||
windows ) | ||
sed '/#build:linux/,/^$/d; /#build:macos/,/^$/d' .goreleaser.yml >.goreleaser.generated.yml | ||
config=".goreleaser.generated.yml" | ||
;; | ||
esac | ||
[ -z "$tag_name" ] || export GORELEASER_CURRENT_TAG="$tag_name" | ||
announce goreleaser release -f "$config" --clean --skip-validate --skip-publish --release-notes="$(mktemp)" | ||
} | ||
|
||
if [ -n "$is_local" ]; then | ||
build_local | ||
else | ||
if [ -n "$do_push" ]; then | ||
if ! git diff --quiet || ! git diff --cached --quiet; then | ||
echo "refusing to continue due to uncomitted local changes" >&2 | ||
exit 1 | ||
fi | ||
announce git push | ||
fi | ||
trigger_deployment | ||
if [ "$deploy_env" = "production" ]; then | ||
echo | ||
echo "Go to Slack to manually approve this production deployment." | ||
fi | ||
fi |