Skip to content

feat(coderabbit-config): validate .coderabbit.yaml so a broken config… #1

feat(coderabbit-config): validate .coderabbit.yaml so a broken config…

feat(coderabbit-config): validate .coderabbit.yaml so a broken config… #1

name: Bump coderabbit-config-validate callers
# When the coderabbit-config-validate reusable workflow (or the checker + vendored
# schema behind it) is updated on main, open a SHA-bump PR in every repo that pins
# a caller against it. PRs are opened by Cloud Code Bot so they are easy to filter
# and merge.
#
# This is a thin entrypoint over the shared bumper at
# .github/bump-callers/bump-callers.sh — the same script drives every other fleet.
# Keeping ONE implementation is deliberate: a forked copy is how other shared
# machinery in the org has drifted. The entrypoints differ only in their
# path-filter trigger and the parameters passed below. (They stay separate rather
# than one matrix because their triggers differ — a cursor-review.yml change must
# not spuriously bump these callers, and vice versa.)
#
# This fleet matters more than most for the SCHEMA, not the workflow file: the
# vendored schema.v2.json is what every consumer is graded against, and it moves
# on its own schedule via refresh-coderabbit-schema.yml. Without this fleet a
# refreshed schema would sit on main while every pinned caller kept validating
# against a months-old copy — the exact vendoring-rots failure the refresh job
# exists to prevent, reintroduced one layer down.
#
# The caller list is NOT hardcoded here. This repo is PUBLIC (workflow file and
# Actions run logs are both publicly viewable), and most callers are private, so
# their names must never appear in this file or its logs. The list lives in the
# repo-level Actions SECRET `CODERABBIT_CONFIG_CALLERS` as a JSON array of
# {"repo","file","label"} objects, same shape as the other fleets' rosters.
#
# A SECRET, not a variable (BE-6472): the roster reaches the script through the
# step's `env:` below, and Actions prints that env block BEFORE the step runs — so
# a variable's raw value would be published in this public repo's run log ahead of
# any masking the script could do. A secret is runner-masked everywhere, that dump
# included. `bump-callers.sh` still `::add-mask::`es every repo name before IT
# echoes anything: Actions masks the roster as ONE exact string, not each name
# inside it, so a name echoed on its own would otherwise print in the clear.
#
# The roster is seeded EMPTY, so `ALLOW_EMPTY: "true"` below: this fleet grows as
# callers land (v1 wires one repo; the rest follow), and an empty list is a clean
# no-op rather than an error. Flip it to "false" once the fleet has live callers —
# at that point an empty roster is a bug, and a silent clean exit would leave every
# caller pinned to a stale checker with nothing red anywhere to say so.
#
# Update flow — adding/removing a caller needs NO public commit:
# jq -c . callers.json | gh secret set CODERABBIT_CONFIG_CALLERS --repo Comfy-Org/github-workflows
# Keep the canonical callers.json in a PRIVATE infra/ops repo so roster edits have
# a reviewed source of truth; the org audit log records each edit. (The specific
# home repo is intentionally not named here — this file is public.)
#
# Recovery note: GitHub evaluates a `paths:` filter against only the first 300
# changed files of a push, so a change here buried in a larger main push can
# create NO run at all. `workflow_dispatch` above is the recovery — run it once
# from main and the fleet catches up. Run it once when this fleet first lands,
# too: landing a fleet does not touch the reusable it watches, so its own merge
# matches no path filter and fires no run.
on:
workflow_dispatch: {} # allow on-demand runs (e.g. to re-bump callers)
push:
branches: [main]
paths:
- .github/workflows/coderabbit-config-validate.yml
- .github/coderabbit-config/**
permissions:
contents: read
# Serialize runs of this fleet. The bumper pushes to a STABLE branch
# (ci/bump-coderabbit-config-validate) shared across runs, so two overlapping runs
# (a rapid second main push, or a push racing a manual re-run) would force-reset
# that branch and race the PR update — an older run finishing last could leave the
# committed diff pinned to a stale SHA. cancel-in-progress: false lets the running
# bump finish; GitHub keeps only the newest pending run, so the latest SHA always
# wins (BE-3882).
concurrency:
group: bump-coderabbit-config-callers
cancel-in-progress: false
jobs:
bump:
# Guard against a workflow_dispatch run from a non-main ref: github.sha is the
# tip of whatever ref was selected, and the bumper force-resets a stable shared
# branch — a manual run from an older ref would pin every caller to a stale SHA
# (and run this job's script, with the App token minted below, from an
# unreviewed commit). The push trigger is already main-only, so this only ever
# skips stray manual runs.
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
# The job is a bounded loop of `git`/`gh` network calls, plus the preflight's
# deepening fetch; nothing here should take minutes. Without this a hung call
# would hold a runner for the default 6 hours (and, via the serializing
# concurrency group above, block every later bump behind it).
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# The shared staleness/decommission guard — one implementation for every
# fleet, documented in .github/bump-callers/README.md "Preflight". It decides
# whether this run is a stale re-run (a later commit already touched the
# watched surface and has its own run) or the surface has been
# decommissioned, and emits the SHA the bump below pins.
# WATCHED/WATCHED_ASSETS are LITERAL paths, never the `paths:` globs, and
# must cover EVERY entry in this fleet's filter above: the re-point only pins
# callers to a tip whose watched content it compared, so widen these inputs
# in the same change if you ever widen that filter.
- name: Preflight (staleness / decommission guard)
id: preflight
env:
NEW_SHA: ${{ github.sha }}
WATCHED: .github/workflows/coderabbit-config-validate.yml
WATCHED_ASSETS: .github/coderabbit-config
run: bash .github/bump-callers/preflight.sh
- name: Generate Cloud Code Bot token
# Stale run or decommissioned surface — don't mint an org-wide write token
# for a job that is about to bump nothing.
if: steps.preflight.outputs.proceed == 'true'
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 — pinned: see dependabot.yml ignore (v2+ breaks cross-repo `owner:` token scoping)
id: token
with:
app-id: ${{ vars.APP_ID }}
private-key: ${{ secrets.CLOUD_CODE_BOT_PRIVATE_KEY }}
# `owner:` with no `repositories:` is deliberate and cannot be narrowed:
# the caller list is a runtime secret (see the header), so the repos this
# token must reach are not knowable at authoring time — and naming them
# here would leak private caller names into a public file. The
# PERMISSIONS can be narrowed without naming anything, so they are: the
# bumper commits the rewritten caller file (contents), opens or updates
# the bump PR (pull-requests), and stamps the caller's label through the
# issues API (issues).
owner: Comfy-Org
permission-contents: write
permission-pull-requests: write
permission-issues: write
- name: Bump SHA in caller repos
# Stale run or decommissioned surface — nothing to bump.
if: steps.preflight.outputs.proceed == 'true'
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
# NOT github.sha: when main moved on but the watched surface is
# unchanged, the preflight re-points this run at the verified tip, and
# reading github.sha here would silently discard that re-point.
NEW_SHA: ${{ steps.preflight.outputs.new_sha }}
# Names the roster to fix in an error message. It is a SECRET, not a
# variable; the env key keeps the fleets' historical name so every
# entrypoint and the shared script stay in step.
VAR_NAME: CODERABBIT_CONFIG_CALLERS
TAG: coderabbit-config-validate
WORKFLOW_FILE: coderabbit-config-validate.yml
# An empty roster — `[]`, or a secret nobody has set — is a clean no-op
# here, not an error. See the header for when to flip this.
ALLOW_EMPTY: "true"
# JSON array of {"repo","file","label"} — see the header comment for the
# update flow. Kept in a repo-level SECRET (not this file, and not a
# variable) so private caller names never land in this public repo — nor,
# since a secret is masked in the step's env dump too, in its run logs.
CALLERS_JSON: ${{ secrets.CODERABBIT_CONFIG_CALLERS }}
run: bash .github/bump-callers/bump-callers.sh