name: Build Desktop

on:
  pull_request:
    types: [opened, synchronize]
    branches-ignore:
      - 'l10n_master'
      - 'cf-pages'
    paths:
      - 'apps/desktop/**'
      - 'libs/**'
      - '*'
      - '!*.md'
      - '!*.txt'
      - '.github/workflows/build-desktop.yml'
  push:
    branches:
      - 'main'
      - 'rc'
      - 'hotfix-rc-desktop'
    paths:
      - 'apps/desktop/**'
      - 'libs/**'
      - '*'
      - '!*.md'
      - '!*.txt'
      - '.github/workflows/build-desktop.yml'
  workflow_call:
    inputs: {}
  workflow_dispatch:
    inputs:
      sdk_branch:
        description: "Custom SDK branch"
        required: false
        type: string

defaults:
  run:
    shell: bash

jobs:
  electron-verify:
    name: Verify Electron Version
    runs-on: ubuntu-22.04
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Verify
        run: |
          PACKAGE_VERSION=$(jq -r .devDependencies.electron package.json)
          ELECTRON_BUILDER_VERSION=$(jq -r .electronVersion ./apps/desktop/electron-builder.json)

          if [[ "$PACKAGE_VERSION" == "$ELECTRON_BUILDER_VERSION"  ]]; then
            echo "Versions matches"
          else
            echo "Version missmatch, package.json: $PACKAGE_VERSION, electron-builder.json: $ELECTRON_BUILDER_VERSION"
            exit 1
          fi

  setup:
    name: Setup
    runs-on: ubuntu-22.04
    outputs:
      package_version: ${{ steps.retrieve-version.outputs.package_version }}
      release_channel: ${{ steps.release-channel.outputs.channel }}
      build_number: ${{ steps.increment-version.outputs.build_number }}
      rc_branch_exists: ${{ steps.branch-check.outputs.rc_branch_exists }}
      hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
      node_version: ${{ steps.retrieve-node-version.outputs.node_version }}
      has_secrets: ${{ steps.check-secrets.outputs.has_secrets }}
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Get Package Version
        id: retrieve-version
        run: |
          PKG_VERSION=$(jq -r .version src/package.json)
          echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT

      - name: Increment Version
        id: increment-version
        run: |
          BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
          echo "Setting build number to $BUILD_NUMBER"
          echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT

      - name: Get Version Channel
        id: release-channel
        run: |
          case "${{ steps.retrieve-version.outputs.package_version }}" in
            *"alpha"*)
              echo "channel=alpha" >> $GITHUB_OUTPUT
              echo "[!] We do not yet support 'alpha'"
              exit 1
              ;;
            *"beta"*)
              echo "channel=beta" >> $GITHUB_OUTPUT
              ;;
            *)
              echo "channel=latest" >> $GITHUB_OUTPUT
              ;;
          esac

      - name: Check if special branches exist
        id: branch-check
        run: |
          if [[ $(git ls-remote --heads origin rc) ]]; then
            echo "rc_branch_exists=1" >> $GITHUB_OUTPUT
          else
            echo "rc_branch_exists=0" >> $GITHUB_OUTPUT
          fi

          if [[ $(git ls-remote --heads origin hotfix-rc-desktop) ]]; then
            echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT
          else
            echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
          fi

      - name: Get Node Version
        id: retrieve-node-version
        working-directory: ./
        run: |
          NODE_NVMRC=$(cat .nvmrc)
          NODE_VERSION=${NODE_NVMRC/v/''}
          echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT

      - name: Check secrets
        id: check-secrets
        env:
          AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
        run: |
          has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }}
          echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT

  linux:
    name: Linux Build
    # Note, before updating the ubuntu version of the workflow, ensure the snap base image
    # is equal or greater than the new version. Otherwise there might be GLIBC version issues.
    # The snap base for desktop is defined in `apps/desktop/electron-builder.json`
    # We intentionally keep this runner on the oldest supported OS in GitHub Actions
    # for maximum compatibility across GLIBC versions
    runs-on: ubuntu-22.04
    needs: setup
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Set up environment
        run: |
          sudo apt-get update
          sudo apt-get -y install pkg-config libxss-dev rpm musl-dev musl-tools flatpak flatpak-builder

      - name: Set up Snap
        run: sudo snap install snapcraft --classic

      - name: Print environment
        run: |
          node --version
          npm --version
          snap --version
          snapcraft --version || echo 'snapcraft unavailable'

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
            ${{ env.RUNNER_TEMP }}/.cargo/registry
            ${{ env.RUNNER_TEMP }}/.cargo/git
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        env:
          PKG_CONFIG_ALLOW_CROSS: true
          PKG_CONFIG_ALL_STATIC: true
          TARGET: musl
        run: |
          rustup target add x86_64-unknown-linux-musl
          node build.js cross-platform

      - name: Build application
        run: npm run dist:lin

      - name: Upload .deb artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-amd64.deb
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-amd64.deb
          if-no-files-found: error

      - name: Upload .rpm artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-x86_64.rpm
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x86_64.rpm
          if-no-files-found: error

      - name: Upload .freebsd artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-x64.freebsd
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64.freebsd
          if-no-files-found: error

      - name: Upload .snap artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: bitwarden_${{ env._PACKAGE_VERSION }}_amd64.snap
          path: apps/desktop/dist/bitwarden_${{ env._PACKAGE_VERSION }}_amd64.snap
          if-no-files-found: error

      - name: Upload .AppImage artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
          if-no-files-found: error

      - name: Upload auto-update artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: ${{ needs.setup.outputs.release_channel }}-linux.yml
          path: apps/desktop/dist/${{ needs.setup.outputs.release_channel }}-linux.yml
          if-no-files-found: error

      - name: Build flatpak
        working-directory: apps/desktop
        run: |
          sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
          sudo npm run pack:lin:flatpak

      - name: Upload flatpak artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: com.bitwarden.desktop.flatpak
          path: apps/desktop/dist/com.bitwarden.desktop.flatpak
          if-no-files-found: error


  windows:
    name: Windows Build
    runs-on: windows-2022
    needs:
      - setup
    defaults:
      run:
        shell: pwsh
        working-directory: apps/desktop
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Install AST
        run: dotnet tool install --global AzureSignTool --version 4.0.1

      - name: Set up environmentF
        run: choco install checksum --no-progress

      - name: Rust
        shell: pwsh
        run: |
          rustup target install i686-pc-windows-msvc
          rustup target install aarch64-pc-windows-msvc

      - name: Print environment
        run: |
          node --version
          npm --version
          choco --version
          rustup show

      - name: Login to Azure
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Retrieve secrets
        id: retrieve-secrets
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: bitwarden/gh-actions/get-keyvault-secrets@main
        with:
          keyvault: "bitwarden-ci"
          secrets: "code-signing-vault-url,
            code-signing-client-id,
            code-signing-tenant-id,
            code-signing-client-secret,
            code-signing-cert-name"

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        run: node build.js cross-platform

      - name: Build
        run: npm run build

      - name: Pack
        if: ${{ needs.setup.outputs.has_secrets == 'false' }}
        run: |
          npm run pack:win

      - name: Pack & Sign (dev)
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        env:
          ELECTRON_BUILDER_SIGN: 1
          SIGNING_VAULT_URL: ${{ steps.retrieve-secrets.outputs.code-signing-vault-url }}
          SIGNING_CLIENT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-client-id }}
          SIGNING_TENANT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-tenant-id }}
          SIGNING_CLIENT_SECRET: ${{ steps.retrieve-secrets.outputs.code-signing-client-secret }}
          SIGNING_CERT_NAME: ${{ steps.retrieve-secrets.outputs.code-signing-cert-name }}
        run: |
          npm run pack:win

      - name: Rename appx files for store
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        run: |
          Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.appx" `
            -Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32-store.appx"
          Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64.appx" `
            -Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64-store.appx"
          Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.appx" `
            -Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64-store.appx"

      - name: Package for Chocolatey
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        run: |
          Copy-Item -Path ./stores/chocolatey -Destination ./dist/chocolatey -Recurse
          Copy-Item -Path ./dist/nsis-web/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe `
          -Destination ./dist/chocolatey

          $checksum = checksum -t sha256 ./dist/chocolatey/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
          $chocoInstall = "./dist/chocolatey/tools/chocolateyinstall.ps1"
          (Get-Content $chocoInstall).replace('__version__', "$env:_PACKAGE_VERSION").replace('__checksum__', $checksum) | Set-Content $chocoInstall
          choco pack ./dist/chocolatey/bitwarden.nuspec --version "$env:_PACKAGE_VERSION" --out ./dist/chocolatey

      - name: Fix NSIS artifact names for auto-updater
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        run: |
          Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z `
            -NewName bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z
          Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z `
            -NewName bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z
          Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z `
            -NewName bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z

      - name: Upload portable exe artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-Portable-${{ env._PACKAGE_VERSION }}.exe
          path: apps/desktop/dist/Bitwarden-Portable-${{ env._PACKAGE_VERSION }}.exe
          if-no-files-found: error

      - name: Upload installer exe artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
          path: apps/desktop/dist/nsis-web/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
          if-no-files-found: error

      - name: Upload appx ia32 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.appx
          if-no-files-found: error

      - name: Upload store appx ia32 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-ia32-store.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32-store.appx
          if-no-files-found: error

      - name: Upload NSIS ia32 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z
          path: apps/desktop/dist/nsis-web/bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z
          if-no-files-found: error

      - name: Upload appx x64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-x64.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64.appx
          if-no-files-found: error

      - name: Upload store appx x64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-x64-store.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64-store.appx
          if-no-files-found: error

      - name: Upload NSIS x64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z
          path: apps/desktop/dist/nsis-web/bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z
          if-no-files-found: error

      - name: Upload appx ARM64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.appx
          if-no-files-found: error

      - name: Upload store appx ARM64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-arm64-store.appx
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64-store.appx
          if-no-files-found: error

      - name: Upload NSIS ARM64 artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z
          path: apps/desktop/dist/nsis-web/bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z
          if-no-files-found: error

      - name: Upload nupkg artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: bitwarden.${{ env._PACKAGE_VERSION }}.nupkg
          path: apps/desktop/dist/chocolatey/bitwarden.${{ env._PACKAGE_VERSION }}.nupkg
          if-no-files-found: error

      - name: Upload auto-update artifact
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: ${{ needs.setup.outputs.release_channel }}.yml
          path: apps/desktop/dist/nsis-web/${{ needs.setup.outputs.release_channel }}.yml
          if-no-files-found: error


  macos-build:
    name: MacOS Build
    runs-on: macos-13
    needs:
      - setup
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Set up Node-gyp
        run: python3 -m pip install setuptools

      - name: Rust
        shell: pwsh
        run: rustup target install aarch64-apple-darwin

      - name: Print environment
        run: |
          node --version
          npm --version
          rustup show
          echo "GitHub ref: $GITHUB_REF"
          echo "GitHub event: $GITHUB_EVENT"

      - name: Cache Build
        id: build-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/desktop/build
          key: ${{ runner.os }}-${{ github.run_id }}-build

      - name: Cache Safari
        id: safari-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/browser/dist/Safari
          key: ${{ runner.os }}-${{ github.run_id }}-safari-extension

      - name: Login to Azure
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Download Provisioning Profiles secrets
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        env:
          ACCOUNT_NAME: bitwardenci
          CONTAINER_NAME: profiles
        run: |
          mkdir -p $HOME/secrets

          az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
            --name bitwarden_desktop_appstore.provisionprofile \
            --file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            --output none

      - name: Get certificates
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        run: |
          mkdir -p $HOME/certificates

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
            jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
            jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12

      - name: Set up keychain
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        env:
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security default-keychain -s build.keychain
          security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security set-keychain-settings -lut 1200 build.keychain

          security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain

      - name: Set up provisioning profiles
        if: ${{ needs.setup.outputs.has_secrets == 'true' }}
        run: |
          cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            $GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile

      - name: Increment version
        shell: pwsh
        env:
          BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
        run: |
          $package = Get-Content -Raw -Path electron-builder.json | ConvertFrom-Json
          $package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER"
          $package | ConvertTo-Json -Depth 32 | Set-Content -Path electron-builder.json
          "### MacOS build number: $env:BUILD_NUMBER" | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' && needs.setup.outputs.has_secrets == 'true' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        run: node build.js cross-platform

      - name: Build application (dev)
        run: npm run build


  browser-build:
    name: Browser Build
    needs: setup
    if: ${{ needs.setup.outputs.has_secrets == 'true' }}
    uses: ./.github/workflows/build-browser.yml
    secrets: inherit


  macos-package-github:
    name: MacOS Package GitHub Release Assets
    runs-on: macos-13
    if: ${{ needs.setup.outputs.has_secrets == 'true' }}
    needs:
      - browser-build
      - macos-build
      - setup
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Set up Node-gyp
        run: python3 -m pip install setuptools

      - name: Rust
        shell: pwsh
        run: rustup target install aarch64-apple-darwin

      - name: Print environment
        run: |
          node --version
          npm --version
          rustup show
          echo "GitHub ref: $GITHUB_REF"
          echo "GitHub event: $GITHUB_EVENT"

      - name: Get Build Cache
        id: build-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/desktop/build
          key: ${{ runner.os }}-${{ github.run_id }}-build

      - name: Setup Safari Cache
        id: safari-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/browser/dist/Safari
          key: ${{ runner.os }}-${{ github.run_id }}-safari-extension

      - name: Login to Azure
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Download Provisioning Profiles secrets
        env:
          ACCOUNT_NAME: bitwardenci
          CONTAINER_NAME: profiles
        run: |
          mkdir -p $HOME/secrets

          az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
            --name bitwarden_desktop_appstore.provisionprofile \
            --file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            --output none

      - name: Get certificates
        run: |
          mkdir -p $HOME/certificates

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
            jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
            jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12

      - name: Set up keychain
        env:
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security default-keychain -s build.keychain
          security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security set-keychain-settings -lut 1200 build.keychain

          security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain

      - name: Set up provisioning profiles
        run: |
          cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            $GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile

      - name: Increment version
        shell: pwsh
        env:
          BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
        run: |
          $package = Get-Content -Raw -Path electron-builder.json | ConvertFrom-Json
          $package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER"
          $package | ConvertTo-Json -Depth 32 | Set-Content -Path electron-builder.json
          Write-Output "### MacOS GitHub build number: $env:BUILD_NUMBER"

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        run: node build.js cross-platform

      - name: Build
        if: steps.build-cache.outputs.cache-hit != 'true'
        run: npm run build

      - name: Download Browser artifact
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          path: ${{ github.workspace }}/browser-build-artifacts

      - name: Unzip Safari artifact
        run: |
          SAFARI_DIR=$(find $GITHUB_WORKSPACE/browser-build-artifacts -name 'dist-safari-*.zip')
          echo $SAFARI_DIR
          unzip $SAFARI_DIR/dist-safari.zip -d $GITHUB_WORKSPACE/browser-build-artifacts

      - name: Load Safari extension for .dmg
        run: |
          mkdir PlugIns
          cp -r $GITHUB_WORKSPACE/browser-build-artifacts/Safari/dmg/build/Release/safari.appex PlugIns/safari.appex

      - name: Set up private auth key
        run: |
          mkdir ~/private_keys
          cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
          ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }}
          EOF

      - name: Build application (dist)
        env:
          APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}
          APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP
          APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8
          CSC_FOR_PULL_REQUEST: true
        run: npm run pack:mac

      - name: Upload .zip artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-universal-mac.zip
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-universal-mac.zip
          if-no-files-found: error

      - name: Upload .dmg artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-universal.dmg
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-universal.dmg
          if-no-files-found: error

      - name: Upload .dmg blockmap artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-universal.dmg.blockmap
          path: apps/desktop/dist/Bitwarden-${{ env._PACKAGE_VERSION }}-universal.dmg.blockmap
          if-no-files-found: error

      - name: Upload auto-update artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: ${{ needs.setup.outputs.release_channel }}-mac.yml
          path: apps/desktop/dist/${{ needs.setup.outputs.release_channel }}-mac.yml
          if-no-files-found: error


  macos-package-mas:
    name: MacOS Package Prod Release Asset
    runs-on: macos-13
    if: ${{ needs.setup.outputs.has_secrets == 'true' }}
    needs:
      - browser-build
      - macos-build
      - setup
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Set up Node-gyp
        run: python3 -m pip install setuptools

      - name: Rust
        shell: pwsh
        run: rustup target install aarch64-apple-darwin

      - name: Print environment
        run: |
          node --version
          npm --version
          rustup show
          echo "GitHub ref: $GITHUB_REF"
          echo "GitHub event: $GITHUB_EVENT"

      - name: Get Build Cache
        id: build-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/desktop/build
          key: ${{ runner.os }}-${{ github.run_id }}-build

      - name: Setup Safari Cache
        id: safari-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/browser/dist/Safari
          key: ${{ runner.os }}-${{ github.run_id }}-safari-extension

      - name: Login to Azure
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Retrieve Slack secret
        id: retrieve-slack-secret
        uses: bitwarden/gh-actions/get-keyvault-secrets@main
        with:
          keyvault: bitwarden-ci
          secrets: "slack-bot-token"

      - name: Download Provisioning Profiles secrets
        env:
          ACCOUNT_NAME: bitwardenci
          CONTAINER_NAME: profiles
        run: |
          mkdir -p $HOME/secrets

          az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
            --name bitwarden_desktop_appstore.provisionprofile \
            --file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            --output none

      - name: Get certificates
        run: |
          mkdir -p $HOME/certificates

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
            jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
            jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12

      - name: Set up keychain
        env:
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security default-keychain -s build.keychain
          security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security set-keychain-settings -lut 1200 build.keychain

          security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain

      - name: Set up provisioning profiles
        run: |
          cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            $GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile

      - name: Increment version
        shell: pwsh
        env:
          BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
        run: |
          $package = Get-Content -Raw -Path electron-builder.json | ConvertFrom-Json
          $package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER"
          $package | ConvertTo-Json -Depth 32 | Set-Content -Path electron-builder.json
          Write-Output "### MacOS App Store build number: $env:BUILD_NUMBER"

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        run: node build.js cross-platform

      - name: Build
        if: steps.build-cache.outputs.cache-hit != 'true'
        run: npm run build

      - name: Download Browser artifact
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          path: ${{ github.workspace }}/browser-build-artifacts

      - name: Unzip Safari artifact
        run: |
          SAFARI_DIR=$(find $GITHUB_WORKSPACE/browser-build-artifacts -name 'dist-safari-*.zip')
          echo $SAFARI_DIR
          unzip $SAFARI_DIR/dist-safari.zip -d $GITHUB_WORKSPACE/browser-build-artifacts

      - name: Load Safari extension for App Store
        run: |
          mkdir PlugIns
          cp -r $GITHUB_WORKSPACE/browser-build-artifacts/Safari/mas/build/Release/safari.appex PlugIns/safari.appex

      - name: Set up private auth key
        run: |
          mkdir ~/private_keys
          cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
          ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }}
          EOF

      - name: Build application for App Store
        env:
          APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}
          APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP
          APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8
          CSC_FOR_PULL_REQUEST: true
        run: npm run pack:mac:mas

      - name: Upload .pkg artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-universal.pkg
          path: apps/desktop/dist/mas-universal/Bitwarden-${{ env._PACKAGE_VERSION }}-universal.pkg
          if-no-files-found: error

      - name: Deploy to TestFlight
        id: testflight-deploy
        if: |
          github.event_name != 'pull_request_target'
          && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-desktop')
        env:
          APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}
          APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP
        run: |
          xcrun altool \
            --upload-app \
            --type macos \
            --file "$(find ./dist/mas-universal/Bitwarden*.pkg)" \
            --apiKey $APP_STORE_CONNECT_AUTH_KEY \
            --apiIssuer $APP_STORE_CONNECT_TEAM_ISSUER

      - name: Post message to a Slack channel
        id: slack-message
        if: |
          github.event_name != 'pull_request_target'
          && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-desktop')
        uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
        with:
          channel-id: C074F5UESQ0
          method: chat.postMessage
          token: ${{ steps.retrieve-slack-secret.outputs.slack-bot-token }}
          payload: |
            {
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "Desktop client v${{ env._PACKAGE_VERSION }} <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|build ${{ env.BUILD_NUMBER }}> success on *${{ github.ref_name }}*"
                  }
                }
              ]
            }
        env:
          BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}


  macos-package-dev:
    name: MacOS Package Dev Release Asset
    runs-on: macos-13
    if: ${{ needs.setup.outputs.has_secrets == 'true' }}
    needs:
      - browser-build
      - macos-build
      - setup
    env:
      _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
      _NODE_VERSION: ${{ needs.setup.outputs.node_version }}
      NODE_OPTIONS: --max_old_space_size=4096
    defaults:
      run:
        working-directory: apps/desktop
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Set up Node
        uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
        with:
          cache: 'npm'
          cache-dependency-path: '**/package-lock.json'
          node-version: ${{ env._NODE_VERSION }}

      - name: Set up Node-gyp
        run: python3 -m pip install setuptools

      - name: Print environment
        run: |
          node --version
          npm --version
          echo "GitHub ref: $GITHUB_REF"
          echo "GitHub event: $GITHUB_EVENT"

      - name: Get Build Cache
        id: build-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/desktop/build
          key: ${{ runner.os }}-${{ github.run_id }}-build

      - name: Setup Safari Cache
        id: safari-cache
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        with:
          path: apps/browser/dist/Safari
          key: ${{ runner.os }}-${{ github.run_id }}-safari-extension

      - name: Login to Azure
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Download Provisioning Profiles secrets
        env:
          ACCOUNT_NAME: bitwardenci
          CONTAINER_NAME: profiles
        run: |
          mkdir -p $HOME/secrets

          az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
            --name bitwarden_desktop_appstore.provisionprofile \
            --file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            --output none

      - name: Get certificates
        run: |
          mkdir -p $HOME/certificates

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
            jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
            jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12

          az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
            jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12

      - name: Set up keychain
        env:
          KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
        run: |
          security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security default-keychain -s build.keychain
          security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
          security set-keychain-settings -lut 1200 build.keychain

          security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-app-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/appstore-installer-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
            -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild

          security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain

      - name: Set up provisioning profiles
        run: |
          cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
            $GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile

      - name: Increment version
        shell: pwsh
        env:
          BUILD_NUMBER: ${{ needs.setup.outputs.build_number }}
        run: |
          $package = Get-Content -Raw -Path electron-builder.json | ConvertFrom-Json
          $package | Add-Member -MemberType NoteProperty -Name buildVersion -Value "$env:BUILD_NUMBER"
          $package | ConvertTo-Json -Depth 32 | Set-Content -Path electron-builder.json
          Write-Output "### MacOS Dev build number: $env:BUILD_NUMBER"

      - name: Install Node dependencies
        run: npm ci
        working-directory: ./

      - name: Download SDK Artifacts
        if: ${{ inputs.sdk_branch != '' }}
        uses: bitwarden/gh-actions/download-artifacts@main
        with:
          github_token: ${{secrets.GITHUB_TOKEN}}
          workflow: build-wasm-internal.yml
          workflow_conclusion: success
          branch: ${{ inputs.sdk_branch }}
          artifacts: sdk-internal
          repo: bitwarden/sdk-internal
          path: ../sdk-internal
          if_no_artifact_found: fail

      - name: Override SDK
        if: ${{ inputs.sdk_branch != '' }}
        working-directory: ./
        run: |
          ls -l ../
          npm link ../sdk-internal

      - name: Cache Native Module
        uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
        id: cache
        with:
          path: |
            apps/desktop/desktop_native/napi/*.node
            apps/desktop/desktop_native/dist/*
          key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}

      - name: Build Native Module
        if: steps.cache.outputs.cache-hit != 'true'
        working-directory: apps/desktop/desktop_native
        run: node build.js cross-platform

      - name: Build
        if: steps.build-cache.outputs.cache-hit != 'true'
        run: npm run build

      - name: Download Browser artifact
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
        with:
          path: ${{ github.workspace }}/browser-build-artifacts

      - name: Unzip Safari artifact
        run: |
          SAFARI_DIR=$(find $GITHUB_WORKSPACE/browser-build-artifacts -name 'dist-safari-*.zip')
          echo $SAFARI_DIR
          unzip $SAFARI_DIR/dist-safari.zip -d $GITHUB_WORKSPACE/browser-build-artifacts

      - name: Load Safari extension for App Store
        run: |
          mkdir PlugIns
          cp -r $GITHUB_WORKSPACE/browser-build-artifacts/Safari/masdev/build/Release/safari.appex PlugIns/safari.appex

      - name: Set up private auth key
        run: |
          mkdir ~/private_keys
          cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
          ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }}
          EOF

      - name: Build dev application for App Store
        env:
          APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}
          APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8
        run: npm run pack:mac:masdev

      - name: Zip masdev asset
        run: |
          cd dist/mas-dev-universal
          zip -r Bitwarden-${{ env._PACKAGE_VERSION }}-masdev-universal.zip Bitwarden.app

      - name: Upload masdev artifact
        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
        with:
          name: Bitwarden-${{ env._PACKAGE_VERSION }}-masdev-universal.zip
          path: apps/desktop/dist/mas-dev-universal/Bitwarden-${{ env._PACKAGE_VERSION }}-masdev-universal.zip
          if-no-files-found: error


  crowdin-push:
    name: Crowdin Push
    if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main'
    needs:
      - linux
      - windows
      - macos-package-github
      - macos-package-mas
    runs-on: ubuntu-22.04
    steps:
      - name: Check out repo
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          ref: ${{  github.event.pull_request.head.sha }}

      - name: Login to Azure
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Retrieve secrets
        id: retrieve-secrets
        uses: bitwarden/gh-actions/get-keyvault-secrets@main
        with:
          keyvault: "bitwarden-ci"
          secrets: "crowdin-api-token"

      - name: Upload Sources
        uses: crowdin/github-action@30849777a3cba6ee9a09e24e195272b8287a0a5b # v1.20.4
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
          CROWDIN_PROJECT_ID: "299360"
        with:
          config: apps/desktop/crowdin.yml
          crowdin_branch_name: main
          upload_sources: true
          upload_translations: false


  check-failures:
    name: Check for failures
    if: always()
    runs-on: ubuntu-22.04
    needs:
      - electron-verify
      - browser-build
      - setup
      - linux
      - windows
      - macos-build
      - macos-package-github
      - macos-package-mas
      - crowdin-push
    steps:
      - name: Check if any job failed
        if: |
          github.event_name != 'pull_request_target'
          && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-desktop')
          && contains(needs.*.result, 'failure')
        run: exit 1

      - name: Login to Azure - Prod Subscription
        uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
        if: failure()
        with:
          creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}

      - name: Retrieve secrets
        id: retrieve-secrets
        if: failure()
        uses: bitwarden/gh-actions/get-keyvault-secrets@main
        with:
          keyvault: "bitwarden-ci"
          secrets: "devops-alerts-slack-webhook-url"

      - name: Notify Slack on failure
        uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
        if: failure()
        env:
          SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
        with:
          status: ${{ job.status }}
