ci: unified desktop build pipeline — renderer once, package in parallel#10813
ci: unified desktop build pipeline — renderer once, package in parallel#10813huhuanming wants to merge 1 commit intoxfrom
Conversation
Split desktop CI into two stages: 1. Build renderer once on ubuntu (fastest) 2. Fan out to 3 platform jobs that reuse the renderer artifact This reduces renderer builds from 5x to 1x and yarn installs from 7x to 4x. Existing per-platform workflows are untouched.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
| runs-on: ubuntu-24.04 | ||
| strategy: | ||
| matrix: | ||
| node-version: [24.x] | ||
| steps: | ||
| - name: Show executed time | ||
| run: | | ||
| echo "Executed at: $(date '+%Y-%m-%d %H:%M:%S')" | ||
|
|
||
| - name: Checkout Source Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| lfs: true | ||
|
|
||
| - name: Run Shared Env Setup | ||
| uses: ./.github/actions/shared-env | ||
| with: | ||
| env_file_name: '.env' | ||
| sentry_project: 'desktop' | ||
| covalent_key: ${{ secrets.COVALENT_KEY }} | ||
| sentry_token: ${{ secrets.SENTRY_TOKEN }} | ||
| sentry_dsn_react_native: ${{ secrets.SENTRY_DSN_REACT_NATIVE }} | ||
| sentry_dsn_web: ${{ secrets.SENTRY_DSN_WEB }} | ||
| sentry_dsn_desktop: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||
| sentry_dsn_mas: ${{ secrets.SENTRY_DSN_MAS }} | ||
| sentry_dsn_snap: ${{ secrets.SENTRY_DSN_SNAP }} | ||
| sentry_dsn_winms: ${{ secrets.SENTRY_DSN_WINMS }} | ||
| sentry_dsn_ext: ${{ secrets.SENTRY_DSN_EXT }} | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| cache: 'yarn' | ||
| registry-url: 'https://npm.pkg.github.com' | ||
| scope: '@onekeyhq' | ||
|
|
||
| - name: Get yarn cache directory path | ||
| id: yarn-cache-dir-path | ||
| run: echo "dir=${{ github.workspace }}/.yarn" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Install Dep | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| yarn install --immutable | ||
|
|
||
| - name: Build Renderer | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| cd apps/desktop | ||
| npx cross-env NODE_ENV=production yarn clean:build | ||
| npx cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 webpack build | ||
| node scripts/finalize-renderer-assets.js | ||
|
|
||
| - name: Upload Renderer Artifact | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: desktop-renderer-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/app/build/ | ||
| retention-days: 1 |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
In general, the fix is to explicitly define a permissions: block that grants only the minimal scopes needed for this workflow. Since the workflow only checks out code, uses GitHub Packages as an npm registry, and uploads artifacts, it needs read access to repository contents and packages, and does not need any write scopes.
The best fix here is to add a workflow-level permissions: block near the top of .github/workflows/build-desktop-renderer.yml (for example, after name: and before on:). This block will then apply to all jobs (including build-renderer) that do not override permissions. A suitable minimal configuration is:
permissions:
contents: read
packages: readNo other changes are required to existing steps or functionality, and no imports or external dependencies are involved.
| @@ -3,6 +3,10 @@ | ||
| # Reusable workflow: builds the desktop renderer (webpack) once on ubuntu, | ||
| # then uploads the artifact for downstream platform-specific packaging jobs. | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: read | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: |
| uses: ./.github/workflows/build-desktop-renderer.yml | ||
| with: | ||
| ONEKEY_ALLOW_SKIP_GPG_VERIFICATION: ${{ github.event.inputs.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION || 'false' }} | ||
| secrets: | ||
| COVALENT_KEY: ${{ secrets.COVALENT_KEY }} | ||
| SENTRY_TOKEN: ${{ secrets.SENTRY_TOKEN }} | ||
| SENTRY_DSN_REACT_NATIVE: ${{ secrets.SENTRY_DSN_REACT_NATIVE }} | ||
| SENTRY_DSN_WEB: ${{ secrets.SENTRY_DSN_WEB }} | ||
| SENTRY_DSN_DESKTOP: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||
| SENTRY_DSN_MAS: ${{ secrets.SENTRY_DSN_MAS }} | ||
| SENTRY_DSN_SNAP: ${{ secrets.SENTRY_DSN_SNAP }} | ||
| SENTRY_DSN_WINMS: ${{ secrets.SENTRY_DSN_WINMS }} | ||
| SENTRY_DSN_EXT: ${{ secrets.SENTRY_DSN_EXT }} | ||
|
|
||
| # ────────────────────────────────────────────────── | ||
| # Stage 2: Platform-specific packaging (3 parallel jobs) | ||
| # ────────────────────────────────────────────────── | ||
|
|
||
| # ═══════════════════════════════════════════════════ | ||
| # macOS runner: mac DMG + MAS | ||
| # ═══════════════════════════════════════════════════ | ||
| package-mac: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
In general, the fix is to add an explicit permissions: block that grants only the minimal scopes required for this workflow to run. For a release/build workflow that reads source and uses artifacts but does not push code or modify issues/PRs, contents: read is typically sufficient; if the workflow needs to download/upload artifacts only, that does not require extra scopes beyond contents: read. Because this workflow calls a reusable workflow (build-desktop-renderer.yml) and defines additional jobs, the safest and simplest change is to add a top‑level permissions: block so all jobs (including the called reusable workflow) default to least‑privilege settings.
Concretely, edit .github/workflows/release-desktop-all.yml near the top of the file, right after the on: block (line 10–18). Insert a root‑level permissions: section such as:
permissions:
contents: readThis will apply to all jobs (including renderer, package-mac, and the other platform jobs) that do not override permissions. No imports or additional methods are required; this is purely a YAML configuration addition. If some unshown job genuinely requires write access in the future (for example to create releases), that job can override with its own permissions: while keeping the rest of the workflow restricted.
| @@ -16,6 +16,9 @@ | ||
| type: boolean | ||
| default: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| ONEKEY_ALLOW_SKIP_GPG_VERIFICATION: ${{ github.event.inputs.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION || 'false' }} | ||
|
|
| needs: renderer | ||
| runs-on: macos-26 | ||
| strategy: | ||
| matrix: | ||
| node-version: [24.x] | ||
| env: | ||
| NODE_ENV: production | ||
| YARN_ENABLE_GLOBAL_CACHE: true | ||
| steps: | ||
| - name: Checkout Source Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| lfs: true | ||
|
|
||
| - name: Run Shared Env Setup | ||
| uses: ./.github/actions/shared-env | ||
| with: | ||
| env_file_name: '.env' | ||
| sentry_project: 'desktop' | ||
| covalent_key: ${{ secrets.COVALENT_KEY }} | ||
| sentry_token: ${{ secrets.SENTRY_TOKEN }} | ||
| sentry_dsn_react_native: ${{ secrets.SENTRY_DSN_REACT_NATIVE }} | ||
| sentry_dsn_web: ${{ secrets.SENTRY_DSN_WEB }} | ||
| sentry_dsn_desktop: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||
| sentry_dsn_mas: ${{ secrets.SENTRY_DSN_MAS }} | ||
| sentry_dsn_snap: ${{ secrets.SENTRY_DSN_SNAP }} | ||
| sentry_dsn_winms: ${{ secrets.SENTRY_DSN_WINMS }} | ||
| sentry_dsn_ext: ${{ secrets.SENTRY_DSN_EXT }} | ||
|
|
||
| - name: Warn if GPG verification is skipped | ||
| if: ${{ env.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION == 'true' }} | ||
| run: | | ||
| echo "::warning::GPG verification is SKIPPED for this build. This should only be used in CI/dev builds." | ||
|
|
||
| - name: 'Setup ENV' | ||
| run: | | ||
| eval "$(node -e 'const v=require("./apps/desktop/package.json").version; console.log("pkg_version="+v)')" | ||
| echo "PKG_VERSION=$pkg_version" >> $GITHUB_ENV | ||
| artifacts_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" | ||
| echo "ARTIFACTS_URL=$artifacts_url" >> $GITHUB_ENV | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| cache: 'yarn' | ||
| registry-url: 'https://npm.pkg.github.com' | ||
| scope: '@onekeyhq' | ||
|
|
||
| - name: Get yarn cache directory path | ||
| id: yarn-cache-dir-path | ||
| run: echo "dir=${{ github.workspace }}/.yarn" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Install Dep | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| yarn install --immutable | ||
|
|
||
| - name: Download Renderer Artifact | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: desktop-renderer-${{ github.sha }} | ||
| path: ./apps/desktop/app/build/ | ||
|
|
||
| - name: Compile macOS Liquid Glass Icon | ||
| run: | | ||
| cd apps/desktop | ||
| bash scripts/compile-liquid-icon.sh | ||
|
|
||
| - name: Verify Liquid Glass Icon | ||
| run: | | ||
| cd apps/desktop | ||
| bash scripts/verify-icon-compatibility.sh | ||
|
|
||
| # ── Phase 1: Mac + Linux (Developer ID) ── | ||
|
|
||
| - name: Setup Developer ID Code Signing | ||
| run: | | ||
| echo ${{ secrets.DESKTOP_KEYS_SECRET }} | base64 -d > apps/desktop/sign.p12 | ||
|
|
||
| - name: Install Developer ID provisioning profile for CloudKit | ||
| env: | ||
| DESKTOP_ISO_PROVISION_PROFILE_BASE64: ${{ secrets.DESKTOP_ISO_PROVISION_PROFILE_BASE64 }} | ||
| run: | | ||
| PP_PATH=./apps/desktop/OneKey_Desktop_DeveloperId.provisionprofile | ||
| echo -n "$DESKTOP_ISO_PROVISION_PROFILE_BASE64" | base64 --decode > $PP_PATH | ||
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | ||
| cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles | ||
|
|
||
| - name: 'Build Main Process' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:main | ||
| yarn install-app-deps | ||
|
|
||
| - name: 'Package Mac' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| ASC_PROVIDER: ${{ secrets.ASC_PROVIDER }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | ||
| CSC_LINK: './sign.p12' | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:electron:mac --publish never | ||
|
|
||
| - name: Clean up Developer ID provisioning profile | ||
| if: ${{ always() }} | ||
| run: | | ||
| rm -f ~/Library/MobileDevice/Provisioning\ Profiles/OneKey_Desktop_DeveloperId.provisionprofile | ||
|
|
||
| - name: Upload Artifacts latest.yml | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mac-yml-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*.yml | ||
|
|
||
| - name: Upload universal Mac DMG | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mac-universal-dmg-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*-universal.dmg | ||
|
|
||
| - name: Upload x64 Mac DMG | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mac-x64-dmg-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*-x64.dmg | ||
|
|
||
| - name: Upload arm64 Mac DMG | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mac-arm64-dmg-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*-arm64.dmg | ||
|
|
||
| - name: Upload Mac Release Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mac-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/* | ||
| !./apps/desktop/build-electron/mac-arm64 | ||
| !./apps/desktop/build-electron/mac | ||
| !./apps/desktop/build-electron/builder-debug.yml | ||
|
|
||
| # ── Phase 2: MAS (App Store signing) ── | ||
|
|
||
| - name: Clean build-electron for MAS | ||
| run: rm -rf apps/desktop/build-electron | ||
|
|
||
| - name: Install the Apple certificate and provisioning profile for MAS | ||
| env: | ||
| MAC_INSTALL_P12_BASE64: ${{ secrets.MAC_INSTALL_P12_BASE64 }} | ||
| MAC_INSTALL_P12_PASSWORD: ${{ secrets.MAC_INSTALL_P12_PASSWORD }} | ||
| APPLE_DISTRIBUTION_P12_BASE64: ${{ secrets.APPLE_DISTRIBUTION_P12_BASE64 }} | ||
| APPLE_DISTRIBUTION_P12_PASSWORD: ${{ secrets.APPLE_DISTRIBUTION_P12_PASSWORD }} | ||
| PROVISION_PROFILE_BASE64: ${{ secrets.PROVISION_PROFILE_BASE64 }} | ||
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | ||
| run: | | ||
| MAC_INSTALL_P12_PATH=$RUNNER_TEMP/mac_install_certificate.p12 | ||
| APPLE_DISTRIBUTION_P12_PATH=$RUNNER_TEMP/apple_distribution_certificate.p12 | ||
| PP_PATH=./apps/desktop/OneKey_Mac_App.provisionprofile | ||
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | ||
|
|
||
| echo -n "$MAC_INSTALL_P12_BASE64" | base64 --decode > $MAC_INSTALL_P12_PATH | ||
| echo -n "$APPLE_DISTRIBUTION_P12_BASE64" | base64 --decode > $APPLE_DISTRIBUTION_P12_PATH | ||
| echo -n "$PROVISION_PROFILE_BASE64" | base64 --decode > $PP_PATH | ||
|
|
||
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | ||
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | ||
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | ||
|
|
||
| security import $MAC_INSTALL_P12_PATH -P "$MAC_INSTALL_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | ||
| security import $APPLE_DISTRIBUTION_P12_PATH -P "$APPLE_DISTRIBUTION_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | ||
| security list-keychain -d user -s $KEYCHAIN_PATH | ||
|
|
||
| mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles | ||
| cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles | ||
|
|
||
| - name: 'Package MAS' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| ASC_PROVIDER: ${{ secrets.ASC_PROVIDER }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| cd apps/desktop | ||
| npx electron-builder build -m --config electron-builder-mas.config.js --publish never | ||
|
|
||
| - name: Clean up MAS keychain and provisioning profile | ||
| if: ${{ always() }} | ||
| run: | | ||
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db 2>/dev/null || true | ||
| rm -f ~/Library/MobileDevice/Provisioning\ Profiles/OneKey_Mac_App.provisionprofile | ||
|
|
||
| - name: Upload MAS Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-mas-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/mas-universal/*.pkg | ||
|
|
||
| - name: Validate MAS for Testflight | ||
| env: | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| run: | | ||
| PKG_FILE=$(ls ./apps/desktop/build-electron/mas-universal/*.pkg) | ||
| echo "Found package: $PKG_FILE" | ||
| xcrun altool --validate-app --file "$PKG_FILE" -t macOS -u "$APPLEID" -p "$APPLEIDPASS" --show-progress | ||
|
|
||
| - name: Upload MAS to Testflight | ||
| continue-on-error: true | ||
| env: | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| run: | | ||
| PKG_FILE=$(ls ./apps/desktop/build-electron/mas-universal/*.pkg) | ||
| echo "Uploading package: $PKG_FILE" | ||
| xcrun altool --upload-app --file "$PKG_FILE" -t macOS -u "$APPLEID" -p "$APPLEIDPASS" --show-progress | ||
|
|
||
| # ═══════════════════════════════════════════════════ | ||
| # Windows runner: win NSIS + winms (Microsoft Store) | ||
| # ═══════════════════════════════════════════════════ | ||
| package-win: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
To fix the problem, explicitly define permissions for this workflow so that the GITHUB_TOKEN has only the minimal scopes required. Since the visible parts of this workflow merely check out code, download and upload artifacts, and access packages via NODE_AUTH_TOKEN (which uses secrets.GITHUB_TOKEN), contents: read and packages: read are sufficient as a safe baseline. These can be applied at the top (workflow) level so they affect all jobs, including renderer, package-mac, and the later package-win/Linux jobs referenced but not shown.
The single best minimal‑change fix is: add a workflow‑level permissions block just after the on: block (after line 18 and before the env: section). This sets default permissions for all jobs that do not override them, without modifying any job definitions or steps. No imports or additional methods are needed, since this is YAML configuration only. We do not change any existing behavior of the jobs; we only constrain the implicit token capabilities.
| @@ -16,6 +16,10 @@ | ||
| type: boolean | ||
| default: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: read | ||
|
|
||
| env: | ||
| ONEKEY_ALLOW_SKIP_GPG_VERIFICATION: ${{ github.event.inputs.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION || 'false' }} | ||
|
|
| needs: renderer | ||
| runs-on: windows-2025 | ||
| strategy: | ||
| matrix: | ||
| node-version: [24.x] | ||
| env: | ||
| NODE_ENV: production | ||
| YARN_ENABLE_GLOBAL_CACHE: true | ||
| steps: | ||
| - name: Checkout Source Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| lfs: true | ||
|
|
||
| - name: Run Shared Env Setup | ||
| uses: ./.github/actions/shared-env | ||
| with: | ||
| env_file_name: '.env' | ||
| sentry_project: 'desktop' | ||
| covalent_key: ${{ secrets.COVALENT_KEY }} | ||
| sentry_token: ${{ secrets.SENTRY_TOKEN }} | ||
| sentry_dsn_react_native: ${{ secrets.SENTRY_DSN_REACT_NATIVE }} | ||
| sentry_dsn_web: ${{ secrets.SENTRY_DSN_WEB }} | ||
| sentry_dsn_desktop: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||
| sentry_dsn_mas: ${{ secrets.SENTRY_DSN_MAS }} | ||
| sentry_dsn_snap: ${{ secrets.SENTRY_DSN_SNAP }} | ||
| sentry_dsn_winms: ${{ secrets.SENTRY_DSN_WINMS }} | ||
| sentry_dsn_ext: ${{ secrets.SENTRY_DSN_EXT }} | ||
|
|
||
| - name: Warn if GPG verification is skipped | ||
| if: ${{ env.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION == 'true' }} | ||
| run: | | ||
| Write-Host "::warning::GPG verification is SKIPPED for this build. This should only be used in CI/dev builds." | ||
|
|
||
| - name: 'Setup ENV' | ||
| run: | | ||
| $pkg_version = node -e "console.log(require('./apps/desktop/package.json').version)" | ||
| $pkg_version = $pkg_version.Trim() | ||
| Write-Host "pkg_version=$pkg_version" | ||
| "PKG_VERSION=$pkg_version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | ||
| $artifacts_url = "$env:GITHUB_SERVER_URL/$env:GITHUB_REPOSITORY/actions/runs/$env:GITHUB_RUN_ID" | ||
| "ARTIFACTS_URL=$artifacts_url" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| cache: 'yarn' | ||
| registry-url: 'https://npm.pkg.github.com' | ||
| scope: '@onekeyhq' | ||
|
|
||
| - name: Get yarn cache directory path | ||
| id: yarn-cache-dir-path | ||
| shell: pwsh | ||
| run: echo "dir=${{ github.workspace }}/.yarn" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Install Dep | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| yarn install --immutable | ||
|
|
||
| - name: Download Renderer Artifact | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: desktop-renderer-${{ github.sha }} | ||
| path: ./apps/desktop/app/build/ | ||
|
|
||
| - name: Setup Code Signing file | ||
| run: | | ||
| [IO.File]::WriteAllBytes("apps/desktop/sign.p12", [Convert]::FromBase64String("${{ secrets.DESKTOP_KEYS_SECRET }}")) | ||
|
|
||
| # ── Phase 1: Windows NSIS installer ── | ||
|
|
||
| - name: 'Build Main Process (win)' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:main | ||
| yarn install-app-deps | ||
|
|
||
| - name: 'Package Windows NSIS' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| ASC_PROVIDER: ${{ secrets.ASC_PROVIDER }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | ||
| CSC_LINK: './sign.p12' | ||
| run: | | ||
| cd apps/desktop | ||
| npx electron-builder build -w --config electron-builder-win.config.js --publish never | ||
|
|
||
| - name: Upload x64 Windows exe | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-win-x64-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*-x64.exe | ||
|
|
||
| - name: Upload arm64 Windows exe | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-win-arm64-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*-arm64.exe | ||
|
|
||
| - name: Upload Artifacts latest.yml | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-win-yml-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*.yml | ||
|
|
||
| - name: Upload Windows NSIS Release Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-win-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/* | ||
| !./apps/desktop/build-electron/win-unpacked | ||
| !./apps/desktop/build-electron/win-arm64-unpacked | ||
| !./apps/desktop/build-electron/mac-arm64 | ||
| !./apps/desktop/build-electron/mac | ||
| !./apps/desktop/build-electron/linux-unpacked | ||
| !./apps/desktop/build-electron/builder-debug.yml | ||
|
|
||
| # ── Phase 2: Windows Microsoft Store ── | ||
|
|
||
| - name: Clean build-electron for WinMS | ||
| shell: pwsh | ||
| run: Remove-Item -Recurse -Force apps/desktop/build-electron -ErrorAction SilentlyContinue | ||
|
|
||
| - name: 'Rebuild Main Process (winms, DESK_CHANNEL=ms-store)' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| DESK_CHANNEL: ms-store | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:main | ||
|
|
||
| - name: 'Package Windows Microsoft Store' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| APPLEID: ${{ secrets.APPLEID }} | ||
| APPLEIDPASS: ${{ secrets.APPLEIDPASS }} | ||
| ASC_PROVIDER: ${{ secrets.ASC_PROVIDER }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | ||
| DESK_CHANNEL: ms-store | ||
| CSC_LINK: './sign.p12' | ||
| run: | | ||
| cd apps/desktop | ||
| npx electron-builder build -w --config electron-builder-ms.config.js --publish never | ||
|
|
||
| - name: Upload WinMS universal exe | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-winms-universal-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*.exe | ||
| !./apps/desktop/build-electron/*-x64.exe | ||
| !./apps/desktop/build-electron/*-arm64.exe | ||
|
|
||
| # ═══════════════════════════════════════════════════ | ||
| # Linux runner: AppImage + Snap (amd64 + arm64) | ||
| # ═══════════════════════════════════════════════════ | ||
| package-linux: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
To fix the problem, explicitly declare a permissions block in the workflow so the GITHUB_TOKEN used in all jobs is restricted to the least privileges required. Since the workflow primarily checks out code, downloads/upload artifacts, and uses GITHUB_TOKEN as an auth token for package installation and build tooling, the minimal safe and generic setting is contents: read at the workflow level. This applies to all jobs that do not override permissions, including renderer, package-mac, package-win, and package-linux.
The best fix without altering functionality is to add a top-level permissions block just after the on: section (or immediately before/after env:) in .github/workflows/release-desktop-all.yml. This will not interfere with any secrets or steps and will simply constrain the automatically provided GITHUB_TOKEN to read-only repository contents, which is sufficient for actions/checkout, actions/download-artifact, actions/upload-artifact, and actions/setup-node with GitHub Packages. No additional imports or external dependencies are required.
Concretely:
-
Edit
.github/workflows/release-desktop-all.yml. -
Add:
permissions: contents: read
at the workflow root level (aligned with
name,on, andenv), between the existingon:block and theenv:block (or just abovejobs:if you prefer). No other lines need to change.
| @@ -16,6 +16,9 @@ | ||
| type: boolean | ||
| default: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| ONEKEY_ALLOW_SKIP_GPG_VERIFICATION: ${{ github.event.inputs.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION || 'false' }} | ||
|
|
| needs: renderer | ||
| strategy: | ||
| matrix: | ||
| node-version: [24.x] | ||
| arch: [amd64, arm64] | ||
| include: | ||
| - arch: amd64 | ||
| runs-on: ubuntu-24.04 | ||
| build-flag: --x64 | ||
| - arch: arm64 | ||
| runs-on: ubuntu-24.04-arm | ||
| build-flag: --arm64 | ||
| runs-on: ${{ matrix.runs-on }} | ||
| env: | ||
| NODE_ENV: production | ||
| YARN_ENABLE_GLOBAL_CACHE: true | ||
| steps: | ||
| - name: Checkout Source Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| lfs: true | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y libudev-dev | ||
|
|
||
| - name: Run Shared Env Setup | ||
| uses: ./.github/actions/shared-env | ||
| with: | ||
| env_file_name: '.env' | ||
| sentry_project: 'desktop' | ||
| covalent_key: ${{ secrets.COVALENT_KEY }} | ||
| sentry_token: ${{ secrets.SENTRY_TOKEN }} | ||
| sentry_dsn_react_native: ${{ secrets.SENTRY_DSN_REACT_NATIVE }} | ||
| sentry_dsn_web: ${{ secrets.SENTRY_DSN_WEB }} | ||
| sentry_dsn_desktop: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||
| sentry_dsn_mas: ${{ secrets.SENTRY_DSN_MAS }} | ||
| sentry_dsn_snap: ${{ secrets.SENTRY_DSN_SNAP }} | ||
| sentry_dsn_winms: ${{ secrets.SENTRY_DSN_WINMS }} | ||
| sentry_dsn_ext: ${{ secrets.SENTRY_DSN_EXT }} | ||
|
|
||
| - name: Warn if GPG verification is skipped | ||
| if: ${{ env.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION == 'true' }} | ||
| run: | | ||
| echo "::warning::GPG verification is SKIPPED for this build. This should only be used in CI/dev builds." | ||
|
|
||
| - name: Install Snapcraft | ||
| uses: samuelmeuli/action-snapcraft@v2 | ||
|
|
||
| - name: Install snap dependencies for snapcraft build | ||
| run: | | ||
| sudo snap install core24 | ||
| sudo snap install gnome-46-2404 | ||
| sudo snap install mesa-2404 | ||
| sudo snap install gtk-common-themes | ||
|
|
||
| - name: Configure Snapcraft destructive mode | ||
| run: | | ||
| echo "SNAP_DESTRUCTIVE_MODE=true" >> $GITHUB_ENV | ||
|
|
||
| - name: 'Setup ENV' | ||
| run: | | ||
| eval "$(node -e 'const v=require("./apps/desktop/package.json").version; console.log("pkg_version="+v)')" | ||
| echo "PKG_VERSION=$pkg_version" >> $GITHUB_ENV | ||
| artifacts_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" | ||
| echo "ARTIFACTS_URL=$artifacts_url" >> $GITHUB_ENV | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| cache: 'yarn' | ||
| registry-url: 'https://npm.pkg.github.com' | ||
| scope: '@onekeyhq' | ||
|
|
||
| - name: Get yarn cache directory path | ||
| id: yarn-cache-dir-path | ||
| run: echo "dir=${{ github.workspace }}/.yarn" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Install Dep | ||
| env: | ||
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| yarn install --immutable | ||
|
|
||
| - name: Download Renderer Artifact | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: desktop-renderer-${{ github.sha }} | ||
| path: ./apps/desktop/app/build/ | ||
|
|
||
| # ── Phase 1: AppImage (no SNAP) ── | ||
|
|
||
| - name: 'Build Main Process (AppImage)' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:main | ||
| yarn install-app-deps | ||
|
|
||
| - name: 'Package AppImage' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| cd apps/desktop | ||
| npx electron-builder build -l --config electron-builder.config.js ${{ matrix.build-flag }} --publish never | ||
|
|
||
| - name: Upload AppImage Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-linux-appimage-${{ matrix.arch }}-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/*.AppImage | ||
|
|
||
| # ── Phase 2: Snap (SNAP=true) ── | ||
|
|
||
| - name: Clean build-electron for Snap | ||
| run: rm -rf apps/desktop/build-electron | ||
|
|
||
| - name: 'Rebuild Main Process (Snap, SNAP=true)' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| SNAP: true | ||
| run: | | ||
| cd apps/desktop | ||
| yarn build:main | ||
|
|
||
| - name: 'Package Snap' | ||
| env: | ||
| NODE_OPTIONS: '--max_old_space_size=8192' | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| SNAP: true | ||
| run: | | ||
| cd apps/desktop | ||
| npx electron-builder build -l --config electron-builder-snap.config.js ${{ matrix.build-flag }} --publish never | ||
|
|
||
| - name: Upload Snap Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: onekey-desktop-all-snap-${{ matrix.arch }}-${{ env.BUILD_APP_VERSION }}-${{ env.BUILD_NUMBER }}-${{ env.BUILD_BUNDLE_VERSION }}-${{ github.sha }} | ||
| path: | | ||
| ./apps/desktop/build-electron/* | ||
| !./apps/desktop/build-electron/linux-unpacked | ||
| !./apps/desktop/build-electron/linux-arm64-unpacked | ||
| !./apps/desktop/build-electron/builder-debug.yml |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 4 hours ago
In general, you fix this by explicitly specifying a permissions: block either at the workflow root (to apply to all jobs that don’t override it) or per job, limiting the GITHUB_TOKEN to the least privileges needed. For this workflow, the jobs shown only need to read repository contents and possibly packages; they don’t push commits, create releases, or modify issues/PRs. Thus, a root-level permissions: block with contents: read is an appropriate minimal baseline. If the workflow also needs to read from GitHub Packages via the token, adding packages: read is also safe and minimal.
The single best fix without changing functionality is to add a root-level permissions: section just after the on: block and before env:. This will apply to all jobs (including package-linux at line 455 and the Windows/mac jobs referenced in the snippet) and satisfies the CodeQL requirement. The block should specify contents: read (and optionally packages: read if you want to be explicit for private registries). No additional imports, methods, or code changes are needed elsewhere, as this is purely a YAML configuration change.
| @@ -16,6 +16,10 @@ | ||
| type: boolean | ||
| default: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| packages: read | ||
|
|
||
| env: | ||
| ONEKEY_ALLOW_SKIP_GPG_VERIFICATION: ${{ github.event.inputs.ONEKEY_ALLOW_SKIP_GPG_VERIFICATION || 'false' }} | ||
|
|
Summary
build-desktop-renderer.yml: reusable workflow that builds the desktop renderer (webpack) once on ubuntu-24.04release-desktop-all.yml: orchestrator that calls the renderer build, then fans out to 3 platform packaging jobs in parallelPipeline architecture
Optimization
Notes
release-desktop,release-desktop-win, etc.) are untouchedworkflow_dispatchfor now — can be wired todaily-buildlateronekey-desktop-all-*prefix to avoid collision with existing artifactsTest plan
release-desktop-allvia workflow_dispatch