33 * Running this script with no command line parameters should build all targets for the current platform.
44 * Pass `--target=<short-name>` to build exactly one target instead of the platform default set; the matrix in
55 * `release-candidate.yml` uses this to fan a multi-target serial pass out into one runner per target. Valid short
6- * names: `mas`, `mas-dev`, `dmg`, `appx`, `nsis`.
7- * On Windows, make sure to set CSC_* or WIN_CSC_* environment variables or the NSIS build will fail.
6+ * names: `mas`, `mas-dev`, `dmg`, `appx`, `nsis`, `msi`, `installers`, `nsis-x64`.
7+ * Windows signing uses Azure Artifact Signing, configured in `electron-builder.yaml`'s `win.azureSignOptions`.
8+ * Auth comes from OIDC federated credentials in `release-candidate.yml`; signing is disabled when --mode=dev.
89 * On Mac, the CSC_* variables are optional but will be respected if present.
910 * See also: https://www.electron.build/code-signing
1011 */
@@ -46,18 +47,12 @@ const getPlatformFlag = function () {
4647 * Run `electron-builder` once to build one or more target(s).
4748 * @param {object } wrapperConfig - overall configuration object for the wrapper script.
4849 * @param {object } target - the target to build in this call.
49- * If the `target.name` is `'nsis'` then the environment must contain code-signing config (CSC_* or WIN_CSC_*).
50- * If the `target.name` is `'appx'` then code-signing config will be stripped from the environment if present.
5150 */
5251const runBuilder = function ( wrapperConfig , target ) {
53- // the AppX build fails if CSC_* or WIN_CSC_* variables are set
52+ // Strip CSC_* env vars for AppX (would conflict with the Store-managed cert) and for unsigned builds.
53+ // Windows signing itself now goes through Azure (not CSC), so these vars are typically absent anyway.
5454 const shouldStripCSC = ( target . name . indexOf ( 'appx' ) === 0 ) || ( ! wrapperConfig . doSign ) ;
5555 const childEnvironment = shouldStripCSC ? stripCSC ( process . env ) : process . env ;
56- if ( wrapperConfig . doSign &&
57- ( target . name . indexOf ( 'nsis' ) === 0 ) &&
58- ! ( childEnvironment . CSC_LINK || childEnvironment . WIN_CSC_LINK ) ) {
59- throw new Error ( `Signing NSIS build requires CSC_LINK or WIN_CSC_LINK` ) ;
60- }
6156 const platformFlag = getPlatformFlag ( ) ;
6257 let allArgs = [ platformFlag , target . name ] ;
6358 if ( target . platform === 'darwin' ) {
@@ -75,6 +70,38 @@ const runBuilder = function (wrapperConfig, target) {
7570 // APPLE_API_KEY / APPLE_API_KEY_ID / APPLE_API_ISSUER are present in
7671 // the environment.
7772 }
73+ // Appx-only means every target name in the pass starts with 'appx'. A mixed pass that bundles
74+ // appx with nsis or msi keeps signing on for the non-appx parts; only the pure-appx case opts
75+ // out so the Store can re-sign its container with unsigned inner binaries (today's behavior).
76+ const targetNames = target . name . trim ( ) . split ( / \s + / ) ;
77+ const isAppxOnly = targetNames . every ( name => name . startsWith ( 'appx' ) ) ;
78+ if ( target . platform === 'win32' && wrapperConfig . doSign && ! isAppxOnly ) {
79+ // Supply Azure Artifact Signing config via CLI rather than electron-builder.yaml. Putting it
80+ // in YAML would activate signing for every build, including PR CI and local dev where Azure
81+ // auth isn't available — and some signing paths (notably the NSIS uninstaller) ignore the
82+ // win.signAndEditExecutable flag, so per-target gating isn't reliable. AppX-only passes skip
83+ // signing entirely: the Microsoft Store re-signs the outer .appx during certification, and
84+ // we want the inner binaries unsigned (electron-builder would otherwise sign them via signExts).
85+ const required = [
86+ 'AZURE_SIGNING_ENDPOINT' ,
87+ 'AZURE_SIGNING_ACCOUNT_NAME' ,
88+ 'AZURE_SIGNING_PROFILE_NAME' ,
89+ 'AZURE_SIGNING_PUBLISHER_NAME'
90+ ] ;
91+ const missing = required . filter ( name => ! childEnvironment [ name ] ) ;
92+ if ( missing . length > 0 ) {
93+ throw new Error ( `Azure signing requires env vars: ${ missing . join ( ', ' ) } ` ) ;
94+ }
95+ // Wrap values in double quotes so spaces (e.g. a multi-word publisherName) survive shell
96+ // re-tokenization. spawnSync(shell: true) joins argv with spaces and runs through cmd.exe /
97+ // /bin/sh, so any internal whitespace would otherwise become an arg separator.
98+ allArgs . push (
99+ `--c.win.azureSignOptions.endpoint="${ childEnvironment . AZURE_SIGNING_ENDPOINT } "` ,
100+ `--c.win.azureSignOptions.codeSigningAccountName="${ childEnvironment . AZURE_SIGNING_ACCOUNT_NAME } "` ,
101+ `--c.win.azureSignOptions.certificateProfileName="${ childEnvironment . AZURE_SIGNING_PROFILE_NAME } "` ,
102+ `--c.win.azureSignOptions.publisherName="${ childEnvironment . AZURE_SIGNING_PUBLISHER_NAME } "`
103+ ) ;
104+ }
78105 if ( ! wrapperConfig . doPackage ) {
79106 allArgs . push ( '--dir' , '--c.compression=store' ) ;
80107 }
0 commit comments