feat(clerk-js): Add initial protect integration #22430
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| merge_group: | |
| pull_request: | |
| branches: | |
| - main | |
| - release/v4 | |
| - vincent-and-the-doctor | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Check triggering actor permissions to prevent PRs from forks accessing secrets by default, preventing them from exfiltrating secrets for malicious purposes | |
| check-permissions: | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| name: Check Permissions | |
| steps: | |
| - name: Skip permission check for same‑repo PRs | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }} | |
| run: echo "Permission check not required." | |
| - name: Get User Permission | |
| if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} | |
| id: checkAccess | |
| uses: actions-cool/check-user-permission@v2 | |
| with: | |
| require: write | |
| username: ${{ github.triggering_actor }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check User Permission | |
| if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && steps.checkAccess.outputs.require-result == 'false' }} | |
| run: | | |
| echo "${{ github.triggering_actor }} does not have permissions on this repo." | |
| echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}" | |
| echo "Job originally triggered by ${{ github.actor }}" | |
| exit 1 | |
| pre-checks: | |
| needs: [check-permissions] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| name: Formatting | Dedupe | Changeset | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| timeout-minutes: ${{ vars.TIMEOUT_MINUTES_NORMAL && fromJSON(vars.TIMEOUT_MINUTES_NORMAL) || 5 }} | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup | |
| id: config | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| - name: Verify lockfile is deduped | |
| run: pnpm dedupe --check | |
| - name: Check Formatting | |
| run: pnpm format:check | |
| - name: Require Changeset | |
| if: ${{ !(github.event_name == 'merge_group') }} | |
| run: | | |
| if [[ "${{ github.event.pull_request.user.login }}" = "clerk-cookie" || "${{ github.event.pull_request.user.login }}" = "renovate[bot]" ]]; then | |
| echo 'Skipping'; | |
| exit 0; | |
| else | |
| pnpm changeset status --since=origin/main; | |
| fi | |
| build-packages: | |
| needs: [check-permissions] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| name: Build Packages | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| shell: bash | |
| timeout-minutes: ${{ vars.TIMEOUT_MINUTES_NORMAL && fromJSON(vars.TIMEOUT_MINUTES_NORMAL) || 10 }} | |
| env: | |
| TURBO_SUMMARIZE: false | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup | |
| id: config | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-summarize: ${{ env.TURBO_SUMMARIZE }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| - name: Turbo Build | |
| run: pnpm turbo build $TURBO_ARGS --only | |
| - name: Upload Turbo Summary | |
| uses: actions/upload-artifact@v4 | |
| if: ${{ env.TURBO_SUMMARIZE == 'true' }} | |
| continue-on-error: true | |
| with: | |
| name: turbo-summary-report-build-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: .turbo/runs | |
| retention-days: 5 | |
| static-analysis: | |
| needs: [check-permissions, build-packages] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| name: Static analysis | |
| permissions: | |
| contents: read | |
| actions: write # needed for actions/upload-artifact | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| timeout-minutes: ${{ vars.TIMEOUT_MINUTES_NORMAL && fromJSON(vars.TIMEOUT_MINUTES_NORMAL) || 10 }} | |
| env: | |
| TURBO_SUMMARIZE: false | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup | |
| id: config | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-summarize: ${{ env.TURBO_SUMMARIZE }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| - name: Check size using bundlewatch | |
| run: pnpm turbo bundlewatch $TURBO_ARGS | |
| env: | |
| BUNDLEWATCH_GITHUB_TOKEN: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }} | |
| CI_REPO_OWNER: ${{ vars.REPO_OWNER }} | |
| CI_REPO_NAME: ${{ vars.REPO_NAME }} | |
| CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }} | |
| CI_BRANCH: ${{ github.ref }} | |
| CI_BRANCH_BASE: refs/heads/main | |
| - name: Lint packages using publint | |
| run: pnpm turbo lint:publint $TURBO_ARGS | |
| - name: Lint types using attw | |
| run: pnpm turbo lint:attw $TURBO_ARGS | |
| - name: Run lint | |
| run: pnpm turbo lint $TURBO_ARGS | |
| - name: Upload Turbo Summary | |
| uses: actions/upload-artifact@v4 | |
| if: ${{ env.TURBO_SUMMARIZE == 'true' }} | |
| continue-on-error: true | |
| with: | |
| name: turbo-summary-report-lint-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: .turbo/runs | |
| retention-days: 5 | |
| unit-tests: | |
| needs: [check-permissions, build-packages] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| name: Unit Tests (${{ matrix.node-version }}, ${{ matrix.filter-label }}${{ matrix.clerk-use-rq == 'true' && ', RQ' || '' }}) | |
| permissions: | |
| contents: read | |
| actions: write # needed for actions/upload-artifact | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| timeout-minutes: ${{ vars.TIMEOUT_MINUTES_NORMAL && fromJSON(vars.TIMEOUT_MINUTES_NORMAL) || 10 }} | |
| env: | |
| TURBO_SUMMARIZE: false | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - node-version: 22 | |
| test-filter: "**" | |
| clerk-use-rq: "false" | |
| filter-label: "**" | |
| - node-version: 22 | |
| test-filter: "--filter=@clerk/shared --filter=@clerk/clerk-js" | |
| clerk-use-rq: "true" | |
| filter-label: "shared, clerk-js" | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup | |
| id: config | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| # Ensures that all builds are cached appropriately with a consistent run name `Unit Tests (18)`. | |
| node-version: ${{ matrix.node-version }} | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-summarize: ${{ env.TURBO_SUMMARIZE }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| - name: Rebuild @clerk/shared with CLERK_USE_RQ=true | |
| if: ${{ matrix.clerk-use-rq == 'true' }} | |
| run: pnpm turbo build $TURBO_ARGS --filter=@clerk/shared --force | |
| env: | |
| CLERK_USE_RQ: true | |
| - name: Rebuild dependent packages with CLERK_USE_RQ=true | |
| if: ${{ matrix.clerk-use-rq == 'true' }} | |
| run: pnpm turbo build $TURBO_ARGS --filter=@clerk/shared^... --force | |
| env: | |
| CLERK_USE_RQ: true | |
| - name: Run tests in packages | |
| run: | | |
| if [ "${{ matrix.test-filter }}" = "**" ]; then | |
| echo "Running full test suite on Node ${{ matrix.node-version }}" | |
| pnpm turbo test $TURBO_ARGS | |
| else | |
| echo "Running tests: ${{ matrix.filter-label }}" | |
| pnpm turbo test $TURBO_ARGS ${{ matrix.test-filter }} | |
| fi | |
| env: | |
| NODE_VERSION: ${{ matrix.node-version }} | |
| CLERK_USE_RQ: ${{ matrix.clerk-use-rq }} | |
| - name: Run Typedoc tests | |
| run: | | |
| # Only run Typedoc tests for one matrix version and main test run | |
| if [ "${{ matrix.node-version }}" == "22" ] && [ "${{ matrix.test-filter }}" = "**" ]; then | |
| pnpm test:typedoc | |
| fi | |
| env: | |
| NODE_VERSION: ${{ matrix.node-version }} | |
| - name: Upload Turbo Summary | |
| uses: actions/upload-artifact@v4 | |
| if: ${{ env.TURBO_SUMMARIZE == 'true' }} | |
| continue-on-error: true | |
| with: | |
| name: turbo-summary-report-unit-${{ github.run_id }}-${{ github.run_attempt }}-node-${{ matrix.node-version }}${{ matrix.clerk-use-rq == 'true' && '-rq' || '' }} | |
| path: .turbo/runs | |
| retention-days: 5 | |
| integration-tests: | |
| needs: [check-permissions, build-packages] | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| name: Integration Tests (${{ matrix.test-name }}, ${{ matrix.test-project }}${{ matrix.next-version && format(', {0}', matrix.next-version) || '' }}${{ matrix.clerk-use-rq == 'true' && ', RQ' || '' }}) | |
| permissions: | |
| contents: read | |
| actions: write # needed for actions/upload-artifact | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| timeout-minutes: ${{ vars.TIMEOUT_MINUTES_LONG && fromJSON(vars.TIMEOUT_MINUTES_LONG) || 15 }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test-name: [ | |
| 'generic', | |
| 'express', | |
| 'ap-flows', | |
| 'elements', | |
| 'localhost', | |
| 'sessions', | |
| 'sessions:staging', | |
| 'handshake', | |
| 'handshake:staging', | |
| 'astro', | |
| 'expo-web', | |
| 'tanstack-react-start', | |
| 'vue', | |
| 'nuxt', | |
| 'react-router', | |
| 'machine', | |
| 'custom', | |
| ] | |
| test-project: ["chrome"] | |
| include: | |
| - test-name: 'billing' | |
| test-project: 'chrome' | |
| clerk-use-rq: 'false' | |
| - test-name: 'billing' | |
| test-project: 'chrome' | |
| clerk-use-rq: 'true' | |
| - test-name: 'nextjs' | |
| test-project: 'chrome' | |
| next-version: '14' | |
| - test-name: 'nextjs' | |
| test-project: 'chrome' | |
| next-version: '15' | |
| clerk-use-rq: 'false' | |
| - test-name: 'nextjs' | |
| test-project: 'chrome' | |
| next-version: '15' | |
| clerk-use-rq: 'true' | |
| - test-name: 'nextjs' | |
| test-project: 'chrome' | |
| next-version: '16' | |
| - test-name: 'quickstart' | |
| test-project: 'chrome' | |
| next-version: '15' | |
| - test-name: 'quickstart' | |
| test-project: 'chrome' | |
| next-version: '16' | |
| steps: | |
| - name: Checkout Repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup | |
| id: config | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| playwright-enabled: true | |
| - name: Verify jq is installed | |
| shell: bash | |
| run: | | |
| if ! command -v jq &> /dev/null; then | |
| echo "jq not found, installing..." | |
| sudo apt-get update && sudo apt-get install -y jq | |
| fi | |
| jq --version | |
| - name: Task Status | |
| id: task-status | |
| env: | |
| E2E_APP_CLERK_JS_DIR: ${{runner.temp}} | |
| E2E_CLERK_VERSION: "latest" | |
| E2E_NEXTJS_VERSION: ${{ matrix.next-version }} | |
| E2E_PROJECT: ${{ matrix.test-project }} | |
| INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }} | |
| run: | | |
| # Use turbo's built-in --affected flag to detect changes | |
| # This automatically uses GITHUB_BASE_REF in GitHub Actions | |
| TASK_COUNT=$(pnpm turbo run test:integration:${{ matrix.test-name }} --affected --dry=json 2>/dev/null | jq '.tasks | length' 2>/dev/null || echo "0") | |
| if [ "$TASK_COUNT" -gt 0 ]; then | |
| AFFECTED=1 | |
| else | |
| AFFECTED=0 | |
| fi | |
| echo "affected=${AFFECTED}" | |
| echo "affected=${AFFECTED}" >> $GITHUB_OUTPUT | |
| - name: Rebuild @clerk/shared with CLERK_USE_RQ=true | |
| if: ${{ steps.task-status.outputs.affected == '1' && matrix.clerk-use-rq == 'true' }} | |
| run: pnpm turbo build $TURBO_ARGS --filter=@clerk/shared --force | |
| env: | |
| CLERK_USE_RQ: true | |
| - name: Rebuild dependent packages with CLERK_USE_RQ=true | |
| if: ${{ steps.task-status.outputs.affected == '1' && matrix.clerk-use-rq == 'true' }} | |
| run: pnpm turbo build $TURBO_ARGS --filter=@clerk/shared^... --force | |
| env: | |
| CLERK_USE_RQ: true | |
| - name: Verdaccio | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| uses: ./.github/actions/verdaccio | |
| with: | |
| publish-cmd: | | |
| if [ "$(pnpm config get registry)" = "https://registry.npmjs.org/" ]; then echo 'Error: Using default registry' && exit 1; else CLERK_USE_RQ=${{ matrix.clerk-use-rq }} pnpm turbo build $TURBO_ARGS --only && pnpm changeset publish --no-git-tag; fi | |
| - name: Edit .npmrc [link-workspace-packages=false] | |
| run: sed -i -E 's/link-workspace-packages=(deep|true)/link-workspace-packages=false/' .npmrc | |
| - name: Install @clerk/backend in /integration | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| working-directory: ./integration | |
| run: | | |
| pnpm init | |
| pnpm config set minimum-release-age-exclude @clerk/* | |
| pnpm add @clerk/backend | |
| - name: Install @clerk/clerk-js in os temp | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| working-directory: ${{runner.temp}} | |
| run: | | |
| mkdir clerk-js && cd clerk-js | |
| pnpm init | |
| pnpm config set minimum-release-age-exclude @clerk/* | |
| pnpm add @clerk/clerk-js | |
| - name: Copy components @clerk/astro | |
| if: ${{ matrix.test-name == 'astro' }} | |
| run: cd packages/astro && pnpm copy:components | |
| - name: Write all ENV certificates to files in integration/certs | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| uses: actions/github-script@v7 | |
| env: | |
| INTEGRATION_CERTS: "${{secrets.INTEGRATION_CERTS}}" | |
| INTEGRATION_ROOT_CA: "${{secrets.INTEGRATION_ROOT_CA}}" | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| const rootCa = process.env.INTEGRATION_ROOT_CA; | |
| console.log('rootCa', rootCa); | |
| fs.writeFileSync(path.join(process.env.GITHUB_WORKSPACE, 'integration/certs', 'rootCA.pem'), rootCa); | |
| const certs = JSON.parse(process.env.INTEGRATION_CERTS); | |
| for (const [name, cert] of Object.entries(certs)) { | |
| fs.writeFileSync(path.join(process.env.GITHUB_WORKSPACE, 'integration/certs', name), cert); | |
| } | |
| - name: LS certs | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| working-directory: ./integration/certs | |
| run: ls -la && pwd | |
| - name: Run Integration Tests | |
| if: ${{ steps.task-status.outputs.affected == '1' }} | |
| id: integration-tests | |
| timeout-minutes: 25 | |
| run: pnpm turbo test:integration:${{ matrix.test-name }} $TURBO_ARGS | |
| env: | |
| E2E_APP_CLERK_JS_DIR: ${{runner.temp}} | |
| E2E_CLERK_VERSION: "latest" | |
| E2E_NEXTJS_VERSION: ${{ matrix.next-version }} | |
| E2E_PROJECT: ${{ matrix.test-project }} | |
| E2E_CLERK_ENCRYPTION_KEY: ${{ matrix.clerk-encryption-key }} | |
| CLERK_USE_RQ: ${{ matrix.clerk-use-rq }} | |
| INTEGRATION_INSTANCE_KEYS: ${{ secrets.INTEGRATION_INSTANCE_KEYS }} | |
| MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }} | |
| NODE_EXTRA_CA_CERTS: ${{ github.workspace }}/integration/certs/rootCA.pem | |
| - name: Upload test-results | |
| if: ${{ cancelled() || failure() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: playwright-traces-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.test-name }}${{ matrix.next-version && format('-next{0}', matrix.next-version) || '' }}${{ matrix.clerk-use-rq == 'true' && '-rq' || '' }} | |
| path: integration/test-results | |
| retention-days: 1 | |
| pkg-pr-new: | |
| name: Publish with pkg-pr-new | |
| if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} | |
| needs: [check-permissions, build-packages] | |
| runs-on: "blacksmith-8vcpu-ubuntu-2204" | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| TURBO_SUMMARIZE: false | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| show-progress: false | |
| - name: Setup Node | |
| uses: ./.github/actions/init-blacksmith | |
| with: | |
| turbo-enabled: true | |
| node-version: 22 | |
| turbo-signature: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} | |
| turbo-summarize: ${{ env.TURBO_SUMMARIZE }} | |
| turbo-team: ${{ vars.TURBO_TEAM }} | |
| turbo-token: ${{ secrets.TURBO_TOKEN }} | |
| - name: Publish with pkg-pr-new | |
| run: pnpm run build && pnpx pkg-pr-new@${{ vars.PKG_PR_NEW_VERSION || '0.0.49' }} publish --compact --pnpm './packages/*' |