name: E2E Tests on: workflow_dispatch: inputs: skip_llm: description: "Skip LLM-dependent assertions (default: true)" type: boolean default: true jobs: authorize: name: Authorize optional paid E2E runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read steps: - name: Require default branch and allowlisted numeric actor IDs env: GH_TOKEN: ${{ github.token }} REF: ${{ github.ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} ACTOR_ID: ${{ github.actor_id }} TRIGGERING_ACTOR: ${{ github.triggering_actor }} ALLOWED_ACTOR_IDS: ${{ vars.RUNNER_E2E_ALLOWED_ACTOR_IDS }} run: | set -euo pipefail test "$REF" = "refs/heads/$DEFAULT_BRANCH" jq -e 'type == "array" and length > 0 and all(.[]; type == "number" and . > 0 and floor == .)' <<< "${ALLOWED_ACTOR_IDS:-}" >/dev/null triggering_actor_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)" jq -e --argjson candidate "$triggering_actor_id" 'index($candidate) != null' <<< "$ALLOWED_ACTOR_IDS" >/dev/null jq -e --argjson candidate "$ACTOR_ID" 'index($candidate) != null' <<< "$ALLOWED_ACTOR_IDS" >/dev/null e2e: needs: authorize runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: read environment: name: runner-e2e-paid env: PAPERCLIP_E2E_SKIP_LLM: ${{ inputs.skip_llm && 'true' || 'false' }} steps: - name: Reauthorize execution before optional provider access env: GH_TOKEN: ${{ github.token }} REF: ${{ github.ref }} DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} ACTOR_ID: ${{ github.actor_id }} TRIGGERING_ACTOR: ${{ github.triggering_actor }} ALLOWED_ACTOR_IDS: ${{ vars.RUNNER_E2E_ALLOWED_ACTOR_IDS }} run: | set -euo pipefail test "$REF" = "refs/heads/$DEFAULT_BRANCH" jq -e 'type == "array" and length > 0 and all(.[]; type == "number" and . > 0 and floor == .)' <<< "${ALLOWED_ACTOR_IDS:-}" >/dev/null triggering_actor_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)" jq -e --argjson candidate "$triggering_actor_id" 'index($candidate) != null' <<< "$ALLOWED_ACTOR_IDS" >/dev/null jq -e --argjson candidate "$ACTOR_ID" 'index($candidate) != null' <<< "$ALLOWED_ACTOR_IDS" >/dev/null - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6 with: version: 9 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: 24 - run: pnpm install --frozen-lockfile - run: pnpm build - run: google-chrome --version - name: Run e2e tests env: PAPERCLIP_PLAYWRIGHT_CHANNEL: "chrome" ANTHROPIC_API_KEY: ${{ !inputs.skip_llm && secrets.ANTHROPIC_API_KEY || '' }} run: pnpm run test:e2e - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: name: playwright-report path: | tests/e2e/playwright-report/ tests/e2e/test-results/ retention-days: 14