ci(desktop): add signed macOS canary build#2419
Conversation
Build, sign, and notarize a main-only Apple Silicon DMG without granting release publishing permissions or touching updater assets. Co-authored-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
| exit 1 | ||
| fi | ||
|
|
||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d29bb97ecb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| echo "name=$NAME" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Upload signed canary | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 |
There was a problem hiding this comment.
Keep signed canaries out of public artifacts
Because block/buzz is the OSS/public source repo, uploading the signed DMG with actions/upload-artifact does not make it private: GitHub's artifact docs say workflow artifacts can be downloaded by signed-in users with repository read access, which in a public repo is effectively any GitHub user. That exposes production-signed -test builds for the full retention window instead of limiting them to explicit testers, so this should use a genuinely access-controlled store or environment rather than a workflow artifact.
Useful? React with 👍 / 👎.
wesbillman
left a comment
There was a problem hiding this comment.
Reviewed the workflow against release.yml and the release-safety contracts; ran both contract scripts locally at the PR head (d29bb97ec) — release ref contract passed / signed canary contract passed — and confirmed the branch contains current main.
What holds up well:
- Publishing surface is genuinely zero:
contents: readat both workflow and job level, nogh release, noTAURI_SIGNING_PRIVATE_KEY,createUpdaterArtifacts: false, and the new contract test inscripts/test-signed-canary-contract.shis wired into CI viatest-release-ref-contract.sh, so regressions failci.yml. - The
-test.<run>prerelease version derivation sorts below the next real patch release under semver, so even a stray DMG can't masquerade as newer than a real release — and there's no updater artifact to feed the updater anyway. - Build steps faithfully mirror
release.yml(mesh-llm rev viatomllib, llama cache keying, DMG text-size, entitlements staged to${RUNNER_TEMP}/entitlements.plistfor the codesign helper), plus it addsverify-macos-entitlements.shto the post-sign checks. - Actions pinned by SHA,
persist-credentials: false, zizmor green. - The RELEASING.md claim that the Release workflow "cannot build from
main" is accurate —verify-release-ref.shgates both the setup and build jobs onrefs/tags/v<version>.
Two things worth a look:
-
"Private ... Actions artifact" oversells it.
block/buzzis a public repo; workflow-run artifacts on public repos are downloadable by any logged-in GitHub user (UI and API) for the retention window. So this ships a Gatekeeper-valid, production-identity-signed DMG that anyone can grab for 7 days. Probably acceptable — release DMGs are public anyway — but the PR body and RELEASING.md ("private Actions artifact") should say "short-lived" or "unpublished" rather than "private", so nobody relies on a confidentiality property that doesn't exist. -
The manual-only guard in the contract test has trigger gaps.
grep -qE '^ (push|pull_request|schedule):'won't catchpull_request_target:,workflow_call:,workflow_run:, orrepository_dispatch:. Suggest widening the alternation (or inverting: assert theon:block contains onlyworkflow_dispatch). Cheap change, closes the loophole the test exists to guard.
Nit: minimumSystemVersion: 10.15 on an arm64-only build is a no-op (Apple Silicon floor is 11.0) — harmless, mirrors the release config.
Verdict: LGTM once the "private" wording is fixed; item 2 is a nice-to-have hardening.
Document the public visibility of short-lived Actions artifacts and require workflow_dispatch to remain the canary workflow’s only trigger. Co-authored-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
…ad-lifecycle * origin/main: fix(desktop): strip GIF metadata extensions before upload (#2425) feat(desktop): gate sign-out behind key backup + typed confirmation (#2424) ci(desktop): add signed macOS canary build (#2419) feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122) Show team count separately in channel template rows (#2404) fix(dev): restore shared worktree identity from keyring (#2400) fix(onboarding): skip community profile setup for existing relay members (#2300) fix(mobile): preserve and display sidebar section icons (#2403) Unify sidebar chrome across themes (#2380) feat(media): add S3-truth per-community storage sweep (#2044)
…obile-releasing Co-authored-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co> * origin/main: fix(desktop): strip GIF metadata extensions before upload (#2425) feat(desktop): gate sign-out behind key backup + typed confirmation (#2424) ci(desktop): add signed macOS canary build (#2419) feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122) Show team count separately in channel template rows (#2404) fix(dev): restore shared worktree identity from keyring (#2400) fix(onboarding): skip community profile setup for existing relay members (#2300) fix(mobile): preserve and display sidebar section icons (#2403) Unify sidebar chrome across themes (#2380) feat(media): add S3-truth per-community storage sweep (#2044) feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests (#2206) Co-authored-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co> Signed-off-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co> # Conflicts: # RELEASING.md
…ad-lifecycle * origin/main: fix(desktop): strip GIF metadata extensions before upload (#2425) feat(desktop): gate sign-out behind key backup + typed confirmation (#2424) ci(desktop): add signed macOS canary build (#2419) feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122) Show team count separately in channel template rows (#2404) fix(dev): restore shared worktree identity from keyring (#2400) fix(onboarding): skip community profile setup for existing relay members (#2300) fix(mobile): preserve and display sidebar section icons (#2403) Unify sidebar chrome across themes (#2380) feat(media): add S3-truth per-community storage sweep (#2044) Signed-off-by: npub1dpf98sl35hm9k65t8h6cvh5n6knn2msugh5k5nmysxwnw5wlh7uqn2wgp4 <685253c3f1a5f65b6a8b3df5865e93d5a7356e1c45e96a4f64819d3751dfbfb8@sprout-oss.stage.blox.sqprod.co>
Why
Testers need a Gatekeeper-valid build of current
mainwithout creating a release or updating existing installations.What
workflow_dispatchto remain the only triggerRisk Assessment
Low — the workflow is manual-only and cannot create tags, GitHub Releases, or auto-updater assets. It does use the production Apple signing identity for explicitly requested canary builds; any signed-in GitHub user can download the artifact during its seven-day lifetime.
References
scripts/test-signed-canary-contract.shscripts/test-release-ref-contract.shUpdate Jul 22, 14:32: Addressed review feedback
workflow_dispatchassertionGenerated with Codex