Skip to content

Commit c1f1885

Browse files
attempt 1: using self hosted runner in new job
1 parent aa9b10d commit c1f1885

File tree

3 files changed

+126
-28
lines changed

3 files changed

+126
-28
lines changed

.github/workflows/build.yml

+83-4
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,30 @@ env:
6161
container: |
6262
null
6363
# Name of the secret that contains the certificate.
64-
certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX
64+
certificate-secret: INSTALLER_CERT_WINDOWS_CER
6565
# Name of the secret that contains the certificate password.
66-
certificate-password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD
66+
certificate-password-secret: INSTALLER_CERT_WINDOWS_PASSWORD
6767
# File extension for the certificate.
6868
certificate-extension: pfx
69+
# Container for windows cert signing
70+
certificate-container: INSTALLER_CERT_WINDOWS_CONTAINER
6971
# Quoting on the value is required here to allow the same comparison expression syntax to be used for this
7072
# and the companion needs.select-targets.outputs.merge-channel-files property (output values always have string
7173
# type).
7274
mergeable-channel-file: 'false'
7375
artifacts:
7476
- path: '*Windows_64bit.exe'
7577
name: Windows_X86-64_interactive_installer
78+
- path: '*Windows_64bit_unsigned.exe'
79+
name: Windows_X86-64_interactive_installer_unsigned
7680
- path: '*Windows_64bit.msi'
7781
name: Windows_X86-64_MSI
82+
- path: '*Windows_64bit_unsigned.msi'
83+
name: Windows_X86-64_MSI_unsigned
7884
- path: '*Windows_64bit.zip'
7985
name: Windows_X86-64_zip
86+
- path: '*Windows_64bit_unsigned.zip'
87+
name: Windows_X86-64_zip_unsigned
8088
- config:
8189
name: Linux
8290
runs-on: ubuntu-latest
@@ -345,14 +353,15 @@ jobs:
345353
IS_NIGHTLY: ${{ needs.build-type-determination.outputs.is-nightly }}
346354
IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }}
347355
CAN_SIGN: ${{ secrets[matrix.config.certificate-secret] != '' }}
356+
IS_WINDOWS_CONFIG: ${{ matrix.config.name == 'Windows' }}
348357
# The CREATE_* environment vars are only used to run tests. These secrets are optional. Dependent tests will
349358
# be skipped if not available.
350359
CREATE_USERNAME: ${{ secrets.CREATE_USERNAME }}
351360
CREATE_PASSWORD: ${{ secrets.CREATE_PASSWORD }}
352361
CREATE_CLIENT_SECRET: ${{ secrets.CREATE_CLIENT_SECRET }}
353362
run: |
354363
# See: https://www.electron.build/code-signing
355-
if [ $CAN_SIGN = false ]; then
364+
if [ $CAN_SIGN = false ] || [ $IS_WINDOWS_CONFIG = true ]; then
356365
echo "Skipping the app signing: certificate not provided."
357366
else
358367
export CSC_LINK="${{ runner.temp }}/signing_certificate.${{ matrix.config.certificate-extension }}"
@@ -372,7 +381,7 @@ jobs:
372381
yarn --cwd electron-app rebuild
373382
yarn --cwd electron-app build
374383
yarn --cwd electron-app package
375-
384+
376385
# Both macOS jobs generate a "channel update info file" with same path and name. The second job to complete would
377386
# overwrite the file generated by the first in the workflow artifact.
378387
- name: Stage channel file for merge
@@ -406,11 +415,76 @@ jobs:
406415
name: ${{ env.JOB_TRANSFER_ARTIFACT }}
407416
path: ${{ env.BUILD_ARTIFACTS_PATH }}
408417

