Protect release credentials with environment scope #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Official Release DMG | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| name: Sign, notarize, and draft release | |
| environment: release | |
| runs-on: macos-15 | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Checkout tagged source | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Select Xcode | |
| run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer | |
| - name: Validate tag and derive release version | |
| id: release | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| [[ "$GITHUB_REF_NAME" == "v$version" && "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9]+)*$ ]] || { | |
| echo "Release tags must use vX.Y.Z format; received $GITHUB_REF_NAME" >&2 | |
| exit 1 | |
| } | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: Validate signing configuration | |
| env: | |
| APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| : "${APPLE_TEAM_ID:?Missing APPLE_TEAM_ID Actions variable}" | |
| - name: Import Developer ID certificate into temporary keychain | |
| env: | |
| CERTIFICATE_P12_BASE64: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_P12_BASE64 }} | |
| CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| : "${CERTIFICATE_P12_BASE64:?Missing APPLE_DEVELOPER_ID_CERTIFICATE_P12_BASE64 secret}" | |
| : "${CERTIFICATE_PASSWORD:?Missing APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD secret}" | |
| KEYCHAIN_PASSWORD="$(openssl rand -base64 32)" | |
| keychain="$RUNNER_TEMP/pinative-signing.keychain-db" | |
| certificate="$RUNNER_TEMP/developer-id.p12" | |
| echo "$CERTIFICATE_P12_BASE64" | base64 --decode > "$certificate" | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain" | |
| security set-keychain-settings -lut 21600 "$keychain" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain" | |
| security import "$certificate" -k "$keychain" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$keychain" | |
| security list-keychain -d user -s "$keychain" | |
| security default-keychain -d user -s "$keychain" | |
| rm -f "$certificate" | |
| - name: Configure temporary notarization credentials | |
| env: | |
| API_KEY_ID: ${{ secrets.APPLE_NOTARY_API_KEY_ID }} | |
| API_ISSUER_ID: ${{ secrets.APPLE_NOTARY_API_ISSUER_ID }} | |
| API_KEY_P8_BASE64: ${{ secrets.APPLE_NOTARY_API_KEY_P8_BASE64 }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| : "${API_KEY_ID:?Missing APPLE_NOTARY_API_KEY_ID secret}" | |
| : "${API_ISSUER_ID:?Missing APPLE_NOTARY_API_ISSUER_ID secret}" | |
| : "${API_KEY_P8_BASE64:?Missing APPLE_NOTARY_API_KEY_P8_BASE64 secret}" | |
| keychain="$RUNNER_TEMP/pinative-signing.keychain-db" | |
| key="$RUNNER_TEMP/AuthKey_${API_KEY_ID}.p8" | |
| echo "$API_KEY_P8_BASE64" | base64 --decode > "$key" | |
| xcrun notarytool store-credentials "pinative-notary-${GITHUB_RUN_ID}" \ | |
| --key "$key" \ | |
| --key-id "$API_KEY_ID" \ | |
| --issuer "$API_ISSUER_ID" \ | |
| --keychain "$keychain" | |
| rm -f "$key" | |
| - name: Build, sign, notarize, and verify DMG | |
| env: | |
| APPLE_TEAM_ID: ${{ vars.APPLE_TEAM_ID }} | |
| POSTHOG_PROJECT_API_KEY: ${{ secrets.POSTHOG_PROJECT_API_KEY }} | |
| NOTARYTOOL_PROFILE: pinative-notary-${{ github.run_id }} | |
| NOTARY_SUBMISSION_RESULT_PATH: ${{ runner.temp }}/pinative-notary-result.json | |
| run: | | |
| scripts/build-release-dmg.sh --official "${{ steps.release.outputs.version }}" \ | |
| --build-number "$GITHUB_RUN_NUMBER" \ | |
| --notary-profile "$NOTARYTOOL_PROFILE" | |
| - name: Capture Apple notarization diagnostics | |
| if: failure() | |
| env: | |
| NOTARYTOOL_PROFILE: pinative-notary-${{ github.run_id }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| result="$RUNNER_TEMP/pinative-notary-result.json" | |
| log="$RUNNER_TEMP/pinative-notary-log.json" | |
| [[ -s "$result" ]] || { | |
| echo "No notarization submission result was created; the failure occurred before or during submission." | |
| exit 0 | |
| } | |
| submission_id="$(plutil -extract id raw "$result")" | |
| xcrun notarytool log "$submission_id" "$log" \ | |
| --keychain-profile "$NOTARYTOOL_PROFILE" \ | |
| --keychain "$RUNNER_TEMP/pinative-signing.keychain-db" | |
| cat "$log" | |
| - name: Upload notarization diagnostics | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: notarization-diagnostics-${{ github.run_id }} | |
| path: | | |
| ${{ runner.temp }}/pinative-notary-result.json | |
| ${{ runner.temp }}/pinative-notary-log.json | |
| if-no-files-found: warn | |
| retention-days: 30 | |
| - name: Upload verified release artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: PiNative-${{ steps.release.outputs.version }} | |
| path: | | |
| dist/PiNative-${{ steps.release.outputs.version }}.dmg | |
| dist/PiNative-${{ steps.release.outputs.version }}.dmg.sha256 | |
| if-no-files-found: error | |
| retention-days: 30 | |
| - name: Create draft GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ steps.release.outputs.version }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| notes="$RUNNER_TEMP/release-notes.md" | |
| cat > "$notes" <<EOF | |
| ## PiNative $VERSION | |
| ### Requirements | |
| - macOS 14 or newer. | |
| - [Pi](https://pi.dev) installed and configured separately before launching PiNative. | |
| ### Install | |
| 1. Open \`PiNative-$VERSION.dmg\`. | |
| 2. Drag \`PiNative.app\` into Applications. | |
| 3. Launch PiNative from Applications. | |
| macOS may request permission for features that need it on first use. This official release is Developer ID signed and Apple-notarized; do not disable Gatekeeper. | |
| EOF | |
| gh release create "$GITHUB_REF_NAME" \ | |
| --verify-tag \ | |
| --draft \ | |
| --title "PiNative $VERSION" \ | |
| --notes-file "$notes" \ | |
| "dist/PiNative-$VERSION.dmg" \ | |
| "dist/PiNative-$VERSION.dmg.sha256" | |
| - name: Remove temporary signing keychain | |
| if: always() | |
| shell: bash | |
| run: | | |
| security delete-keychain "$RUNNER_TEMP/pinative-signing.keychain-db" || true |