From 1c0ce80e8ea8a3e047d2ed8b2ea35e9292a89981 Mon Sep 17 00:00:00 2001 From: BlindMaster24 <375291171150z@gmail.com> Date: Thu, 17 Sep 2026 10:54:12 +0300 Subject: [PATCH] fix(ci): keep a refused Claude credential from reddening a pull request (#6585) * fix(ci): keep a refused Claude credential from reddening a PR An expired subscription ends the claude-code-action step with exit 0, so the classifier that exists for "the API refused this run" never sees it -- its condition is a failed step -- and the final "posted nothing" step reddens the pull request although nothing is wrong with the repository. Verified against five real runs (35159059540, 35184688775, 35185722358, 35186543654, 35187380192): step 8 success, step 10 found no cause, step 11 failure, transcript {"error":"oauth_org_not_allowed"} plus a result entry with api_error_status 403. A usage-limited run carries 429 and a rejected rate_limit_event, and a real review carries is_error false with no status, so the 401/403 test fires on the refused credential alone. * fix(ci): stop a refused credential reddening the issue analysis The same exit-0 refusal reaches this workflow's "posted no reply" check, which fails for the same reason and shows up as seven failed runs in a day. It never attaches to a pull request -- the trigger excludes them -- so this is the same step and the same 401/403 transcript test applied where the refusal lands. Reported only as a warning annotation: nothing was analysed, and there is no comment worth posting about a credential the maintainer has to renew. --- .github/workflows/claude-issue-analyst.yml | 18 +++++++++++++++++- .github/workflows/claude-pr-review.yml | 17 ++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/claude-issue-analyst.yml b/.github/workflows/claude-issue-analyst.yml index 894c6a5e9..3d7edf554 100644 --- a/.github/workflows/claude-issue-analyst.yml +++ b/.github/workflows/claude-issue-analyst.yml @@ -437,8 +437,24 @@ jobs: path: ${{ runner.temp }}/claude-execution-output.json if-no-files-found: ignore retention-days: 7 - - name: Fail if the analysis posted no reply + # A refused credential ends the action with exit 0, so the step below cannot + # tell it from a reply that landed: the transcript is the only place it appears. + - name: Report an analysis the credential refused + id: refused if: ${{ !cancelled() }} + env: + TRANSCRIPT: ${{ runner.temp }}/claude-execution-output.json + ISSUE: ${{ github.event.issue.number }} + run: | + set -euo pipefail + [ -f "$TRANSCRIPT" ] || exit 0 + jq -e 'any(.[]; .type == "result" and ((.api_error_status // 0) == 401 or (.api_error_status // 0) == 403))' "$TRANSCRIPT" >/dev/null 2>&1 \ + || jq -e 'any(.[]; ((.error // "") | test("^(oauth_|authentication_|invalid_api_key)")))' "$TRANSCRIPT" >/dev/null 2>&1 \ + || exit 0 + echo "skipped=true" >> "$GITHUB_OUTPUT" + echo "::warning::No analysis of #${ISSUE}: the Claude credential was refused, so this issue was not examined." + - name: Fail if the analysis posted no reply + if: ${{ !cancelled() && steps.refused.outputs.skipped != 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index 82be90ff1..e7ef3af73 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -228,10 +228,25 @@ jobs: echo "skipped=true" >> "$GITHUB_OUTPUT" echo "::notice::No review of #${PR}: ${reason}." gh pr comment "$PR" --repo "$REPO" --body "No review ran on this head: ${reason}. Nothing in this pull request was examined. A maintainer can ask for one with \`@claude review\`." + # A refused credential ends the action with exit 0, so the step above never + # sees it: the transcript is the only place that refusal appears. + - name: Report a review the credential refused + id: refused + if: ${{ !cancelled() }} + env: + TRANSCRIPT: ${{ runner.temp }}/claude-execution-output.json + run: | + set -euo pipefail + [ -f "$TRANSCRIPT" ] || exit 0 + jq -e 'any(.[]; .type == "result" and ((.api_error_status // 0) == 401 or (.api_error_status // 0) == 403))' "$TRANSCRIPT" >/dev/null 2>&1 \ + || jq -e 'any(.[]; ((.error // "") | test("^(oauth_|authentication_|invalid_api_key)")))' "$TRANSCRIPT" >/dev/null 2>&1 \ + || exit 0 + echo "skipped=true" >> "$GITHUB_OUTPUT" + echo "::warning::No review of #${PR}: the Claude credential was refused, so nothing in this pull request was examined." # updated_at, not created_at: a re-review may edit its earlier comment. # --paginate prints one jq count per page, so the pages are summed. - name: Fail if the review posted nothing - if: ${{ !cancelled() && steps.pinned-sha.outcome == 'success' && steps.reviewed.outputs.done != 'true' && steps.throttled.outputs.skipped != 'true' }} + if: ${{ !cancelled() && steps.pinned-sha.outcome == 'success' && steps.reviewed.outputs.done != 'true' && steps.throttled.outputs.skipped != 'true' && steps.refused.outputs.skipped != 'true' }} env: HEAD_SHA: ${{ steps.pinned-sha.outputs.sha }} STARTED_AT: ${{ steps.started.outputs.at }}