Support for Azure Trusted Signing in Electron Builder
- Electron-Builder Version: 24.13.3
- Node Version: 18.16.0
- Electron Version: 31.0.2
- Electron Type (current, beta, nightly): electron-updater: 6.2.1
- Target: Windows
I'm inquiring about the possibility of integrating Azure Trusted Signing within the Electron Builder workflow. Currently, my build process involves:
- Signing the executable using the azure/[email protected] GitHub Action.
- Packaging and releasing the signed executable, ensuring auto-update functionality with s3 provider.
If you could provide guidance on how to integrate Azure Trusted Signing more seamlessly with Electron Builder or if there are plans to support this in the future, it would be greatly appreciated.
Thank you for your time and assistance.
I guess a lot of those powershell commands could be copy-pasted/translated into electron-builder's signing workflow, but if any updates happen to that github action, they won't be propagated into electron-builder without someone opening an issue here. Would that be a problem?
We're also interested in this. There is a nice guide for implementation of trusted EV code signing using Azure here: https://melatonin.dev/blog/code-signing-on-windows-with-azure-trusted-signing/
Basically, we'd need to call the action multiple times:
- on the executable files after they have been built
- on the installer executable after everything has been packaged in
Currently, it seems that steps 1 and 2 are done in one action and therefore it's not possible to execute code signing after each of the steps using the GitHub action, right?
From the github action code it looks like a powershell script that installs the TrustedSigning module and then invokes it with appropriate params is all that is required:
Install-Module -Name TrustedSigning -RequiredVersion 0.4.1 -Force -Repository PSGallery
Invoke-TrustedSigning @params
This should be possible to add to electron-builder with some extra env vars?
I quickly put together a basic copy of the action code for an afterSign hook, which maybe you'd be able to test with.
Basically, we skip the signing stage for the regular signing process. Instead, we leverage the afterSign for running the powershell commands.
Would you be willing to do some investigating from there? Not sure if the params need to be passed in as a var or as a literal string. I don't have any azure account to test this myself
// electron-builder-config.ts
import { AfterPackContext, Configuration } from "app-builder-lib"
import { CustomWindowsSignTaskConfiguration } from "app-builder-lib/out/codeSign/windowsCodeSign"
import { WinPackager } from "app-builder-lib/out/winPackager"
import { execFile } from "child_process"
// Configuration object
export default {
// base configuration
win: {
// block signing
sign: (_configuration: CustomWindowsSignTaskConfiguration, _packager: WinPackager | undefined) => {
return Promise.resolve()
}
},
afterSign: async (context: AfterPackContext) => {
await new Promise((resolve, reject) => execFile(
`chcp 65001 >NUL & powershell.exe`,
["-Name", "TrustedSigning", "-RequiredVersion", "0.4.1", "-Force", "-Repository", "PSGallery",],
{
shell: true,
timeout: 60 * 1000,
},
(error, stdout, stderr) => {
if (error || stderr) {
reject(error?.message || stderr)
}
resolve(stdout)
}
))
// requires the following env vars also set:
// AZURE_TENANT_ID
// AZURE_CLIENT_ID
// AZURE_CLIENT_SECRET
// AZURE_CLIENT_CERTIFICATE_PATH
// AZURE_CLIENT_SEND_CERTIFICATE_CHAIN
// AZURE_USERNAME
// AZURE_PASSWORD
const params: any = {}
// Variables you can define
const trustedSigningAccountName = undefined
const certificateProfileName = undefined
const files = undefined
const filesFolder = undefined
const filesFolderFilter = undefined
const filesFolderRecurse = false // boolean
const filesFolderDepth = undefined // integer
const filesCatalog = undefined
const fileDigest = undefined
const timestampRfc3161 = undefined
const timestampDigest = undefined
const appendSignature = false // boolean
const description = undefined
const descriptionUrl = undefined
const generateDigestPath = undefined
const generateDigestXml = false // boolean
const ingestDigestPath = undefined
const signDigest = false // boolean
const generatePageHashes = false // boolean
const suppressPageHashes = false // boolean
const generatePkcs7 = false // boolean
const pkcs7Options = undefined
const pkcs7Oid = undefined
const enhancedKeyUsage = undefined
const excludeEnvironmentCredential = false // boolean
const excludeWorkloadIdentityCredential = false // boolean
const excludeManagedIdentityCredential = false // boolean
const excludeSharedTokenCacheCredential = false // boolean
const excludeVisualStudioCredential = false // boolean
const excludeVisualStudioCodeCredential = false // boolean
const excludeAzureCliCredential = false // boolean
const excludeAzurePowerShellCredential = false // boolean
const excludeAzureDeveloperCliCredential = false // boolean
const excludeInteractiveBrowserCredential = false // boolean
const timeout = undefined // integer
const batchSize = undefined // integer
const notNullOrEmptyString = (value: any) => {
if (typeof value === 'string') {
return value.trim().length !== 0
}
return value !== undefined || value !== null
}
if (notNullOrEmptyString(trustedSigningAccountName)) {
params.CodeSigningAccountName = trustedSigningAccountName
}
if (notNullOrEmptyString(certificateProfileName)) {
params.CertificateProfileName = certificateProfileName
}
if (notNullOrEmptyString(files)) {
params.Files = files
}
if (notNullOrEmptyString(filesFolder)) {
params.FilesFolder = filesFolder
}
if (notNullOrEmptyString(filesFolderFilter)) {
params.FilesFolderFilter = filesFolderFilter
}
if (notNullOrEmptyString(filesFolderRecurse)) {
params.FilesFolderRecurse = filesFolderRecurse // boolean
}
if (notNullOrEmptyString(filesFolderDepth)) {
params.FilesFolderDepth = filesFolderDepth // integer
}
if (notNullOrEmptyString(filesCatalog)) {
params.FilesCatalog = filesCatalog
}
if (notNullOrEmptyString(fileDigest)) {
params.FileDigest = fileDigest
}
if (notNullOrEmptyString(timestampRfc3161)) {
params.TimestampRfc3161 = timestampRfc3161
}
if (notNullOrEmptyString(timestampDigest)) {
params.TimestampDigest = timestampDigest
}
if (notNullOrEmptyString(appendSignature)) {
params.AppendSignature = appendSignature // boolean
}
if (notNullOrEmptyString(description)) {
params.Description = description
}
if (notNullOrEmptyString(descriptionUrl)) {
params.DescriptionUrl = descriptionUrl
}
if (notNullOrEmptyString(generateDigestPath)) {
params.GenerateDigestPath = generateDigestPath
}
if (notNullOrEmptyString(generateDigestXml)) {
params.GenerateDigestXml = generateDigestXml // boolean
}
if (notNullOrEmptyString(ingestDigestPath)) {
params.IngestDigestPath = ingestDigestPath
}
if (notNullOrEmptyString(signDigest)) {
params.SignDigest = signDigest // boolean
}
if (notNullOrEmptyString(generatePageHashes)) {
params.GeneratePageHashes = generatePageHashes // boolean
}
if (notNullOrEmptyString(suppressPageHashes)) {
params.SuppressPageHashes = suppressPageHashes // boolean
}
if (notNullOrEmptyString(generatePkcs7)) {
params.GeneratePkcs7 = generatePkcs7 // boolean
}
if (notNullOrEmptyString(pkcs7Options)) {
params.Pkcs7Options = pkcs7Options
}
if (notNullOrEmptyString(pkcs7Oid)) {
params.Pkcs7Oid = pkcs7Oid
}
if (notNullOrEmptyString(enhancedKeyUsage)) {
params.EnhancedKeyUsage = enhancedKeyUsage
}
if (notNullOrEmptyString(excludeEnvironmentCredential)) {
params.ExcludeEnvironmentCredential = excludeEnvironmentCredential // boolean
}
if (notNullOrEmptyString(excludeWorkloadIdentityCredential)) {
params.ExcludeWorkloadIdentityCredential = excludeWorkloadIdentityCredential // boolean
}
if (notNullOrEmptyString(excludeManagedIdentityCredential)) {
params.ExcludeManagedIdentityCredential = excludeManagedIdentityCredential // boolean
}
if (notNullOrEmptyString(excludeSharedTokenCacheCredential)) {
params.ExcludeSharedTokenCacheCredential = excludeSharedTokenCacheCredential // boolean
}
if (notNullOrEmptyString(excludeVisualStudioCredential)) {
params.ExcludeVisualStudioCredential = excludeVisualStudioCredential // boolean
}
if (notNullOrEmptyString(excludeVisualStudioCodeCredential)) {
params.ExcludeVisualStudioCodeCredential = excludeVisualStudioCodeCredential // boolean
}
if (notNullOrEmptyString(excludeAzureCliCredential)) {
params.ExcludeAzureCliCredential = excludeAzureCliCredential // boolean
}
if (notNullOrEmptyString(excludeAzurePowerShellCredential)) {
params.ExcludeAzurePowerShellCredential = excludeAzurePowerShellCredential // boolean
}
if (notNullOrEmptyString(excludeAzureDeveloperCliCredential)) {
params.ExcludeAzureDeveloperCliCredential = excludeAzureDeveloperCliCredential // boolean
}
if (notNullOrEmptyString(excludeInteractiveBrowserCredential)) {
params.ExcludeInteractiveBrowserCredential = excludeInteractiveBrowserCredential // boolean
}
if (notNullOrEmptyString(timeout)) {
params.Timeout = timeout // integer
}
if (notNullOrEmptyString(batchSize)) {
params.BatchSize = batchSize // integer
}
await new Promise((resolve, reject) => execFile(
`chcp 65001 >NUL & powershell.exe`,
["Invoke-TrustedSigning", params],
{
shell: true,
timeout: 60 * 1000,
},
(error, stdout, stderr) => {
if (error || stderr) {
reject(error?.message || stderr)
}
resolve(stdout)
}
))
},
}
Can confirm that this approach works! Here is what I ended up using:
electron-builder.yml:
...
afterSign: ./scripts/after-sign.js
win:
sign: ./scripts/nop.js
scripts/after-sign.js:
const { spawnSync } = require('node:child_process');
exports.default = async function sign(context) {
spawnSync(
'powershell.exe',
['Install-Module', '-Name', 'TrustedSigning', '-RequiredVersion', '0.4.1', '-Force', '-Repository', 'PSGallery'],
{ shell: true, stdio: 'inherit' },
);
const params = {
Endpoint: 'https://eus.codesigning.azure.net/',
CodeSigningAccountName: '<code signing account name>',
CertificateProfileName: '<certificate profile name>',
FilesFolder: context.appOutDir,
FilesFolderFilter: 'exe,dll',
FileDigest: 'SHA256',
TimestampRfc3161: 'http://timestamp.acs.microsoft.com',
TimestampDigest: 'SHA256',
};
spawnSync('powershell.exe', ['Invoke-TrustedSigning', params], { shell: true, stdio: 'inherit' });
};
scripts/nop.js:
exports.default = async function nop() {};
@MikeJerred Wouldn't your proposed solution result in only the packaged executables being signed, not the installer (e.g. NSIS executable file) that results from the packaging process? It seems that the after-sign.js is not executed after the installer has been compiled.
Another problem I've spotted: When testing your script, I received the following output + Invoke-TrustedSigning [object Object] plus an error about missing mandatory parameters. It seems to me that passing a compiled string might work better (but still have to test it myself):
const paramsString = Object.keys(params).map(key => ` -${key} ${params[key]}`).join('');
spawnSync('powershell.exe', ['Invoke-TrustedSigning', paramsString], { shell: true, stdio: 'inherit' });
I just received confirmation from MS that I have approval for the trusted signing cert. Based on some of the above hacks, I may have to skip Windows signing and use a signtool manually since installers as well as app needs to be signed.
Signing the installer after the electron-builder packing process during and extra build step results in wrong sha512 hashes in the resulting update YAML files.
I've managed to get this signed with my own script during the build...all executables checkout out nicely. Gone are the days of EV certs.
I'm looking into implementing this in electron-builder, but won't have a way to test (as I don't have any Azure account). So if anyone is willing, I'd be happy to supply a patch-package patch for testing out my implementation.
What are the required params for Invoke-TrustedSigning?
Just these?
const params = {
Endpoint: 'https://eus.codesigning.azure.net/',
CodeSigningAccountName: '<code signing account name>',
CertificateProfileName: '<certificate profile name>',
FilesFolder: context.appOutDir,
FilesFolderFilter: 'exe,dll',
FileDigest: 'SHA256',
TimestampRfc3161: 'http://timestamp.acs.microsoft.com',
TimestampDigest: 'SHA256',
};
I also see this example configuration here: https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations
"Endpoint": "<Trusted Signing account endpoint>",
"CodeSigningAccountName": "<Trusted Signing account name>",
"CertificateProfileName": "<Certificate profile name>",
Reason I ask is to see if there are any default values I can apply or using enums (for things like TimestampDigest) where it probably doesn't have to be a basic string property.
I'm looking into implementing this in electron-builder, but won't have a way to test (as I don't have any Azure account). So if anyone is willing, I'd be happy to supply a patch-package patch for testing out my implementation.
What are the required params for
Invoke-TrustedSigning? Just these?const params = { Endpoint: 'https://eus.codesigning.azure.net/', CodeSigningAccountName: '<code signing account name>', CertificateProfileName: '<certificate profile name>', FilesFolder: context.appOutDir, FilesFolderFilter: 'exe,dll', FileDigest: 'SHA256', TimestampRfc3161: 'http://timestamp.acs.microsoft.com', TimestampDigest: 'SHA256', };I also see this example configuration here: https://learn.microsoft.com/en-us/azure/trusted-signing/how-to-signing-integrations
"Endpoint": "<Trusted Signing account endpoint>", "CodeSigningAccountName": "<Trusted Signing account name>", "CertificateProfileName": "<Certificate profile name>",Reason I ask is to see if there are any default values I can apply or using enums (for things like
TimestampDigest) where it probably doesn't have to be a basicstringproperty.
I am happy to help with testing. Those params (plus the azure auth env vars) were enough for the signing to complete without errors when I tried it.
Okay, nvm, the patch is too large. My best recommendation is cloning electron-builder, pulling this PR https://github.com/electron-userland/electron-builder/pull/8458 via gh pr checkout 8458 or checkout branch azure-signing, compile with pnpm compile, and copy the compiled files into your project directly.
Example setup: https://github.com/electron-userland/electron-builder/blob/master/CONTRIBUTING.md#to-setup-a-local-dev-environment
From there, the configuration is within win.azureOptions (other name suggestions are welcome). I took the minimal required fields I could find in the Azure docs, then left it open with [k: string]: string for custom usage scenarios
https://github.com/electron-userland/electron-builder/blob/0d24b78d43ce12f74f5bc073478688c7ad814034/packages/app-builder-lib/src/options/winOptions.ts#L178-L202
Not sure if my local dev setup is correct because I get an error when doing this:
$ npx electron-builder --dir
Error: Cannot find module 'resedit'
Require stack:
- D:\dev\projects\glint\electron\.yalc\app-builder-lib\out\electron\electronWin.js
- D:\dev\projects\glint\electron\.yalc\app-builder-lib\out\electron\ElectronFramework.js
- D:\dev\projects\glint\electron\.yalc\app-builder-lib\out\packager.js
- D:\dev\projects\glint\electron\.yalc\app-builder-lib\out\index.js
- D:\dev\projects\glint\electron\.yalc\electron-builder\out\builder.js
- D:\dev\projects\glint\electron\.yalc\electron-builder\out\cli\cli.js
- D:\dev\projects\glint\electron\.yalc\electron-builder\cli.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1145:15)
at Function.Module._load (node:internal/modules/cjs/loader:986:27)
at Module.require (node:internal/modules/cjs/loader:1233:19)
at require (node:internal/modules/helpers:179:18)
at Object.<anonymous> (D:\dev\projects\glint\electron\.yalc\app-builder-lib\src\electron\electronWin.ts:3:1)
at Module._compile (node:internal/modules/cjs/loader:1358:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
at Module.load (node:internal/modules/cjs/loader:1208:32)
at Function.Module._load (node:internal/modules/cjs/loader:1024:12)
at Module.require (node:internal/modules/cjs/loader:1233:19)
at require (node:internal/modules/helpers:179:18)
at Object.<anonymous> (D:\dev\projects\glint\electron\.yalc\app-builder-lib\src\electron\ElectronFramework.ts:13:1)
at Module._compile (node:internal/modules/cjs/loader:1358:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
at Module.load (node:internal/modules/cjs/loader:1208:32)
at Function.Module._load (node:internal/modules/cjs/loader:1024:12)
You'll either need to start with the base v25.0.5 installed in your package.json (as that includes most recent dependencies to be resolved during install) before using yalc or you can temporarily add "resedit": "^1.7.0", to your devDependencies
https://github.com/electron-userland/electron-builder/blob/c081df8e04494645028c4160bcc1376f029cbca5/packages/app-builder-lib/package.json#L76
You'll either need to start with the base v25.0.5 installed in your package.json (as that includes most recent dependencies to be resolved during
install) before using yalc or you can temporarily add"resedit": "^1.7.0",to yourdevDependencieshttps://github.com/electron-userland/electron-builder/blob/c081df8e04494645028c4160bcc1376f029cbca5/packages/app-builder-lib/package.json#L76
That has fixed that issue, however it still doesn't work:
$ npx electron-builder --dir
• electron-builder version=25.0.6 os=10.0.19045
• loaded configuration file=D:\dev\projects\glint\electron\electron-builder.yml
⨯ Invalid configuration object. electron-builder 25.0.6 has been initialized using a configuration object that does not match the API schema.
- configuration.win has an unknown property 'azureOptions'. These properties are valid:
Looks like yalc isn't copying over the newly updated scheme.json.
https://github.com/electron-userland/electron-builder/blob/52df0604c998f38324640a9d93f884824edd7691/packages/app-builder-lib/scheme.json
You can copy paste it manually in your node modules path or take the hard-copy approach (instead of using yalc) that I typically use instead using rsync. cp also would work, but I just prefer the logging/update-only/include args that rsync provides
rsync -upaRv --include='*.js' --include='*.d.ts' --include='*.nsi' --include='*.json' --include='*/' --include='*.py*' --include='*.tiff' --exclude='*' ~/Development/electron-builder/packages/./* node_modules/
@MikeJerred I'm thinking of releasing the refactored signing code as part of 25.0.7 with logging that azure signing is in beta.
Previous signing configurations will still work, but logging has been added to note deprecated fields and where they've been moved to (probably within signtoolOptions)
Once released, I would like additional volunteers to test it though with DEBUG=electron-builder env var for console logs to make sure everything is kosher and can un-tag it as a beta feature. CC @OrganicChem @jmeinke @iliakolev 🙃
You could also possibly release it on the beta release channel, if the changes are too impactful? But as only warnings will show, this shouldn't be a problem?
Anyway, also switching here to Azure Trusted Signing, as our previous certificate was expired. As soon as everything is in place on Azure (verifying company etc) I also will test this out!
Excellent! Thank you
Previous logic is all in place for using signtool.exe, however, the new config has been moved to within a dedicated property signtoolOptions so a bit of refactoring also took place to keep the implementation clean (and avoid installing azure signing provider+modules on every signing request)
It'll be default released to next tag (as opposed to latest).
Alrighty. Beta signing implementation has been released in ^25.1, please give it a shot with DEBUG=electron-builder and report back!
I'm expecting bug reports, so I also request patience as I get this implementation fully functional. 🙃 Also, not sure if the cmd line debug logs will need any info redacted before posting them here since it's a verbatim log of the powershell Invoke-TrustedSigning command (double check any password/tokens provided aren't present)
From my local testing, I got this working up until the point it does Invoke-TrustedSigning as then the parallels VM prompts for Endpoint (since I didn't pass it in as an argument for test purposes), as I don't have an Azure account to test with. Requires NuGet package provider to be installed and TrustedSigning module, but both also required "-Scope", "CurrentUser" since the cmd prompt that is automatically executed within a parallels VM is not elevated to admin.
Logs below with DEBUG=electron-builder
• signing file=dist/win-unpacked/electron-quick-start-typescript.exe certificateFile=Foo Bar.pfx
• signing with Azure Trusted Signing path=/Users/dev/Development/electron-builder-test-2/dist/win-unpacked/electron-quick-start-typescript.exe
• executing file=prlctl args=list -i -s name
• executing file=prlctl args=exec {6db0fa46-4f04-432a-a546-f8584beac98f} --current-user powershell.exe -NoProfile -NonInteractive -Command Get-Command pwsh.exe
• ensure that 'Share folders' is set to 'All Disks', see https://goo.gl/E6XphP
• unable to find pwsh.exe, falling back to powershell.exe
• executing file=prlctl args=exec {6db0fa46-4f04-432a-a546-f8584beac98f} --current-user powershell.exe Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser
• executed file=prlctl stdout=
Name Version Source Summary
---- ------- ------ -------
nuget 2.8.5.208 https://onege... NuGet provider for the OneGet meta-package manager
• executing file=prlctl args=exec {6db0fa46-4f04-432a-a546-f8584beac98f} --current-user powershell.exe Install-Module -Name TrustedSigning -RequiredVersion 0.4.1 -Force -Repository PSGallery -Scope CurrentUser
• executed file=prlctl
• executing file=prlctl args=exec {6db0fa46-4f04-432a-a546-f8584beac98f} --current-user powershell.exe Invoke-TrustedSigning -Files /Users/dev/Development/electron-builder-test-2/dist/win-unpacked/electron-quick-start-typescript.exe
Implementation details: https://github.com/electron-userland/electron-builder/blob/master/packages/app-builder-lib/src/codeSign/windowsSignAzureManager.ts
Configuration details: https://github.com/electron-userland/electron-builder/blob/b3ce7f788cccf87ba841c9189a3b8758cd7c27c2/packages/app-builder-lib/src/options/winOptions.ts#L88-L91 https://github.com/electron-userland/electron-builder/blob/b3ce7f788cccf87ba841c9189a3b8758cd7c27c2/packages/app-builder-lib/src/options/winOptions.ts#L190-L210
I installed 25.1.0 but doing DEBUG=electron-builder npx electron-builder --dir gives an error:
Error: Cannot find module 'app-builder-lib/out/util/config/load'
Require stack:
- D:\dev\projects\glint\electron\node_modules\electron-builder\out\cli\cli.js
- D:\dev\projects\glint\electron\node_modules\electron-builder\cli.js
at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
at Function.Module._load (node:internal/modules/cjs/loader:985:27)
The app-builder-lib in node_modules is v25.0.5, and it doesn't have a config folder under out/util
Thanks for checking.
Hmmm, it sounds like it desynced the release versioning during the CI/CD. It's been acting finicky lately. Can you try force installing app-builder-lib: 25.1.1 in your package.json?
For some reason a 25.1.0 version wasn't published, but a 25.1.1 was https://www.npmjs.com/package/app-builder-lib?activeTab=versions
I'll look into the dependency resolution issue
I added "app-builder-lib": "25.1.1" to my package.json but I get this error on npm install:
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: [email protected]
npm WARN node_modules/dmg-builder
npm WARN dmg-builder@"^25" from [email protected]
npm WARN node_modules/electron-builder
npm WARN dev electron-builder@"^25.1.0" from the root project
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer dmg-builder@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: peer dmg-builder@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer dmg-builder@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: electron-builder-squirrel-windows@undefined
npm WARN node_modules/electron-builder-squirrel-windows
npm WARN peer electron-builder-squirrel-windows@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer electron-builder-squirrel-windows@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: electron-builder-squirrel-windows@undefined
npm WARN node_modules/electron-builder-squirrel-windows
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer electron-builder-squirrel-windows@"^25.1.025.1.0" from [email protected]
npm WARN node_modules/app-builder-lib
npm WARN dev app-builder-lib@"25.1.1" from the root project
npm WARN 1 more (electron-builder)
npm ERR! code ETARGET
npm ERR! notarget No matching version found for dmg-builder@^25.1.025.1.0.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.
Kk. I've redeployed the monorepo to resync all the workspace versions. Please try 25.1.2
Kk. I've redeployed the monorepo to resync all the workspace versions. Please try
25.1.2
OK this version installs properly. It should also be noted that the docs are stating to use win.azureOptions but actually it should be win.azureSignOptions, regardless I am not seeing any error but the executable is not being signed.
This is my electron-builder.yml:
win:
publisherName: Logic Over Snacks Ltd.
azureSignOptions:
endpoint: https://eus.codesigning.azure.net/
certificateProfileName: ...
codeSigningAccountName: ...
I also have set the 3 env vars AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET.
I run this command: DEBUG=electron-builder npx electron-builder --dir which completes without errors, but the executable created does not have a digital signature.
@MikeJerred Can you please upload/send the logs for the azure signing steps? Should start after the line
• signing with Azure Trusted Signing path=/Users/dev/Development/electron-builder-test-2/dist/win-unpacked/electron-quick-start-typescript.exe
Please make sure to redact any sensitive info from the logs if present. Also am happy to discuss further via discord (@onegoldfish) to streamline debugging/implementing this feature.
This is the log, I redacted some long bits that I don't think are relevant:
$ DEBUG=electron-builder npx electron-builder --dir
• electron-builder version=25.1.2 os=10.0.19045
• loaded configuration file=D:\dev\projects\glint\electron\electron-builder.yml
• effective config config=directories
...
<contents of electron-builder.yml>
...
• writing effective config file=packaged\builder-effective-config.yaml
• skipped dependencies rebuild reason=npmRebuild is set to false
• packaging platform=win32 arch=x64 electron=29.1.4 appOutDir=packaged\win-unpacked
• spawning command=D:\dev\projects\glint\electron\node_modules\app-builder-bin\win\x64\app-builder.exe unpack-electron --configuration [{"platform":"win32","arch":"x64","version":"29.1.4"}] --output D:\dev\projects\glint\electron\packaged\win-unpacked --distMacOsAppName Electron.app
• map async taskCount=2
• map async taskCount=1
• map async taskCount=73
• exited command=app-builder.exe code=0 pid=31416
• asar usage is disabled — this is strongly not recommended solution=enable asar and use asarUnpack to unpack files that must be externally available
• spawning command=D:\dev\projects\glint\electron\node_modules\app-builder-bin\win\x64\app-builder.exe node-dep-tree --dir D:\dev\projects\glint\electron --flatten
• unresolved deps unresolved=lowercase-keys nodeModuleDir=D:\dev\projects\glint\node_modules round=0
• unresolved deps unresolved=lowercase-keysresponselike nodeModuleDir=D:\dev\projects\glint\node_modules round=0
...
<a lot of "unresolved deps">
...
• exited command=app-builder.exe code=0 pid=6080 out=[{...<lots of packages>...}]
• asar usage is disabled — this is strongly not recommended solution=enable asar and use asarUnpack to unpack files that must be externally available
• spawning command=D:\dev\projects\glint\electron\node_modules\app-builder-bin\win\x64\app-builder.exe icon --format ico --root D:\dev\projects\glint\electron\build --root D:\dev\projects\glint\electron --out D:\dev\projects\glint\electron\packaged\.icon-ico
• path resolved path=D:\dev\projects\glint\electron\build\icon.ico outputFormat=ico
• exited command=app-builder.exe code=0 pid=35164 out={"icons":[{"file":"D:\\dev\\projects\\glint\\electron\\build\\icon.ico","size":256}],"isFallback":false}
• spawning command=D:\dev\projects\glint\electron\node_modules\app-builder-bin\win\x64\app-builder.exe rcedit --args ["D:\\dev\\projects\\glint\\electron\\packaged\\win-unpacked\\Glint.exe","--set-version-string","FileDescription","An interface tool for git","--set-version-string","ProductName","Glint","--set-version-string","LegalCopyright","Copyright © 2024 Logic Over Snacks Ltd.","--set-file-version","1.8.9","--set-product-version","1.8.9.0","--set-version-string","InternalName","Glint","--set-version-string","OriginalFilename","","--set-version-string","CompanyName","Logic Over Snacks Ltd.","--set-icon","D:\\dev\\projects\\glint\\electron\\build\\icon.ico"]
• found existing path=C:\Users\mjerr\AppData\Local\electron-builder\Cache\winCodeSign\winCodeSign-2.6.0
• execute command command='C:\Users\mjerr\AppData\Local\electron-builder\Cache\winCodeSign\winCodeSign-2.6.0\rcedit-x64.exe' 'D:\dev\projects\glint\electron\packaged\win-unpacked\Glint.exe' --set-version-string FileDescription 'An interface tool for git' --set-version-string ProductName Glint --set-version-string LegalCopyright 'Copyright © 2024 Logic Over Snacks Ltd.' --set-file-version 1.8.9 --set-product-version 1.8.9.0 --set-version-string InternalName Glint --set-version-string OriginalFilename '' --set-version-string CompanyName 'Logic Over Snacks Ltd.' --set-icon 'D:\dev\projects\glint\electron\build\icon.ico' workingDirectory=
• command executed executable=C:\Users\mjerr\AppData\Local\electron-builder\Cache\winCodeSign\winCodeSign-2.6.0\rcedit-x64.exe
• exited command=app-builder.exe code=0 pid=30740
wine&sign: 0s 390ms
Well that's super odd, it's hitting neither this line https://github.com/electron-userland/electron-builder/blob/5e21509a3f40d1a21f6f9ec9bf1d9d72c7149a21/packages/app-builder-lib/src/codeSign/windowsCodeSign.ts#L13 nor https://github.com/electron-userland/electron-builder/blob/5e21509a3f40d1a21f6f9ec9bf1d9d72c7149a21/packages/app-builder-lib/src/codeSign/windowsCodeSign.ts#L17
The code in my node_modules has those lines, it looks like I have the correct packages installed as far as I can see. Am I setting the debug flag correctly to enable the feature?
Honestly, I'm confused because those are log.info commands, so it should be showing up without even having the DEBUG env var present. I tested the signtool implementation locally and it worked correctly too (in addition to the correct logging). Not sure why nothing is showing up for your logs, but it does have me worried that the signing refactor broke something for end-users.