diff --git a/.github/workflows/bypass-size-gate.yml b/.github/workflows/bypass-size-gate.yml new file mode 100644 index 00000000..a4e742c2 --- /dev/null +++ b/.github/workflows/bypass-size-gate.yml @@ -0,0 +1,70 @@ +name: Bypass size gate + +# Caps how large a PR a "review-bypass" collaborator (e.g. @Luca-Timo) can +# self-merge without a maintainer review. The branch-protection bypass list +# alone is binary — once a user is on it they can merge anything without +# review. This workflow reports a REQUIRED status check that fails when a +# bypass user's PR exceeds the configured size threshold, which blocks the +# merge even with bypass enabled. Other contributors are unaffected (the +# check reports success for them so the required-check gate doesn't trip). +# +# To tune: edit LINE_LIMIT or BYPASS_USERS below. +# +# Trigger note: uses `pull_request_target` so the workflow has the elevated +# permissions of the base repo's GITHUB_TOKEN (read PR metadata, write +# checks). The script never executes code FROM the PR — it only reads +# metadata via the API — so this is safe against fork-PR attacks. + +on: + pull_request_target: + types: [opened, reopened, synchronize, ready_for_review] + +permissions: + pull-requests: read + checks: write + +jobs: + size-gate: + runs-on: ubuntu-latest + steps: + - name: Compute PR size and report check status + uses: actions/github-script@v7 + with: + script: | + // Tune these two constants if the policy shifts. + const LINE_LIMIT = 300; + const BYPASS_USERS = ['Luca-Timo']; + + const pr = context.payload.pull_request; + const author = pr.user.login; + const linesChanged = pr.additions + pr.deletions; + const filesChanged = pr.changed_files; + + let conclusion, title, summary; + + if (!BYPASS_USERS.includes(author)) { + // Not a bypass user — this gate doesn't apply to them. They + // go through normal review. Report success so the required + // check doesn't block their merge. + conclusion = 'success'; + title = 'Not applicable'; + summary = `This gate only restricts review-bypass for: ${BYPASS_USERS.join(', ')}. PRs from other authors (${author} here) go through the normal review path and are unaffected.`; + } else if (linesChanged <= LINE_LIMIT) { + conclusion = 'success'; + title = `OK — within bypass limit (${linesChanged} lines)`; + summary = `Small PR: ${linesChanged} lines changed across ${filesChanged} file(s). Within the ${LINE_LIMIT}-line self-merge limit for @${author}. Can be merged without a maintainer review.`; + } else { + conclusion = 'failure'; + title = `Too large for bypass (${linesChanged} lines)`; + summary = `Large PR: ${linesChanged} lines changed across ${filesChanged} file(s). Exceeds the ${LINE_LIMIT}-line self-merge limit for @${author} — needs an approving review from a maintainer before merge. Split into smaller PRs or wait for review.`; + } + + await github.rest.checks.create({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'bypass-size-gate', + head_sha: pr.head.sha, + status: 'completed', + conclusion, + output: { title, summary } + });