# This workflow will run in the context of the source of the PR. # On a PR from a fork, the workflow will not have access to secrets, and so any parts of the build that require secrets will not run. # If additional artifacts are needed, the failed "build-cli-target.yml" workflow held up by the check-run should be re-run. name: Build CLI on: pull_request: types: [opened, synchronize] branches-ignore: - 'l10n_master' - 'cf-pages' paths: - 'apps/cli/**' - 'bitwarden_license/bit-cli/**' - 'bitwarden_license/bit-common/**' - 'libs/**' - '*' - '!*.md' - '!*.txt' - '.github/workflows/build-cli.yml' push: branches: - 'main' - 'rc' - 'hotfix-rc-cli' paths: - 'apps/cli/**' - 'bitwarden_license/bit-cli/**' - 'bitwarden_license/bit-common/**' - 'libs/**' - '*' - '!*.md' - '!*.txt' - '.github/workflows/build-cli.yml' workflow_call: inputs: {} workflow_dispatch: inputs: sdk_branch: description: "Custom SDK branch" required: false type: string defaults: run: working-directory: apps/cli permissions: contents: read jobs: setup: name: Setup runs-on: ubuntu-24.04 outputs: package_version: ${{ steps.retrieve-package-version.outputs.package_version }} node_version: ${{ steps.retrieve-node-version.outputs.node_version }} has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} steps: - name: Check out repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - name: Get Package Version id: retrieve-package-version run: | PKG_VERSION=$(jq -r .version package.json) echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT" - 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 run: | has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }} echo "has_secrets=$has_secrets" >> "$GITHUB_OUTPUT" cli: name: CLI ${{ matrix.os.base }}${{ matrix.os.target_suffix }} - ${{ matrix.license_type.readable }} strategy: matrix: os: [ { base: "linux", distro: "ubuntu-22.04", target_suffix: "" }, { base: "linux", distro: "ubuntu-22.04-arm", target_suffix: "-arm64" }, { base: "mac", distro: "macos-15-intel", target_suffix: "" }, { base: "mac", distro: "macos-15", target_suffix: "-arm64" } ] license_type: [ { type: "oss", build_prefix: "oss", artifact_prefix: "-oss", readable: "open source license" }, { type: "commercial", build_prefix: "bit", artifact_prefix: "", readable: "commercial license" } ] runs-on: ${{ matrix.os.distro }} needs: setup env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} _WIN_PKG_FETCH_VERSION: 22.15.1 _WIN_PKG_VERSION: 3.5 permissions: contents: read id-token: write steps: - name: Check out repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - name: Setup Unix Vars run: | LOWER_RUNNER_OS="$(printf '%s' "$RUNNER_OS" | awk '{print tolower($0)}')" SHORT_RUNNER_OS="$(printf '%s' "$RUNNER_OS" | awk '{print substr($0, 1, 3)}' | awk '{print tolower($0)}')" { echo "LOWER_RUNNER_OS=$LOWER_RUNNER_OS" echo "SHORT_RUNNER_OS=$SHORT_RUNNER_OS" } >> "$GITHUB_ENV" - name: Set up Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: cache: 'npm' cache-dependency-path: '**/package-lock.json' node-version: ${{ env._NODE_VERSION }} - name: Install run: npm ci working-directory: ./ - name: Remove commercial packages if: ${{ matrix.license_type.type == 'oss' }} run: rm -rf node_modules/@bitwarden/commercial-sdk-internal 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: Build & Package Unix env: _SHORT_RUNNER_OS: ${{ env.SHORT_RUNNER_OS }} run: npm run "dist:${{ matrix.license_type.build_prefix }}:$_SHORT_RUNNER_OS${{ matrix.os.target_suffix }}" --quiet - name: Login to Azure if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} uses: bitwarden/gh-actions/azure-login@main with: subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} tenant_id: ${{ secrets.AZURE_TENANT_ID }} client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Get certificates if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} run: | mkdir -p "$HOME/certificates" 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" - name: Get Azure Key Vault secrets id: get-kv-secrets if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} uses: bitwarden/gh-actions/get-keyvault-secrets@main with: keyvault: gh-clients secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER" - name: Log out from Azure uses: bitwarden/gh-actions/azure-logout@main - name: Set up keychain if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.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/devid-app-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: Sign binary if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: MACOS_CERTIFICATE_NAME: "Developer ID Application: 8bit Solutions LLC" _LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }} run: codesign --sign "$MACOS_CERTIFICATE_NAME" --verbose=3 --force --options=runtime --entitlements ./entitlements.plist --timestamp "./dist/${{ matrix.license_type.build_prefix }}/$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}/bw" - name: Zip Unix env: _LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }} _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} run: | cd "./dist/${{ matrix.license_type.build_prefix }}/$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}" zip "../../bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" ./bw - name: Set up private auth key if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: _APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }} run: | mkdir ~/private_keys cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8 $_APP_STORE_CONNECT_AUTH_KEY EOF - name: Notarize app if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }} APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8 _LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }} run: | echo "Create keychain profile" xcrun notarytool store-credentials "notarytool-profile" --key-id "$APP_STORE_CONNECT_AUTH_KEY" --key "$APP_STORE_CONNECT_AUTH_KEY_PATH" --issuer "$APP_STORE_CONNECT_TEAM_ISSUER" codesign --sign "Developer ID Application: 8bit Solutions LLC" --verbose=3 --force --options=runtime --timestamp "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" echo "Notarize app" xcrun notarytool submit "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" --keychain-profile "notarytool-profile" --wait - name: Version Test env: _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} _LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }} run: | unzip "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" -d "./test" testVersion=$(./test/bw -v) echo "version: $_PACKAGE_VERSION" echo "testVersion: $testVersion" if [[ $testVersion != "$_PACKAGE_VERSION" ]]; then echo "Version test failed." exit 1 fi - name: Upload unix zip asset uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip path: apps/cli/dist/bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip if-no-files-found: error # We want to confirm the CLI is runnable using the dependencies defined in `apps/cli/package.json`. - name: Remove node_modules (root) run: rm -rf node_modules working-directory: ./ - name: Remove package.json (root) run: rm package.json working-directory: ./ - name: Install (CLI) run: npm i - name: Output help run: node ./build/bw.js --help cli-windows: name: Windows - ${{ matrix.license_type.readable }} strategy: matrix: license_type: [ { type: "oss", build_prefix: "oss", artifact_prefix: "-oss", readable: "open source license" }, { type: "commercial", build_prefix: "bit", artifact_prefix: "", readable: "commercial license" } ] runs-on: windows-2022 permissions: contents: read id-token: write needs: setup env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} _WIN_PKG_FETCH_VERSION: 22.15.1 _WIN_PKG_VERSION: 3.5 steps: - name: Check out repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - name: Install AST run: dotnet tool install --global AzureSignTool --version 4.0.1 - name: Setup Windows builder run: | choco install checksum --no-progress choco install reshack --no-progress choco install nasm --no-progress - name: Set up Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: cache: 'npm' cache-dependency-path: '**/package-lock.json' node-version: ${{ env._NODE_VERSION }} - name: Get pkg-fetch shell: pwsh run: | cd $HOME $fetchedUrl = "https://github.com/yao-pkg/pkg-fetch/releases/download/v$env:_WIN_PKG_VERSION/node-v$env:_WIN_PKG_FETCH_VERSION-win-x64" New-Item -ItemType directory -Path .\.pkg-cache New-Item -ItemType directory -Path .\.pkg-cache\v$env:_WIN_PKG_VERSION Invoke-RestMethod -Uri $fetchedUrl ` -OutFile ".\.pkg-cache\v$env:_WIN_PKG_VERSION\fetched-v$env:_WIN_PKG_FETCH_VERSION-win-x64" - name: Setup Version Info shell: pwsh run: | $major,$minor,$patch = $env:_PACKAGE_VERSION.split('.') $versionInfo = @" 1 VERSIONINFO FILEVERSION $major,$minor,$patch,0 PRODUCTVERSION $major,$minor,$patch,0 FILEOS 0x40004 FILETYPE 0x1 { BLOCK "StringFileInfo" { BLOCK "040904b0" { VALUE "CompanyName", "Bitwarden Inc." VALUE "ProductName", "Bitwarden" VALUE "FileDescription", "Bitwarden CLI" VALUE "FileVersion", "$env:_PACKAGE_VERSION" VALUE "ProductVersion", "$env:_PACKAGE_VERSION" VALUE "OriginalFilename", "bw.exe" VALUE "InternalName", "bw" VALUE "LegalCopyright", "Copyright Bitwarden Inc." } } BLOCK "VarFileInfo" { VALUE "Translation", 0x0409 0x04B0 } } "@ $versionInfo | Out-File ./version-info.rc # https://github.com/vercel/pkg-fetch/issues/188 - name: Resource Hacker shell: cmd run: | set PATH=%PATH%;C:\Program Files (x86)\Resource Hacker set WIN_PKG=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\fetched-v%_WIN_PKG_FETCH_VERSION%-win-x64 set WIN_PKG_BUILT=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\built-v%_WIN_PKG_FETCH_VERSION%-win-x64 copy %WIN_PKG% %WIN_PKG_BUILT% ResourceHacker -open %WIN_PKG_BUILT% -save %WIN_PKG_BUILT% -action delete -mask ICONGROUP,1, ResourceHacker -open version-info.rc -save version-info.res -action compile ResourceHacker -open %WIN_PKG_BUILT% -save %WIN_PKG_BUILT% -action addoverwrite -resource version-info.res - name: Log in to Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} uses: bitwarden/gh-actions/azure-login@main with: subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} tenant_id: ${{ secrets.AZURE_TENANT_ID }} client_id: ${{ secrets.AZURE_CLIENT_ID }} - 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: Log out from Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} uses: bitwarden/gh-actions/azure-logout@main - name: Install run: npm ci working-directory: ./ - name: Remove commercial packages if: ${{ matrix.license_type.type == 'oss' }} run: Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "node_modules/@bitwarden/commercial-sdk-internal" 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: Build & Package Windows run: npm run dist:${{ matrix.license_type.build_prefix }}:win --quiet - name: Sign executable if: ${{ needs.setup.outputs.has_secrets == 'true' }} shell: pwsh env: 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 }} EXE_PATH: dist/${{ matrix.license_type.build_prefix }}/windows/bw.exe run: . .\scripts\sign-cli.ps1 - name: Package Chocolatey shell: pwsh if: ${{ matrix.license_type.build_prefix == 'bit' }} env: _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} run: | Copy-Item -Path stores/chocolatey -Destination dist/chocolatey -Recurse Copy-Item dist/${{ matrix.license_type.build_prefix }}/windows/bw.exe -Destination dist/chocolatey/tools Copy-Item ${{ github.workspace }}/LICENSE.txt -Destination dist/chocolatey/tools choco pack dist/chocolatey/bitwarden-cli.nuspec --version "$env:_PACKAGE_VERSION" --out dist/chocolatey - name: Zip Windows shell: cmd run: 7z a ./dist/bw${{ matrix.license_type.artifact_prefix}}-windows-%_PACKAGE_VERSION%.zip ./dist/${{ matrix.license_type.build_prefix }}/windows/bw.exe - name: Version Test run: | dir ./dist/ Expand-Archive -Path "./dist/bw${{ matrix.license_type.artifact_prefix }}-windows-${env:_PACKAGE_VERSION}.zip" -DestinationPath "./test/${{ matrix.license_type.build_prefix }}/windows" $testVersion = Invoke-Expression '& ./test/${{ matrix.license_type.build_prefix }}/windows/bw.exe -v' echo "version: $env:_PACKAGE_VERSION" echo "testVersion: $testVersion" if($testVersion -ne $env:_PACKAGE_VERSION) { Throw "Version test failed." } - name: Upload windows zip asset uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: bw${{ matrix.license_type.artifact_prefix }}-windows-${{ env._PACKAGE_VERSION }}.zip path: apps/cli/dist/bw${{ matrix.license_type.artifact_prefix }}-windows-${{ env._PACKAGE_VERSION }}.zip if-no-files-found: error - name: Upload Chocolatey asset if: matrix.license_type.build_prefix == 'bit' uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: bitwarden-cli.${{ env._PACKAGE_VERSION }}.nupkg path: apps/cli/dist/chocolatey/bitwarden-cli.${{ env._PACKAGE_VERSION }}.nupkg if-no-files-found: error - name: Zip NPM Build Artifact env: _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} run: Get-ChildItem -Path .\build | Compress-Archive -DestinationPath ".\bitwarden-cli-${env:_PACKAGE_VERSION}-npm-build.zip" - name: Upload NPM Build Directory asset if: matrix.license_type.build_prefix == 'bit' uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: bitwarden-cli-${{ env._PACKAGE_VERSION }}-npm-build.zip path: apps/cli/bitwarden-cli-${{ env._PACKAGE_VERSION }}-npm-build.zip if-no-files-found: error snap: name: Build Snap # 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 CLI is defined in `apps/cli/stores/snap/snapcraft.yaml` runs-on: ubuntu-22.04 needs: [setup, cli] env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} steps: - name: Check out repo uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - name: Print environment env: _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} run: | whoami echo "GitHub ref: $GITHUB_REF" echo "GitHub event: $GITHUB_EVENT" echo "BW Package Version: $_PACKAGE_VERSION" - name: Get bw linux cli uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: bw-linux-${{ env._PACKAGE_VERSION }}.zip path: apps/cli/dist/snap - name: Setup Snap Package env: _PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }} run: | cp -r stores/snap/* -t dist/snap sed -i "s/__version__/$_PACKAGE_VERSION/g" "dist/snap/snapcraft.yaml" cd dist/snap ls -alth - name: Build snap uses: snapcore/action-build@3bdaa03e1ba6bf59a65f84a751d943d549a54e79 # v1.3.0 with: path: apps/cli/dist/snap - name: Install Snap run: sudo snap install dist/snap/bw*.snap --dangerous - name: Test Snap shell: pwsh run: | $testVersion = Invoke-Expression '& bw -v' if($testVersion -ne $env:_PACKAGE_VERSION) { Throw "Version test failed." } env: BITWARDENCLI_APPDATA_DIR: "/home/runner/snap/bw/x1/.config/Bitwarden CLI" - name: Cleanup Test & Update Snap for Publish shell: pwsh run: sudo snap remove bw - name: Upload snap asset uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: bw_${{ env._PACKAGE_VERSION }}_amd64.snap path: apps/cli/dist/snap/bw_${{ env._PACKAGE_VERSION }}_amd64.snap if-no-files-found: error check-failures: name: Check for failures if: always() runs-on: ubuntu-24.04 permissions: contents: read id-token: write needs: - setup - cli - cli-windows - snap steps: - name: Check if any job failed working-directory: ${{ github.workspace }} if: | github.event_name != 'pull_request_target' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-cli') && contains(needs.*.result, 'failure') run: exit 1 - name: Log in to Azure if: failure() uses: bitwarden/gh-actions/azure-login@main with: subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} tenant_id: ${{ secrets.AZURE_TENANT_ID }} client_id: ${{ secrets.AZURE_CLIENT_ID }} - 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: Log out from Azure if: failure() uses: bitwarden/gh-actions/azure-logout@main - 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 }}