Skip to content

Commit

Permalink
fix: remove concurrency of windows codesign to resolve azure trusted …
Browse files Browse the repository at this point in the history
…signing file locks(#8632)
  • Loading branch information
mmaietta authored Oct 28, 2024
1 parent 96f5c3e commit 645e2ab
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 34 deletions.
5 changes: 5 additions & 0 deletions .changeset/sour-points-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-builder-lib": patch
---

fix: only sign concurrently when using local signtool. azure can't be in parallel due to resources being locked during usage
24 changes: 21 additions & 3 deletions packages/app-builder-lib/src/codeSign/windowsCodeSign.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { log } from "builder-util"
import { log, retry } from "builder-util"
import { WindowsConfiguration } from "../options/winOptions"
import { VmManager } from "../vm/vm"
import { WinPackager } from "../winPackager"
Expand All @@ -11,7 +11,8 @@ export interface WindowsSignOptions {
export async function signWindows(options: WindowsSignOptions, packager: WinPackager): Promise<boolean> {
if (options.options.azureSignOptions) {
log.info({ path: log.filePath(options.path) }, "signing with Azure Trusted Signing (beta)")
return (await packager.azureSignManager.value).signUsingAzureTrustedSigning(options)
const packageManager = await packager.azureSignManager.value
return signWithRetry(async () => packageManager.signUsingAzureTrustedSigning(options))
}

log.info({ path: log.filePath(options.path) }, "signing with signtool.exe")
Expand All @@ -34,7 +35,24 @@ export async function signWindows(options: WindowsSignOptions, packager: WinPack
if (fields.length) {
log.warn({ fields, reason: "please move to win.signtoolOptions.<field_name>" }, `deprecated field`)
}
return (await packager.signtoolManager.value).signUsingSigntool(options)
const packageManager = await packager.signtoolManager.value
return signWithRetry(async () => packageManager.signUsingSigntool(options))
}

function signWithRetry(signer: () => Promise<boolean>): Promise<boolean> {
return retry(signer, 3, 1000, 1000, 0, (e: any) => {
const message = e.message
if (
// https://github.com/electron-userland/electron-builder/issues/1414
message?.includes("Couldn't resolve host name") ||
// https://github.com/electron-userland/electron-builder/issues/8615
message?.includes("being used by another process.")
) {
log.warn({ error: message }, "attempt to sign failed, another attempt will be made")
return true
}
return false
})
}

export async function getPSCmd(vm: VmManager): Promise<string> {
Expand Down
43 changes: 12 additions & 31 deletions packages/app-builder-lib/src/winPackager.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import BluebirdPromise from "bluebird-lst"
import { Arch, InvalidConfigurationError, log, use, executeAppBuilder, CopyFileTransformer, FileTransformer, walk, retry } from "builder-util"
import { Arch, CopyFileTransformer, executeAppBuilder, FileTransformer, InvalidConfigurationError, use, walk } from "builder-util"
import { createHash } from "crypto"
import { readdir } from "fs/promises"
import * as isCI from "is-ci"
import { Lazy } from "lazy-val"
import * as path from "path"
import { signWindows, WindowsSignOptions } from "./codeSign/windowsCodeSign"
import { WindowsSignAzureManager } from "./codeSign/windowsSignAzureManager"
import { FileCodeSigningInfo, getSignVendorPath, WindowsSignToolManager } from "./codeSign/windowsSignToolManager"
import { AfterPackContext } from "./configuration"
import { DIR_TARGET, Platform, Target } from "./core"
Expand All @@ -23,9 +24,6 @@ import { isBuildCacheEnabled } from "./util/flags"
import { time } from "./util/timer"
import { getWindowsVm, VmManager } from "./vm/vm"
import { execWine } from "./wine"
import { signWindows } from "./codeSign/windowsCodeSign"
import { WindowsSignOptions } from "./codeSign/windowsCodeSign"
import { WindowsSignAzureManager } from "./codeSign/windowsSignAzureManager"

export class WinPackager extends PlatformPackager<WindowsConfiguration> {
_iconPath = new Lazy(() => this.getOrConvertIcon("ico"))
Expand Down Expand Up @@ -128,7 +126,7 @@ export class WinPackager extends PlatformPackager<WindowsConfiguration> {
options: this.platformSpecificBuildOptions,
}

const didSignSuccessfully = await this.doSign(signOptions)
const didSignSuccessfully = await signWindows(signOptions, this)
if (!didSignSuccessfully && this.forceCodeSigning) {
throw new InvalidConfigurationError(
`App is not signed and "forceCodeSigning" is set to true, please ensure that code signing configuration is correct, please see https://electron.build/code-signing`
Expand All @@ -137,25 +135,6 @@ export class WinPackager extends PlatformPackager<WindowsConfiguration> {
return didSignSuccessfully
}

private async doSign(options: WindowsSignOptions) {
return retry(
() => signWindows(options, this),
3,
500,
500,
0,
(e: any) => {
// https://github.com/electron-userland/electron-builder/issues/1414
const message = e.message
if (message != null && message.includes("Couldn't resolve host name")) {
log.warn({ error: message }, `cannot sign`)
return true
}
return false
}
)
}

async signAndEditResources(file: string, arch: Arch, outDir: string, internalName?: string | null, requestedExecutionLevel?: RequestedExecutionLevel | null) {
const appInfo = this.appInfo

Expand Down Expand Up @@ -267,20 +246,20 @@ export class WinPackager extends PlatformPackager<WindowsConfiguration> {
return false
}

await BluebirdPromise.map(readdir(packContext.appOutDir), (file: string): any => {
const files = await readdir(packContext.appOutDir)
for (const file of files) {
if (file === exeFileName) {
return this.signAndEditResources(
await this.signAndEditResources(
path.join(packContext.appOutDir, exeFileName),
packContext.arch,
packContext.outDir,
path.basename(exeFileName, ".exe"),
this.platformSpecificBuildOptions.requestedExecutionLevel
)
} else if (this.shouldSignFile(file)) {
return this.sign(path.join(packContext.appOutDir, file))
await this.sign(path.join(packContext.appOutDir, file))
}
return null
})
}

if (!isAsar) {
return true
Expand All @@ -291,7 +270,9 @@ export class WinPackager extends PlatformPackager<WindowsConfiguration> {
return walk(outDir, (file, stat) => stat.isDirectory() || this.shouldSignFile(file))
}
const filesToSign = await Promise.all([filesPromise(["resources", "app.asar.unpacked"]), filesPromise(["swiftshader"])])
await BluebirdPromise.map(filesToSign.flat(1), file => this.sign(file), { concurrency: 4 })
for (const file of filesToSign.flat(1)) {
await this.sign(file)
}

return true
}
Expand Down

0 comments on commit 645e2ab

Please sign in to comment.