Skip to content

Commit d34fdcf

Browse files
authored
chore: implement remote executable signing for windows binary builds (#28636)
* chore: implement remote executable signing for windows to comply with new signing key storage requirements [run ci] * bump circleci cache to avoid electron install issues [run ci] * chore: use fs-extra to ensure and create directory for temporary files and use os package to locate OS tmp directory
1 parent c6f5e9a commit d34fdcf

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

.circleci/cache-version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Bump this version to force CI to re-create the cache from scratch.
22

3-
01-02-24
3+
01-04-24

.circleci/workflows.yml

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ windowsWorkflowFilters: &windows-workflow-filters
7979
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
8080
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
8181
- equal: [ 'feature/experimental-retries', << pipeline.git.branch >> ]
82-
- equal: [ 'ryanm/fix/service-worker-capture', << pipeline.git.branch >> ]
82+
- equal: [ 'chore/update_windows_signing', << pipeline.git.branch >> ]
83+
- equal: [ 'lerna-optimize-tasks', << pipeline.git.branch >> ]
84+
- equal: [ 'em/shallow-checkout', << pipeline.git.branch >> ]
85+
- equal: [ 'mschile/mochaEvents_win_sep', << pipeline.git.branch >> ]
8386
- matches:
8487
pattern: /^release\/\d+\.\d+\.\d+$/
8588
value: << pipeline.git.branch >>
@@ -149,7 +152,7 @@ commands:
149152
name: Set environment variable to determine whether or not to persist artifacts
150153
command: |
151154
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
152-
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "publish-binary" && "$CIRCLE_BRANCH" != "ryanm/fix/service-worker-capture" ]]; then
155+
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "publish-binary" && "$CIRCLE_BRANCH" != "chore/update_windows_signing" ]]; then
153156
export SHOULD_PERSIST_ARTIFACTS=true
154157
fi' >> "$BASH_ENV"
155158
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
@@ -1150,8 +1153,10 @@ commands:
11501153
# set variable CSC_FOR_PULL_REQUEST=true
11511154
command: |
11521155
set -e
1153-
NEEDS_CODE_SIGNING=`node -p 'process.platform === "win32" || process.platform === "darwin"'`
1154-
if [[ "$NEEDS_CODE_SIGNING" == "true" ]]; then
1156+
NEEDS_CODE_SIGNING_WINDOWS=`node -p 'process.platform === "win32"'`
1157+
NEEDS_CODE_SIGNING_MAC=`node -p 'process.platform === "darwin"'`
1158+
1159+
if [[ "$NEEDS_CODE_SIGNING_MAC" == "true" ]]; then
11551160
echo "Checking for required environment variables..."
11561161
if [ -z "$CSC_LINK" ]; then
11571162
echo "Need to provide environment variable CSC_LINK"
@@ -1164,6 +1169,29 @@ commands:
11641169
exit 1
11651170
fi
11661171
echo "Succeeded."
1172+
elif [[ "$NEEDS_CODE_SIGNING_WINDOWS" == "true" ]]; then
1173+
echo "Checking for required environment variables..."
1174+
if [ -z "$WINDOWS_SIGN_USER_NAME" ]; then
1175+
echo "Need to provide environment variable WINDOWS_SIGN_USER_NAME"
1176+
echo "with password for fetching and signing certificate"
1177+
exit 1
1178+
fi
1179+
if [ -z "$WINDOWS_SIGN_USER_PASSWORD" ]; then
1180+
echo "Need to provide environment variable WINDOWS_SIGN_USER_PASSWORD"
1181+
echo "for fetching and signing certificate"
1182+
exit 1
1183+
fi
1184+
if [ -z "$WINDOWS_SIGN_CREDENTIAL_ID" ]; then
1185+
echo "Need to provide environment variable WINDOWS_SIGN_CREDENTIAL_ID"
1186+
echo "for identifying certificate"
1187+
exit 1
1188+
fi
1189+
if [ -z "$WINDOWS_SIGN_USER_TOTP" ]; then
1190+
echo "Need to provide environment variable WINDOWS_SIGN_USER_TOTP"
1191+
echo "for signing certificate"
1192+
exit 1
1193+
fi
1194+
echo "Succeeded."
11671195
else
11681196
echo "Not code signing for this platform"
11691197
fi

electron-builder.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
"executableName": "Cypress"
1717
},
1818
"win": {
19+
"signingHashAlgorithms": [
20+
"sha256"
21+
],
22+
"sign": "./scripts/windows-sign.js",
1923
"target": "dir"
2024
},
2125
"afterPack": "./scripts/after-pack-hook.js",

scripts/windows-sign.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// This signing procedure only runs on windows binary builds to leverage remote signing in order to
2+
// fullfil new requirements around OV and IV code signing.
3+
// @see https://www.ssl.com/article/code-signing-key-storage-requirements-will-change-on-june-1-2023/ for more details.
4+
5+
// Signing delegation happens inside the electron-builder.json, which can be seen in the configuration:
6+
// "sign": "./scripts/windows-sign.js"
7+
// @see https://www.electron.build/configuration/win#how-do-delegate-code-signing for configuration reference.
8+
9+
// sampled from https://github.com/electron-userland/electron-builder/issues/6158#issuecomment-899798533
10+
const path = require('path')
11+
const { tmpdir } = require('os')
12+
const fs = require('fs-extra')
13+
const childProcess = require('child_process')
14+
15+
const TEMP_DIR = path.join(tmpdir(), 'release', 'tmp')
16+
17+
// create the temp directory we need for CodeSignTool in order to avoid manual confirmations
18+
fs.ensureDirSync(TEMP_DIR)
19+
20+
function sign (configuration) {
21+
// credentials from ssl.com
22+
const USER_NAME = process.env.WINDOWS_SIGN_USER_NAME
23+
const USER_PASSWORD = process.env.WINDOWS_SIGN_USER_PASSWORD
24+
const CREDENTIAL_ID = process.env.WINDOWS_SIGN_CREDENTIAL_ID
25+
const USER_TOTP = process.env.WINDOWS_SIGN_USER_TOTP
26+
27+
if (USER_NAME && USER_PASSWORD && USER_TOTP && CREDENTIAL_ID) {
28+
console.log(`Signing ${configuration.path}`)
29+
const { name, dir } = path.parse(configuration.path)
30+
31+
// Since the CodeSignTool can only be run in the directory it is installed, we want to
32+
// download the CodeSignTool and explode it into the current directory. This isn't a repeat operation
33+
// in this case since we are only signing the executable, which is one file.
34+
console.log('downloading CodeSignTool for Windows from ssl.com...')
35+
childProcess.execSync('curl https://www.ssl.com/download/codesigntool-for-windows/ -o codesigntool-for-windows.zip')
36+
childProcess.execSync('tar -xvf codesigntool-for-windows.zip')
37+
childProcess.execSync('rm ./codesigntool-for-windows.zip')
38+
39+
// CodeSignTool can't sign in place without verifying the overwrite with a
40+
// manual interaction so we are creating a new file in a temp directory and
41+
// then replacing the original file with the signed file.
42+
const tempFile = path.join(TEMP_DIR, name)
43+
44+
console.log('executing signing...')
45+
// Sign the executable with the signing tool. For CLI reference, @see https://www.ssl.com/guide/esigner-codesigntool-command-guide/.
46+
childProcess.execSync(`CodeSignTool.bat sign -input_file_path="${configuration.path}" -output_dir_path="${TEMP_DIR}" -credential_id="${CREDENTIAL_ID}" -username="${USER_NAME}" -password="${USER_PASSWORD}" -totp_secret="${USER_TOTP}"`)
47+
48+
console.log('signing complete! Moving signed files back to package directory...')
49+
childProcess.execSync(`mv "${tempFile}" "${dir}"`)
50+
console.log('move completed!')
51+
} else {
52+
console.warn(`windows-sign.js - Can't sign file ${configuration.path}, missing value for:
53+
${USER_NAME ? '' : 'WINDOWS_SIGN_USER_NAME'}
54+
${USER_PASSWORD ? '' : 'WINDOWS_SIGN_USER_PASSWORD'}
55+
${CREDENTIAL_ID ? '' : 'WINDOWS_SIGN_CREDENTIAL_ID'}
56+
${USER_TOTP ? '' : 'WINDOWS_SIGN_USER_TOTP'}
57+
`)
58+
59+
process.exit(1)
60+
}
61+
}
62+
63+
exports.default = sign

0 commit comments

Comments
 (0)