Skip to content

fix(release): harden packaging and add CI [release:v0.1.0]#3

Merged
tcballard merged 3 commits into
mainfrom
codex/release-hardening-ci
Jul 13, 2026
Merged

fix(release): harden packaging and add CI [release:v0.1.0]#3
tcballard merged 3 commits into
mainfrom
codex/release-hardening-ci

Conversation

@tcballard

Copy link
Copy Markdown
Owner

Summary

Implements v0.1.0 release hardening and CI follow-up.

Adds:

  • Off-repository app packaging to avoid cloud File Provider metadata
  • Post-stapling and final-ZIP signature, Gatekeeper, and ticket verification
  • Configurable final release output paths
  • GitHub Actions coverage for Swift tests and unsigned packaging

Scope

Included

  • Temporary local app-bundle assembly for signed and unsigned releases
  • Cleanup of temporary packaging and verification directories
  • Strict signature checks after stapling and after extracting the final ZIP
  • Gatekeeper and stapler validation of the final signed archive
  • Homebrew-ready cask stanza ordering and configurable cask output
  • macOS CI for tests, shell syntax, packaging, and artifact presence
  • README documentation for the hardened workflow and RELEASE_OUTPUT_DIR

Excluded

  • A new signed or notarized application release
  • Automatic GitHub release or Homebrew tap publication
  • Product behavior changes
  • Changes to the existing v0.1.0 archive

Product / Architecture Decisions

  • App bundles are assembled under TMPDIR; only final ZIP and cask artifacts are written to RELEASE_OUTPUT_DIR.
  • package-app.sh remains reusable through APP_OUTPUT_DIR, with its existing dist default preserved for development workflows.
  • Signed releases fail unless both the in-place stapled app and a clean extraction of the final ZIP pass verification.
  • CI uses unsigned packaging because Developer ID credentials and notarization are release-owner concerns, while bundle assembly and archive integrity remain continuously testable.

User-Facing Contract

CLI

The existing signed release command is unchanged. A release owner may optionally set:

RELEASE_OUTPUT_DIR=/path/to/artifacts ./Scripts/release.sh

Human Output

Successful release output still prints the ZIP and generated cask paths. A signature, Gatekeeper, stapler, or final-archive failure now stops the release before those paths are reported.

JSON Output

No JSON contract changes.

Exit Codes

  • 0: Packaging and all applicable verification completed.
  • Non-zero: Build, signing, notarization, stapling, archive extraction, Gatekeeper, or artifact verification failed.

Verification

Ran

zsh -n Scripts/*.sh
swift test --scratch-path /tmp/meanwhile-hardening-tests
RELEASE_OUTPUT_DIR=/tmp/meanwhile-hardening-dist \
SWIFT_BUILD_PATH=/tmp/meanwhile-hardening-build \
GITHUB_REPOSITORY=tcballard/Meanwhile \
./Scripts/release-unsigned.sh
ruby -c /tmp/meanwhile-hardening-dist/meanwhile.rb
unzip -t /tmp/meanwhile-hardening-dist/Meanwhile-0.1.0-unsigned.zip
git diff --check

Covered

  • 33 Swift tests pass with zero failures.
  • Signed script syntax is valid without submitting another notarization request.
  • Unsigned production builds package both executables into a strictly verified app bundle.
  • The final ZIP extracts without errors and contains the expected app bundle.
  • Temporary packaging directories are removed after completion.
  • Generated cask Ruby syntax is valid.

Review Path

Review Scripts/release.sh and Scripts/release-unsigned.sh first, then Scripts/package-app.sh and Scripts/make-cask.sh, followed by .github/workflows/ci.yml and the README.

Notes For Reviewer

The original failure came from assembling the signed app inside a cloud-managed dist directory, which attached Finder/File Provider metadata rejected by codesign. The prior workflow also verified the bundle before stapling but did not re-verify the shipped archive afterward.

Packages signed apps outside cloud-managed working directories, verifies the stapled app and a clean extraction of the final ZIP, and makes release output paths configurable.
Runs the Swift test suite, validates release script syntax, and exercises unsigned app packaging on pull requests and main.
Removes the completed decision document and its README reference now that the v0.1 scope and release gates are finished.
@tcballard
tcballard marked this pull request as ready for review July 13, 2026 16:58
@tcballard
tcballard merged commit 9e7b605 into main Jul 13, 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