Skip to content

feat: add deterministic CLAUDE_CODE_OAUTH_TOKEN precondition check - #106

Merged
twistedmelonman merged 5 commits into
mainfrom
claude/add-oauth-token-precondition-90-session1
Aug 8, 2026
Merged

feat: add deterministic CLAUDE_CODE_OAUTH_TOKEN precondition check#106
twistedmelonman merged 5 commits into
mainfrom
claude/add-oauth-token-precondition-90-session1

Conversation

@twistedmelonman

Copy link
Copy Markdown
Member

Summary

  • mac-dev-server-setup#58 hit a CI failure where claude-code-action failed with CLAUDE_OUTCOME: failure and no verdict rendered. The downstream verdict-parsing logic correctly fail-closed to BLOCK, but the actual root cause — a missing CLAUDE_CODE_OAUTH_TOKEN repo secret — was only visible deep in the action's own error output, misreported as a substantive review BLOCK rather than an infrastructure/config gap.
  • Adds a new "Verify CLAUDE_CODE_OAUTH_TOKEN is configured" step to both claude-assistant.yml and claude-blocking-review.yml — the two reusable workflows that actually invoke claude-code-action — placed before that invocation. Checks secrets.claude_oauth_token != '' and fails loudly with an actionable ::error:: if the caller's secret resolves empty.
  • claude.yml (the top-level caller stub for claude-assistant.yml) needed no change — it only passes the secret through and never invokes claude-code-action directly.
  • In claude-blocking-review.yml, the check is gated behind the same doc-check/dependabot-check skip outputs as the review step itself, so a misconfigured repo still gets a clean SKIPPED verdict on doc-only or Dependabot PRs instead of failing on PRs that would never have invoked claude-code-action anyway.
  • In claude-assistant.yml, the check is deliberately unconditional — that workflow has no skip paths, and by the time its job executes the caller (claude.yml) has already confirmed an authorized @claude mention, so the token is always required. A comment documents why required: false on that file's secret declaration is a GitHub dispatch-time-validation workaround (see 67630a7), not a signal the token is genuinely optional — confirmed via gh search code that all 11+ fleet callers pass the secret through unconditionally.
  • Bumps claude-blocking-review.yml to v3.2.0 (additive header note, matching the file's established versioning convention; tagging happens after merge per repo convention).

Review iteration

This PR went through two rounds of local pre-push review before landing on the final shape:

  1. First push: flagged (non-blocking, filed as Token verification runs before doc-only/Dependabot skip checks — fails repos with missing secrets even on skippable PRs #105) that the token check in claude-blocking-review.yml ran before the doc-only/Dependabot skip checks, which would fail misconfigured repos even on PRs that would have skipped review anyway. Fixed by moving the step and adding the matching if: gate.
  2. Second push: flagged (blocking) that claude-assistant.yml's check has no equivalent if: gate. Investigated and confirmed this is correct as-is (not a bug) — added a comment explaining why, rather than an incorrect gate.

Test plan

  • Extracted the shell-side check into a standalone harness and exercised TOKEN_SET=true (proceeds) and TOKEN_SET=false (errors, exit 1)
  • YAML validated on both files
  • zizmor finding counts/types identical before and after on both files (committed with SKIP=zizmor per the documented escape hatch — dotfiles pre-commit/config.yaml, PR CLAUDE_OUTCOME_RETRY comment slightly mischaracterizes the skipped-first-step case #155 — for pre-existing, unrelated findings)
  • Local pre-commit and pre-push review hooks (code-reviewer, adversarial-reviewer, full-diff + codebase review) all passed on the final state

Closes #90, closes #105.

https://claude.ai/code/session_019yrvtEbtQxBxDmZ4Fu9GrU

Claude Code Bot and others added 5 commits August 7, 2026 18:01
mac-dev-server-setup#58 hit a CI failure where the claude-code-action
step failed with CLAUDE_OUTCOME: failure and no verdict rendered. The
downstream verdict-parsing logic correctly fail-closed to BLOCK, but
the actual root cause — a missing CLAUDE_CODE_OAUTH_TOKEN repo secret
— was only visible deep in the action's own error output, misreported
as a substantive review BLOCK rather than an infrastructure/config
gap, wasting a CI cycle before someone dug through logs to find it.

Adds a new "Verify CLAUDE_CODE_OAUTH_TOKEN is configured" step to both
claude-assistant.yml and claude-blocking-review.yml — the two reusable
workflows that actually invoke claude-code-action — placed before that
invocation. Checks `secrets.claude_oauth_token != ''` and fails loudly
with an actionable ::error:: (pointing at Settings > Secrets and
/install-github-app) if the caller's secret resolves empty.

claude.yml (the top-level caller stub for claude-assistant.yml) needed
no change — it only passes the secret through and never invokes
claude-code-action directly, so the check belongs in the reusable
workflow where the actual invocation happens.

Note: claude-blocking-review.yml's `secrets: claude_oauth_token:
required: true` only guarantees the caller supplied a `secrets:`
block, not that the underlying repo secret it references is actually
set — a caller referencing an unconfigured CLAUDE_CODE_OAUTH_TOKEN
still satisfies `required: true` while passing an empty string
through, which is exactly the gap this closes.

Bumps claude-blocking-review.yml to v3.2.0 (additive header note,
matching the file's established versioning convention; tagging
happens after merge per repo convention). claude-assistant.yml has no
in-file minor-version history to extend, so its header is unchanged.

Verified: extracted the shell-side check into a standalone harness and
exercised TOKEN_SET=true (proceeds) and TOKEN_SET=false (errors, exit
1). YAML validated on both files. zizmor finding counts/types
identical before and after on both files (committed with SKIP=zizmor
per the documented escape hatch — dotfiles pre-commit/config.yaml, PR
#155 — for the same pre-existing, unrelated findings noted in the #92
and #94 PRs).

Closes #90.
Pre-push whole-codebase review (filed as #105) correctly flagged that
the "Verify CLAUDE_CODE_OAUTH_TOKEN is configured" step added in the
previous commit ran unconditionally right after the permissions
preflight — before the "Check for doc-only diff" and "Check for
Dependabot PR" skip-detection steps. A repo with CLAUDE_CODE_OAUTH_TOKEN
unset would fail the token check even on a doc-only or Dependabot PR
that would never have invoked claude-code-action in the first place,
breaking the doc-only skip's cost/noise-reduction guarantee for
misconfigured repos.

Moves the step to immediately before "Run Claude Code Review" and adds
the same `if: steps.doc-check.outputs.skip != 'true' &&
steps.dependabot-check.outputs.skip != 'true'` gate already used by
"Estimate review parameters", "Minimize prior review comments", and
the review step itself. Net change is a pure move (delete + re-add
with the if: gate) — no other logic touched.

claude-assistant.yml has no doc-only/Dependabot skip-check steps (it's
the @claude-mention assistant, not the PR-gating reviewer), so its
token-check placement from the previous commit is unaffected and
correct as-is.

Verified: YAML valid, zizmor finding count/type on this file unchanged
before/after (same 5 pre-existing findings noted in the prior commit).

Closes #105 (filed by pre-push review against this PR's first commit).
…nt.yml

Pre-push whole-codebase review flagged (as BLOCKING) that the token
check in claude-assistant.yml has no `if:` gate, while
claude-blocking-review.yml's equivalent step is gated behind doc-only/
Dependabot skip outputs — reading this as a regression that would fail
callers who "legitimately omit the secret" per its `required: false`
declaration.

Investigated and confirmed the premise is incorrect for this file:
`required: false` was added in 67630a7 specifically to work around a
GitHub dispatch-time validation quirk (required: true + a job-level
if: gate on the CALLER's job causes startup_failure even on no-op
runs) — it is not a statement that the token is optional when the job
actually runs. claude-assistant.yml's `run` job has no internal `if:`
of its own to gate behind; the @claude-mention guard lives entirely in
the caller (claude.yml), so by the time this job executes at all, an
authorized @claude mention has already been confirmed and the token is
always required. Verified via `gh search code` that every fleet caller
(11+ repos across smartwatermelon and nightowlstudiollc) passes
secrets.CLAUDE_CODE_OAUTH_TOKEN through unconditionally — none use an
alternate auth path.

No functional change — this is a documentation-only commit adding a
comment that explains why the unconditional check is deliberate and
correct, so a future reader (human or automated reviewer) doesn't
repeat the same plausible-but-incorrect inference from `required:
false` alone.

Addresses the blocking finding from pre-push review on this branch.
@twistedmelonman
twistedmelonman merged commit 543ce3e into main Aug 8, 2026
4 checks passed
@twistedmelonman
twistedmelonman deleted the claude/add-oauth-token-precondition-90-session1 branch August 8, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant