Skip to content

Build & release

Releases are tag-driven and built by GitHub Actions. Local builds live in Build from source; this page is how a shipped release actually happens.

Every push and PR to main runs the CI workflow on macos-15 / Xcode 16.4:

  1. Validate property lists (plutil -lint).
  2. Check installer script syntax (zsh -n).
  3. SwiftLint.
  4. swift build.
  5. swift test --filter PDFSmokeTests (fast PDF load/export sanity).
  6. swift test (full suite).
  7. xcodebuild build then xcodebuild test (Xcode-side, CODE_SIGNING_ALLOWED=NO).

Two more workflows guard quality: CodeQL (scheduled Swift analysis) and Dependency Review (fails a PR on moderate-or-higher advisories in dependency changes).

The Release workflow triggers on a v* or release-v* tag (or manual dispatch):

  1. Build a universal Apple Silicon + Intel app via ./scripts/install-mac.sh --clean --no-open --package-only --package Orifold.zip.
  2. Package and mount-test the versioned DMG, then verify the exact shipped app’s resource bundle and code signature.
  3. Generate SHA-256 sidecars and manifest.json, while keeping stable-name Orifold.dmg and Orifold.zip assets.
  4. Publish every asset to the tagged GitHub Release, mark it latest, and dispatch a documentation rebuild.

The website serves the universal DMG. The one-line installer and Homebrew cask use Orifold.zip from the same latest release; the in-app updater verifies the published checksum before installation.

Note

Signing & notarization, honestly. Release builds are ad-hoc signed and not notarized by default, so macOS shows an “unidentified developer” prompt on first open — the installer and cask clear the download quarantine to smooth this. If the Developer ID secrets are configured, the same workflow imports the certificate and produces a properly signed (and optionally notarized) build instead.

The Developer ID secrets the workflow looks for

When these repository secrets are present, the release job imports the certificate into a temporary keychain and signs with it:

ORIFOLD_DEVELOPER_ID_CERTIFICATE_BASE64, ORIFOLD_DEVELOPER_ID_CERTIFICATE_PASSWORD, ORIFOLD_SIGNING_IDENTITY, ORIFOLD_APPLE_ID, ORIFOLD_APPLE_TEAM_ID, ORIFOLD_APPLE_APP_SPECIFIC_PASSWORD.

The identical path works locally — set the same variables and run the --package-only and make-dmg.sh commands to produce signed/notarized artifacts on your own machine.

Before shipping, the same command list in Testing & the release gate must pass, plus the installed-app workflow audit and a final smoke check of the published artifact.

  • .build/install.log — build output from a source build.
  • ~/.orifold/prebuilt-install.log — the prebuilt install attempt.
  • CI: the uploaded Orifold-xcresults bundle on the workflow run.