Skip to content

fix(release): fail the build when Apple rejects a notarization - #385

Merged
markcallen merged 2 commits into
mainfrom
assert-notarization-accepted
Oct 1, 2026
Merged

markcallen merged 2 commits into
mainfrom
assert-notarization-accepted

Conversation

@markcallen

Copy link
Copy Markdown
Contributor

Follow-up to #384.

Problem

xcrun notarytool submit --wait exits 0 as long as the submission completed — including when Apple comes back Invalid. The hook added in #384 checked only the exit code, so a rejected binary would have been archived and uploaded as though it had passed. Moving notarization ahead of the first upload only helps if notarization can actually fail the build.

Change

scripts/sign-and-notarize-darwin.sh — submit with --output-format json, read status and id with plutil (always present on macOS, so no new dependency), and require Accepted. On failure, print the raw response and fetch notarytool log for the submission so the rejection reason lands in the workflow output.

scripts/smoke-sign-notarize-hook.sh (new) — covers the hook's failure paths with codesign, ditto, and xcrun stubbed on PATH, so it runs with no signing identity, no credentials, and no network:

Case Expected
Accepted exit 0
Invalid, notarytool exits 0 exit 1 ← the regression
Rejected, notarytool exits 1 exit 1
missing APPLE_API_KEY_ISSUER_ID exit 1
missing App Store Connect key file exit 1
non-darwin build exit 0, no-op

.github/workflows/examples-smoke.yml — runs it as a macos-latest job.

Validation

  • Ran the smoke test against the previous exit-code-only logic: it fails on exactly the Invalid case (expected exit 1, got 0). Restored the fix: all six cases pass.
  • shellcheck clean on both scripts; yamllint clean on the workflow.
  • pnpm test — 385 passed.

Note

I drafted a matching line for the shared publishing rule and backed it out: it pushed the emitted publishing.md to 5118 bytes against the 5120-byte budget, and a 2-byte margin isn't worth it for a tool-specific caveat. The rule already carries the ordering requirement; the status-assertion detail lives in the script comment and is now pinned by the smoke test. Worth knowing that rule is at 5076/5120 — the next edit to it will likely need a trim elsewhere.

🤖 Generated with Claude Code

`xcrun notarytool submit --wait` exits 0 as long as the submission itself
completed, including when Apple returns `Invalid`. The sign-and-notarize
hook trusted that exit code, so a rejected binary would have been archived
and uploaded as if it had passed — the gate could not actually fail.

Read the submission JSON with plutil (always present on macOS, so no new
dependency) and require status `Accepted`. On failure, print the raw
response and fetch the notary log so the rejection reason lands in the
workflow output instead of requiring a separate round trip.

Add scripts/smoke-sign-notarize-hook.sh covering the Accepted, Invalid,
Rejected, missing-credential, missing-key-file, and non-darwin paths with
codesign/ditto/xcrun stubbed on PATH, so it needs no signing identity,
credentials, or network. Verified it fails against the previous
exit-code-only logic and passes against the fix. Wired it into
examples-smoke.yml as a macOS job.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@markcallen
markcallen requested a balanced review from Copilot October 1, 2026 18:28
@codecov

codecov Bot commented Oct 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The release guard is correct and tested; the remaining environment-isolation issue is non-blocking.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Ensures Apple notarization rejection aborts releases before artifacts are uploaded.

Changes:

  • Validates notarization JSON status and reports rejection logs.
  • Adds macOS smoke coverage for success and failure paths.
  • Runs the smoke test in CI.
File Description
scripts/​sign-and-notarize-darwin.sh Enforces Accepted notarization status.
scripts/​smoke-sign-notarize-hook.sh Adds stubbed hook smoke tests.
.github/​workflows/​examples-smoke.yml Adds the macOS smoke job.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread scripts/smoke-sign-notarize-hook.sh
…s env

`env` without `-u` keeps inherited variables, so a developer or runner with
APPLE_API_KEY_ISSUER_ID already exported would have sent that case down the
normal notarization path and failed the smoke test for the wrong reason.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@markcallen
markcallen merged commit d0e3256 into main Oct 1, 2026
48 checks passed
@markcallen
markcallen deleted the assert-notarization-accepted branch October 1, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants