mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #271] [MERGED] feat(cursor-review-auto-label): optional bot_app_id + BOT_APP_PRIVATE_KEY pair #273
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#273
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/271
Author: @mattmillerai
Created: 9/8/2026
Status: ✅ Merged
Merged: 9/8/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-12530-auto-label-bot-app-id📝 Commits (2)
ed87601feat(cursor-review-auto-label): optional bot_app_id + BOT_APP_PRIVATE_KEY pair8e3660efix(cursor-review-auto-label): make the App-pair selection fail closed📊 Changes
3 files changed (+150 additions, -15 deletions)
View changed files
📝
.github/workflows/cursor-review-auto-label.yml(+109 -10)📝
README.md(+1 -1)📝
docs/callers/cursor-review-auto-label.md(+40 -4)📄 Description
ELI-5
The auto-label workflow always minted its GitHub App token from one hardcoded
app (
vars.APP_ID, the write-broad CLOUD_CODE_BOT). This adds an optionalsecond way in: set a
bot_app_idinput and pass the matchingBOT_APP_PRIVATE_KEY, and it mints from that narrower app instead. Saynothing and everything behaves exactly as it does today.
What changed
All in
.github/workflows/cursor-review-auto-label.yml(plus its caller doc):bot_app_id(afterruns_on), default''. App IDsaren't secret, so it's an input, not a secret — same shape as
cursor-review.ymlandpr-size.ymlalready use in this repo.BOT_APP_PRIVATE_KEY, andCLOUD_CODE_BOT_PRIVATE_KEYdrops torequired: false(re-described asrequired only when
bot_app_idis unset).Refuse an incomplete or mixed App pair, ahead ofthe mint. It enforces exactly one complete pair — every other shape exits
1 with an explicit
::error::: an id with no key, a key with no id, themix (
bot_app_idalongside aCLOUD_CODE_BOT_PRIVATE_KEYmapping),neither key, and an empty
vars.APP_IDon the default path.if: inputs.bot_app_id != ''/
== '', each reading one pair with no||on the key side, and eachrequesting
permission-pull-requests: write— the only permissiongh pr edit --add-labelneeds.docs/callers/cursor-review-auto-label.md: prerequisites table marked"Required unless
bot_app_idis set", rows added for the new input andsecret, narrow-app caller snippet under "Caller", and the "Why the App token
is mandatory" section reworded (an App mint is still mandatory; only which
App is now optional). The root
README.mdcatalog row got the sameone-clause sync, since it stated the old requirement as unconditional.
Why
vars.APP_IDis resolved at the step, not as an inputdefault:varsin a reusable workflow resolves in the caller's context. Reading itat the step is exactly where the old line read it, so the resolution path for
existing callers is untouched. A
varsdefault is documented as legal butneither sibling reusable here uses one.
Chesterton's Fence — the two lines this changes
Both
required: trueand thevars.APP_IDhardcode date to the workflow'screation commit
c84f75d(2026-06-02), and its own comment states the intent:"the label must be applied by a GitHub App so it triggers the downstream review
run". That intent is some App credential being present, not that specific
app — the single-app hardcode was the original design, not a guard added to fix
a later bug. The preflight preserves the intent exactly: a run with no usable
credential still fails, loudly.
What genuinely changes is where it fails. Before: omitting the
secrets:mapping was a startup failure with zero jobs. Now: the run starts and fails at
step 1 with a message naming the missing key. Mapping a secret that happens to
be unset (the quieter case the caller docs call out) previously reached
create-github-app-tokenand hard-failed there with a generic error; it nowfails at the preflight with an actionable one. Neither case ever produced a
green run, before or after.
The credential selection, and why it fails closed
The first cut selected the key with one expression:
GitHub's
&&/||return operands, not booleans, so a setbot_app_idwith anempty
BOT_APP_PRIVATE_KEYevaluates the left side to''and falls through tothe legacy key — silently minting from the write-broad app a caller explicitly
asked to avoid. The preflight made that unreachable, but the invariant then
lived in a different step, one
if:/continue-on-error/reorder away frombeing void. Four of six panel reviewers flagged exactly that.
It is now two mutually exclusive steps gated on
bot_app_id, each reading asingle pair. There is no fallback operand to fall through to; the mint fails
closed by its own shape. The one remaining
||issteps.app-token-narrow.outputs.token || steps.app-token-default.outputs.token,which selects between two same-purpose outputs of which exactly one ever exists
— not a credential fallback, and neither mint is
continue-on-error, so afailed mint fails the job before the label step.
app-id: ${{ inputs.bot_app_id || vars.APP_ID }}is likewise gone; each stepnames its own app id literally.
Verification
Re-run on the review-fix commit, in a clean worktree:
actionlint .github/workflows/cursor-review-auto-label.yml— 0 findings(actionlint shellchecks
run:blocks, so the expanded preflight script iscovered).
zizmor --persona=regular .github/workflows/cursor-review-auto-label.yml—no findings (1 suppressed). The
github-app"blanket installationpermissions" finding CodeRabbit surfaced is resolved by the two
permission-pull-requests: writeinputs.python3 -m unittest discover -s .github/workflow-pins/tests— 316 tests,OK;
python3 .github/workflow-pins/check_workflow_pins.py— OK, 11workflows, every ref checkout guarded. (
test-workflow-pins.ymlis the one CIjob path-filtered onto
.github/workflows/**, so it is what this diff trips.)bash .github/bump-callers/tests/test_bump_callers.sh— 437 passed, 0failed (this file is referenced by name in that suite).
python3 .github/agents-md-integrity/check_agents_md.py --root .— passed(2 pre-existing warnings: AGENTS.md at 155 lines, no CODEOWNERS).
yaml.safe_load— parses; inputs still[review_label, skip_label, runs_on, bot_app_id], both secrets stillrequired: false, steps now[Refuse an incomplete or mixed App pair, Generate GitHub App token (narrow App), Generate GitHub App token (default CLOUD_CODE_BOT), Apply label ...].permission-pull-requests: writesufficing for a label write is not assumedfrom docs alone:
pr-area-label.yml'slabel-prjob already applies a PRlabel in this org holding exactly
contents: read+pull-requests: write.Residual
this environment holds no access to, so "the default path still works" is
established by reading the rendered expressions, not by observing a run. The
first real proof will be the pin-bump PRs
bump-auto-label-callers.ymlopensafter this merges — somebody should confirm one auto-label run goes green
rather than assuming it.
secrets: inheritis now load-bearing against the mix check. A caller thatuses
secrets: inheritand happens to hold a repo/org secret literally namedBOT_APP_PRIVATE_KEYwill now hard-fail where it previously ran. That name isintroduced by this PR, so no current caller can be in that state, but a repo
that later adds the secret for another purpose would trip it. The alternative —
softening the invariant to "at least one" — is the fail-open the panel's High
finding was about, so the loud failure was taken deliberately; the
::error::names
secrets: inheritexplicitly.permission-pull-requests: writenarrows the DEFAULT path too, not just thenew one. If a caller's CLOUD_CODE_BOT installation lacked that permission the
mint now fails where it used to succeed — but the subsequent
gh pr edit --add-labelwould have 403'd anyway, so the run was already red;it now fails earlier and more legibly.
secrets:block entirely used to fail at startupconsuming no runner; it now starts a job and fails at the preflight. Unchanged
from the first commit, restated because it is a real change to a failure mode.
into the
comfy-cloud-mcp-serverpull_requestcaller is a change in thatrepo and out of scope; this PR only makes it expressible.
(BE-####)suffixAGENTS.mdasks for,because this repo is public and internal tracking references must stay out of
world-readable text. The branch name carries the autolink instead.
Provenance
README.mdcatalog-row sync, rewording the doc's "Why the App token is mandatory" paragraph, and the review-fix commit8e3660e(fail-closed mint split, three added preflight arms, token permission narrowing) — the last is a response to the review panel + CodeRabbit, not to the ticket. See## Residualfor what remains unexercised.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.