Conversation
…d scope headers Under set -euo pipefail, command substitutions for RATE_REMAINING, RATE_LIMIT, and SCOPES caused the script to exit immediately when grep returned 1 for missing headers. This caused fine-grained PATs and GitHub App tokens (which omit x-oauth-scopes) as well as responses missing rate limit headers to fail health check silently. Make the command substitutions non-fatal with || true so missing headers evaluate cleanly to empty strings, enabling the fine-grained token fallback branch to execute and outputs to be written. Also unskip the corresponding unit tests in check-token-health_test.bats. Fixes projectbluefin#339 Signed-off-by: Danathar <Danathar@users.noreply.github.com>
hanthor
left a comment
There was a problem hiding this comment.
Verified: real set -e defect, correct fix, and the un-skipped tests genuinely cover it
The defect is real. check_token_health.sh line 4 is set -euo pipefail. With pipefail, grep's exit 1 on a missing header propagates through | awk | tr, and because a bare VAR=$(...) assignment takes the pipeline's status, set -e kills the script. So a fine-grained PAT or App token — which never sends x-oauth-scopes — aborts the health check at the scope parse. Adding || true is the right minimal fix.
The un-skipped tests are not vacuous. I checked by removing the fix and re-running, which is the only way to know a newly-enabled test is actually testing something:
$ git checkout test/350 # this branch merged into origin/main
$ sed -i 's/ || true$//' .github/actions/check-token-health/check_token_health.sh
$ bats tests/unit/check-token-health_test.bats
not ok 11 missing rate limit headers report unknown and still pass
not ok 19 fine-grained token without a scopes header skips the scope check
Both tests you un-skipped fail the moment the fix is reverted. They are load-bearing. (A third case also flipped, but that was my sed over-matching a pre-existing || true on line 25 — "${GITHUB_API}/user" 2>/dev/null) || true — not something this PR introduced. Discounting it.)
These are also not "asserts non-zero exit" tests — they check [ "${status}" -eq 0 ] and the reported output, so a crash would not pass them.
Full gates, this branch merged into origin/main @ 1db684b:
bats tests/unit -> 180 ok, 0 not ok
just lint -> exit 0
just check -> exit 0
Identical to the baseline I measured on unmodified main (180/180, lint 0, check 0), so nothing regressed.
For the record, on main those two cases are reported as skips, which matches your description exactly:
ok 48 missing rate limit headers report unknown and still pass # skip known defect #339: ...
ok 56 fine-grained token without a scopes header skips the scope check # skip known defect #339: ...
Blocker is not the code
No CI has executed on this PR. get_check_runs returns total_count: 0, and the workflow run is parked:
Unit Tests, run_number 55, head_sha 1615a30
event: pull_request, status: completed, conclusion: action_required
A maintainer needs to approve fork workflow runs before BATS unit tests and validate can report. The change itself looks good to me.
Minor, non-blocking
|| true on all three assignments is correct but slightly blunt: it also swallows a genuine awk/tr failure, not just "header absent". If you want to be precise, RATE_REMAINING=$(grep -i ... || true) — moving the guard inside the substitution onto grep specifically — keeps the rest of the pipeline fail-fast. Equivalent in practice here; take it or leave it.
Generated by Claude Code
hanthor's review on projectbluefin#350 confirmed the fix itself is correct and the un-skipped tests are load-bearing, but flagged that `|| true` on the whole assignment also swallows a genuine awk/tr failure, not just "header absent". Moved the guard onto grep specifically for all three assignments, so the rest of each pipeline stays fail-fast. Verified: all 24 check-token-health tests and the full 180-test suite still pass, plus shellcheck and `just check`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LNgJ8VMdoqzGequbxsP2Kc
|
@hanthor — took the precise version, pushed in |
There was a problem hiding this comment.
Read the script and the diff against the current tree; the fix is correct.
- The defect is real:
check_token_health.sh:4setsset -euo pipefail, so when a header is absent,grepexits 1,pipefailmakes the wholeRATE_REMAINING=$(grep ... | awk ... | tr ...)pipeline fail, anderrexitaborts the script (lines 37–38 and theSCOPES=line). That makes the documented fine-grained/App-token branch ([[ -n "${SCOPES}" ]], and the "unknown/unknown" rate-limit fallback at line 39) unreachable for exactly the token types that omit those headers. { grep ... || true; }is the right minimal shape: it neutralizes only grep's not-found status while leaving real awk/sed/tr failures fatal, unlike appending|| trueto the whole assignment.- Good that the fix un-skips the two bats tests that documented this as known defect #339, so the behaviour is now pinned rather than just patched.
Looks correct to me — approval is a maintainer's call.
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
There was a problem hiding this comment.
Read the fix against the actual script. This is a real defect and the fix is correct:
check_token_health.sh:4setsset -euo pipefail. Withpipefail, when a header is absent,grep -i "^x-ratelimit-remaining:" ...exits 1, the wholegrep | awk | trpipeline fails, the assignment fails, andset -eaborts the script — exactly as the two previously-skipped tests documented ("known defect #339").- Wrapping the grep as
{ grep ... || true; }inside the pipeline (lines 37–38, 46) neutralizes only the no-match case while leaving the rest of the pipeline's error behavior intact. - The downstream guards already handle the empty result:
[[ -n "${RATE_REMAINING}" && ... ]]at line 41 and[[ -n "${SCOPES}" ]]at line 49, so "unknown/unknown" reporting and the fine-grained-token skip both become reachable, which is what the two un-skipped tests assert.
Looks correct to me. (I cannot approve; a maintainer should.)
— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78
|
Closing in favour of #385, which lands the same fix for #339 — |
Summary
Fixes #339
Under
set -euo pipefail, the command substitutions forRATE_REMAINING,RATE_LIMIT, andSCOPEScausedcheck_token_health.shto abort immediately whenevergrepexited non-zero (i.e., whenever a header was not present in the HTTP response).Consequences:
x-oauth-scopes, causing the script to exit with code 1 rather than falling back to the intended fine-grained token branch.valid,rate_remaining,expires_at) were never written toGITHUB_OUTPUTon those paths.This PR adds
|| trueto the three command substitutions so that absent headers evaluate cleanly to empty strings, allowing:unknown/unknown.x-oauth-scopesto hit the "No OAuth scopes header (likely a fine-grained token — skipping scope check)" path and pass validation.Also unskips the two regression test cases in
tests/unit/check-token-health_test.batscovering absent rate limit headers and fine-grained tokens without scopes.Verification
bats tests/unit/check-token-health_test.bats: 24/24 passing, 0 skipped, 0 failing.check_token_health.sh: clean (0 errors/warnings).— hive: backend=agy