mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
fix(ci): restrict BM Bossbot to trusted PR authors
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -65,6 +65,24 @@ jobs:
|
||||
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}"
|
||||
|
||||
- name: Classify PR author
|
||||
id: trust
|
||||
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
|
||||
env:
|
||||
@@ -75,8 +93,36 @@ jobs:
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
||||
|
||||
- name: Decline outside contributor PRs
|
||||
id: outside
|
||||
if: steps.trust.outputs.trusted_author != 'true'
|
||||
env:
|
||||
HEAD_SHA: ${{ steps.pr.outputs.head_sha }}
|
||||
AUTHOR_ASSOCIATION: ${{ steps.trust.outputs.author_association }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
review_file="${RUNNER_TEMP}/bm-bossbot-review.json"
|
||||
jq -n \
|
||||
--arg sha "${HEAD_SHA}" \
|
||||
--arg association "${AUTHOR_ASSOCIATION}" \
|
||||
'{
|
||||
reviewed_head_sha: $sha,
|
||||
review_complete: false,
|
||||
verdict: "needs_human",
|
||||
blocking_findings: [
|
||||
{
|
||||
title: "BM Bossbot does not run for outside contributors",
|
||||
body: "This PR author association is \($association). BM Bossbot only runs for OWNER, MEMBER, and COLLABORATOR pull requests, so this PR requires a maintainer path outside the automatic merge gate."
|
||||
}
|
||||
],
|
||||
nonblocking_findings: [],
|
||||
summary: "BM Bossbot intentionally did not run Codex because this PR was not opened by an owner, member, or collaborator."
|
||||
}' > "${review_file}"
|
||||
echo "review_file=${review_file}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Collect sanitized PR context
|
||||
id: context
|
||||
if: steps.trust.outputs.trusted_author == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
PR_NUMBER: ${{ steps.pr.outputs.pr_number }}
|
||||
@@ -149,7 +195,7 @@ jobs:
|
||||
|
||||
- name: Run BM Bossbot review with Codex
|
||||
id: codex
|
||||
if: steps.context.outputs.diff_truncated != 'true'
|
||||
if: steps.trust.outputs.trusted_author == 'true' && steps.context.outputs.diff_truncated != 'true'
|
||||
uses: openai/codex-action@v1
|
||||
with:
|
||||
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
||||
@@ -159,6 +205,17 @@ jobs:
|
||||
sandbox: read-only
|
||||
safety-strategy: drop-sudo
|
||||
|
||||
- name: Select BM Bossbot review output
|
||||
id: review_output
|
||||
if: always()
|
||||
env:
|
||||
OUTSIDE_REVIEW_FILE: ${{ steps.outside.outputs.review_file }}
|
||||
CONTEXT_REVIEW_FILE: ${{ steps.context.outputs.review_file }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
review_file="${OUTSIDE_REVIEW_FILE:-${CONTEXT_REVIEW_FILE:-${RUNNER_TEMP}/missing-bm-bossbot-review.json}}"
|
||||
echo "review_file=${review_file}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Finalize BM Bossbot approval
|
||||
if: always()
|
||||
env:
|
||||
@@ -166,7 +223,7 @@ jobs:
|
||||
run: |
|
||||
uv run --script scripts/bm_bossbot_status.py finalize \
|
||||
--event "${{ steps.pr.outputs.event_file }}" \
|
||||
--review "${{ steps.context.outputs.review_file }}" \
|
||||
--review "${{ steps.review_output.outputs.review_file }}" \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--run-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
||||
|
||||
|
||||
@@ -106,10 +106,38 @@ def test_bm_bossbot_rejects_oversized_diffs_without_partial_approval() -> None:
|
||||
assert "review_complete: false" in workflow_text
|
||||
assert 'verdict: "needs_human"' in workflow_text
|
||||
assert "Diff exceeds BM Bossbot review limit" in workflow_text
|
||||
assert run_codex["if"] == "steps.context.outputs.diff_truncated != 'true'"
|
||||
assert (
|
||||
run_codex["if"]
|
||||
== "steps.trust.outputs.trusted_author == 'true' && steps.context.outputs.diff_truncated != 'true'"
|
||||
)
|
||||
assert "head -c 120000" not in workflow_text
|
||||
|
||||
|
||||
def test_bm_bossbot_does_not_run_codex_for_outside_contributors() -> None:
|
||||
workflow_text = WORKFLOW_PATH.read_text(encoding="utf-8")
|
||||
workflow = _workflow()
|
||||
steps = workflow["jobs"]["review"]["steps"]
|
||||
|
||||
classify = next(step for step in steps if step["name"] == "Classify PR author")
|
||||
outside = next(step for step in steps if step["name"] == "Decline outside contributor PRs")
|
||||
collect = next(step for step in steps if step["name"] == "Collect sanitized PR context")
|
||||
run_codex = next(step for step in steps if step["name"] == "Run BM Bossbot review with Codex")
|
||||
select_review = next(step for step in steps if step["name"] == "Select BM Bossbot review output")
|
||||
finalize = next(step for step in steps if step["name"] == "Finalize BM Bossbot approval")
|
||||
|
||||
assert "OWNER|MEMBER|COLLABORATOR" in classify["run"]
|
||||
assert outside["if"] == "steps.trust.outputs.trusted_author != 'true'"
|
||||
assert collect["if"] == "steps.trust.outputs.trusted_author == 'true'"
|
||||
assert (
|
||||
run_codex["if"]
|
||||
== "steps.trust.outputs.trusted_author == 'true' && steps.context.outputs.diff_truncated != 'true'"
|
||||
)
|
||||
assert select_review["if"] == "always()"
|
||||
assert "BM Bossbot does not run for outside contributors" in workflow_text
|
||||
assert "missing-bm-bossbot-review.json" in workflow_text
|
||||
assert '--review "${{ steps.review_output.outputs.review_file }}"' in finalize["run"]
|
||||
|
||||
|
||||
def test_bm_bossbot_prompt_references_engineering_style_and_json_bullets() -> None:
|
||||
prompt = PROMPT_PATH.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user