[staging/5.1.0] Derive the signing public key and harden the update-publish preflight - #2394
Merged
NipunaRanasinghe merged 5 commits intoSep 8, 2026
Conversation
COSIGN_PUBLIC_KEY and WSO2_UPDATE_PUBLIC_KEY held the same public key in two encodings -- raw PEM for cosign's verify steps, base64 of that PEM for the string baked into product.json. Two hand-set secrets for one value, and the consistency check compared them to each other. That check could not see the mismatch that matters. Both public secrets can agree perfectly and still belong to a different keypair than COSIGN_PRIVATE_KEY, which is what actually signs; the in-run verify steps would pass too, because they verified against the same public secret. The failure would surface on users' machines after release, as every client rejecting every artifact. The public half is now derived from the signing key with cosign public-key --key env://COSIGN_PRIVATE_KEY so the comparison is pinned-key vs the key that signs, and the verify steps check signatures against a key that provably belongs to the signing pair. Verified with two throwaway keypairs: correct config passes, a pinned key from the other pair is refused (the case the old check missed), and a non-base64 pinned value is refused. COSIGN_PUBLIC_KEY is no longer referenced anywhere and can be deleted from the repository secrets -- one fewer value to set and to keep in sync. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit e3e67f5)
WSO2_UPDATE_PUBLIC_KEY was optional, and its absence was silent in the worst direction: HAS_PINNED_KEY went false, the key comparison was skipped, and WSO2_UPDATE_REQUIRE_ARTIFACT_SIGNATURE computed to false — so a green release shipped clients that pin no key and accept unverified artifacts, then published a source document for them. Check it in resolve-versions rather than in Publish Update Source. build-macos and build-windows bake WSO2_UPDATE_URL and WSO2_UPDATE_PUBLIC_KEY into product.json well before that job runs, so a late check cannot stop a run from producing those installers — it can only decline to publish afterwards. The early gate costs seconds instead of a full build, and covers the bucket, the artifacts CDN base, the update URL and the signing key alongside it. With presence guaranteed, the pinned-key DER comparison is unconditional in both workflows, and publish-components.yml requires the same secret in its own preflight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 68e50fb)
The gate fired on publish_update_source alone, so a release with build_packed_installers off — or with no publish_tag — failed for missing publish secrets even though Publish Update Source skips itself in exactly those cases. Mirror that job's own conditions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 6c93a4c)
…ilds run Checking only that WSO2_UPDATE_PUBLIC_KEY is non-empty left the failure this change is about — a pinned key from the wrong pair — to the late check in Publish Update Source, which runs after build-macos and build-windows have already baked that key into product.json. Nothing downstream would catch it either: the signing steps verify against the signing key itself, so they pass. Derive and compare in resolve-versions instead. cosign-installer plus one `cosign public-key` costs seconds, and it also exercises COSIGN_PASSWORD, which otherwise burns a full build before failing at the derive step. The late comparison is now redundant and removed; Publish Update Source still derives signing.pub for signature verification. Also guard the decode with `[ -s pinned.pem ]` in both workflows — `base64 -d` accepts the empty string, so an empty secret used to skip the friendly error and die at openssl — and drop a comment left describing a `cosign.pub` write that no longer exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit f4fc335)
A release with AWS_UPDATE_S3_BUCKET set but no credentials — or the reverse — would run the full macOS and Windows builds before anything noticed. The preflight already covers the bucket; the keys that write to it belong beside it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> (cherry picked from commit 17bc1dd)
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
gigara
approved these changes
Sep 8, 2026
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.
Backport of #2327 to
staging/5.1.0. Five commits, cherry-picked frome3e67f5,68e50fb,6c93a4c,f4fc335and17bc1ddwith no conflicts, in their original order.Why
#2384 and #2385 backported the component-update mechanism (#2247, #2248) to this branch, but the CI
fixes that landed on
mainafterwards were not part of either PR.build.ymlon this branch istherefore #2248's original, and a
workflow_dispatchstarted onstaging/5.1.0runs it.That is already failing. In
run 34251747457
the macOS job fails at
Publish Squirrel.Mac update payload to update bucket:The step's gate on this branch is
env.HAS_AWS == 'true', which is onlysecrets.AWS_ACCESS_KEY_ID != ''— the secret exists, so the gate opens — but the key is never putin the step's environment. It also omits
publish_update_sourcefrom its condition, so it runs on anightly that publishes nothing. The direct fix for that specific step is in #2328, which is stacked
on this PR; this one carries the preflight work it builds on.
The macOS job did not fail before #2385 only because
installers/mac/build.shon this branchignored
INSTALLER_PROFILE, so no-mac.zipwas produced and the upload path was inert.What this contains
e3e67f5— derive the signing public key from the signing key instead of configuring it twice.68e50fb— require the pinned client key on any run that publishes updates.6c93a4c— don't fail the preflight on runs that would not publish.f4fc335— compare the pinned key against the signing key before the builds run, so a mismatchfails in seconds rather than surfacing as every client rejecting every artifact after release.
17bc1dd— require the update-bucket credentials in the publish preflight.Net effect on
build.yml: three new steps inresolve-versions(Check the publish path is configured,cosign-installer,Verify the pinned client key matches the signing key), all gatedon
publish_update_source && build_packed_installers && publish_tag != '', and theHAS_PINNED_KEYscaffolding they replace is removed.Scope
Only
.github/workflows/build.ymland.github/workflows/publish-components.yml. No installerscripts, no product code.
The scheduled nightly is not affected either way — a
scheduletrigger readsbuild.ymlfromthe default branch. This matters for
workflow_dispatchruns started onstaging/5.1.0, and forthis branch being able to cut a release.
Verification
build.ymlandpublish-components.ymlon this branch arebyte-identical to
main, and noHAS_AWSorHAS_INSTALLER_BUCKETscaffolding remains.Not verified: no CI run has exercised this branch. The check worth running before merge is a
daily-build.ymldispatch on this branch withbuild_branch=builds/nightly-testandpublish_tag=nightly-test, which reproduces the failing route without touching production.Part 1 of 2
#2328's backport is stacked on this branch and must merge after it.