CD: migrate nupkg signing from PFX to GCP KMS via Jsign (LOC-6563)#59
Merged
Conversation
PR #57 + #58 shipped the binding's net6.0 + arm64/proxy/UA changes, but the next CD dispatch failed at the signing step: the PFX certificate stored in BASE64_PFX_CONTENT expired on 2026-03-29 (error NU3018 NotTimeValid). Migrating to the same KMS-backed signing pattern the C# SDK adopted in PR #704 (browserstack/browserstack-csharp-sdk, merged 2026-03-31). Same KMS key, same Sectigo cert, same tool chain — only the artifact path differs. Why Jsign rather than `nuget sign -CertificateFingerprint`: - Microsoft hard-blocks CNG keys for `dotnet nuget sign` (NU3001 Scenario 6: https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3001). - `signtool.exe` (which does support KMS via CSP) cannot sign .nupkg. - Jsign 7.0 is the only tool that supports both nupkg and Google Cloud KMS natively. Changes - New `comodo_signing_cert.crt` at repo root — public Sectigo cert (same bytes as browserstack-binary/scripts/ and csharp-sdk repo). - New `scripts/sign_nupkg.sh` — exchanges SA creds for an OAuth access token via google-auth, downloads + SHA-256-verifies Jsign, signs each nupkg with `--storetype GOOGLECLOUD` and TSA http://timestamp.sectigo.com. - `.github/workflows/cd.yml`: - Removed: `Setup nuget` (nuget/setup-nuget@v1), `Create PFX certificate`, `Sign Nuget Package` (the PFX/nuget-sign one). - Added: `Setup GCP credentials` (printf, not echo — `echo` on Windows Git Bash corrupts multiline JSON), `Install google-auth`, `Setup Java 17` (Temurin), `Sign Nuget Package` (the jsign one), `Cleanup credentials` with `if: always()`. - `Push package to Nuget Repository`: `nuget push` -> `dotnet nuget push` (since the nuget.exe action was removed; dotnet nuget push ships with the SDK already on the runner). GitHub Secrets required before this branch ships: - ADD: `GCP_SA_KEY` (raw JSON from Vault /master/bigquery/service_account/local/windows_codesign/cert_file_json) - REMOVE after one green run (separate cleanup PR): `BASE64_PFX_CONTENT`, `CERT_PASSWORD`. Tracks LOC-6563. References browserstack-csharp-sdk#704. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CD has been broken since the PFX certificate stored in
BASE64_PFX_CONTENTexpired on 2026-03-29. The next dispatch after merging #57 + #58 failed withNU3018: NotTimeValidat the signing step.This PR migrates nupkg signing to the same KMS-backed pattern the C# SDK adopted in browserstack/browserstack-csharp-sdk#704 (merged 2026-03-31). Same KMS key, same Sectigo cert, same tool — Jsign 7.0 on the
windows-latestrunner talking to GCP Cloud KMS REST directly via OAuth.Why Jsign and not
nuget sign -CertificateFingerprintdotnet nuget sign(NU3001 Scenario 6)signtool.exe(which supports KMS via/csp) cannot sign.nupkg(wrong format)dotnet/signis Azure-Key-Vault-onlyWhy no PoC
The reference PR #704 has been signing real production nupkgs to NuGet.org with this exact recipe since 2026-03-31. We're using the same KMS key, same cert, same tool, same runner, same Java distribution. The signing operation is artifact-agnostic; only the artifact path differs.
Changes
New files
comodo_signing_cert.crt(repo root) — public Sectigo cert, expires 2027-04-30. Identical bytes to the one inbrowserstack-binary/scripts/andbrowserstack-csharp-sdk.scripts/sign_nupkg.sh— google-auth token exchange + Jsign download + SHA-256 verify + sign loop..github/workflows/cd.ymlSetup nuget(thenuget/setup-nuget@v1action),Create PFX certificate,Sign Nuget Package(the PFX one).Setup GCP credentials(usingprintf '%s'—echoon Windows Git Bash corrupts multiline JSON),Install google-auth,Setup Java 17(Temurin),Sign Nuget Package(the jsign one),Cleanup credentialsstep withif: always().Push package to Nuget Repositorynow usesdotnet nuget push(thenuget.exeaction was removed;dotnet nuget pushships with the SDK).working-directory: ${{ github.workspace }}because they need to see paths from the repo root (scripts/,comodo_signing_cert.crt).GitHub Secrets
MUST ADD before merging this PR
GCP_SA_KEY/master/bigquery/service_account/local/windows_codesign/cert_file_json. Same SA the C# SDK PR #704 uses.REMOVE in a follow-up cleanup PR (after one green CD run)
BASE64_PFX_CONTENTCERT_PASSWORDDon't delete in the same PR — keep one tag cycle in case of fast rollback.
Test plan
GCP_SA_KEYsecret is added, dispatchcd.ymlfrom this branch viagh workflow run cd.yml --ref LOC-6563-cd-kms-signingor the Actions UISigning BrowserStackLocal/BrowserStackLocal/bin/Release/BrowserStackLocal.3.1.0.nupkgfollowed by no errorBrowserStackLocal.3.1.0.nupkglands on NuGet.orgdotnet nuget verify --allon the published nupkg from a fresh machine reports success with author signature anchored to the Sectigo certCleanup credentialsran (visible even on failure paths becauseif: always())Failure modes to watch for
storepassrejected by KMS: SA key doesn't havecloudkms.cryptoKeyVersions.useToSignIAM. The SA is already authorized for binary + csharp-sdk so this shouldn't happen, but if it does, check IAM bindings onprojects/browserstack-production/locations/us-east1/keyRings/prod-comodo-win-cert-keyring.python3 -m pip install google-authfails onwindows-latest: pin to a known version.JSIGN_SHA256inscripts/sign_nupkg.shto the current hash from https://github.com/ebourg/jsign/releases.Reference
🤖 Generated with Claude Code