-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Windows builds using a new ssl.com code signing certificate #3050
Conversation
.github/actions/build-zui/action.yml
Outdated
- name: Make values from package.json available in Actions steps | ||
id: zui-package | ||
uses: RadovanPelka/github-action-json@v1.0.1 | ||
with: | ||
path: apps/zui/package.json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this because one of the env variables to be passed to the esigner tool is the expected filename of what would be signed, and that filename includes both the app name (Zui
or Zui Insiders
) and the version string, both of which are in package.json
.
.github/actions/build-zui/action.yml
Outdated
APPLE_ID: ${{ inputs.apple_id }} | ||
APPLE_ID_PASSWORD: ${{ inputs.apple_id_password }} | ||
APPLE_TEAM_ID: ${{ inputs.apple_team_id }} | ||
CODE_SIGN_SCRIPT_PATH: ${{ github.workspace }}/esigner-codesign/dist/index.js | ||
INPUT_COMMAND: sign | ||
INPUT_FILE_PATH: ${{ github.workspace }}/dist/apps/zui/${{ fromJSON(steps.zui-package.outputs.productName) }} Setup ${{ fromJSON(steps.zui-package.outputs.version) }}.exe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fromJSON()
wrappers are needed because the Action I added above to pull values from the package.json
delivers strings with quotes around them, and when these remained intact the esigner tool interpreted them as parts of the filename and choked.
.github/actions/build-zui/action.yml
Outdated
- name: Check for successful signing with SignTool | ||
if: runner.os == 'Windows' | ||
run: | | ||
"C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe" verify /pa "${{ github.workspace }}/dist/apps/zui/${{ fromJSON(steps.zui-package.outputs.productName) }} Setup ${{ fromJSON(steps.zui-package.outputs.version) }}.exe" | ||
shell: cmd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While getting the esigner tool working with electron-builder, one buggy-seeming thing I encountered is that even if the custom signing code returns false
due to an error, the electron-builder apparently still behaved as if it succeeded. Here's an example run where you can see what happens: At first it looks green/successful, but if you expand the "Build Zui" step and scroll to the bottom you can see the red failure message. Bad, right?
This would have made it likely that we could one day be producing unsigned builds and not be aware. I found via web searches that this signtool verify /pa
approach adequately sniffs out if an executable is, indeed, signed. I tested it out and it does what we need (example run catching an unsigned build).
apps/zui/electron-builder-config.js
Outdated
// Actions taken from: | ||
// https://github.com/electron-userland/electron-builder/issues/6158#issuecomment-1994110062 | ||
if (process.env.CODE_SIGN_SCRIPT_PATH) { | ||
const version = zuiPackage.version; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code I borrowed from the GitHub issue was doing this via:
const version = execSync('node -p "require(\'./package.json\').version"').toString().trim();
I don't know why he didn't opt to just require
the package.json
and access the value directly like I'm doing there. My approach feels cleaner, so I'm going with it. But I figured I'd point it out in case I'm missing something subtle.
I learned here that we can keep electron-builder.json and provide a path to a file responsible for signing. I might need a zoom to talk more about how this all works. |
Thanks for the improvements, @jameskerr. I had to push a couple more small commits to make things run successfully in Actions but I ultimately did successfully make both a Zui Dev build and a Zui Insiders Dev Build both based on c048ce8 from this branch. I manually checked the validity of the certificates by looking at the Properties of the |
tl;dr
Our current Windows code signing certificate expires in about a week, so this gets our build up and running with a new certificate.
Details
When @nwt and I discussed getting a new certificate, we quickly learned of changes in the past year that would affect our decision. In brief, ballot CSC-17 from the CA/B Forum established new industry standards regarding the storage of private keys. This has made it such that the easiest way for us to continue signing our builds in an automated fashion would involve using a cloud-based signing service. In shopping around for the best prices, the cheapest option we found was from ssl.com that offers a 1-year OV certificate for $129 and their eSigner cloud service costs $20/mo for 20 signings with additional signings costing $1/each. Since we release a Zui Insiders build most days we could easily burn through more than 20 signings per month, but the cost doesn't seem prohibitive and if we wanted to pinch pennies we could tweak the Insiders build schedule (e.g., make it something we manually trigger when we know something worthy has been committed that justifies a new build, since often all we'll have had on a given day are advances in the Zed pointer that may not affect functionality at all.)
Having gotten it working, I've been reminded that starting over with a new certificate unfortunately lands us back in Windows Defender "unrecognized app" status. I remember this well from several years back when we first started signing the app. As always, Microsoft is intentionally opaque and doesn't disclose the details of what it takes to build up the necessary "reputation", but articles like this one and the cynical peanut gallery on HackerNews all make it pretty clear that we just need to be prepared to eat it for a couple months. We've been through this before, and other than a couple users raising mild concerns, we've survived.
Here's evidence of the Defender screens and the cert info checking out as expected for both a Zui dev build and a Zui Insiders dev build both based on this branch.
In terms of implementing the change, there's not a seamless integration yet with electron-builder, but @nwt and I found this comment that seemed promising and indeed my successful approach uses it pretty much verbatim. In addition to just being more code, it unfortunately also meant morphing our electron-builder config from a simple JSON file to a
.js
file since it requires custom signer code. That said, I was still able to maintain our approach that delivers builds for the 2x2 of (Zui, Zui Insiders) x (Dev Build, Release Build) with minimal code duplication.I'll put some other comments inline to explain some other details of the implementation.
If this passes muster, here's a to-do list of follow-on tasks I intend to do right after this merges:
CONTRIBUTING.md
.