Skip to content

Commit

Permalink
update build.yml and check-certificates.yml
Browse files Browse the repository at this point in the history
  • Loading branch information
davegarthsimpson committed Jun 29, 2024
1 parent aa9b10d commit b1607cd
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 27 deletions.
78 changes: 74 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,22 @@ env:
container: |
null
# Name of the secret that contains the certificate.
certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX
certificate-secret: INSTALLER_CERT_WINDOWS_CER
# Name of the secret that contains the certificate password.
certificate-password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD
certificate-password-secret: INSTALLER_CERT_WINDOWS_PASSWORD
# File extension for the certificate.
certificate-extension: pfx
# Container for windows cert signing
certificate-container: INSTALLER_CERT_WINDOWS_CONTAINER
# Quoting on the value is required here to allow the same comparison expression syntax to be used for this
# and the companion needs.select-targets.outputs.merge-channel-files property (output values always have string
# type).
mergeable-channel-file: 'false'
artifacts:
- path: '*Windows_64bit.exe'
name: Windows_X86-64_interactive_installer
- path: '*Windows_64bit_signed.exe'
name: Windows_X86-64_interactive_installer_signed
- path: '*Windows_64bit.msi'
name: Windows_X86-64_MSI
- path: '*Windows_64bit.zip'
Expand Down Expand Up @@ -345,14 +349,15 @@ jobs:
IS_NIGHTLY: ${{ needs.build-type-determination.outputs.is-nightly }}
IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }}
CAN_SIGN: ${{ secrets[matrix.config.certificate-secret] != '' }}
IS_WINDOWS_CONFIG: ${{ matrix.config.name == 'Windows' }}
# The CREATE_* environment vars are only used to run tests. These secrets are optional. Dependent tests will
# be skipped if not available.
CREATE_USERNAME: ${{ secrets.CREATE_USERNAME }}
CREATE_PASSWORD: ${{ secrets.CREATE_PASSWORD }}
CREATE_CLIENT_SECRET: ${{ secrets.CREATE_CLIENT_SECRET }}
run: |
# See: https://www.electron.build/code-signing
if [ $CAN_SIGN = false ]; then
if [ $CAN_SIGN = false ] || [ $IS_WINDOWS_CONFIG = true ]; then
echo "Skipping the app signing: certificate not provided."
else
export CSC_LINK="${{ runner.temp }}/signing_certificate.${{ matrix.config.certificate-extension }}"
Expand All @@ -372,7 +377,7 @@ jobs:
yarn --cwd electron-app rebuild
yarn --cwd electron-app build
yarn --cwd electron-app package
# Both macOS jobs generate a "channel update info file" with same path and name. The second job to complete would
# overwrite the file generated by the first in the workflow artifact.
- name: Stage channel file for merge
Expand Down Expand Up @@ -406,11 +411,71 @@ jobs:
name: ${{ env.JOB_TRANSFER_ARTIFACT }}
path: ${{ env.BUILD_ARTIFACTS_PATH }}

sign-windows:
runs-on: [self-hosted, windows-sign-pc]
needs: build

defaults:
run:
shell: bash

env:
BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts
INSTALLER_CERT_WINDOWS_CER: "/tmp/cert.cer"
# We are hardcoding the path for signtool because is not present on the windows PATH env var by default.
# Keep in mind that this path could change when upgrading to a new runner version
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x86/signtool.exe"

steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ${{ env.JOB_TRANSFER_ARTIFACT }}
path: ${{ env.BUILD_ARTIFACTS_PATH }}

- name: Save artifact path to variable
shell: bash
run: |
ARTIFACT=$(find "${{ env.BUILD_ARTIFACTS_PATH }}" -name "*Windows_64bit.exe" | head -n 1)
# Convert to Windows-style path with forward slashes
FULL_PATH=$(cygpath -w $ARTIFACT | sed 's|\\|/|g')
echo "ARTIFACT_PATH=$FULL_PATH" >> $GITHUB_ENV
- name: Save Win signing certificate to file
run: echo "${{ secrets.INSTALLER_CERT_WINDOWS_CER }}" | base64 --decode > ${{ env.INSTALLER_CERT_WINDOWS_CER }}

