diff --git a/.buildkite/commands/build-for-windows.ps1 b/.buildkite/commands/build-for-windows.ps1 index 0d8847cf14..56d741c065 100644 --- a/.buildkite/commands/build-for-windows.ps1 +++ b/.buildkite/commands/build-for-windows.ps1 @@ -34,10 +34,6 @@ If (@('1', 'true') -contains $useAzureTrustedSigning) { $setupScript = (Get-Command setup_azure_trusted_signing.ps1 -ErrorAction Stop).Source & $setupScript If ($LastExitCode -ne 0) { Exit $LastExitCode } -} Else { - # setup_windows_code_signing.ps1 comes from CI Toolkit Plugin - & "setup_windows_code_signing.ps1" - If ($LastExitCode -ne 0) { Exit $LastExitCode } } Write-Host "--- :npm: Installing Node dependencies" diff --git a/apps/studio/forge.config.ts b/apps/studio/forge.config.ts index 8cf4352617..6989f0ad3f 100644 --- a/apps/studio/forge.config.ts +++ b/apps/studio/forge.config.ts @@ -116,15 +116,9 @@ const config: ForgeConfig = { setupExe: 'studio-setup.exe', - // Azure mode: use the custom signing hook that calls signtool - // with Azure Trusted Signing parameters. - // PFX mode: use the local certificate file and password. - ...( windowsSign - ? { windowsSign } - : { - certificateFile: path.join( repoRoot, 'certificate.pfx' ), - certificatePassword: process.env.WINDOWS_CODE_SIGNING_CERT_PASSWORD, - } ), + // Sign via the custom Azure Trusted Signing hook (signtool, SHA256-only). + // Undefined off Windows CI, where the build is left unsigned. + ...( windowsSign ? { windowsSign } : {} ), }, [ 'win32' ] ), diff --git a/apps/studio/windowsSign.ts b/apps/studio/windowsSign.ts index c768dfdc5b..1e51614699 100644 --- a/apps/studio/windowsSign.ts +++ b/apps/studio/windowsSign.ts @@ -7,16 +7,18 @@ import type { WindowsSignOptions } from '@electron/packager'; // dual-signs (SHA1 + SHA256), but Azure only supports SHA256. // The hook calls signtool directly with SHA256-only parameters. // -// Controlled by the USE_AZURE_TRUSTED_SIGNING env var: -// - Unset or not '1'/'true': returns undefined, letting Forge use PFX certificate signing. -// - '1' or 'true': returns the Azure signing hook config, or throws if the -// required Azure env vars are missing. +// Gated on USE_AZURE_TRUSTED_SIGNING, which the signed-build jobs set (see +// build-for-windows.ps1). Package-only jobs — e.g. the Windows E2E run, which +// uses `electron-forge package` and never signs — leave it unset and get +// undefined, so this config (loaded by Forge on every build) stays inert +// there. The throw fires only for a build that asked to sign but is missing +// its Azure env, where signtool would otherwise fail with an opaque exit code. function getWindowsSign(): WindowsSignOptions | undefined { - const useAzureSigning = [ '1', 'true' ].includes( + const signWithAzure = [ '1', 'true' ].includes( ( process.env.USE_AZURE_TRUSTED_SIGNING ?? '' ).trim().toLowerCase() ); - if ( ! useAzureSigning ) { + if ( ! signWithAzure ) { return undefined; } diff --git a/scripts/package-appx.mjs b/scripts/package-appx.mjs index d413e4e347..85bf143461 100644 --- a/scripts/package-appx.mjs +++ b/scripts/package-appx.mjs @@ -4,28 +4,18 @@ import path from 'path'; import convertToWindowsStore from 'electron2appx'; import packageJson from '../apps/studio/package.json' with { type: 'json' }; -const useAzureSigning = [ '1', 'true' ].includes( - ( process.env.USE_AZURE_TRUSTED_SIGNING ?? '' ).trim().toLowerCase() -); - console.log( '--- :electron: Packaging AppX' ); -if ( useAzureSigning ) { - const azureSigning = await import( './azure-signing.cjs' ); - const { assertAzureSigningEnv } = azureSigning.default; - console.log( '~~~ Verifying Azure Trusted Signing env vars...' ); - try { - assertAzureSigningEnv(); - } catch ( error ) { - console.error( error instanceof Error ? error.message : error ); - process.exit( 1 ); - } -} else { - console.log( '~~~ Verifying WINDOWS_CODE_SIGNING_CERT_PASSWORD env var...' ); - if ( ! process.env.WINDOWS_CODE_SIGNING_CERT_PASSWORD ) { - console.error( 'Required env var WINDOWS_CODE_SIGNING_CERT_PASSWORD is not set!' ); - process.exit( 1 ); - } +const { assertAzureSigningEnv, getAzureSignArgs, getAzureSigningConfig } = ( + await import( './azure-signing.cjs' ) +).default; + +console.log( '~~~ Verifying Azure Trusted Signing env vars...' ); +try { + assertAzureSigningEnv(); +} catch ( error ) { + console.error( error instanceof Error ? error.message : error ); + process.exit( 1 ); } // Get architecture from environment variable, default to x64 for backward compatibility @@ -189,54 +179,40 @@ await convertToWindowsStore( { const appxOutputPathSigned = path.resolve( outPath, `${ appxName }-${ architecture }-signed` ); console.log( `~~~ Creating signed .appx for local testing at ${ appxOutputPathSigned }...` ); -if ( useAzureSigning ) { - const sideloadPublisher = - 'CN=Automattic Inc., O=Automattic Inc., L=San Francisco, S=California, C=US'; +const sideloadPublisher = + 'CN=Automattic Inc., O=Automattic Inc., L=San Francisco, S=California, C=US'; - // Build unsigned, then sign with Azure Trusted Signing via signtool. - await convertToWindowsStore( { - ...sharedOptions, - publisher: sideloadPublisher, - devCert: 'nil', - outputDirectory: appxOutputPathSigned, - } ); +// Build unsigned, then sign with Azure Trusted Signing via signtool. +await convertToWindowsStore( { + ...sharedOptions, + publisher: sideloadPublisher, + devCert: 'nil', + outputDirectory: appxOutputPathSigned, +} ); - console.log( '~~~ Signing sideload .appx with Azure Trusted Signing...' ); - const azureSigning = await import( './azure-signing.cjs' ); - const { getAzureSignArgs, getAzureSigningConfig } = azureSigning.default; - const appxFiles = ( await fs.readdir( appxOutputPathSigned ) ).filter( ( f ) => - f.endsWith( '.appx' ) - ); - if ( appxFiles.length === 0 ) { - console.error( 'No .appx file found to sign!' ); - process.exit( 1 ); - } +console.log( '~~~ Signing sideload .appx with Azure Trusted Signing...' ); +const appxFiles = ( await fs.readdir( appxOutputPathSigned ) ).filter( ( f ) => + f.endsWith( '.appx' ) +); +if ( appxFiles.length === 0 ) { + console.error( 'No .appx file found to sign!' ); + process.exit( 1 ); +} - for ( const appxFile of appxFiles ) { - const appxPath = path.join( appxOutputPathSigned, appxFile ); - console.log( `Signing ${ appxPath }...` ); - const { signtoolPath } = getAzureSigningConfig(); - execFileSync( signtoolPath, getAzureSignArgs( appxPath ), { - stdio: 'inherit', - } ); - console.log( `Signed ${ appxFile } successfully.` ); - - // Rename to remove misleading "unsigned" from the filename - const renamedFile = appxFile.replace( ' unsigned', '' ); - if ( renamedFile !== appxFile ) { - const renamedPath = path.join( appxOutputPathSigned, renamedFile ); - await fs.rename( appxPath, renamedPath ); - console.log( `Renamed to ${ renamedFile }` ); - } - } -} else { - // PFX certificate signing - await convertToWindowsStore( { - ...sharedOptions, - publisher: - 'CN="Automattic, Inc.", O="Automattic, Inc.", S=California, C=US', - devCert: 'certificate.pfx', - certPass: process.env.WINDOWS_CODE_SIGNING_CERT_PASSWORD, - outputDirectory: appxOutputPathSigned, +for ( const appxFile of appxFiles ) { + const appxPath = path.join( appxOutputPathSigned, appxFile ); + console.log( `Signing ${ appxPath }...` ); + const { signtoolPath } = getAzureSigningConfig(); + execFileSync( signtoolPath, getAzureSignArgs( appxPath ), { + stdio: 'inherit', } ); + console.log( `Signed ${ appxFile } successfully.` ); + + // Rename to remove misleading "unsigned" from the filename + const renamedFile = appxFile.replace( ' unsigned', '' ); + if ( renamedFile !== appxFile ) { + const renamedPath = path.join( appxOutputPathSigned, renamedFile ); + await fs.rename( appxPath, renamedPath ); + console.log( `Renamed to ${ renamedFile }` ); + } }