Repository navigation
feat(plugin-webhooks): the webhooks service serves the redeliver door from a Request, and the veto no longer waits for realtime (webhooks segment 3 of #22564) #6040
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: Validate Dependencies | |
| on: | |
| pull_request: | |
| paths: | |
| - '**/package.json' | |
| - 'pnpm-lock.yaml' | |
| - '.changeset/config.json' | |
| - 'pnpm-workspace.yaml' | |
| - 'scripts/check-changeset-fixed.mjs' | |
| - 'scripts/check-override-consistency.mjs' | |
| # The consumer-resolution half of the same question (#16186) — an edit to | |
| # the gate must be exercised on the PR that makes it. | |
| - 'scripts/check-vendor-export-contract.mjs' | |
| # The OSV exemption ledger and its check: a PR that touches either must | |
| # run this workflow, or an exemption could be added without the gate | |
| # that governs it ever running on the PR that adds it. | |
| - 'osv-scanner.toml' | |
| - 'scripts/check-osv-exemptions.mjs' | |
| # The pull_request verdict of the OSV step (#22082): an edit to it must | |
| # be exercised on the PR that makes it. | |
| - 'scripts/osv-base-relative.mjs' | |
| # Re-run when the workflow itself changes, so edits to these gates are | |
| # exercised on the PR that introduces them. | |
| - '.github/workflows/validate-deps.yml' | |
| schedule: | |
| # Run daily at 03:00 UTC — narrows the discovery window for a new OSV | |
| # advisory from up to six days (weekly) to one, so the scheduled scan | |
| # is more likely to surface a red before an unrelated PR's blocking | |
| # trigger collides with it (#14645). | |
| - cron: '0 3 * * *' | |
| workflow_dispatch: | |
| jobs: | |
| validate: | |
| name: Validate Package Dependencies | |
| runs-on: ubuntu-latest | |
| # Measured over the 100 most recent completed runs: p50 1.3 min, max | |
| # 1.9 min (#22082). 15 leaves room for a cold pnpm store and two OSV | |
| # scans on a pull request, and stops a hung step long before GitHub's | |
| # 360-minute default would. | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| issues: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v7 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: ./.github/actions/setup-pnpm | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v6 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-v3-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store-v3- | |
| - name: Verify lockfile is up to date | |
| run: | | |
| pnpm install --frozen-lockfile --prefer-offline | |
| - name: Verify Changesets "fixed" group covers every public package | |
| run: node scripts/check-changeset-fixed.mjs | |
| # pnpm overrides pin what THIS workspace resolves, but they do not ship | |
| # with published packages — downstream installs see only the declared | |
| # ranges. If an override target isn't reachable from a publishable | |
| # package's declared range, we test one dependency graph and publish | |
| # another (the 15.1.0 quickstart shipped exactly that: plugin-auth | |
| # declared better-auth ^1.6.23 while CI ran the 1.7.0-rc.1 override, | |
| # and every fresh project 500'd on auth). | |
| # | |
| # The same run also prints two informational censuses (#6046): overrides | |
| # nothing in the dependency tree consumes, and selectors whose upper | |
| # bound excludes their own target (#4961 / #5032). Both are REPORTS and | |
| # never fail the job — an unconsumed override is a legitimate posture | |
| # (#5835 ruling A). `--self-test` proves the check in both directions, | |
| # so run the `check:override-consistency` chain rather than the bare | |
| # script: a self-test nothing invokes is a phantom check. | |
| - name: Verify overrides are reflected in published manifests | |
| run: pnpm check:override-consistency | |
| # The half check-override-consistency structurally cannot cover (#16186). | |
| # It asks whether the override TARGET is reachable from the declared | |
| # range; `^1.7.2` and `^1.7.2` agreed perfectly while both floated onto | |
| # `@better-auth/core@1.7.3`, a PATCH that deleted the export plugin-auth | |
| # imports statically. Three published releases could not load on a fresh | |
| # install and nothing here went red, because pnpm-lock.yaml held 1.7.2. | |
| # | |
| # `--resolve` deliberately ignores the lockfile: for every version the | |
| # DECLARED range admits on the registry -- the way a downstream project | |
| # resolves -- it installs that version outside this workspace and checks | |
| # the export surface. It fails if ANY admitted version is missing a symbol | |
| # we import. With the ranges pinned exact that is one small install per | |
| # vendor; under a caret it is one per published version, which is the cost | |
| # of the risk being taken. | |
| # | |
| # It lives HERE rather than in the lint farm because it needs the network, | |
| # which this job already has, and because the daily schedule is what turns | |
| # "a vendor published something today" into a red in this repo instead of | |
| # in a customer's install. An unreachable registry exits 3 | |
| # (PREREQUISITE NOT MET), never a green. | |
| - name: Verify the declared ranges cannot resolve past our import surface | |
| run: pnpm check:vendor-export-contract-resolve | |
| # Fail the workflow if known vulnerabilities are found — enforces | |
| # security compliance before merging. | |
| # | |
| # Previously this ran `pnpm audit --audit-level=high`, but npm retired the | |
| # audit endpoint (HTTP 410, "This endpoint is being retired. Use the bulk | |
| # advisory endpoint instead.") and pnpm has not migrated, so `pnpm audit` | |
| # now fails unconditionally on every branch (see issue #2974). OSV-Scanner | |
| # reads pnpm-lock.yaml directly against the OSV database and exits non-zero | |
| # when any advisory matches, restoring a working blocking gate. | |
| # | |
| # Note: OSV-Scanner blocks on any severity, not just high/critical. When | |
| # the advisory has a fixed version you take the fix. The ONLY escape | |
| # hatch, for an advisory with no fix available, is an `[[IgnoredVulns]]` | |
| # entry in `osv-scanner.toml` at the repo root — never lowering the gate. | |
| # | |
| # That escape hatch is governed by three conventions (#4965), stated in | |
| # full in the header of osv-scanner.toml: `ignoreUntil` mandatory | |
| # (default 30 days, ceiling 90), `reason` mandatory with an advisory link | |
| # plus a sentence on why it cannot be fixed, and exemptions land in their | |
| # own `osv-exemption`-labelled PR. The scanner enforces none of that — it | |
| # reads a missing `ignoreUntil` as "ignore forever", silently — so the | |
| # step below runs first and fails on any exemption that is missing, | |
| # quoted, expired, over the ceiling, or unexplained. `--self-test` proves | |
| # the check in both directions. | |
| - name: Verify OSV exemptions carry an expiry and a reason | |
| run: | | |
| node scripts/check-osv-exemptions.mjs --self-test | |
| node scripts/check-osv-exemptions.mjs | |
| # Two verdicts, one scanner pin (#22082, ruling A). | |
| # | |
| # `schedule` and `workflow_dispatch` judge `main` ABSOLUTELY: every | |
| # advisory the lockfile matches fails the step. That daily red is the | |
| # signal that files the finding card, and this step is unchanged by the | |
| # pull_request verdict below. | |
| # | |
| # A pull request is judged BASE-RELATIVELY: it answers for the advisories | |
| # it introduces, not for the ones `main` already carries -- those are | |
| # `main`'s to fix, and a pull request that changes no dependency cannot | |
| # fix them. The steps below scan the pull request's lockfile and the merge | |
| # base's, each under its own `osv-scanner.toml`, and | |
| # scripts/osv-base-relative.mjs fails only on an advisory the merge base | |
| # does not match; the others become notices naming the advisory and its | |
| # open finding card. A scan that does not reach a verdict fails closed. | |
| # | |
| # The pin is an untagged upstream commit after the v2.5.0 tag whose | |
| # action.yml runs the ghcr.io/google/osv-scanner-action:v2.5.0 image (the | |
| # comment here used to read v2.3.8). Keep all three `uses:` lines on ONE | |
| # sha: the two verdicts must come from the same scanner. | |
| - name: Audit dependencies for known vulnerabilities (OSV-Scanner) | |
| if: github.event_name != 'pull_request' | |
| uses: google/osv-scanner-action/osv-scanner-action@f4cfcc01edc9c8b756a9b873b7a623ca674da51e # untagged, v2.5.0 image | |
| with: | |
| scan-args: |- | |
| --lockfile=pnpm-lock.yaml | |
| # The checkout is the pull request's test merge (refs/pull/N/merge) at | |
| # depth 1. Its first parent is the base-branch commit GitHub merged the | |
| # pull request into -- the merge base of the scanned tree and the base | |
| # branch -- so ONE depth-1 fetch of that sha is all the history this needs | |
| # (never fetch-depth: 0). When neither pnpm-lock.yaml nor osv-scanner.toml | |
| # differs from it, the pull request cannot introduce an advisory and no | |
| # scan runs. The ledger is part of the condition: a pull request that | |
| # deletes an exemption changes the verdict without touching the lockfile. | |
| - name: Stage the OSV comparison against the merge base (pull request) | |
| id: osv-stage | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| node scripts/osv-base-relative.mjs --self-test | |
| mapfile -t parents < <(git cat-file -p HEAD | sed -n 's/^parent //p') | |
| if [ "${#parents[@]}" -ne 2 ]; then | |
| echo "::error title=OSV base-relative verdict unavailable::HEAD is not the pull request's two-parent test merge (${#parents[@]} parent(s) found), so there is no merge base to judge against" | |
| exit 1 | |
| fi | |
| base="${parents[0]}" | |
| git fetch --no-tags --depth=1 origin "$base" | |
| echo "base=$base" >> "$GITHUB_OUTPUT" | |
| if git diff --quiet "$base" HEAD -- pnpm-lock.yaml osv-scanner.toml; then | |
| echo "::notice title=OSV-Scanner verdict (base-relative)::lockfile unchanged — inherits main's verdict. pnpm-lock.yaml and osv-scanner.toml are identical to the merge base ${base:0:12}, so this pull request introduces no advisory; main's daily scheduled scan judges that lockfile." | |
| echo "compare=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| for side in base head; do | |
| if [ "$side" = base ]; then rev="$base"; else rev=HEAD; fi | |
| mkdir -p ".osv-compare/$side" | |
| git show "$rev:pnpm-lock.yaml" > ".osv-compare/$side/pnpm-lock.yaml" | |
| git show "$rev:osv-scanner.toml" > ".osv-compare/$side/osv-scanner.toml" | |
| done | |
| echo "compare=true" >> "$GITHUB_OUTPUT" | |
| # Both scans may exit non-zero (findings), so neither stops the job; the | |
| # judge below reads each result file against its step's outcome. | |
| # `--config` is explicit because the scanner looks for osv-scanner.toml | |
| # only in the scanned lockfile's own directory (measured on 2.5.0: a | |
| # ledger one directory up is not applied). | |
| - name: OSV-Scanner on the merge base's lockfile (pull request) | |
| id: osv-scan-base | |
| if: steps.osv-stage.outputs.compare == 'true' | |
| continue-on-error: true | |
| uses: google/osv-scanner-action/osv-scanner-action@f4cfcc01edc9c8b756a9b873b7a623ca674da51e # untagged, v2.5.0 image | |
| with: | |
| scan-args: |- | |
| --config=.osv-compare/base/osv-scanner.toml | |
| --format=json | |
| --output-file=.osv-compare/base/results.json | |
| --lockfile=.osv-compare/base/pnpm-lock.yaml | |
| - name: OSV-Scanner on the pull request's lockfile (pull request) | |
| id: osv-scan-head | |
| if: steps.osv-stage.outputs.compare == 'true' | |
| continue-on-error: true | |
| uses: google/osv-scanner-action/osv-scanner-action@f4cfcc01edc9c8b756a9b873b7a623ca674da51e # untagged, v2.5.0 image | |
| with: | |
| scan-args: |- | |
| --config=.osv-compare/head/osv-scanner.toml | |
| --format=json | |
| --output-file=.osv-compare/head/results.json | |
| --lockfile=.osv-compare/head/pnpm-lock.yaml | |
| - name: Judge the pull request's OSV findings against the merge base's (pull request) | |
| if: steps.osv-stage.outputs.compare == 'true' | |
| env: | |
| BASE_OUTCOME: ${{ steps.osv-scan-base.outcome }} | |
| HEAD_OUTCOME: ${{ steps.osv-scan-head.outcome }} | |
| BASE_SHA: ${{ steps.osv-stage.outputs.base }} | |
| # Read-only use: the open-issue search that names an inherited | |
| # advisory's finding card. The verdict never depends on it. | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: | | |
| node scripts/osv-base-relative.mjs \ | |
| --base-results .osv-compare/base/results.json --base-outcome "$BASE_OUTCOME" \ | |
| --head-results .osv-compare/head/results.json --head-outcome "$HEAD_OUTCOME" \ | |
| --base-sha "$BASE_SHA" | |
| - name: List outdated packages | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| run: | | |
| pnpm outdated --recursive || true |