- name: Sign EXE
env:
CERT_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
CONTAINER_NAME: ${{ secrets.INSTALLER_CERT_WINDOWS_CONTAINER }}
# https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
run: |
"${{ env.SIGNTOOL_PATH }}" sign -d "Arduino IDE" -f ${{ env.INSTALLER_CERT_WINDOWS_CER }} -csp "eToken Base Cryptographic Provider" -k "[{{${{ env.CERT_PASSWORD }}}}]=${{ env.CONTAINER_NAME }}" -fd sha256 -tr http://timestamp.digicert.com -td SHA256 -v ${{ env.ARTIFACT_PATH }}
- name: Rename signed EXE
shell: bash
run: |
BASE_NAME=$(echo "${{ env.ARTIFACT_PATH }}" | sed 's/.exe$//')
SIGNED_EXE_PATH="${BASE_NAME}_signed.exe"
mv "${{ env.ARTIFACT_PATH }}" "$SIGNED_EXE_PATH"
echo "SIGNED_ARTIFACT_PATH=$SIGNED_EXE_PATH" >> $GITHUB_ENV
- name: Upload artifacts with signed EXE
uses: actions/upload-artifact@v3
with:
name: Windows_X86-64_interactive_installer_signed
path: ${{ env.SIGNED_ARTIFACT_PATH }}

# This step is needed because the self hosted runner does not delete files automatically
- name: Clean up artifacts
run: rm -rf ${{ env.BUILD_ARTIFACTS_PATH }}

merge-channel-files:
needs:
- build-type-determination
- select-targets
- build
- sign-windows
if: needs.select-targets.outputs.merge-channel-files == 'true'
runs-on: ubuntu-latest
permissions: {}
Expand Down Expand Up @@ -474,6 +539,7 @@ jobs:
needs:
- select-targets
- build
- sign-windows
if: always() && needs.build.result != 'skipped'
runs-on: ubuntu-latest

Expand All @@ -498,6 +564,7 @@ jobs:
needs:
- build-type-determination
- build
- sign-windows
runs-on: ubuntu-latest
outputs:
BODY: ${{ steps.changelog.outputs.BODY }}
Expand Down Expand Up @@ -547,6 +614,7 @@ jobs:
- build-type-determination
- merge-channel-files
- changelog
- sign-windows
if: >
always() &&
needs.build-type-determination.result == 'success' &&
Expand Down Expand Up @@ -580,6 +648,7 @@ jobs:
- build-type-determination
- merge-channel-files
- changelog
- sign-windows
if: >
always() &&
needs.build-type-determination.result == 'success' &&
Expand Down Expand Up @@ -631,6 +700,7 @@ jobs:
- publish
- release
- artifacts
- sign-windows
if: always() && needs.build.result != 'skipped'
runs-on: ubuntu-latest

Expand Down
65 changes: 42 additions & 23 deletions .github/workflows/check-certificates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ jobs:
- identifier: macOS signing certificate # Text used to identify certificate in notifications.
certificate-secret: APPLE_SIGNING_CERTIFICATE_P12 # Name of the secret that contains the certificate.
password-secret: KEYCHAIN_PASSWORD # Name of the secret that contains the certificate password.
type: pkcs12
- identifier: Windows signing certificate
certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX
password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD
certificate-secret: INSTALLER_CERT_WINDOWS_CER
# The password for the Windows certificate is not needed, because its not a container, but a single certificate.
type: x509

steps:
- name: Set certificate path environment variable
Expand All @@ -95,7 +97,7 @@ jobs:
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
run: |
(
openssl pkcs12 \
openssl ${{ matrix.certificate.type }} \
-in "${{ env.CERTIFICATE_PATH }}" \
-legacy \
-noout \
Expand All @@ -122,26 +124,43 @@ jobs:
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
id: get-days-before-expiration
run: |
EXPIRATION_DATE="$(
(
openssl pkcs12 \
-in "${{ env.CERTIFICATE_PATH }}" \
-clcerts \
-legacy \
-nodes \
-passin env:CERTIFICATE_PASSWORD
) | (
openssl x509 \
-noout \
-enddate
) | (
grep \
--max-count=1 \
--only-matching \
--perl-regexp \
'notAfter=(\K.*)'
)
)"
if [[ ${{ matrix.certificate.type }} == "pkcs12" ]]; then
EXPIRATION_DATE="$(
(
openssl pkcs12 \
-in "${{ env.CERTIFICATE_PATH }}" \
-clcerts \
-legacy \
-nodes \
-passin env:CERTIFICATE_PASSWORD
) | (
openssl x509 \
-noout \
-enddate
) | (
grep \
--max-count=1 \
--only-matching \
--perl-regexp \
'notAfter=(\K.*)'
)
)"
elif [[ ${{ matrix.certificate.type }} == "x509" ]]; then
EXPIRATION_DATE="$(
(
openssl x509 \
-in ${{ env.CERTIFICATE_PATH }} \
-noout \
-enddate
) | (
grep \
--max-count=1 \
--only-matching \
--perl-regexp \
'notAfter=(\K.*)'
)
)"
fi
DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))"
Expand Down

0 comments on commit b1607cd

Please sign in to comment.