-
Notifications
You must be signed in to change notification settings - Fork 92
feat(fix): cap automated review->fix cycles per PR #6596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,15 @@ | |
| # check-fix-eligibility.sh — Determine if a bot-triggered fix should auto-run. | ||
| # | ||
| # Inputs (env vars): | ||
| # GH_TOKEN — GitHub token for API calls | ||
| # PR_NUM — Pull request number | ||
| # SOURCE_REPO — Repository in owner/repo format | ||
| # TRIGGER_SOURCE — Username that triggered the fix | ||
| # GH_TOKEN — GitHub token for API calls | ||
| # PR_NUM — Pull request number | ||
| # SOURCE_REPO — Repository in owner/repo format | ||
| # TRIGGER_SOURCE — Username that triggered the fix | ||
| # REVIEW_MAX_FIX_CYCLES — Cap on review-bot CHANGES_REQUESTED cycles before | ||
| # blocking further bot-triggered fixes. Default 3, | ||
| # 0 disables. Non-numeric values warn and fall back | ||
| # to the default. CI-runtime gating knob, not an | ||
| # agent behavior knob — see ADR 0081. | ||
| # | ||
| # Exits 0 if fix should proceed, 1 if it should be skipped. | ||
| # Emits GitHub Actions annotations (::warning::) for skip reasons. | ||
|
|
@@ -59,3 +64,54 @@ if [[ "${PR_IS_BOT}" != "true" || "${PR_LOGIN}" != "app/fullsend-ai-coder" ]]; t | |
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| # Cap automated fix cycles: block further bot-triggered fixes once the | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [medium] GHA workflow command injection REVIEW_MAX_FIX_CYCLES is interpolated into a ::warning:: annotation before numeric validation succeeds. At this point it contains the raw invalid value. The existing code sanitizes PR_IS_BOT and PR_LOGIN via _sanitize_for_annotation for the same reason. Although the source is vars.REVIEW_MAX_FIX_CYCLES (settable only by repo admins), the new interpolation should follow the same defense-in-depth pattern. Suggested fix: Pass the value through _sanitize_for_annotation before the ::warning:: emission on line 68. |
||
| # review bot has requested changes REVIEW_MAX_FIX_CYCLES times on this PR. | ||
| # Each CHANGES_REQUESTED review is one trip around the review->fix loop; | ||
| # uncapped, a standing disagreement between the review and fix agents can | ||
| # oscillate until someone notices the bill. Human /fs-fix is unaffected — | ||
| # it already exited at the TRIGGER_SOURCE check above, before this gate. | ||
| REVIEW_MAX_FIX_CYCLES="${REVIEW_MAX_FIX_CYCLES:-3}" | ||
| if [[ ! "${REVIEW_MAX_FIX_CYCLES}" =~ ^[0-9]+$ ]]; then | ||
| # Mirrors route-review-model.sh's TRIVIAL_MAX_LINES handling, but falls | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [medium] dangling cross-reference The inline comment references route-review-model.sh's TRIVIAL_MAX_LINES handling as precedent, but neither exists in this repository. The PR body notes it ships in draft PR #6590; if that PR is abandoned or modified, this comment becomes misleading. Suggested fix: Replace with self-contained rationale: 'An unenforceable cap must not silently become no cap, so we warn and fall back to the default.' |
||
| # back to the default instead of bailing out entirely — an unenforceable | ||
| # cap must not silently become "no cap". | ||
| echo "::warning::REVIEW_MAX_FIX_CYCLES is not a number (${REVIEW_MAX_FIX_CYCLES}) — using default of 3" | ||
| REVIEW_MAX_FIX_CYCLES=3 | ||
| fi | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [low] edge-case If gh api --paginate returns a 200 with a completely empty body, jq -s 'add' produces null and .[] fails. In practice, GitHub's reviews endpoint always returns an array, and the failure path falls through safely to the else branch. |
||
| if [[ "${REVIEW_MAX_FIX_CYCLES}" != "0" ]]; then | ||
| # The review bot's REST login is "<org>-review[bot]" (see | ||
| # docs/contributing/bot-identities.md). SOURCE_REPO already carries the | ||
| # org, so it's derived here rather than threaded in as a new input — | ||
| # the same construction as the REVIEW_BOT var in the "Pre-fetch review | ||
| # body" step of reusable-dispatch.yml. | ||
| REVIEW_BOT_LOGIN="${SOURCE_REPO%%/*}-review[bot]" | ||
|
|
||
| if CYCLE_COUNT=$(gh api "repos/${SOURCE_REPO}/pulls/${PR_NUM}/reviews" \ | ||
| --paginate 2>/dev/null \ | ||
| | jq -s --arg login "${REVIEW_BOT_LOGIN}" \ | ||
| 'add | [.[] | select(.state == "CHANGES_REQUESTED" and .user.login == $login)] | length'); then | ||
| if (( CYCLE_COUNT >= REVIEW_MAX_FIX_CYCLES )); then | ||
| echo "::warning::PR #${PR_NUM} has reached ${CYCLE_COUNT} automated fix cycles (cap ${REVIEW_MAX_FIX_CYCLES}) — a human needs to look" | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [medium] fail-open When the reviews API call fails, the script proceeds without enforcing the cycle cap ('proceeding without the cap'). This is a fail-open pattern on a safety gate. A transient API failure silently bypasses the cap, undermining its purpose. Suggested fix: Consider failing closed (exit 1) on API failure, or add an explicit comment documenting the fail-open tradeoff and confirming it is intentional. |
||
| MARKER='<!-- fullsend-fix-cycle-cap -->' | ||
| EXISTING_ID=$(gh api "repos/${SOURCE_REPO}/issues/${PR_NUM}/comments" \ | ||
| --paginate 2>/dev/null \ | ||
| | jq -r --arg marker "${MARKER}" '.[] | select(.body | contains($marker)) | .id' \ | ||
| | head -n1 || true) | ||
|
|
||
| if [[ -z "${EXISTING_ID}" ]]; then | ||
| COMMENT_BODY="${MARKER} | ||
| ${CYCLE_COUNT} automated fix cycles reached on this PR — a human needs to look. Trigger \`/fs-fix\` manually to run another cycle." | ||
| jq -n --arg body "${COMMENT_BODY}" '{body: $body}' \ | ||
| | gh api -X POST "repos/${SOURCE_REPO}/issues/${PR_NUM}/comments" --input - >/dev/null \ | ||
| || echo "::warning::Could not post fix-cycle-cap comment on PR #${PR_NUM}" | ||
| fi | ||
|
|
||
| exit 1 | ||
| fi | ||
| else | ||
| echo "::warning::Could not count review cycles for PR #${PR_NUM} — proceeding without the cap" | ||
| fi | ||
| fi | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[low] test-organization
run_test now takes 11 positional arguments. Other test files in the repo cap at 4-5 args using separate setup functions. Optional middle parameters require empty-string placeholders at call sites.
Suggested fix: Consider splitting cycle-cap test state into a separate setup step or environment variables.