Skip to content

fix(release): support optional PAT for release-please PR creation #1

fix(release): support optional PAT for release-please PR creation

fix(release): support optional PAT for release-please PR creation #1

Workflow file for this run

name: "Review Bot"
on:
pull_request_target:
types:
- opened
- synchronize
- reopened
permissions:
contents: read
pull-requests: read
jobs:
review:
name: review-bot
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
# Base-ref checkout only -- this workflow never checks out or executes
# the untrusted PR head; it only reads a computed diff as text and
# feeds it to the pinned, trusted autogen critic (see below).
- name: Checkout repository (base ref, scripts only)
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: "3.12"
- name: Mint review-bot App installation token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.REVIEW_BOT_APP_ID }}
private-key: ${{ secrets.REVIEW_BOT_PRIVATE_KEY }}
# --- Gate 1: eligibility classifier -------------------------------
- name: Classify eligibility
id: classify
shell: pwsh
continue-on-error: true
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
pwsh -File .github/scripts/classify-automerge-eligibility.ps1 `
-PrNumber ${{ github.event.pull_request.number }} `
-Repo ${{ github.repository }}
if ($LASTEXITCODE -eq 0) {
"eligible=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
} else {
"eligible=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
}
- name: Out-of-class - no approval, human review path
if: steps.classify.outputs.eligible != 'true'
run: |
echo "PR is OUT-OF-CLASS. review-bot will not approve or merge. Falling back to human review."
# --- Gate 2: deterministic critic (autogen critic_cli, pinned) ----
# SECURITY (T-38-SEC-PWN / CodeQL actions/checkout-of-untrusted-code,
# PR #17 review-bot.yml lines 59-68): this job runs under
# pull_request_target with a minted App token, so the PR head is
# untrusted content in a privileged context. It MUST NOT be fetched,
# checked out, or merged into the local git object database here --
# not even via a bare `git fetch`. The diff is obtained exclusively
# through the GitHub API (`gh pr diff`, an authenticated HTTPS call
# that returns text, not a git ref) and streamed straight into
# critic_cli over stdin in the "Run critic_cli" step below. No PR-head
# commit ever touches this runner's filesystem or git state.
- name: Checkout autogen (pinned commit, for critic_cli)
if: steps.classify.outputs.eligible == 'true'
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: Coding-Autopilot-System/autogen
# Pinned to origin/main commit b0524b7 (merged PR #17,
# "consolidate refresh stack and workflow hardening"), verified
# via `git log origin/main -- maf_starter/critic_cli.py`. NEVER
# point this at feat/phase-29-peer-critic (closed, unmerged PR
# #14 -- see docs/merge-flow-policy.md).
ref: b0524b762024237d047fde25b50679da42e1a5e2
path: autogen-critic
continue-on-error: true
id: checkout-autogen
- name: Pin verification guard
if: steps.classify.outputs.eligible == 'true' && steps.checkout-autogen.outcome != 'success'
run: |
echo "autogen checkout at the pinned critic_cli SHA failed -- treating as a hard stop (fail-closed). No approval will be issued." >&2
exit 1
- name: Run critic_cli against PR diff (diff via API, no checkout of PR head)
id: critic
if: steps.classify.outputs.eligible == 'true'
working-directory: autogen-critic
env:
PYTHONPATH: ${{ github.workspace }}/autogen-critic
# Read-only default token (permissions: contents: read, pull-requests:
# read) is sufficient for `gh pr diff`; the App token is intentionally
# NOT used here (least privilege -- this step never approves/merges).
GH_TOKEN: ${{ github.token }}
run: |
set -o pipefail
python -m pip install --quiet -r requirements.txt
gh pr diff "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" \
| python -m maf_starter.critic_cli --diff - --severity-gate blocking \
| tee "${{ github.workspace }}/critic-output.txt"
diff_exit=${PIPESTATUS[0]}
critic_exit=${PIPESTATUS[1]}
if [ "${diff_exit}" -ne 0 ]; then
echo "gh pr diff failed (exit ${diff_exit}) -- treating as a hard stop (fail-closed). No approval will be issued." >&2
echo "critic_exit=1" >> "$GITHUB_OUTPUT"
exit 1
fi
echo "critic_exit=${critic_exit}" >> "$GITHUB_OUTPUT"
continue-on-error: true
- name: Request changes - critic findings block auto-merge
if: steps.classify.outputs.eligible == 'true' && steps.critic.outputs.critic_exit != '0'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh pr review "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" \
--request-changes --body-file "${{ github.workspace }}/critic-output.txt" || true
echo "critic_cli reported blocking findings (or could not run). review-bot will not approve." >&2
# --- Gate 3: required CI checks green ------------------------------
- name: Confirm required CI checks are green
id: ci-green
if: steps.classify.outputs.eligible == 'true' && steps.critic.outputs.critic_exit == '0'
continue-on-error: true
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh pr checks "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" --required
# --- Approve + auto-merge (App identity, all three gates clean) ---
- name: Approve and enable auto-merge (review-bot App)
if: >-
steps.classify.outputs.eligible == 'true' &&
steps.critic.outputs.critic_exit == '0' &&
steps.ci-green.outcome == 'success'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh pr review "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" \
--approve --body "cas-review-bot: eligibility=IN-CLASS, critic_cli=0 blocking, CI=green. Auto-approved per docs/merge-flow-policy.md."
gh pr merge "${{ github.event.pull_request.number }}" --repo "${{ github.repository }}" --auto --squash