Update dependency @eslint-react/eslint-plugin to v5.9.1 #1063
Workflow file for this run
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: Refresh SBOM for Dependency PRs | |
| # Auto-refreshes the cached CycloneDX SBOMs (`client/sbom/`, `server/sbom/`) | |
| # on dependency-update PRs opened by Renovate or Dependabot. Without this, | |
| # every bot PR fails the `Verify ... SBOM is up-to-date` checks in | |
| # `run_tests.yml` because the bots only update `package.json` / | |
| # `pnpm-lock.yaml` (or `build.gradle` / `gradle.properties` / | |
| # `settings.gradle`) — they don't run `pnpm run sbom:force` or | |
| # `./gradlew cyclonedxBom`. | |
| # | |
| # Event choice: pull_request_target | |
| # --------------------------------- | |
| # We use `pull_request_target` (not `pull_request`) so this workflow can | |
| # access repo secrets when triggered by Dependabot — `pull_request` events | |
| # from Dependabot don't expose Actions secrets by default. The workflow | |
| # definition is read from the BASE branch (safe from PR tampering), but the | |
| # checked-out code is the PR head, so we add a same-repo guard | |
| # (`head.repo.full_name == github.repository`) to ensure we only run on | |
| # branches Renovate/Dependabot pushed into THIS repo (they never use forks). | |
| # | |
| # Token requirement | |
| # ----------------- | |
| # We deliberately do NOT push with the default `GITHUB_TOKEN`: pushes signed | |
| # by `GITHUB_TOKEN` are excluded from triggering further workflow runs, so | |
| # the failed test workflow on the PR would stay red even after the SBOM | |
| # commit lands. Instead we either: | |
| # 1. Mint a least-privilege installation token from a GitHub App | |
| # (preferred), via the `SBOM_BOT_APP_ID` repo/org variable and the | |
| # `SBOM_BOT_PRIVATE_KEY` secret. Scoped to `contents: write` on the | |
| # single PR head repo. | |
| # 2. Fall back to a fine-grained PAT in `SBOM_BOT_PAT`. | |
| # | |
| # Credential hygiene | |
| # ------------------ | |
| # Checkout runs with the default (read-only) `GITHUB_TOKEN` and | |
| # `persist-credentials: false`, so the write-capable App/PAT token is | |
| # never written into the runner's git config. The push step authenticates | |
| # explicitly via a one-shot URL so the token can't be picked up by | |
| # subsequent steps or build-script lifecycle hooks. | |
| on: | |
| pull_request_target: | |
| branches: [develop, main] | |
| types: [opened, synchronize, reopened] | |
| paths: | |
| - 'client/package.json' | |
| - 'client/pnpm-lock.yaml' | |
| - 'server/build.gradle' | |
| - 'server/gradle.properties' | |
| - 'server/settings.gradle' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: refresh-sbom-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| refresh: | |
| # Only run on bot-opened PRs that target THIS repo (no forks). The | |
| # same-repo check is defense-in-depth: Renovate and Dependabot always | |
| # push into the base repo on their own branches. | |
| if: > | |
| (github.event.pull_request.user.login == 'renovate[bot]' || | |
| github.event.pull_request.user.login == 'dependabot[bot]') && | |
| github.event.pull_request.head.repo.full_name == github.repository | |
| runs-on: ubuntu-latest | |
| steps: | |
| # GitHub disallows the `secrets` context inside step-level `if:` | |
| # expressions (only env/github/inputs/job/matrix/needs/runner/steps/ | |
| # strategy/vars are permitted there) — referencing it directly causes | |
| # the entire workflow to fail to load. Bounce the secret presence | |
| # check through an env var so the gate is expressible. | |
| - name: Detect App token availability | |
| id: app-token-config | |
| env: | |
| APP_PRIVATE_KEY: ${{ secrets.SBOM_BOT_PRIVATE_KEY }} | |
| APP_ID: ${{ vars.SBOM_BOT_APP_ID }} | |
| run: | | |
| if [ -n "${APP_ID:-}" ] && [ -n "${APP_PRIVATE_KEY:-}" ]; then | |
| echo "available=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "available=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Mint GitHub App token (preferred) | |
| id: app-token | |
| if: steps.app-token-config.outputs.available == 'true' | |
| uses: actions/create-github-app-token@v3 | |
| with: | |
| app-id: ${{ vars.SBOM_BOT_APP_ID }} | |
| private-key: ${{ secrets.SBOM_BOT_PRIVATE_KEY }} | |
| # Scope to least privilege: only `contents: write` on the PR head repo. | |
| owner: ${{ github.event.pull_request.head.repo.owner.login }} | |
| repositories: ${{ github.event.pull_request.head.repo.name }} | |
| permission-contents: write | |
| - name: Pick push token (App token > PAT fallback) | |
| id: token | |
| env: | |
| APP_TOKEN: ${{ steps.app-token.outputs.token }} | |
| PAT_TOKEN: ${{ secrets.SBOM_BOT_PAT }} | |
| run: | | |
| if [ -n "${APP_TOKEN:-}" ]; then | |
| echo "source=app" >> "$GITHUB_OUTPUT" | |
| echo "::add-mask::$APP_TOKEN" | |
| echo "value=$APP_TOKEN" >> "$GITHUB_OUTPUT" | |
| elif [ -n "${PAT_TOKEN:-}" ]; then | |
| echo "source=pat" >> "$GITHUB_OUTPUT" | |
| echo "::add-mask::$PAT_TOKEN" | |
| echo "value=$PAT_TOKEN" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "::error::Neither SBOM_BOT_APP_ID/SBOM_BOT_PRIVATE_KEY nor SBOM_BOT_PAT is configured. See .github/workflows/refresh_sbom.yml header for setup details." | |
| exit 1 | |
| fi | |
| - name: Checkout PR branch (read-only, no token persisted) | |
| uses: actions/checkout@v7 | |
| with: | |
| # pull_request_target defaults to the base ref; we want the PR head. | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| # No `token:` here — default GITHUB_TOKEN is sufficient for reading | |
| # this same repo, and `persist-credentials: false` ensures nothing | |
| # writable is left in the git config for later steps (e.g. Gradle | |
| # build scripts or pnpm lifecycle hooks) to pick up. | |
| persist-credentials: false | |
| # Full history so `git diff "$BASE_SHA"...HEAD` always resolves the | |
| # PR base, even on long-lived branches where a shallow clone might | |
| # not include it. | |
| fetch-depth: 0 | |
| - name: Detect which SBOM(s) need refreshing | |
| id: scopes | |
| env: | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| run: | | |
| changed=$(git diff --name-only "$BASE_SHA"...HEAD) | |
| client=false | |
| server=false | |
| if echo "$changed" | grep -qE '^client/(package\.json|pnpm-lock\.yaml)$'; then | |
| client=true | |
| fi | |
| if echo "$changed" | grep -qE '^server/(build\.gradle|gradle\.properties|settings\.gradle)$'; then | |
| server=true | |
| fi | |
| echo "client=$client" >> "$GITHUB_OUTPUT" | |
| echo "server=$server" >> "$GITHUB_OUTPUT" | |
| echo "Client SBOM refresh needed: $client" | |
| echo "Server SBOM refresh needed: $server" | |
| # ---------- Server SBOM ---------- | |
| - name: Set up JDK 25 | |
| if: steps.scopes.outputs.server == 'true' | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: '25' | |
| distribution: 'zulu' | |
| cache: 'gradle' | |
| - name: Regenerate server SBOM | |
| if: steps.scopes.outputs.server == 'true' | |
| working-directory: ./server | |
| run: | | |
| chmod +x ./gradlew | |
| ./gradlew cyclonedxBom | |
| # ---------- Client SBOM ---------- | |
| # `pnpm sbom` reads the lockfile directly, so we deliberately do NOT run | |
| # `pnpm install` — skipping it both saves time and avoids running | |
| # dependency lifecycle scripts. Corepack provides pnpm itself. | |
| - name: Enable Corepack | |
| if: steps.scopes.outputs.client == 'true' | |
| run: corepack enable | |
| - name: Set up Node.js | |
| if: steps.scopes.outputs.client == 'true' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24.17.0' | |
| - name: Regenerate client SBOM | |
| if: steps.scopes.outputs.client == 'true' | |
| working-directory: ./client | |
| run: pnpm run sbom:force | |
| - name: Commit and push if SBOM changed | |
| env: | |
| PUSH_TOKEN: ${{ steps.token.outputs.value }} | |
| PR_BRANCH: ${{ github.event.pull_request.head.ref }} | |
| PR_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| run: | | |
| if git diff --quiet -- client/sbom server/sbom; then | |
| echo "SBOM already current — nothing to commit. This typically means the workflow re-ran on its own commit; safe to skip." | |
| exit 0 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add client/sbom server/sbom | |
| git commit -m "chore: refresh SBOM after dependency update" | |
| # Authenticate the push via a one-shot URL rather than persisting | |
| # the write token into git config. The token is masked in logs. | |
| git push "https://x-access-token:${PUSH_TOKEN}@github.com/${PR_REPO}.git" "HEAD:${PR_BRANCH}" |