Skip to content

feat(release): unify signed delivery channels#32

Merged
tcballard merged 1 commit into
mainfrom
codex/unified-release-train
Jul 22, 2026
Merged

feat(release): unify signed delivery channels#32
tcballard merged 1 commit into
mainfrom
codex/unified-release-train

Conversation

@tcballard

Copy link
Copy Markdown
Owner

Summary

Implements Issue #24 while aligning the Issue #29 App Store route behind one release identity.

Adds:

  • one shared marketing version and build number for both signed macOS channels;
  • fail-closed tag, generated-project, app, extension, and exported-package checks;
  • a local release-candidate command that records both artifacts, checksums, and source commit;
  • documentation for one release train with channel-specific security boundaries.

Scope

Included

  • Developer ID and Mac App Store artifacts share Configuration/Release.xcconfig.
  • The tag workflow rejects releases whose tag differs from the bundle version.
  • The Developer ID route verifies version/build before and after archive extraction.
  • The App Store route archives, exports, and inspects the Apple Distribution summary for the app and Finder Action.
  • App Store structural preflight now verifies the shared version/build.

Excluded

  • Publishing a GitHub release or updating Homebrew from this PR.
  • Uploading or submitting a new App Store build.
  • Removing the App Store sandbox or local-only provider policy.
  • Claiming the existing ad-hoc v0.1.0 download has been replaced.

Product / Architecture Decisions

  • Chose one release train with two delivery channels: source commit, version, build, and candidate evidence are shared.
  • Kept channel-specific artifacts because Apple Distribution and Developer ID have different signing and sandbox contracts.
  • Kept the Store binary local-only; alignment does not broaden its provider surface.
  • Made release candidates require a clean committed worktree so the manifest commit identifies the actual source.
  • Kept publication and App Store submission owner-controlled and separate from candidate creation.

User-Facing Contract

CLI

./script/release_identity.sh
./script/release_candidate.sh
./script/release_local.sh
./script/archive_app_store.sh

release_candidate.sh [VERSION] [BUILD] rejects values that differ from the shared contract, runs tests, builds both signed channels, and writes a manifest.

Human Output

  • Reports the verified version/build, artifact paths, SHA-256 checksums, and publication boundary.
  • Explains incomplete credential sets and dirty-worktree failures directly.

JSON Output

  • No JSON contract changes.

Exit Codes

  • 0: requested identity check, build, export, or candidate gate succeeded.
  • non-zero: identity drift, dirty source, signing/export failure, test failure, or artifact verification failure.

Verification

Ran

swift test
./script/release_identity.sh --verify 0.1.0 2
./script/preflight_app_store.sh
BUILD_CONFIGURATION=Release SORTING_HAT_SIGN_IDENTITY="Developer ID Application: Thomas Ballard (R8HXTBY3NM)" ./script/build_and_run.sh package
SORTING_HAT_APP_STORE_OUTPUT=/private/tmp/SortingHat-Unified-Release-Final/AppStore ./script/archive_app_store.sh
./script/generate_xcode_project.sh
git diff --check

Covered

  • 74 Swift tests passed.
  • Mismatched 0.2.0 (2) identity failed closed against contract 0.1.0 (2).
  • Dirty-worktree candidate creation failed closed before signing or notarization.
  • App Store structural preflight passed for 0.1.0 (2).
  • The direct app and nested extension passed Developer ID signature verification at 0.1.0 (2).
  • Xcode exported a local Apple Distribution package; its distribution summary verified both binaries at 0.1.0 (2).
  • No artifact was notarized, uploaded, submitted, or published in this implementation pass.

Review Path

Review Configuration/Release.xcconfig and project.yml, then the identity and candidate scripts, the two channel scripts, the tag workflow assertions, and finally the README/distribution wording.

Notes For Reviewer

  • The existing App Store Connect build remains selected and untouched.
  • The existing GitHub v0.1.0 artifact remains the older ad-hoc build until a later owner-authorized release is published.
  • A full release_candidate.sh run intentionally performs Developer ID notarization, so it was not invoked merely to test orchestration in this PR.

Defines one version and build contract for Developer ID and Mac App Store artifacts, rejects tag and bundle drift, and adds a local release-candidate manifest spanning both channels.

Keeps the App Store sandbox and local-only provider boundary intact while verifying Apple Distribution export separately from Developer ID notarization.
@tcballard
tcballard merged commit 766cc87 into main Jul 22, 2026
1 check passed
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.

1 participant