fix: prevent tokenizer from destroying existing token attachments #19
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: Build & Release | |
| on: | |
| push: | |
| tags: ['v*'] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to release (e.g. v2.0.0-RC.3)' | |
| required: true | |
| type: string | |
| runner: | |
| description: 'Runner to use' | |
| type: choice | |
| default: 'macos-latest' | |
| options: | |
| - macos-latest | |
| - self-hosted | |
| create_release: | |
| description: 'Create GitHub Release' | |
| type: boolean | |
| default: true | |
| # Required GitHub Secrets: | |
| # DEVELOPER_ID_P12 - Base64-encoded Developer ID Application certificate (.p12) | |
| # DEVELOPER_ID_PASSWORD - Password for the Developer ID .p12 | |
| # MAC_DEVELOPMENT_P12 - Base64-encoded Mac Development certificate (.p12) | |
| # MAC_DEVELOPMENT_PASSWORD - Password for the Mac Development .p12 | |
| # NOTARY_KEY_ID - App Store Connect API Key ID | |
| # NOTARY_ISSUER_ID - App Store Connect API Issuer ID | |
| # NOTARY_AUTH_KEY - Base64-encoded App Store Connect API Key (.p8) | |
| jobs: | |
| release: | |
| runs-on: ${{ inputs.runner || 'macos-latest' }} | |
| permissions: | |
| contents: write | |
| env: | |
| WORKSPACE: RuntimeViewer-arm64e.xcworkspace | |
| BUILD_PATH: ./Products/Archives | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.tag || github.ref }} | |
| - name: Clone sibling dependencies | |
| run: | | |
| cd .. | |
| for repo in MachOKit MachOObjCSection MachOSwiftSection; do | |
| rm -rf "$repo" | |
| git clone --depth 1 "https://github.com/MxIris-Reverse-Engineering/${repo}.git" | |
| done | |
| # TODO: The sibling repos use branch: "main" in Package.swift remote | |
| # fallbacks. They should be pinned to specific revisions or tags for | |
| # reproducible CI builds. | |
| - name: Select Xcode 26.2 | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: '26.2' | |
| - name: Import code signing certificates | |
| env: | |
| DEVELOPER_ID_P12: ${{ secrets.DEVELOPER_ID_P12 }} | |
| DEVELOPER_ID_PASSWORD: ${{ secrets.DEVELOPER_ID_PASSWORD }} | |
| MAC_DEVELOPMENT_P12: ${{ secrets.MAC_DEVELOPMENT_P12 }} | |
| MAC_DEVELOPMENT_PASSWORD: ${{ secrets.MAC_DEVELOPMENT_PASSWORD }} | |
| run: | | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| KEYCHAIN_PASSWORD=$(openssl rand -base64 32) | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| echo "$DEVELOPER_ID_P12" | base64 --decode > "$RUNNER_TEMP/developer_id.p12" | |
| security import "$RUNNER_TEMP/developer_id.p12" \ | |
| -P "$DEVELOPER_ID_PASSWORD" \ | |
| -A -t cert -f pkcs12 \ | |
| -k "$KEYCHAIN_PATH" | |
| echo "$MAC_DEVELOPMENT_P12" | base64 --decode > "$RUNNER_TEMP/mac_development.p12" | |
| security import "$RUNNER_TEMP/mac_development.p12" \ | |
| -P "$MAC_DEVELOPMENT_PASSWORD" \ | |
| -A -t cert -f pkcs12 \ | |
| -k "$KEYCHAIN_PATH" | |
| # Import Apple intermediate certificates (required on self-hosted runners) | |
| # Use || true because these may already exist on GitHub-hosted runners | |
| for cert_url in \ | |
| https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer \ | |
| https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer; do | |
| cert_file="$RUNNER_TEMP/$(basename "$cert_url")" | |
| curl -sL "$cert_url" -o "$cert_file" | |
| security import "$cert_file" -k "$KEYCHAIN_PATH" -T /usr/bin/codesign || true | |
| done | |
| security list-keychain -d user -s \ | |
| "$KEYCHAIN_PATH" \ | |
| $(security list-keychain -d user | tr -d '"') | |
| security set-key-partition-list -S apple-tool:,apple: \ | |
| -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| - name: Resolve package dependencies | |
| run: | | |
| xcodebuild -resolvePackageDependencies \ | |
| -workspace $WORKSPACE \ | |
| -scheme "RuntimeViewer macOS" \ | |
| -skipPackagePluginValidation \ | |
| -skipMacroValidation | |
| # ── macOS: Archive & Export Catalyst Helper ── | |
| - name: Archive Catalyst helper | |
| run: | | |
| xcodebuild archive \ | |
| -workspace $WORKSPACE \ | |
| -scheme RuntimeViewerCatalystHelper \ | |
| -configuration Release \ | |
| -destination 'generic/platform=macOS,variant=Mac Catalyst' \ | |
| -archivePath $BUILD_PATH/RuntimeViewerCatalystHelper.xcarchive \ | |
| -skipPackagePluginValidation \ | |
| -skipMacroValidation \ | |
| CURRENT_PROJECT_VERSION=$(date +"%Y%m%d.%H.%M") | |
| - name: Export Catalyst helper | |
| run: | | |
| EXPORT_PATH=RuntimeViewerUsingAppKit | |
| rm -rf "$EXPORT_PATH/RuntimeViewerCatalystHelper.app" | |
| xcodebuild -exportArchive \ | |
| -archivePath $BUILD_PATH/RuntimeViewerCatalystHelper.xcarchive \ | |
| -configuration Release \ | |
| -exportPath "$EXPORT_PATH" \ | |
| -exportOptionsPlist ArchiveExportConfig-Catalyst.plist \ | |
| -quiet | |
| rm -f "$EXPORT_PATH/Packaging.log" | |
| rm -f "$EXPORT_PATH/DistributionSummary.plist" | |
| rm -f "$EXPORT_PATH/ExportOptions.plist" | |
| # ── macOS: Archive & Export Main App ── | |
| - name: Archive macOS app | |
| run: | | |
| xcodebuild archive \ | |
| -workspace $WORKSPACE \ | |
| -scheme "RuntimeViewer macOS" \ | |
| -configuration Release \ | |
| -destination 'generic/platform=macOS' \ | |
| -archivePath $BUILD_PATH/RuntimeViewer.xcarchive \ | |
| -skipPackagePluginValidation \ | |
| -skipMacroValidation \ | |
| CURRENT_PROJECT_VERSION=$(date +"%Y%m%d.%H.%M") | |
| - name: Export macOS app | |
| run: | | |
| EXPORT_PATH=$BUILD_PATH/Products/Export | |
| rm -rf "$EXPORT_PATH" | |
| xcodebuild -exportArchive \ | |
| -archivePath $BUILD_PATH/RuntimeViewer.xcarchive \ | |
| -configuration Release \ | |
| -exportPath "$EXPORT_PATH" \ | |
| -exportOptionsPlist ArchiveExportConfig.plist \ | |
| -quiet | |
| if [ ! -d "$EXPORT_PATH/RuntimeViewer.app" ]; then | |
| echo "Error: App not found at $EXPORT_PATH/RuntimeViewer.app" | |
| exit 1 | |
| fi | |
| # ── macOS: Notarization ── | |
| - name: Notarize macOS app | |
| env: | |
| NOTARY_KEY_ID: ${{ secrets.NOTARY_KEY_ID }} | |
| NOTARY_ISSUER_ID: ${{ secrets.NOTARY_ISSUER_ID }} | |
| NOTARY_AUTH_KEY: ${{ secrets.NOTARY_AUTH_KEY }} | |
| run: | | |
| if [ -z "$NOTARY_KEY_ID" ]; then | |
| echo "Notarization secrets not configured, skipping." | |
| exit 0 | |
| fi | |
| EXPORT_PATH=$BUILD_PATH/Products/Export | |
| APP_PATH="$EXPORT_PATH/RuntimeViewer.app" | |
| ZIP_PATH="$EXPORT_PATH/RuntimeViewer-notarize.zip" | |
| API_KEY_DIR="$RUNNER_TEMP/notary_keys/private_keys" | |
| mkdir -p "$API_KEY_DIR" | |
| echo "$NOTARY_AUTH_KEY" | base64 --decode > "$API_KEY_DIR/AuthKey_${NOTARY_KEY_ID}.p8" | |
| echo "Zipping app for notarization..." | |
| /usr/bin/ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH" | |
| echo "Submitting to Apple Notary Service..." | |
| xcrun notarytool submit "$ZIP_PATH" \ | |
| --key "$API_KEY_DIR/AuthKey_${NOTARY_KEY_ID}.p8" \ | |
| --key-id "$NOTARY_KEY_ID" \ | |
| --issuer "$NOTARY_ISSUER_ID" \ | |
| --wait | |
| echo "Stapling notarization ticket..." | |
| xcrun stapler staple "$APP_PATH" | |
| # ── iOS Simulator ── | |
| - name: Build iOS Simulator app | |
| run: | | |
| xcodebuild build \ | |
| -workspace $WORKSPACE \ | |
| -scheme "RuntimeViewer iOS" \ | |
| -configuration Release \ | |
| -destination 'generic/platform=iOS Simulator' \ | |
| -derivedDataPath ./DerivedData \ | |
| -skipPackagePluginValidation \ | |
| -skipMacroValidation \ | |
| CODE_SIGNING_ALLOWED=NO | |
| # ── Package ── | |
| - name: Package artifacts | |
| run: | | |
| EXPORT_PATH=$BUILD_PATH/Products/Export | |
| /usr/bin/ditto -c -k --keepParent "$EXPORT_PATH/RuntimeViewer.app" \ | |
| RuntimeViewer-macOS.zip | |
| cd ./DerivedData/Build/Products/Release-iphonesimulator | |
| /usr/bin/ditto -c -k --keepParent RuntimeViewer.app \ | |
| "$GITHUB_WORKSPACE/RuntimeViewer-iOS-Simulator.zip" | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-artifacts | |
| path: | | |
| RuntimeViewer-macOS.zip | |
| RuntimeViewer-iOS-Simulator.zip | |
| # ── Release (manual only) ── | |
| - name: Create Release | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.create_release }} | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="${{ inputs.tag }}" | |
| CHANGELOG_FILE="Changelogs/${TAG}.md" | |
| NOTES_ARGS=() | |
| if [ -f "$CHANGELOG_FILE" ]; then | |
| echo "Using changelog from $CHANGELOG_FILE" | |
| NOTES_ARGS=(--notes-file "$CHANGELOG_FILE") | |
| else | |
| echo "No changelog found for $TAG, using auto-generated notes" | |
| NOTES_ARGS=(--generate-notes) | |
| fi | |
| gh release create "$TAG" \ | |
| --title "RuntimeViewer $TAG" \ | |
| "${NOTES_ARGS[@]}" \ | |
| RuntimeViewer-macOS.zip \ | |
| RuntimeViewer-iOS-Simulator.zip | |
| - name: Clean up keychain | |
| if: always() | |
| run: | | |
| if [ -f "$RUNNER_TEMP/app-signing.keychain-db" ]; then | |
| security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" | |
| fi |