From 22d56bb1fbfe5dc856d057e7a7993dbea7154643 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com> Date: Thu, 21 May 2026 16:54:20 +0100 Subject: [PATCH] test Depot runners for team commits (#6394) Co-authored-by: ConnorYoh <40631091+ConnorYoh@users.noreply.github.com> --- .github/config/.files.yaml | 1 - .github/workflows/PR-Auto-Deploy-V2.yml | 38 ++++++++-- .../workflows/PR-Demo-Comment-with-react.yml | 54 ++++++++++++-- .github/workflows/_runner-pick.yml | 65 +++++++++++++++++ .github/workflows/ai-engine.yml | 2 + .github/workflows/aur-publish.yml | 2 +- .github/workflows/backend-build.yml | 8 ++- .github/workflows/build-enterprise.yml | 19 ++++- .github/workflows/build.yml | 1 + .github/workflows/check-licence.yml | 2 + .github/workflows/check-openapi.yml | 8 ++- .github/workflows/deploy-on-v2-commit.yml | 53 ++++++++++++-- .github/workflows/docker-compose-tests.yml | 13 +++- .github/workflows/e2e-live.yml | 12 +++- .github/workflows/e2e-stubbed.yml | 12 +++- .../frontend-backend-licenses-update.yml | 16 +++-- .github/workflows/frontend-validation.yml | 6 +- .github/workflows/multiOSReleases.yml | 17 +++-- .github/workflows/nightly.yml | 6 +- .github/workflows/swagger.yml | 8 ++- .github/workflows/tauri-build.yml | 1 + .github/workflows/test-build-docker.yml | 72 +++++++++++++++++-- .github/workflows/testdriver.yml | 44 +++++++++--- AGENTS.md | 23 ++++++ build.gradle | 7 ++ settings.gradle | 23 ++++++ 26 files changed, 462 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/_runner-pick.yml diff --git a/.github/config/.files.yaml b/.github/config/.files.yaml index 2c825666a..aaa63cc58 100644 --- a/.github/config/.files.yaml +++ b/.github/config/.files.yaml @@ -8,7 +8,6 @@ openapi: &openapi docker-base: &docker-base - docker/base/Dockerfile - - ".github/workflows/push-docker-base.yml" docker: &docker - docker/embedded/Dockerfile diff --git a/.github/workflows/PR-Auto-Deploy-V2.yml b/.github/workflows/PR-Auto-Deploy-V2.yml index f535bd0cd..3f26d889e 100644 --- a/.github/workflows/PR-Auto-Deploy-V2.yml +++ b/.github/workflows/PR-Auto-Deploy-V2.yml @@ -23,9 +23,13 @@ permissions: pull-requests: write jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + check-pr: if: (github.event_name == 'pull_request' && github.event.action != 'closed') || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} outputs: should_deploy: ${{ steps.decide.outputs.should_deploy }} is_fork: ${{ steps.resolve.outputs.is_fork }} @@ -97,8 +101,8 @@ jobs: echo "allow_fork=${allow_fork:-false}" >> $GITHUB_OUTPUT deploy-v2-pr: - needs: check-pr - runs-on: ubuntu-latest + needs: [pick, check-pr] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} if: needs.check-pr.outputs.should_deploy == 'true' && (needs.check-pr.outputs.is_fork == 'false' || needs.check-pr.outputs.allow_fork == 'true') # Concurrency control - only one deployment per PR at a time concurrency: @@ -108,6 +112,10 @@ jobs: contents: read issues: write pull-requests: write + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner @@ -179,7 +187,12 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 # Fetch full history for commit hash detection + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Get version number @@ -224,8 +237,20 @@ jobs: echo "Image needs to be built" fi - - name: Build and push V2 image - if: steps.check-image.outputs.exists == 'false' + - name: Build and push V2 image (Depot) + if: env.USE_DEPOT == 'true' && steps.check-image.outputs.exists == 'false' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/embedded/Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} + build-args: VERSION_TAG=v2-alpha + platforms: linux/amd64 + + - name: Build and push V2 image (Docker fork fallback) + if: env.USE_DEPOT != 'true' && steps.check-image.outputs.exists == 'false' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . @@ -351,7 +376,8 @@ jobs: cleanup-v2-deployment: if: github.event.action == 'closed' - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: contents: read issues: write diff --git a/.github/workflows/PR-Demo-Comment-with-react.yml b/.github/workflows/PR-Demo-Comment-with-react.yml index 2ebf33a6b..a2332d2cf 100644 --- a/.github/workflows/PR-Demo-Comment-with-react.yml +++ b/.github/workflows/PR-Demo-Comment-with-react.yml @@ -34,8 +34,12 @@ permissions: pull-requests: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + check-comment: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: issues: write if: | @@ -175,11 +179,15 @@ jobs: } deploy-pr: - needs: check-comment - runs-on: ubuntu-latest + needs: [pick, check-comment] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: issues: write pull-requests: write + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner @@ -232,7 +240,12 @@ jobs: MAVEN_PUBLIC_URL: ${{ secrets.MAVEN_PUBLIC_URL }} STIRLING_PDF_DESKTOP_UI: false + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Login to Docker Hub @@ -241,7 +254,22 @@ jobs: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - - name: Build and push PR-specific image + - name: Build and push PR-specific image (Depot) + if: env.USE_DEPOT == 'true' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/embedded/Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }} + build-args: | + VERSION_TAG=alpha + PROTOTYPES_BUILD=${{ needs.check-comment.outputs.enable_prototypes }} + platforms: linux/amd64 + + - name: Build and push PR-specific image (Docker fork fallback) + if: env.USE_DEPOT != 'true' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . @@ -255,8 +283,19 @@ jobs: PROTOTYPES_BUILD=${{ needs.check-comment.outputs.enable_prototypes }} platforms: linux/amd64 - - name: Build and push engine image - if: needs.check-comment.outputs.enable_prototypes == 'true' + - name: Build and push engine image (Depot) + if: env.USE_DEPOT == 'true' && needs.check-comment.outputs.enable_prototypes == 'true' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: ./engine + file: ./engine/Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:engine-pr-${{ needs.check-comment.outputs.pr_number }} + platforms: linux/amd64 + + - name: Build and push engine image (Docker fork fallback) + if: env.USE_DEPOT != 'true' && needs.check-comment.outputs.enable_prototypes == 'true' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: ./engine @@ -471,7 +510,8 @@ jobs: handle-label-commands: if: ${{ github.event.issue.pull_request != null }} - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/_runner-pick.yml b/.github/workflows/_runner-pick.yml new file mode 100644 index 000000000..43be06555 --- /dev/null +++ b/.github/workflows/_runner-pick.yml @@ -0,0 +1,65 @@ +name: _runner-pick + +# Tiny reusable workflow that classifies the trigger as either a "fork PR +# from an untrusted contributor" or a "trusted commit" so downstream jobs +# can pick a runner class without each one duplicating the 200-char gate +# expression in their own `runs-on:`. +# +# Caller pattern: +# +# jobs: +# pick: +# uses: ./.github/workflows/_runner-pick.yml +# +# real-work: +# needs: pick +# runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-8' }} +# steps: [...] +# +# Output: +# is_fork: "true" when the trigger is a pull_request from a fork or an +# untrusted author_association, "false" otherwise. + +on: + workflow_call: + outputs: + is_fork: + description: '"true" if the trigger is an untrusted fork PR.' + value: ${{ jobs.pick.outputs.is_fork }} + +permissions: + contents: read + +jobs: + pick: + runs-on: ubuntu-latest + timeout-minutes: 1 + outputs: + is_fork: ${{ steps.decide.outputs.is_fork }} + steps: + - name: Classify the trigger + id: decide + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + HEAD_REPO_FORK: ${{ github.event.pull_request.head.repo.fork }} + AUTHOR_ASSOC: ${{ github.event.pull_request.author_association }} + run: | + set -eu + if [ -z "${PR_NUMBER:-}" ]; then + # Not a pull_request event at all (push, schedule, workflow_dispatch, + # workflow_call from a non-PR trigger) -> trusted by default. + echo "is_fork=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + if [ "${HEAD_REPO_FORK}" = "true" ]; then + echo "is_fork=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + case "${AUTHOR_ASSOC}" in + OWNER|MEMBER|COLLABORATOR) + echo "is_fork=false" >> "$GITHUB_OUTPUT" + ;; + *) + echo "is_fork=true" >> "$GITHUB_OUTPUT" + ;; + esac diff --git a/.github/workflows/ai-engine.yml b/.github/workflows/ai-engine.yml index b4a6e8f3c..8f6d9de30 100644 --- a/.github/workflows/ai-engine.yml +++ b/.github/workflows/ai-engine.yml @@ -17,6 +17,8 @@ jobs: permissions: contents: read pull-requests: write + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/aur-publish.yml b/.github/workflows/aur-publish.yml index a6f86ceae..561c8c2de 100644 --- a/.github/workflows/aur-publish.yml +++ b/.github/workflows/aur-publish.yml @@ -106,7 +106,7 @@ jobs: - name: Publish stirling-pdf-desktop to AUR if: ${{ github.event_name == 'release' || inputs.dry_run == false }} - uses: KSXGitHub/github-actions-deploy-aur@v4.1.3 + uses: KSXGitHub/github-actions-deploy-aur@da03e160361ce01bf087e790b6ffd196d7dccff7 # v4.1.3 with: pkgname: stirling-pdf-desktop pkgbuild: .github/aur/stirling-pdf-desktop/PKGBUILD diff --git a/.github/workflows/backend-build.yml b/.github/workflows/backend-build.yml index 4fba78c6e..faed8eb89 100644 --- a/.github/workflows/backend-build.yml +++ b/.github/workflows/backend-build.yml @@ -13,8 +13,14 @@ permissions: pull-requests: write jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + build: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-8' }} + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/build-enterprise.yml b/.github/workflows/build-enterprise.yml index 9ffcdb67a..344ccef19 100644 --- a/.github/workflows/build-enterprise.yml +++ b/.github/workflows/build-enterprise.yml @@ -17,11 +17,23 @@ name: Enterprise E2E (Playwright) on: workflow_call: + inputs: + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking." + required: false + type: string + default: "8" push: branches: ["main"] schedule: - cron: "0 4 * * *" workflow_dispatch: + inputs: + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking." + required: false + type: string + default: "8" # No `concurrency:` block here on purpose. When this workflow is called via # workflow_call from build.yml, ${{ github.workflow }}/event_name/pr_number @@ -35,13 +47,18 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + playwright-e2e-enterprise: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '8') }} timeout-minutes: 45 env: PREMIUM_KEY: ${{ secrets.PREMIUM_KEY_ENTERPRISE }} PREMIUM_ENABLED: "true" SYSTEM_ENABLEANALYTICS: "false" + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3a2db2a15..feb934e97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -135,6 +135,7 @@ jobs: permissions: contents: read packages: read + id-token: write uses: ./.github/workflows/test-build-docker.yml secrets: inherit with: diff --git a/.github/workflows/check-licence.yml b/.github/workflows/check-licence.yml index a6bf421dc..7fe235e1e 100644 --- a/.github/workflows/check-licence.yml +++ b/.github/workflows/check-licence.yml @@ -11,6 +11,8 @@ permissions: jobs: check-licence: runs-on: ubuntu-latest + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/check-openapi.yml b/.github/workflows/check-openapi.yml index 7a65e8415..7ef0e47c9 100644 --- a/.github/workflows/check-openapi.yml +++ b/.github/workflows/check-openapi.yml @@ -10,8 +10,14 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + check-generate-openapi-docs: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/deploy-on-v2-commit.yml b/.github/workflows/deploy-on-v2-commit.yml index f691c989f..d8adc81cc 100644 --- a/.github/workflows/deploy-on-v2-commit.yml +++ b/.github/workflows/deploy-on-v2-commit.yml @@ -10,11 +10,21 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + deploy-v2-on-push: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} concurrency: group: deploy-v2-push-V2 cancel-in-progress: true + permissions: + contents: read + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner @@ -25,7 +35,12 @@ jobs: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Get commit hashes for frontend and backend @@ -90,8 +105,22 @@ jobs: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - - name: Build and push frontend image - if: steps.check-frontend.outputs.exists == 'false' + - name: Build and push frontend image (Depot) + if: env.USE_DEPOT == 'true' && steps.check-frontend.outputs.exists == 'false' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/frontend/Dockerfile + push: true + tags: | + ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} + ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-latest + build-args: VERSION_TAG=v2-alpha + platforms: linux/amd64 + + - name: Build and push frontend image (Docker fork fallback) + if: env.USE_DEPOT != 'true' && steps.check-frontend.outputs.exists == 'false' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . @@ -105,8 +134,22 @@ jobs: build-args: VERSION_TAG=v2-alpha platforms: linux/amd64 - - name: Build and push backend image - if: steps.check-backend.outputs.exists == 'false' + - name: Build and push backend image (Depot) + if: env.USE_DEPOT == 'true' && steps.check-backend.outputs.exists == 'false' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/backend/Dockerfile + push: true + tags: | + ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} + ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-latest + build-args: VERSION_TAG=v2-alpha + platforms: linux/amd64 + + - name: Build and push backend image (Docker fork fallback) + if: env.USE_DEPOT != 'true' && steps.check-backend.outputs.exists == 'false' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . diff --git a/.github/workflows/docker-compose-tests.yml b/.github/workflows/docker-compose-tests.yml index a580df8ab..de546824b 100644 --- a/.github/workflows/docker-compose-tests.yml +++ b/.github/workflows/docker-compose-tests.yml @@ -11,17 +11,28 @@ on: required: false type: string default: "false" + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking. Tuned to 4 because bench showed 16 was within noise of 4." + required: false + type: string + default: "4" permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + docker-compose-tests: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '4') }} permissions: actions: write contents: read checks: write + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner diff --git a/.github/workflows/e2e-live.yml b/.github/workflows/e2e-live.yml index 47fd0a6c9..995ffe8f0 100644 --- a/.github/workflows/e2e-live.yml +++ b/.github/workflows/e2e-live.yml @@ -5,13 +5,23 @@ name: Playwright E2E (live backend) # server. on: workflow_call: + inputs: + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking." + required: false + type: string + default: "8" permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + playwright-e2e-live: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '8') }} timeout-minutes: 30 steps: - name: Harden Runner diff --git a/.github/workflows/e2e-stubbed.yml b/.github/workflows/e2e-stubbed.yml index d2d41ea67..a99f398f5 100644 --- a/.github/workflows/e2e-stubbed.yml +++ b/.github/workflows/e2e-stubbed.yml @@ -5,13 +5,23 @@ name: Playwright E2E (stubbed) # mocks API responses in the browser. on: workflow_call: + inputs: + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking. Tuned to 8 to match the other playwright workflows; bench showed flat scaling above 8." + required: false + type: string + default: "8" permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + playwright-e2e: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '8') }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/frontend-backend-licenses-update.yml b/.github/workflows/frontend-backend-licenses-update.yml index f0e8039db..0821b46e5 100644 --- a/.github/workflows/frontend-backend-licenses-update.yml +++ b/.github/workflows/frontend-backend-licenses-update.yml @@ -19,9 +19,13 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + files-changed: name: detect what files changed - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} timeout-minutes: 3 outputs: licenses-frontend: ${{ steps.changes.outputs.licenses-frontend }} @@ -44,8 +48,8 @@ jobs: generate-frontend-license-report: if: needs.files-changed.outputs.licenses-frontend == 'true' name: Generate Frontend License Report - needs: files-changed - runs-on: ubuntu-latest + needs: [pick, files-changed] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: contents: write pull-requests: write @@ -307,13 +311,15 @@ jobs: generate-backend-license-report: if: needs.files-changed.outputs.licenses-backend == 'true' - needs: files-changed + needs: [pick, files-changed] name: Generate Backend License Report - runs-on: ubuntu-latest + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: contents: write pull-requests: write repository-projects: write # Required for enabling automerge + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/frontend-validation.yml b/.github/workflows/frontend-validation.yml index 3cdd3c63d..3f3601009 100644 --- a/.github/workflows/frontend-validation.yml +++ b/.github/workflows/frontend-validation.yml @@ -11,8 +11,12 @@ permissions: pull-requests: write jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + frontend-validation: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/multiOSReleases.yml b/.github/workflows/multiOSReleases.yml index 8ef352dfa..3e6cb55f4 100644 --- a/.github/workflows/multiOSReleases.yml +++ b/.github/workflows/multiOSReleases.yml @@ -36,9 +36,13 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + determine-matrix: if: ${{ vars.CI_PROFILE != 'lite' }} - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} version: ${{ steps.versionNumber.outputs.versionNumber }} @@ -108,8 +112,10 @@ jobs: fi build-jars: - needs: determine-matrix - runs-on: ubuntu-latest + needs: [pick, determine-matrix] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} strategy: matrix: variant: @@ -189,6 +195,7 @@ jobs: SM_API_KEY: ${{ secrets.SM_API_KEY }} WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} RELEASE_GPG_PRIVATE_KEY: ${{ secrets.RELEASE_GPG_PRIVATE_KEY }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 @@ -600,8 +607,8 @@ jobs: create-release: if: (github.event_name == 'workflow_dispatch' && github.event.inputs.test_mode != 'true') || github.event_name == 'release' || github.ref == 'refs/heads/V2-master' - needs: [determine-matrix, build, build-jars] - runs-on: ubuntu-latest + needs: [pick, determine-matrix, build, build-jars] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} permissions: contents: write steps: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f43524670..b18b9f2be 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -13,9 +13,13 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + playwright-all-browsers: name: Playwright (chromium + firefox + webkit) - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/swagger.yml b/.github/workflows/swagger.yml index 36173ad36..ae5db11a3 100644 --- a/.github/workflows/swagger.yml +++ b/.github/workflows/swagger.yml @@ -22,9 +22,15 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + push: if: ${{ vars.CI_PROFILE != 'lite' }} - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} + env: + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/tauri-build.yml b/.github/workflows/tauri-build.yml index 1a07adf68..12ab13130 100644 --- a/.github/workflows/tauri-build.yml +++ b/.github/workflows/tauri-build.yml @@ -84,6 +84,7 @@ jobs: WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} RELEASE_GPG_PRIVATE_KEY: ${{ secrets.RELEASE_GPG_PRIVATE_KEY }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 diff --git a/.github/workflows/test-build-docker.yml b/.github/workflows/test-build-docker.yml index 5e6ddb67b..bb462c92e 100644 --- a/.github/workflows/test-build-docker.yml +++ b/.github/workflows/test-build-docker.yml @@ -12,11 +12,19 @@ on: required: false type: string default: "false" + depot_cores: + description: "Depot runner vCPU count (used in runs-on). Override for benchmarking." + required: false + type: string + default: "8" permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + # TODO: extract a pre-matrix `prepare` job that runs once and produces # shared artifacts for the three matrix entries below to consume: # 1. `task backend:build` — currently runs 3× in parallel with @@ -32,7 +40,14 @@ jobs: # spring-security=true matrix entry if `task backend:build` and # `task backend:build:ci` produce equivalent JARs (verify before wiring). test-build-docker-images: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '8') }} + permissions: + contents: read + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' && inputs.docker-base-changed != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} strategy: fail-fast: false matrix: @@ -105,10 +120,16 @@ jobs: DISABLE_ADDITIONAL_FEATURES: true STIRLING_PDF_DESKTOP_UI: false + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up QEMU + if: env.USE_DEPOT != 'true' uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' id: buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 @@ -134,7 +155,22 @@ jobs: echo "platforms=linux/amd64,linux/arm64/v8" >> "$GITHUB_OUTPUT" fi - - name: Build ${{ matrix.docker-rev }} + - name: Build ${{ matrix.docker-rev }} (Depot) + if: env.USE_DEPOT == 'true' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./${{ matrix.docker-rev }} + push: false + platforms: ${{ steps.build-params.outputs.platforms }} + build-args: | + BASE_IMAGE=${{ steps.build-params.outputs.base_image }} + provenance: true + sbom: true + + - name: Build ${{ matrix.docker-rev }} (Docker fork fallback) + if: env.USE_DEPOT != 'true' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: builder: ${{ steps.buildx.outputs.name }} @@ -162,7 +198,14 @@ jobs: if-no-files-found: warn test-build-unoserver-image: - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || format('depot-ubuntu-24.04-{0}', inputs.depot_cores || '8') }} + permissions: + contents: read + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' && inputs.docker-base-changed != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 @@ -172,14 +215,35 @@ jobs: - name: Checkout Repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up QEMU + if: env.USE_DEPOT != 'true' uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' id: buildx uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - name: Build docker/unoserver/Dockerfile + - name: Build docker/unoserver/Dockerfile (Depot) + if: env.USE_DEPOT == 'true' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/unoserver/Dockerfile + push: false + load: true + platforms: linux/amd64 + tags: stirling-unoserver:pr-test + provenance: false + sbom: false + + - name: Build docker/unoserver/Dockerfile (Docker fork fallback) + if: env.USE_DEPOT != 'true' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: builder: ${{ steps.buildx.outputs.name }} diff --git a/.github/workflows/testdriver.yml b/.github/workflows/testdriver.yml index 9322dccee..278e3237e 100644 --- a/.github/workflows/testdriver.yml +++ b/.github/workflows/testdriver.yml @@ -20,9 +20,19 @@ permissions: contents: read jobs: + pick: + uses: ./.github/workflows/_runner-pick.yml + deploy: if: ${{ vars.CI_PROFILE != 'lite' }} - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} + permissions: + contents: read + id-token: write + env: + USE_DEPOT: ${{ needs.pick.outputs.is_fork != 'true' }} + DEPOT_TOKEN: ${{ secrets.DEPOT_TOKEN }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 @@ -51,7 +61,12 @@ jobs: MAVEN_PUBLIC_URL: ${{ secrets.MAVEN_PUBLIC_URL }} DISABLE_ADDITIONAL_FEATURES: true + - name: Set up Depot CLI + if: env.USE_DEPOT == 'true' + uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.0.0 + - name: Set up Docker Buildx + if: env.USE_DEPOT != 'true' uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - name: Get version number @@ -66,7 +81,20 @@ jobs: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_API }} - - name: Build and push test image + - name: Build and push test image (Depot) + if: env.USE_DEPOT == 'true' + uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.16.0 + with: + project: ${{ vars.DEPOT_PROJECT_ID }} + context: . + file: ./docker/embedded/Dockerfile + push: true + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:test-${{ github.sha }} + build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} + platforms: linux/amd64 + + - name: Build and push test image (Docker fork fallback) + if: env.USE_DEPOT != 'true' uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . @@ -125,7 +153,8 @@ jobs: files-changed: if: always() name: detect what files changed - runs-on: ubuntu-latest + needs: pick + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} timeout-minutes: 3 outputs: frontend: ${{ steps.changes.outputs.frontend }} @@ -145,9 +174,8 @@ jobs: test: if: needs.files-changed.outputs.frontend == 'true' - needs: [deploy, files-changed] - runs-on: ubuntu-latest - + needs: [pick, deploy, files-changed] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} steps: - name: Harden Runner uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 @@ -180,8 +208,8 @@ jobs: FORCE_COLOR: "3" cleanup: - needs: [deploy, test] - runs-on: ubuntu-latest + needs: [pick, deploy, test] + runs-on: ${{ needs.pick.outputs.is_fork == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} if: always() steps: diff --git a/AGENTS.md b/AGENTS.md index fa0340c27..7264001a0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -458,3 +458,26 @@ The frontend is organized with a clear separation of concerns: - Confirm approach before making structural changes - Request guidance on preferences (cross-platform vs specific tools, etc.) - Verify understanding of requirements before proceeding + + +## Stack reality check (don't trust LLM training data) + +This codebase is on bleeding-edge versions of its core JVM stack: **Spring Boot 4.0.6**, +**Jackson 3 (`tools.jackson`)**, **JDK 21/25 source/target with JDK 25 toolchain**. +All three are *post*-2024 releases and your training corpus is overwhelmingly Spring Boot 2/3 and +Jackson 2 patterns — those patterns will compile, run differently, or hallucinate APIs that no +longer exist. + +Before writing or editing Spring / Jackson / JDK code: + +1. Open an existing module in `app/core/` or `app/common/` and grep for the actual imports being + used — `import tools.jackson...` not `import com.fasterxml.jackson...`, and the new + `org.springframework.boot` 4.x package layout. +2. If you're not sure whether an API exists in this stack version, **check the source on disk + first** (the dependency JARs are downloaded under `~/.gradle/caches/modules-2/`). +3. Do not silently downgrade a Spring Boot 4 pattern to a Spring Boot 3 equivalent. If something + doesn't work, surface it to the human — don't guess. + +Same goes for Jackson 3's API surface (renamed `ObjectMapper` builder methods, new +`tools.jackson.databind` namespace) and JDK 25 preview features. Ground your code in this repo's +actual imports, not what worked three years ago. diff --git a/build.gradle b/build.gradle index ec0a8c5df..7f63ee047 100644 --- a/build.gradle +++ b/build.gradle @@ -619,3 +619,10 @@ tasks.register('buildRestartHelper', Jar) { println "restart-helper.jar created at: ${destinationDirectory.get()}/restart-helper.jar" } } + + +tasks.withType(Test).configureEach { + // maxParallelForks: parallelise JUnit across cores + // Half of available CPUs is a safe default; bump if your tests are I/O-bound. + maxParallelForks = Math.max(1, (Runtime.runtime.availableProcessors().intdiv(2)) as int) +} diff --git a/settings.gradle b/settings.gradle index 85b1c4520..c712f672a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,6 +23,29 @@ plugins { id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' } +// Depot remote build cache. Silently no-ops when DEPOT_TOKEN is absent +// (local dev without depot login, and fork PRs where GitHub hides secrets), +// so contributors without Depot access still build fine on local cache only. +buildCache { + def depotToken = System.getenv('DEPOT_TOKEN') + local { + enabled = true + } + if (depotToken) { + remote(HttpBuildCache) { + url = 'https://cache.depot.dev' + enabled = true + // Only CI runs push to the shared cache; dev laptops pull-only + // so a misconfigured local task can't poison everyone else. + push = System.getenv('CI') == 'true' + credentials { + username = '' + password = depotToken + } + } + } +} + rootProject.name = 'Stirling PDF' // Flavors: core | proprietary (default) | saas.