|
| 1 | +name: Enterprise E2E (Playwright) |
| 2 | + |
| 3 | +# Enterprise Playwright suite — exercises premium-key gated features (audit, |
| 4 | +# teams, analytics) plus full OAuth + SAML logins via the Keycloak compose |
| 5 | +# stacks under testing/compose. Slow and secret-gated, so it runs in three |
| 6 | +# situations: |
| 7 | +# |
| 8 | +# - PRs that touch proprietary / premium / SSO compose / enterprise tests |
| 9 | +# (path-filtered against .github/config/.files.yaml `proprietary`), |
| 10 | +# - every push to main (post-merge safety net), |
| 11 | +# - on a nightly cron schedule (catches Keycloak image drift, license |
| 12 | +# expiry, upstream proprietary changes), |
| 13 | +# - manual workflow_dispatch. |
| 14 | +# |
| 15 | +# Auto-skipped when secrets.PREMIUM_KEY_ENTERPRISE is missing (forks, dependabot). |
| 16 | + |
| 17 | +on: |
| 18 | + push: |
| 19 | + branches: ["main"] |
| 20 | + pull_request: |
| 21 | + branches: ["main"] |
| 22 | + schedule: |
| 23 | + - cron: "0 4 * * *" |
| 24 | + workflow_dispatch: |
| 25 | + |
| 26 | +concurrency: |
| 27 | + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref_name || github.ref }} |
| 28 | + cancel-in-progress: true |
| 29 | + |
| 30 | +permissions: |
| 31 | + contents: read |
| 32 | + |
| 33 | +jobs: |
| 34 | + files-changed: |
| 35 | + name: detect what files changed |
| 36 | + runs-on: ubuntu-latest |
| 37 | + timeout-minutes: 3 |
| 38 | + outputs: |
| 39 | + proprietary: ${{ steps.changes.outputs.proprietary }} |
| 40 | + steps: |
| 41 | + - name: Harden Runner |
| 42 | + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 |
| 43 | + with: |
| 44 | + egress-policy: audit |
| 45 | + - name: Checkout repository |
| 46 | + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| 47 | + - name: Check for file changes |
| 48 | + uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 |
| 49 | + id: changes |
| 50 | + with: |
| 51 | + filters: .github/config/.files.yaml |
| 52 | + |
| 53 | + playwright-e2e-enterprise: |
| 54 | + # Run on PRs only if relevant files changed; always run on push-to-main, |
| 55 | + # cron, and manual dispatch. Auto-skipped when the secret is missing. |
| 56 | + if: | |
| 57 | + secrets.PREMIUM_KEY_ENTERPRISE != '' && ( |
| 58 | + github.event_name != 'pull_request' || |
| 59 | + needs.files-changed.outputs.proprietary == 'true' |
| 60 | + ) |
| 61 | + needs: files-changed |
| 62 | + runs-on: ubuntu-latest |
| 63 | + timeout-minutes: 45 |
| 64 | + env: |
| 65 | + PREMIUM_KEY: ${{ secrets.PREMIUM_KEY_ENTERPRISE }} |
| 66 | + PREMIUM_ENABLED: "true" |
| 67 | + SYSTEM_ENABLEANALYTICS: "false" |
| 68 | + steps: |
| 69 | + - name: Harden Runner |
| 70 | + uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 |
| 71 | + with: |
| 72 | + egress-policy: audit |
| 73 | + - name: Checkout repository |
| 74 | + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| 75 | + - name: Set up JDK 25 |
| 76 | + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 |
| 77 | + with: |
| 78 | + java-version: "25" |
| 79 | + distribution: "temurin" |
| 80 | + - name: Set up Node.js |
| 81 | + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 |
| 82 | + with: |
| 83 | + node-version: "22" |
| 84 | + cache: "npm" |
| 85 | + cache-dependency-path: frontend/package-lock.json |
| 86 | + - name: Install Task |
| 87 | + uses: go-task/setup-task@3be4020d41929789a01026e0e427a4321ce0ad44 # v2.0.0 |
| 88 | + - name: Install Playwright (chromium only) |
| 89 | + run: task frontend:test:e2e:install -- chromium |
| 90 | + |
| 91 | + # ───────── OAuth round-trip ───────── |
| 92 | + - name: Bring up Keycloak + Stirling-PDF (OAuth) |
| 93 | + working-directory: testing/compose |
| 94 | + run: docker compose -f docker-compose-keycloak-oauth.yml up -d --build |
| 95 | + - name: Wait for OAuth stack ready |
| 96 | + working-directory: testing/compose |
| 97 | + run: | |
| 98 | + for i in $(seq 1 60); do |
| 99 | + if bash validate-oauth-test.sh; then |
| 100 | + exit 0 |
| 101 | + fi |
| 102 | + sleep 5 |
| 103 | + done |
| 104 | + docker compose -f docker-compose-keycloak-oauth.yml logs --tail=200 |
| 105 | + exit 1 |
| 106 | + - name: Run enterprise OAuth Playwright tests |
| 107 | + id: oauth-tests |
| 108 | + run: task frontend:test:e2e -- --project=enterprise --grep "OAuth" |
| 109 | + - name: Tear down OAuth stack |
| 110 | + if: always() |
| 111 | + working-directory: testing/compose |
| 112 | + run: docker compose -f docker-compose-keycloak-oauth.yml down -v |
| 113 | + |
| 114 | + # ───────── SAML round-trip ───────── |
| 115 | + - name: Bring up Keycloak + Stirling-PDF (SAML) |
| 116 | + working-directory: testing/compose |
| 117 | + run: docker compose -f docker-compose-keycloak-saml.yml up -d --build |
| 118 | + - name: Wait for SAML stack ready |
| 119 | + working-directory: testing/compose |
| 120 | + run: | |
| 121 | + for i in $(seq 1 60); do |
| 122 | + if bash validate-saml-test.sh; then |
| 123 | + exit 0 |
| 124 | + fi |
| 125 | + sleep 5 |
| 126 | + done |
| 127 | + docker compose -f docker-compose-keycloak-saml.yml logs --tail=200 |
| 128 | + exit 1 |
| 129 | + - name: Run enterprise SAML Playwright tests |
| 130 | + id: saml-tests |
| 131 | + run: task frontend:test:e2e -- --project=enterprise --grep "SAML" |
| 132 | + - name: Tear down SAML stack |
| 133 | + if: always() |
| 134 | + working-directory: testing/compose |
| 135 | + run: docker compose -f docker-compose-keycloak-saml.yml down -v |
| 136 | + |
| 137 | + # ───────── License-gated feature tests (no IdP needed) ───────── |
| 138 | + - name: Start backend for feature tests (premium-enabled, no SSO) |
| 139 | + env: |
| 140 | + SYSTEM_ENABLEANALYTICS: "false" |
| 141 | + run: | |
| 142 | + nohup ./gradlew :stirling-pdf:bootRun > /tmp/backend-ent.log 2>&1 & |
| 143 | + echo $! > /tmp/backend-ent.pid |
| 144 | + - name: Wait for backend ready |
| 145 | + run: | |
| 146 | + start=$SECONDS |
| 147 | + for i in $(seq 1 300); do |
| 148 | + if curl -fsS http://localhost:8080/api/v1/info/status >/dev/null 2>&1; then |
| 149 | + echo "Backend up after $((SECONDS - start))s" |
| 150 | + exit 0 |
| 151 | + fi |
| 152 | + sleep 2 |
| 153 | + done |
| 154 | + tail -200 /tmp/backend-ent.log || true |
| 155 | + exit 1 |
| 156 | + - name: Run enterprise feature Playwright tests |
| 157 | + id: feature-tests |
| 158 | + run: task frontend:test:e2e -- --project=enterprise --grep "Enterprise license" |
| 159 | + - name: Print backend log on failure |
| 160 | + if: failure() |
| 161 | + run: | |
| 162 | + echo "::group::Enterprise backend log" |
| 163 | + tail -500 /tmp/backend-ent.log || true |
| 164 | + echo "::endgroup::" |
| 165 | + - name: Stop backend |
| 166 | + if: always() |
| 167 | + run: | |
| 168 | + if [ -f /tmp/backend-ent.pid ]; then |
| 169 | + kill "$(cat /tmp/backend-ent.pid)" 2>/dev/null || true |
| 170 | + fi |
| 171 | + - name: Upload Playwright report |
| 172 | + if: always() |
| 173 | + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 |
| 174 | + with: |
| 175 | + name: playwright-report-enterprise-${{ github.run_id }} |
| 176 | + path: frontend/playwright-report/ |
| 177 | + retention-days: 7 |
0 commit comments