Rules enforced on 100% of Vercel repositories, via a GitHub organization ruleset that requires the workflow in this repo to pass before any pull request can merge.
The Vercel OIDC token must not be used directly in JS/TS code
(.js .jsx .cjs .mjs .ts .tsx .cts .mts). Flagged on added lines of a
PR diff:
| Pattern | Why |
|---|---|
VERCEL_OIDC_TOKEN (env var) |
It is a snapshot that expires and is never refreshed |
x-vercel-oidc-token (header, case-insensitive) |
Same — raw header value expires |
getVercelOidcTokenSync |
The sync variant cannot refresh an expired token |
Instead, do this:
import { getVercelOidcToken } from '@vercel/oidc';
const token = await getVercelOidcToken();If direct usage is genuinely required (e.g. you are implementing
@vercel/oidc itself), add an allow comment on the offending line or the
line directly above it:
// vercel-rules-allow no-direct-oidc-token -- implementing @vercel/oidc
const token = process.env.VERCEL_OIDC_TOKEN;A bare vercel-rules-allow (no rule list) allows all rules on that line.
.github/workflows/vercel-repo-rules.ymlis referenced by an organization ruleset with the "Require workflows to pass before merging" rule.- GitHub runs the workflow in the context of each target repository on
pull_request(opened / synchronize / reopened — branch, path, and type filters are ignored for required workflows) and onmerge_group(passes immediately; the diff was already checked on the PR run). - The target repo's
GITHUB_TOKENcannot read this repo, so the workflow is fully self-contained: the check script is embedded in the workflow file at build time. It fetches the PR diff from the GitHub API (no checkout, no dependency install — the run takes seconds) and falls back to a shallowgit difffor PRs too large for the API diff (HTTP 406). - The check is intentionally regex-based, not parser-based, and scans only the PR diff's added lines, so it stays fast at any repo size.
- Org Settings → Repository → Rulesets → New ruleset → New branch ruleset.
- Enforcement status: start with Evaluate, switch to Active once the rollout looks clean.
- Target repositories: All repositories.
- Target branches: Default branch only (GitHub warns against targeting all branches — required workflows block direct pushes to targeted branches).
- Enable Require workflows to pass before merging and add
vercel/global-repo-rules→ branchmain→.github/workflows/vercel-repo-rules.yml. - Configure bypass actors (e.g. a break-glass team) as needed.
Requirements: this repo's visibility must cover the targets (a public workflow repo runs anywhere; internal covers internal + private repos), and GitHub Actions must be enabled in target repositories.
pnpm test # runs node --test (scanner tests + generated-file sync check)
pnpm build # regenerates .github/workflows/vercel-repo-rules.ymlrules/no-direct-oidc-token/check.mjs— the rule implementation (source of truth). Zero dependencies; runnable locally:git diff main...HEAD | node rules/no-direct-oidc-token/check.mjsscripts/vercel-repo-rules.template.yml— workflow scaffolding.scripts/build-workflows.mjs— embeds the check script into the template..github/workflows/vercel-repo-rules.yml— generated, do not edit. CI fails if it is out of sync with the sources.
Note: the banned names are assembled from string fragments inside
check.mjs and its tests so that PRs to this repo do not trip the rule
itself. Keep it that way when editing.
- Add
rules/<rule-id>/check.mjs+ tests following the existing pattern (read a unified diff, scan added lines, emit::errorannotations, supportvercel-rules-allow <rule-id>). - Add a job or step for it in
scripts/vercel-repo-rules.template.ymland extendscripts/build-workflows.mjsto embed it. pnpm build, commit the regenerated workflow, and document the rule here.