Add opt-in unsigned macOS release path when Apple secrets are absent - #1200
Merged
Conversation
Closes #1199 Co-authored-by: Cursor <cursoragent@cursor.com> Crow-Session: CE798EB8-CEED-482E-92C1-92F2EDCAE07D Co-Authored-By: Claude <noreply@anthropic.com>
dhilgaertner
requested changes
Sep 4, 2026
dhilgaertner
left a comment
Contributor
There was a problem hiding this comment.
Code & Security Review
Critical Issues (if any)
None.
Architecture / Existing Patterns
- Existing pathway:
scripts/macos-sign-notarize.sh+.github/workflows/release.ymlsigning step (ADR 0021). This PR extends that path with--skip-signingrather than inventing a parallel packaging flow — the right shape. - Green: Admin-gated
CROW_ALLOW_UNSIGNED_RELEASErepo/org variable, explicit--skip-signingin CI (notCROW_ALLOW_UNSIGNEDenv), fail-closed default when the variable is unset, and signing unchanged when secrets are present. ADR 0021 anddocs/macos-release-signing.mdare updated consistently. Rejected alternatives (per-tagworkflow_dispatchinput) are documented.
Security Review
Strengths:
- Unsigned publish requires an admin-controlled repository/org variable and absent signing secrets; an arbitrary tag push cannot reach the unsigned path alone.
- Release notes and script output clearly label artifacts as unsigned and Gatekeeper-quarantined; unsigned builds are always marked
prerelease. --skip-signingskips codesign, notarytool, and staple entirely; no ephemeral keychain or cert import on the unsigned path.- SHA256 sidecars are still emitted for unsigned artifacts.
Concerns:
- Green: Accepting
CROW_ALLOW_UNSIGNED=1locally is intentional and documented; CI does not pass that env — only the gated--skip-signingflag.
Code Quality
- Yellow —
.github/workflows/release.yml: The new "Write release notes" heredocs preserve YAML indentation inside the body (confirmed: each line is emitted with ~10 leading spaces). GitHub markdown ATX headings require 0–3 leading spaces, so## Unsigned prereleaseand## Installwill not render as headings — the unsigned warning may appear as indented/code-block text instead of a prominent banner. Dedent heredoc content to column 0 (or use a checked-in template +sed). - Yellow —
.github/workflows/release.yml: The unsigned-branch gate concatenates cert/password aliases (${A:-}${B:-}${C:-}), whilerequire_secrets()inscripts/macos-sign-notarize.shusesfirst_set(first non-empty wins). If multiple alias secrets are populated during migration, the workflow may think secrets are present and attempt signing with a concatenated blob thatrequire_secretswould never use. Reuse the same presence semantics (e.g. a small shared helper orfirst_setcopied into the workflow step). - Green:
macos_sign_notarize_mainnow resets flag state per invocation — good for testability. - Green: Added
Crow.appexistence check before packing avoids silently skipping the app zip. - Green:
usage()awk rewrite is more robust than the fixedsedline range. - Green: Tests pass (
bash scripts/macos-sign-notarize_test.sh— 55 passed);shellcheckclean on changed scripts.
Summary Table
| Color | Meaning | Verdict effect |
|---|---|---|
| Red | Must fix | Request changes |
| Yellow | Should fix | Request changes |
| Green | Consider | Approve allowed |
Recommendation: Request Changes — driven by [0 Red, 2 Yellow, 5 Green] findings.
Move release notes out of YAML-indented heredocs so ATX headings render, and match signing-secret presence to first_set (first non-empty alias). Co-authored-by: Cursor <cursoragent@cursor.com> Crow-Session: CE798EB8-CEED-482E-92C1-92F2EDCAE07D Co-Authored-By: Claude <noreply@anthropic.com>
Collaborator
Author
|
Addressed both yellow findings in the latest push:
|
dhilgaertner
approved these changes
Sep 4, 2026
dhilgaertner
left a comment
Contributor
There was a problem hiding this comment.
Code & Security Review
Critical Issues (if any)
None.
Architecture / Existing Patterns
- Existing pathway:
scripts/macos-sign-notarize.sh+.github/workflows/release.ymlsigning step (ADR 0021). This PR extends that path with--skip-signing/CROW_ALLOW_UNSIGNEDand an admin-gated workflow branch — it does not invent a parallel packaging flow. - Green: Prior Yellow findings are resolved: release notes now come from
scripts/write-release-notes.sh(ATX headings at column 0, covered bywrite-release-notes_test.sh), and the unsigned-path gate in.github/workflows/release.ymlreuses the samefirst_setfirst-non-empty alias semantics asrequire_secrets()inscripts/macos-sign-notarize.sh. - Green:
CROW_ALLOW_UNSIGNED_RELEASEis repo/org-admin gated; CI passes--skip-signingexplicitly rather thanCROW_ALLOW_UNSIGNEDenv; default remains fail-closed; signing is unchanged when secrets are present. ADR 0021,docs/macos-release-signing.md, andCHANGELOG.mdare aligned.
Security Review
Strengths:
- Unsigned publish requires admin-controlled
CROW_ALLOW_UNSIGNED_RELEASE=trueand absent Developer ID cert/password; an arbitrary tag push cannot reach the unsigned path alone. - Unsigned artifacts are always
prerelease, labeled prominently inscripts/write-release-notes.sh, and skip codesign/notarytool/staple entirely (no ephemeral keychain on that path). - SHA256 sidecars are still emitted;
CROW_VERSIONcontinues to be validated against theVERSIONfile before packaging.
Concerns:
- Green: Local
CROW_ALLOW_UNSIGNED=1/--skip-signingis intentional for developer dry-runs and is documented indocs/macos-release-signing.md; it does not weaken the GitHub Release gate.
Code Quality
- Green:
macos_sign_notarize_mainresets per-invocation state; unsigned path adds aCrow.appexistence check before packing;usage()awk rewrite is more robust. - Green: Tests pass locally:
bash scripts/macos-sign-notarize_test.sh(55),bash scripts/write-release-notes_test.sh(17);shellcheckclean on changed scripts;swift buildsucceeds.
Summary Table
| Color | Meaning | Verdict effect |
|---|---|---|
| Red | Must fix | Request changes |
| Yellow | Should fix | Request changes |
| Green | Consider | Approve allowed |
Recommendation: Approve — driven by [0 Red, 0 Yellow, 8 Green] findings.
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.
Closes #1199
Summary
--skip-signing(andCROW_ALLOW_UNSIGNED=1) toscripts/macos-sign-notarize.shso the usual CLI tarball/zip andCrow.appzip are produced without codesign, notarytool, or staple. Default remains fail-closed when secrets are missing.CROW_ALLOW_UNSIGNED_RELEASE=true. When it is set and Apple secrets are absent, the workflow passes--skip-signing, marks the release a prerelease, and the notes say the build is unsigned and Gatekeeper-quarantined. Secrets present → signing is unchanged.Test plan
bash scripts/macos-sign-notarize_test.sh(55 passed, including--skip-signingandCROW_ALLOW_UNSIGNED=1)shellcheck scripts/macos-sign-notarize.sh scripts/macos-sign-notarize_test.shCROW_ALLOW_UNSIGNED_RELEASE=trueand no Apple secrets, a tag (e.g.v0.2.0-rc.N) completes green and publishes a prerelease with the unsigned universalcrow+crowdtarball andCrow.app, labeled unsignedMade with Cursor