Files
phernandez d8c9156ffd feat(ci): make BM Bossbot a deterministic merge gate
Remove the Codex LLM review and the per-PR image job — both spent API
tokens on every Bossbot run and the connector review already covers
code review. The gate is now fully deterministic: Tests passed for the
head SHA, non-draft, trusted author, zero unresolved review threads.
Prompt/schema files removed; guard tests updated to forbid
openai/codex-action and image generation from reappearing.

Signed-off-by: phernandez <paul@basicmachines.co>
2026-06-10 09:43:47 -05:00

194 lines
7.3 KiB
YAML

name: BM Bossbot
"on":
workflow_run:
workflows:
- Tests
types:
- completed
workflow_dispatch:
inputs:
pr_number:
description: Pull request number to review
required: true
# Review-thread activity re-evaluates the approval status without re-running
# the full LLM review: new feedback flips the gate to failure, resolving the
# last thread restores a previously earned approval for the same head SHA.
pull_request_review:
types:
- submitted
pull_request_review_comment:
types:
- created
pull_request_review_thread:
types:
- resolved
- unresolved
permissions:
contents: read
pull-requests: write
statuses: write
issues: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
BM_BOSSBOT_STATUS_CONTEXT: "BM Bossbot Approval"
jobs:
review:
name: BM Bossbot Review
# Job-level concurrency (not workflow-level): thread-recheck events for the
# same PR must never cancel an in-flight review run, and vice versa.
concurrency:
group: bm-bossbot-review-${{ github.event.workflow_run.pull_requests[0].number || inputs.pr_number }}
cancel-in-progress: true
if: |
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.pull_requests[0].number != ''
)
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.pr.outputs.pr_number }}
should_review: ${{ steps.pr.outputs.should_review }}
steps:
- name: Checkout trusted base ref
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 1
- name: Set up uv
uses: astral-sh/setup-uv@v3
- name: Normalize PR event
id: pr
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
event_file="${RUNNER_TEMP}/bm-bossbot-event.json"
should_review=true
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
pr_number="${{ inputs.pr_number }}"
tested_sha=""
else
pr_number="$(jq -r '.workflow_run.pull_requests[0].number // ""' "${GITHUB_EVENT_PATH}")"
tested_sha="$(jq -r '.workflow_run.head_sha // ""' "${GITHUB_EVENT_PATH}")"
fi
gh api "repos/${GITHUB_REPOSITORY}/pulls/${pr_number}" > "${RUNNER_TEMP}/pull.json"
current_head_sha="$(jq -r '.head.sha' "${RUNNER_TEMP}/pull.json")"
draft="$(jq -r '.draft' "${RUNNER_TEMP}/pull.json")"
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
tests_run_id="$(
gh api -X GET "repos/${GITHUB_REPOSITORY}/actions/workflows/test.yml/runs" \
-f event=push \
-f head_sha="${current_head_sha}" \
-f status=completed \
--jq '[.workflow_runs[] | select(.conclusion == "success")][0].id // ""'
)"
if [ -z "${tests_run_id}" ]; then
should_review=false
echo "BM Bossbot skipped PR ${pr_number}: no successful Tests workflow for ${current_head_sha}."
fi
fi
if [ "${draft}" = "true" ]; then
should_review=false
echo "BM Bossbot skipped PR ${pr_number}: draft pull request."
fi
if [ -n "${tested_sha}" ] && [ "${tested_sha}" != "${current_head_sha}" ]; then
should_review=false
echo "BM Bossbot skipped PR ${pr_number}: Tests passed for ${tested_sha}, but current head is ${current_head_sha}."
fi
jq --arg repo "${GITHUB_REPOSITORY}" \
'{repository:{full_name:$repo}, pull_request:{number:.number,title:.title,body:(.body // ""),html_url:.html_url,head:{sha:.head.sha,ref:.head.ref},base:{ref:.base.ref,sha:.base.sha},author_association:.author_association,draft:.draft}}' \
"${RUNNER_TEMP}/pull.json" > "${event_file}"
echo "event_file=${event_file}" >> "${GITHUB_OUTPUT}"
echo "pr_number=$(jq -r '.pull_request.number' "${event_file}")" >> "${GITHUB_OUTPUT}"
echo "head_sha=$(jq -r '.pull_request.head.sha' "${event_file}")" >> "${GITHUB_OUTPUT}"
echo "head_ref=$(jq -r '.pull_request.head.ref' "${event_file}")" >> "${GITHUB_OUTPUT}"
echo "author_association=$(jq -r '.pull_request.author_association // ""' "${event_file}")" >> "${GITHUB_OUTPUT}"
echo "tested_sha=${tested_sha}" >> "${GITHUB_OUTPUT}"
echo "should_review=${should_review}" >> "${GITHUB_OUTPUT}"
- name: Classify PR author
id: trust
if: steps.pr.outputs.should_review == 'true'
env:
AUTHOR_ASSOCIATION: ${{ steps.pr.outputs.author_association }}
run: |
set -euo pipefail
case "${AUTHOR_ASSOCIATION}" in
OWNER|MEMBER|COLLABORATOR)
trusted_author=true
;;
*)
trusted_author=false
;;
esac
echo "trusted_author=${trusted_author}" >> "${GITHUB_OUTPUT}"
echo "author_association=${AUTHOR_ASSOCIATION}" >> "${GITHUB_OUTPUT}"
- name: Mark BM Bossbot approval pending
if: steps.pr.outputs.should_review == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
uv run --script scripts/bm_bossbot_status.py pending \
--event "${{ steps.pr.outputs.event_file }}" \
--repo "${GITHUB_REPOSITORY}" \
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
- name: Finalize BM Bossbot approval
if: always() && steps.pr.outputs.should_review == 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
uv run --script scripts/bm_bossbot_status.py finalize \
--event "${{ steps.pr.outputs.event_file }}" \
--trusted "${{ steps.trust.outputs.trusted_author }}" \
--repo "${GITHUB_REPOSITORY}" \
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
recheck:
name: BM Bossbot Thread Recheck
if: |
github.event_name == 'pull_request_review' ||
github.event_name == 'pull_request_review_comment' ||
github.event_name == 'pull_request_review_thread'
runs-on: ubuntu-latest
# Job-level concurrency: collapse bursts of thread events for one PR while
# staying isolated from the review job's group so neither cancels the other.
concurrency:
group: bm-bossbot-recheck-${{ github.event.pull_request.number }}
cancel-in-progress: true
steps:
- name: Checkout trusted base ref
uses: actions/checkout@v6
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 1
- name: Set up uv
uses: astral-sh/setup-uv@v3
- name: Re-evaluate approval from review-thread state
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
uv run --script scripts/bm_bossbot_status.py recheck \
--pr-number "${{ github.event.pull_request.number }}" \
--repo "${GITHUB_REPOSITORY}" \
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"