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 }}