Summary
Publish Developer ID-signed and Apple-notarized swiftpkg installer releases instead of the current unsigned .pkg artifacts.
Why
The release workflow currently invokes UNSIGNED=1 ./scripts/release.sh, and the README describes the installer as unsigned. Signed and notarized releases provide a normal Gatekeeper installation experience and are a prerequisite for distributing the official installer through Homebrew Cask.
Proposed work
- Obtain and protect a Developer ID Application certificate, a Developer ID Installer certificate, and an App Store Connect API key or a
notarytool keychain profile.
- Decide on a trusted release runner:
- Preferred: a self-hosted, access-controlled macOS runner with the certificates and notary profile installed in its keychain.
- Alternative: import encrypted/base64 certificate material into a temporary GitHub Actions keychain and configure
notarytool with App Store Connect credentials from GitHub Actions secrets.
- Change the tag-release workflow to run the existing signed path in
scripts/release.sh, supplying APP_SIGN_IDENTITY, INSTALLER_SIGN_IDENTITY, and NOTARY_PROFILE; remove UNSIGNED=1 for production tags.
- Keep the current unsigned path only for explicitly non-production or local testing, if still useful.
- Ensure the workflow uploads the notarized
.pkg and SHA256SUMS to the matching GitHub Release.
- Update the README to remove the unsigned/Gatekeeper-override guidance once signed releases are live.
Workflow shape
- name: Build, sign, notarize, and publish release
env:
APP_SIGN_IDENTITY: ${{ secrets.APP_SIGN_IDENTITY }}
INSTALLER_SIGN_IDENTITY: ${{ secrets.INSTALLER_SIGN_IDENTITY }}
NOTARY_PROFILE: swiftpkg-notary
GH_PUBLISH: "1"
GITHUB_REPOSITORY: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: ./scripts/release.sh
On GitHub-hosted runners, add setup steps before this job to import the Developer ID certificates into a temporary keychain and create the notarytool keychain profile from protected App Store Connect API-key secrets. Do not print certificate passwords, API keys, or profile material in logs.
Acceptance criteria
- A pushed
v<version> tag produces a Universal 2 swiftpkg-<version>-universal.pkg signed with the project Developer ID Installer identity.
- The embedded executable is signed with the Developer ID Application identity, hardened runtime, and timestamp.
- The installer is accepted by Apple notarization and stapled.
- Release verification runs and passes
codesign --verify --strict, pkgutil --check-signature, xcrun stapler validate, and spctl --assess --type install.
- The GitHub Release contains the notarized installer and a matching SHA-256 checksum.
- The public install documentation accurately describes the signing and notarization status.
Summary
Publish Developer ID-signed and Apple-notarized
swiftpkginstaller releases instead of the current unsigned.pkgartifacts.Why
The release workflow currently invokes
UNSIGNED=1 ./scripts/release.sh, and the README describes the installer as unsigned. Signed and notarized releases provide a normal Gatekeeper installation experience and are a prerequisite for distributing the official installer through Homebrew Cask.Proposed work
notarytoolkeychain profile.notarytoolwith App Store Connect credentials from GitHub Actions secrets.scripts/release.sh, supplyingAPP_SIGN_IDENTITY,INSTALLER_SIGN_IDENTITY, andNOTARY_PROFILE; removeUNSIGNED=1for production tags..pkgandSHA256SUMSto the matching GitHub Release.Workflow shape
On GitHub-hosted runners, add setup steps before this job to import the Developer ID certificates into a temporary keychain and create the
notarytoolkeychain profile from protected App Store Connect API-key secrets. Do not print certificate passwords, API keys, or profile material in logs.Acceptance criteria
v<version>tag produces a Universal 2swiftpkg-<version>-universal.pkgsigned with the project Developer ID Installer identity.codesign --verify --strict,pkgutil --check-signature,xcrun stapler validate, andspctl --assess --type install.