Build & EV Sign Windows builds (#517

* Add way to provide apple ID and app password to notarise script

* Add utility to generate electron-builder.json for release & nightly builds

* Run Build & Test on staging too

* First attempt at build & deploy for macOS with signing and notarisation

* Fix quote mismatch

* use correct quotes

* add runs-on

* Fix inputs.mode usage

* remove quotes

* chmod +x

* Fix artifact paths

* Fix deploy condition

* Fix deploy condition

* Fix artifact path

* Iterate

* Fix workflow

* Fix env

* Iterate

* Fix missing env

* Fix version calculation

* Iterate

* Fix config not taking effect

* Update build_and_deploy.yaml

* Fix alignments

* delint

* Fix alignment

* Update build_macos.yaml

* Add ability to EV sign using eSigner CKA

* Initial work to build & sign Windows nightlies in CI

* Format

* Format

* Fix gha

* fix winSign

* Fix install command

* Add signtool to path

* Update build_and_deploy.yaml

* Fix quotes

* Test

* Fix comments

* Fix cmd

* Try again

* arg slashes

* Fix exe path

* Fix matrix strategy

* Use ampersand-call

* fwd slash ftw?

* ls *

* 🌲

* tree dist

* prepend path

* Specify /fd and /td to modern signtool

* /tr not /t for CKA

* Test signing

* missing comma

* 🤦‍♂️

* Fix wrong mv

* Lets sign

* Fix config gen

* Debug

* Fix typo

* Multiple drives why

* Try NVL sandbox creds

* Update

* Attempt to disable logger

* Try again

* Iterate

* Update build_macos.yaml

* Update build_and_deploy.yaml

* Update build_macos.yaml

* Update build_and_deploy.yaml

* Update build_and_deploy.yaml

* Try custom build of eSigner CKA

* Fix typos

* Update build_windows.yaml

* Update build_and_deploy.yaml

* Update build_windows.yaml

* Update build_and_deploy.yaml

* Fix symlinking

* Fix working-directory incantation

* exe

* remove debug

* Prettier

* Vendor check in SSL.com executable

* Download CKA from packages.element.io instead

* Use demo creds

* StrictMode

* Switch back to 0207 (unsigned)

* Fix call syntax

* Revert env inc

* Partial rollback

* Trace

* Trace less

* Fix CN being passed wrong

* DEBUG

* Debug 2

* Fix ConvertFrom-StringData

* 0214

* Test

* Test

* Untested

* Revert to 0207

* stash

* Try with 20230221

* Restore scripts/electron_winSign.js

* Prepare for merge

* Update build_windows.yaml

* Update build_and_deploy.yaml

* Restore .github/workflows/build_and_deploy.yaml

* Restore .github/workflows/build_and_deploy.yaml

* Fix bad restore
This commit is contained in:
Michael Telatynski 2023-02-22 13:51:19 +00:00 committed by GitHub
parent c9d7e37e09
commit a0a9ec830c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 379 additions and 219 deletions

View file

@ -2,7 +2,7 @@ name: Build and Deploy
on:
# Nightly build
schedule:
- cron: '0 9 * * *'
- cron: "0 9 * * *"
# Manual nightly & release
workflow_dispatch:
inputs:
@ -19,6 +19,16 @@ on:
required: true
type: boolean
default: true
windows_32bit:
description: Whether to build Windows 32-bit
required: true
type: boolean
default: true
windows_64bit:
description: Whether to build Windows 64-bit
required: true
type: boolean
default: true
linux:
description: Whether to build Linux
required: true
@ -34,7 +44,7 @@ concurrency:
cancel-in-progress: true
env:
# XXX: UPDATE THIS BEFORE WHEN GOING LIVE
R2_BUCKET: 'packages-element-io-test'
R2_BUCKET: "packages-element-io-test"
jobs:
prepare:
uses: ./.github/workflows/build_prepare.yaml
@ -47,6 +57,30 @@ jobs:
CF_R2_TOKEN: ${{ secrets.CF_R2_TOKEN }}
CF_R2_S3_API: ${{ secrets.CF_R2_S3_API }}
windows_32bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_32bit
needs: prepare
name: Windows 32-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
deploy-mode: true
arch: x86
version: ${{ needs.prepare.outputs.win32-x86-version }}
windows_64bit:
if: github.event_name != 'workflow_dispatch' || inputs.windows_64bit
needs: prepare
name: Windows 64-bit
uses: ./.github/workflows/build_windows.yaml
secrets: inherit
with:
sign: true
deploy-mode: true
arch: x64
version: ${{ needs.prepare.outputs.win32-x64-version }}
macos:
if: github.event_name != 'workflow_dispatch' || inputs.macos
needs: prepare
@ -73,6 +107,8 @@ jobs:
deploy:
needs:
- macos
- windows_32bit
- windows_64bit
runs-on: ubuntu-latest
name: Deploy
if: always() && (github.event != 'workflow_dispatch' || inputs.deploy)

View file

@ -70,7 +70,7 @@ jobs:
env:
SQLCIPHER_STATIC: ${{ inputs.sqlcipher == 'static' && '1' || '' }}
- name: '[Nightly] Resolve version'
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |

View file

@ -69,14 +69,14 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
run: "yarn build:native:universal"
- name: '[Nightly] Resolve version'
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
run: |
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
# We split these because electron-builder gets upset if we set CSC_LINK even to an empty string
- name: '[Signed] Build App'
- name: "[Signed] Build App"
if: inputs.sign != ''
run: |
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }}
@ -88,7 +88,7 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.APPLE_CSC_LINK }}
- name: '[Unsigned] Build App'
- name: "[Unsigned] Build App"
if: inputs.sign == ''
run: |
scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }}
@ -127,12 +127,12 @@ jobs:
VERSION: ${{ inputs.version }}
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: '[Nightly] Strip version from installer file'
- name: "[Nightly] Strip version from installer file"
if: inputs.deploy-mode && inputs.version != ''
run: |
mv dist/install/macos/*.dmg "dist/install/macos/Element Nightly.dmg"
- name: '[Release] Prepare release latest symlink'
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
run: |
ln -s "$(find . -type f -iname "*.dmg" | xargs -0 -n1 -- basename)" "Element.dmg"

View file

@ -31,6 +31,12 @@ on:
linux-version:
description: "The version string the next Linux Nightly should use, only output for calculate-nightly-versions"
value: ${{ jobs.prepare.outputs.linux-version }}
win32-x64-version:
description: "The version string the next Windows x64 Nightly should use, only output for calculate-nightly-versions"
value: ${{ jobs.prepare.outputs.win32-x64-version }}
win32-x86-version:
description: "The version string the next Windows x86 Nightly should use, only output for calculate-nightly-versions"
value: ${{ jobs.prepare.outputs.win32-x86-version }}
jobs:
prepare:
name: Prepare
@ -39,6 +45,8 @@ jobs:
outputs:
macos-version: ${{ steps.versions.outputs.macos }}
linux-version: ${{ steps.versions.outputs.linux }}
win32-x64-version: ${{ steps.versions.outputs.win_x64 }}
win32-x86-version: ${{ steps.versions.outputs.win_x86 }}
steps:
- uses: actions/checkout@v3
@ -77,9 +85,14 @@ jobs:
LINUX=$(aws s3 cp s3://$R2_BUCKET/debian/dists/default/main/binary-amd64/Packages - --endpoint-url $R2_URL --region auto | grep "Package: element-nightly" -A 50 | grep Version -m1 | sed -n 's/Version: //p')
echo "linux=$(scripts/generate-nightly-version.ts --latest $LINUX)" >> $GITHUB_OUTPUT
WINx64=$(aws s3 cp s3://$R2_BUCKET/nightly/update/win32/x64/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8-)
echo "win_x64=$(scripts/generate-nightly-version.ts --latest $WINx64)" >> $GITHUB_OUTPUT
WINx86=$(aws s3 cp s3://$R2_BUCKET/nightly/update/win32/ia32/RELEASES - --endpoint-url $R2_URL --region auto | awk '{print $2}' | cut -d "-" -f 5 | cut -c 8-)
echo "win_x86=$(scripts/generate-nightly-version.ts --latest $WINx86)" >> $GITHUB_OUTPUT
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }}
# XXX: UPDATE THIS BEFORE WHEN GOING LIVE
R2_BUCKET: 'packages-element-io-test'
R2_BUCKET: "packages-element-io-test"
R2_URL: ${{ secrets.CF_R2_S3_API }}

View file

@ -3,14 +3,34 @@
# the correct cache scoping, and additional care must be taken to not run untrusted actions on the develop branch.
on:
workflow_call:
secrets:
ESIGNER_USER_NAME:
required: false
ESIGNER_USER_PASSWORD:
required: false
ESIGNER_USER_TOTP:
required: false
inputs:
arch:
type: string
required: true
description: "The architecture to build for, one of 'x64' | 'x86'"
version:
type: string
required: false
description: "Version string to override the one in package.json, used for non-release builds"
sign:
type: string
required: false
description: "Whether to sign & notarise the build, requires 'packages.element.io' environment"
deploy-mode:
type: string
required: false
description: "Whether to arrange artifacts in the arrangement needed for deployment, skipping unrelated ones"
jobs:
build:
runs-on: windows-latest
environment: ${{ inputs.sign && 'packages.element.io' || '' }}
steps:
- uses: kanga333/variable-mapper@master
id: config
@ -50,12 +70,14 @@ jobs:
# ActiveTCL package on choco is from 2015,
# this one is newer but includes more than we need
- name: Choco install tclsh
if: steps.cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
choco install -y magicsplat-tcl-tk --no-progress
echo "${HOME}/AppData/Local/Apps/Tcl86/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Choco install NetWide Assembler
if: steps.cache.outputs.cache-hit != 'true'
shell: pwsh
run: |
choco install -y nasm --no-progress
@ -82,12 +104,86 @@ jobs:
refreshenv
yarn build:native --target ${{ steps.config.outputs.target }}
- name: Install and configure eSigner CKA
id: esigner
if: inputs.sign
run: |
Set-StrictMode -Version 'Latest'
# Download
Invoke-WebRequest -OutFile eSigner_CKA.exe "https://packages.element.io/tools/SSL.COM%20eSigner%20CKA_1.0.4-build-20230221_signed.exe"
# Install
New-Item -ItemType Directory -Force -Path "$env:INSTALL_DIR"
./eSigner_CKA.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="${{ env.INSTALL_DIR }}" | Out-Null
# Disable logger
$LogConfig = Get-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
$LogConfig[0] = '<log4net threshold="OFF">'
$LogConfig | Set-Content -Path ${{ env.INSTALL_DIR }}/log4net.config
# Configure
${{ env.INSTALL_DIR }}/eSignerCKATool.exe config -mode "${{ env.MODE }}" -user "${{ secrets.ESIGNER_USER_NAME }}" -pass "${{ secrets.ESIGNER_USER_PASSWORD }}" -totp "${{ secrets.ESIGNER_USER_TOTP }}" -key "${{ env.MASTER_KEY_FILE }}" -r
${{ env.INSTALL_DIR }}/eSignerCKATool.exe unload
${{ env.INSTALL_DIR }}/eSignerCKATool.exe load
# Find certificate
$CodeSigningCert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
echo Certificate: $CodeSigningCert
# Extract thumbprint and subject name
$Thumbprint = $CodeSigningCert.Thumbprint
$SubjectName = ($CodeSigningCert.Subject -replace ", ?", "`n" | ConvertFrom-StringData).CN
echo "config-args=--signtool-thumbprint '$Thumbprint' --signtool-subject-name '$SubjectName'" >> $env:GITHUB_OUTPUT
env:
# XXX: UPDATE THIS BEFORE WHEN GOING LIVE
MODE: sandbox
INSTALL_DIR: C:\Users\runneradmin\eSignerCKA
MASTER_KEY_FILE: C:\Users\runneradmin\eSignerCKA\master.key
- name: "[Nightly] Resolve version"
id: nightly
if: inputs.version != ''
shell: bash
run: |
echo "config-args=--nightly '${{ inputs.version }}'" >> $GITHUB_OUTPUT
- name: Build App
run: "yarn build --publish never -w ${{ steps.config.outputs.build-args }}"
run: |
yarn ts-node scripts/generate-builder-config.ts ${{ steps.nightly.outputs.config-args }} ${{ steps.esigner.outputs.config-args }}
yarn build --publish never -w --config electron-builder.json ${{ steps.config.outputs.build-args }}
env:
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.22000.0/x86/signtool.exe"
- name: Prepare artifacts for deployment
if: inputs.deploy-mode
shell: bash
run: |
mv dist _dist
mkdir -p dist/install/win32/${{ inputs.arch }}/msi dist/update/win32/${{ inputs.arch }}
mv _dist/squirrel-windows*/*.exe dist/install/win32/${{ inputs.arch }}/
mv _dist/squirrel-windows*/*.nupkg dist/update/win32/${{ inputs.arch }}/
mv _dist/squirrel-windows*/RELEASES dist/update/win32/${{ inputs.arch }}/
# mv _dist/*.msi dist/install/win32/${{ inputs.arch }}/msi/
# We don't wish to store the installer for every nightly ever, so we only keep the latest
- name: "[Nightly] Strip version from installer file"
if: inputs.deploy-mode && inputs.version != ''
shell: bash
run: |
mv dist/install/win32/${{ inputs.arch }}/*.exe "dist/install/win32/${{ inputs.arch }}/Element Nightly Setup.exe"
# mv dist/install/win32/${{ inputs.arch }}/msi/*.msi "dist/install/win32/${{ inputs.arch }}/msi/Element Nightly Setup.msi"
- name: "[Release] Prepare release latest symlink"
if: inputs.deploy-mode && inputs.version == ''
shell: bash
run: |
ln -s "$(find . -type f -iname "*.exe" | xargs -0 -n1 -- basename)" "Element Setup.exe"
working-directory: "dist/install/win32/${{ inputs.arch }}"
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: win-${{ inputs.arch }}
name: ${{ inputs.deploy-mode && 'packages.element.io' || format('win-{0}', inputs.arch) }}
path: dist
retention-days: 1

View file

@ -22,10 +22,12 @@ const NIGHTLY_APP_ID = "im.riot.nightly";
const NIGHTLY_APP_NAME = "element-desktop-nightly";
const argv = parseArgs<{
nightly?: string;
"nightly"?: string;
"signtool-thumbprint"?: string;
"signtool-subject-name"?: string;
"deb-custom-control"?: string;
}>(process.argv.slice(2), {
string: ["nightly", "deb-custom-control"],
string: ["nightly", "deb-custom-control", "signtool-thumbprint", "signtool-subject-name"],
});
interface File {
@ -54,7 +56,10 @@ interface PackageBuild {
target: {
target: string;
};
sign: string;
sign?: string;
signingHashAlgorithms?: string[];
certificateSubjectName?: string;
certificateSha1?: string;
};
deb?: {
fpm?: string[];
@ -108,6 +113,13 @@ async function main(): Promise<number | void> {
cfg.extraMetadata!.version = version;
}
if (argv["signtool-thumbprint"] && argv["signtool-subject-name"]) {
delete cfg.win.sign;
cfg.win.signingHashAlgorithms = ["sha256"];
cfg.win.certificateSubjectName = argv["signtool-subject-name"];
cfg.win.certificateSha1 = argv["signtool-thumbprint"];
}
if (os.platform() === "linux") {
// Electron crashes on debian if there's a space in the path.
// https://github.com/vector-im/element-web/issues/13171
@ -123,9 +135,11 @@ async function main(): Promise<number | void> {
await fsProm.writeFile(ELECTRON_BUILDER_CFG_FILE, JSON.stringify(cfg, null, 4));
}
main().then((ret) => {
main()
.then((ret) => {
process.exit(ret!);
}).catch((e) => {
})
.catch((e) => {
console.error(e);
process.exit(1);
});

View file

@ -8,6 +8,7 @@ const HIDDEN_FILES = [
".DS_Store",
"index.html",
"/fonts/",
"/tools/",
"/nginx-theme/",
".~tmp~/",
"msi/",