418+
sign-windows:
419+
runs-on: [self-hosted, windows-sign-pc]
420+
needs: build
421+
422+
defaults:
423+
run:
424+
shell: bash
425+
426+
env:
427+
BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts
428+
INSTALLER_CERT_WINDOWS_CER: "/tmp/cert.cer"
429+
# We are hardcoding the path for signtool because is not present on the windows PATH env var by default.
430+
# Keep in mind that this path could change when upgrading to a new runner version
431+
SIGNTOOL_PATH: "C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x86/signtool.exe"
432+
433+
steps:
434+
- name: Download artifact
435+
uses: actions/download-artifact@v3
436+
with:
437+
name: ${{ env.JOB_TRANSFER_ARTIFACT }}
438+
path: ${{ env.BUILD_ARTIFACTS_PATH }}
439+
440+
- name: Find and process exe and msi artifacts
441+
shell: bash
442+
env:
443+
CERT_PASSWORD: ${{ secrets.INSTALLER_CERT_WINDOWS_PASSWORD }}
444+
CONTAINER_NAME: ${{ secrets.INSTALLER_CERT_WINDOWS_CONTAINER }}
445+
# https://stackoverflow.com/questions/17927895/automate-extended-validation-ev-code-signing-with-safenet-etoken
446+
run: |
447+
shopt -s nullglob
448+
for ARTIFACT in "${{ env.BUILD_ARTIFACTS_PATH }}"/*_unsigned.{exe,msi}; do
449+
echo "Processing $ARTIFACT"
450+
FILENAME=$(basename "$ARTIFACT")
451+
BASE_NAME="${FILENAME%.*}"
452+
EXTENSION="${FILENAME##*.}"
453+
# Remove '_unsigned' from the base name
454+
SIGNED_BASE_NAME="${BASE_NAME%_unsigned}"
455+
456+
# Sign and rename EXE and MSI files
457+
if [[ "$EXTENSION" == "exe" || "$EXTENSION" == "msi" ]]; then
458+
echo "Signing $ARTIFACT"
459+
"${{ 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 "$ARTIFACT"
460+
SIGNED_ARTIFACT_PATH="${{ env.BUILD_ARTIFACTS_PATH }}/${SIGNED_BASE_NAME}.${EXTENSION}"
461+
mv "$ARTIFACT" "$SIGNED_ARTIFACT_PATH"
462+
echo "Renamed $ARTIFACT to $SIGNED_ARTIFACT_PATH"
463+
fi
464+
done
465+
466+
- name: Upload signed EXE
467+
uses: actions/upload-artifact@v3
468+
with:
469+
name: Windows_X86-64_interactive_installer
470+
path: ${{ env.BUILD_ARTIFACTS_PATH }}/*Windows_64bit.exe
471+
472+
- name: Upload signed MSI
473+
uses: actions/upload-artifact@v3
474+
with:
475+
name: Windows_X86-64_MSI
476+
path: ${{ env.BUILD_ARTIFACTS_PATH }}/*Windows_64bit.msi
477+
478+
# This step is needed because the self hosted runner does not delete files automatically
479+
- name: Clean up artifacts
480+
run: rm -rf ${{ env.BUILD_ARTIFACTS_PATH }}
481+
409482
merge-channel-files:
410483
needs:
411484
- build-type-determination
412485
- select-targets
413486
- build
487+
- sign-windows
414488
if: needs.select-targets.outputs.merge-channel-files == 'true'
415489
runs-on: ubuntu-latest
416490
permissions: {}
@@ -474,6 +548,7 @@ jobs:
474548
needs:
475549
- select-targets
476550
- build
551+
- sign-windows
477552
if: always() && needs.build.result != 'skipped'
478553
runs-on: ubuntu-latest
479554

@@ -498,6 +573,7 @@ jobs:
498573
needs:
499574
- build-type-determination
500575
- build
576+
- sign-windows
501577
runs-on: ubuntu-latest
502578
outputs:
503579
BODY: ${{ steps.changelog.outputs.BODY }}
@@ -547,6 +623,7 @@ jobs:
547623
- build-type-determination
548624
- merge-channel-files
549625
- changelog
626+
- sign-windows
550627
if: >
551628
always() &&
552629
needs.build-type-determination.result == 'success' &&
@@ -580,6 +657,7 @@ jobs:
580657
- build-type-determination
581658
- merge-channel-files
582659
- changelog
660+
- sign-windows
583661
if: >
584662
always() &&
585663
needs.build-type-determination.result == 'success' &&
@@ -631,6 +709,7 @@ jobs:
631709
- publish
632710
- release
633711
- artifacts
712+
- sign-windows
634713
if: always() && needs.build.result != 'skipped'
635714
runs-on: ubuntu-latest
636715

.github/workflows/check-certificates.yml

+42-23
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ jobs:
7474
- identifier: macOS signing certificate # Text used to identify certificate in notifications.
7575
certificate-secret: APPLE_SIGNING_CERTIFICATE_P12 # Name of the secret that contains the certificate.
7676
password-secret: KEYCHAIN_PASSWORD # Name of the secret that contains the certificate password.
77+
type: pkcs12
7778
- identifier: Windows signing certificate
78-
certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX
79-
password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD
79+
certificate-secret: INSTALLER_CERT_WINDOWS_CER
80+
# The password for the Windows certificate is not needed, because its not a container, but a single certificate.
81+
type: x509
8082

8183
steps:
8284
- name: Set certificate path environment variable
@@ -95,7 +97,7 @@ jobs:
9597
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
9698
run: |
9799
(
98-
openssl pkcs12 \
100+
openssl ${{ matrix.certificate.type }} \
99101
-in "${{ env.CERTIFICATE_PATH }}" \
100102
-legacy \
101103
-noout \
@@ -122,26 +124,43 @@ jobs:
122124
CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }}
123125
id: get-days-before-expiration
124126
run: |
125-
EXPIRATION_DATE="$(
126-
(
127-
openssl pkcs12 \
128-
-in "${{ env.CERTIFICATE_PATH }}" \
129-
-clcerts \
130-
-legacy \
131-
-nodes \
132-
-passin env:CERTIFICATE_PASSWORD
133-
) | (
134-
openssl x509 \
135-
-noout \
136-
-enddate
137-
) | (
138-
grep \
139-
--max-count=1 \
140-
--only-matching \
141-
--perl-regexp \
142-
'notAfter=(\K.*)'
143-
)
144-
)"
127+
if [[ ${{ matrix.certificate.type }} == "pkcs12" ]]; then
128+
EXPIRATION_DATE="$(
129+
(
130+
openssl pkcs12 \
131+
-in "${{ env.CERTIFICATE_PATH }}" \
132+
-clcerts \
133+
-legacy \
134+
-nodes \
135+
-passin env:CERTIFICATE_PASSWORD
136+
) | (
137+
openssl x509 \
138+
-noout \
139+
-enddate
140+
) | (
141+
grep \
142+
--max-count=1 \
143+
--only-matching \
144+
--perl-regexp \
145+
'notAfter=(\K.*)'
146+
)
147+
)"
148+
elif [[ ${{ matrix.certificate.type }} == "x509" ]]; then
149+
EXPIRATION_DATE="$(
150+
(
151+
openssl x509 \
152+
-in ${{ env.CERTIFICATE_PATH }} \
153+
-noout \
154+
-enddate
155+
) | (
156+
grep \
157+
--max-count=1 \
158+
--only-matching \
159+
--perl-regexp \
160+
'notAfter=(\K.*)'
161+
)
162+
)"
163+
fi
145164
146165
DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))"
147166

electron-app/scripts/package.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ async function getArtifactName(version) {
100100
switch (platform) {
101101
case 'win32': {
102102
if (arch === 'x64') {
103-
return `${name}_${version}_Windows_64bit.\$\{ext}`;
103+
return `${name}_${version}_Windows_64bit_unsigned.\$\{ext}`;
104104
}
105105
throw new Error(`Unsupported platform, arch: ${platform}, ${arch}`);
106106
}

0 commit comments

Comments
 (0)