chore(release): v0.14.0 #56
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: "Release" | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| jobs: | |
| release: | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: macos-latest | |
| args: "--target aarch64-apple-darwin" | |
| rust-targets: aarch64-apple-darwin | |
| bun-target: bun-darwin-arm64 | |
| sidecar-name: stockai-backend-aarch64-apple-darwin | |
| - platform: ubuntu-24.04 | |
| args: "--bundles deb,appimage" | |
| bun-target: bun-linux-x64 | |
| sidecar-name: stockai-backend-x86_64-unknown-linux-gnu | |
| - platform: windows-latest | |
| bun-target: bun-windows-x64 | |
| sidecar-name: stockai-backend-x86_64-pc-windows-msvc.exe | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2.2.0 | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.rust-targets }} | |
| - name: Rust cache | |
| uses: swatinem/rust-cache@v2.9.1 | |
| with: | |
| workspaces: src-tauri | |
| - name: Install Linux system dependencies | |
| if: matrix.platform == 'ubuntu-24.04' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libgtk-3-dev \ | |
| libwebkit2gtk-4.1-dev \ | |
| libsoup-3.0-dev \ | |
| libjavascriptcoregtk-4.1-dev \ | |
| libappindicator3-dev \ | |
| librsvg2-dev \ | |
| patchelf | |
| # Tauri 内置的 linuxdeploy(2024-07 老版)给 AppDir 解析依赖时,对 sidecar | |
| # (Bun 编译的大二进制)跑 ldd 失败会直接 abort,导致 AppImage 打包 "failed to run linuxdeploy"。 | |
| # 预置较新版 linuxdeploy(遇 ldd 失败改为警告跳过)到 Tauri 缓存覆盖之。 | |
| # pin SHA256 防供应链篡改:哈希不符则构建 loud 失败,需人工复核后更新此值。 | |
| - name: Pre-seed pinned linuxdeploy (Linux AppImage) | |
| if: matrix.platform == 'ubuntu-24.04' | |
| env: | |
| LD_SHA256: 514d4ffe2a2f757369b41863a4f63fbbb222c429652803ebc081cb16ba21ac25 | |
| run: | | |
| mkdir -p ~/.cache/tauri | |
| curl -fsSL --retry 5 -o ~/.cache/tauri/linuxdeploy-x86_64.AppImage \ | |
| https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage | |
| echo "${LD_SHA256} ${HOME}/.cache/tauri/linuxdeploy-x86_64.AppImage" | sha256sum -c - | |
| chmod +x ~/.cache/tauri/linuxdeploy-x86_64.AppImage | |
| - name: Install frontend dependencies | |
| run: bun install | |
| - name: Check macOS signing availability | |
| id: check-signing | |
| if: matrix.platform == 'macos-latest' | |
| run: | | |
| if [ -n "$APPLE_CERT" ]; then | |
| echo "available=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "available=false" >> "$GITHUB_OUTPUT" | |
| echo "⚠️ APPLE_CERTIFICATE not configured, skipping code signing" | |
| fi | |
| env: | |
| APPLE_CERT: ${{ secrets.APPLE_CERTIFICATE }} | |
| - name: Import Apple Certificate | |
| if: matrix.platform == 'macos-latest' && steps.check-signing.outputs.available == 'true' | |
| uses: apple-actions/import-codesign-certs@v3 | |
| with: | |
| p12-file-base64: ${{ secrets.APPLE_CERTIFICATE }} | |
| p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| - name: Build sidecar binary | |
| shell: bash | |
| env: | |
| BUN_TARGET: ${{ matrix.bun-target }} | |
| OUTFILE: src-tauri/bin/${{ matrix.sidecar-name }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| run: | | |
| mkdir -p src-tauri/bin | |
| # build-script.ts 内部已经处理了 BUN_NO_CODESIGN_MACHO_BINARY=1 和 xattr -cr 以及 codesign | |
| bun sidecar/build-script.ts | |
| # 验证二进制是否生成且已签名 | |
| ls -la src-tauri/bin/${{ matrix.sidecar-name }} | |
| - name: Verify Sidecar Integrity & Signature | |
| shell: bash | |
| run: | | |
| BINARY="src-tauri/bin/${{ matrix.sidecar-name }}" | |
| bun scripts/verify-bundle.ts "$BINARY" | |
| - name: Sidecar Self-Check | |
| shell: bash | |
| run: | | |
| BINARY="src-tauri/bin/${{ matrix.sidecar-name }}" | |
| echo "🚀 Running Sidecar Self-Check..." | |
| # 检查二进制依赖 (macOS) | |
| if [ "${{ matrix.platform }}" = "macos-latest" ]; then | |
| echo "📚 Dependencies (otool -L):" | |
| otool -L "$BINARY" | |
| echo "🖋️ Signature Check (Pre-bundle):" | |
| codesign -vvv --deep --strict "$BINARY" | |
| fi | |
| echo "✅ Sidecar binary verified (signature + dependencies checked above)." | |
| - name: Check Signing Secrets | |
| shell: bash | |
| run: | | |
| SIGNING_READY=true | |
| if [ -z "${{ secrets.APPLE_CERTIFICATE }}" ]; then echo "⚠️ APPLE_CERTIFICATE missing"; SIGNING_READY=false; fi | |
| if [ -z "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" ]; then echo "⚠️ APPLE_CERTIFICATE_PASSWORD missing"; SIGNING_READY=false; fi | |
| if [ -z "${{ secrets.APPLE_SIGNING_IDENTITY }}" ]; then echo "⚠️ APPLE_SIGNING_IDENTITY missing"; SIGNING_READY=false; fi | |
| if [ -z "${{ secrets.APPLE_ID }}" ]; then echo "⚠️ APPLE_ID missing"; SIGNING_READY=false; fi | |
| if [ -z "${{ secrets.APPLE_PASSWORD }}" ]; then echo "⚠️ APPLE_PASSWORD missing"; SIGNING_READY=false; fi | |
| if [ -z "${{ secrets.APPLE_TEAM_ID }}" ]; then echo "⚠️ APPLE_TEAM_ID missing"; SIGNING_READY=false; fi | |
| if [ "$SIGNING_READY" = true ]; then | |
| echo "✅ All macOS signing secrets are present. Pipeline will attempt signing and notarization." | |
| else | |
| echo "❌ Signing secrets incomplete. macOS build will be unsigned and may be marked as 'damaged'." | |
| fi | |
| - name: Deep Cleanup of Extended Attributes | |
| if: matrix.platform == 'macos-latest' | |
| shell: bash | |
| run: | | |
| echo "🧹 Cleaning up attributes for signing..." | |
| find . -type f -exec xattr -c {} \; || true | |
| - name: Build and publish release (signed) | |
| if: matrix.platform != 'macos-latest' || steps.check-signing.outputs.available == 'true' | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| # 自动更新器签名私钥,缺失时 tauri-action 仍会构建但不生成 .sig/latest.json | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| # linuxdeploy(AppImage 格式)嵌套调用时需自解压运行,避免 runner 无 FUSE | |
| APPIMAGE_EXTRACT_AND_RUN: 1 | |
| with: | |
| tagName: ${{ github.ref_name }} | |
| releaseName: "StockAI ${{ github.ref_name }}" | |
| releaseBody: | | |
| See the [CHANGELOG](https://github.com/hyhmrright/StockAI/blob/main/CHANGELOG.md) for what's new in this release. | |
| releaseDraft: false | |
| prerelease: false | |
| args: ${{ matrix.args }} | |
| - name: Build and publish release (unsigned macOS) | |
| if: matrix.platform == 'macos-latest' && steps.check-signing.outputs.available != 'true' | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # 即便 Apple 证书缺失,更新器仍需用 minisign 私钥签名产物 | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| with: | |
| tagName: ${{ github.ref_name }} | |
| releaseName: "StockAI ${{ github.ref_name }}" | |
| releaseBody: | | |
| See the [CHANGELOG](https://github.com/hyhmrright/StockAI/blob/main/CHANGELOG.md) for what's new in this release. | |
| releaseDraft: false | |
| prerelease: false | |
| args: ${{ matrix.args }} | |
| - name: Staple and Final Verify (macOS) | |
| if: matrix.platform == 'macos-latest' && steps.check-signing.outputs.available == 'true' | |
| shell: bash | |
| run: | | |
| echo "🔍 Searching for generated DMG..." | |
| DMG_PATH=$(find src-tauri/target -name "StockAI_*_aarch64.dmg" | head -n 1) | |
| if [ -z "$DMG_PATH" ]; then | |
| echo "❌ DMG not found! Skipping staple check." | |
| exit 1 | |
| fi | |
| echo "✅ Found DMG: $DMG_PATH" | |
| # 显式尝试装订公证票据 (Stapling) | |
| echo "📨 Stapling notarization ticket..." | |
| xcrun stapler staple "$DMG_PATH" || echo "⚠️ Stapling failed, maybe already stapled or notarization pending." | |
| echo "📂 Mounting DMG for deep verification..." | |
| mkdir -p /tmp/stockai_mnt | |
| hdiutil attach "$DMG_PATH" -mountpoint /tmp/stockai_mnt | |
| echo "🔍 Running Deep Integrity Check..." | |
| bun scripts/verify-bundle.ts /tmp/stockai_mnt/StockAI.app | |
| echo "🛡️ Verifying Gatekeeper Assessment..." | |
| spctl --assess --type exec --context context:primary-signature --verbose /tmp/stockai_mnt/StockAI.app | |
| echo "📤 Detaching DMG..." | |
| hdiutil detach /tmp/stockai_mnt | |
| echo "✨ Bundle integrity verified successfully." |