Skip to content

Revoke app token post-step has unbounded curl — slow GitHub /installation/token hangs the whole workflow #1435

Description

@glaicier-gastown

Summary

The Revoke app token post-step in action.yml runs an unbounded curl -L -X DELETE against ${GITHUB_API_URL:-https://api.github.com}/installation/token with no --max-time, no --connect-timeout, and no || true. When that endpoint hangs or is slow, the curl call waits out the runner timeout and the whole workflow is marked failed even though the main Run Claude Code Action step already posted its review comment(s) successfully.

Failure signature (canonical)

claude    Run Claude Code    No buffered inline comments
claude    Run Claude Code    ##[group]Run curl -L \
claude    Run Claude Code      -X DELETE \
claude    Run Claude Code      -H "Accept: application/vnd.github+json" \
claude    Run Claude Code      -H "Authorization: ***" \
claude    Run Claude Code      ${GITHUB_API_URL:-https://api.github.com}/installation/token
claude    Run Claude Code      0     0    0     0    0     0      0      0 --:--:--

The progress meter (0 0 0 0 0 0 0 0 --:--:--) confirms curl is open and waiting on bytes from the endpoint.

Impact in caller's workflow

On the M365 Migration Planner repo, we observed:

  • 5/20 success rate (25%) across one day of runs on 2026-06-24
  • 100% failure rate from 2026-06-24 21:19Z onward (across multiple PRs)
  • Each failure pattern is identical: main step posts the verdict comment, post-step crashes during cleanup, workflow marked failed
  • Our review-gate keys off comment content (not workflow status), so the gate works — but downstream consumers that key off workflow conclusion see a red status

Affected location

action.yml (verified at v1 SHA 428971d2ecd6e3a7cb0ee0da2a3a8b33fdb3678d, 2026-06-24):

- name: Revoke app token
  if: always() && inputs.github_token == '' && steps.run.outputs.github_token != '' && steps.run.outputs.skipped_due_to_workflow_validation_mismatch != 'true'
  shell: bash
  run: |
    curl -L \
      -X DELETE \
      -H "Accept: application/vnd.github+json" \
      -H "Authorization: Bearer ${{ steps.run.outputs.github_token }}" \
      -H "X-GitHub-Api-Version: 2022-11-28" \
      ${GITHUB_API_URL:-https://api.github.com}/installation/token

Suggested fix

Either of these resolves the cleanup-shadowing-success failure mode:

Option A (minimal):

    curl -L \
      --max-time 10 \
      --connect-timeout 5 \
      -X DELETE \
      ...
      ${GITHUB_API_URL:-https://api.github.com}/installation/token || true

Option B: add continue-on-error: true at the step level.

Both keep the security intent (best-effort revoke of the temp installation token) without letting cleanup hide a successful review. The temp token has a 1-hour TTL — failing-to-revoke is a soft signal, not a security gap.

Reproduction

Cannot deterministically reproduce; the underlying /installation/token slowness appears upstream-of-action. But the failure mode (one slow endpoint hanging a curl with no timeout → workflow marked failed) is deterministic given those conditions.

Workaround consumers can apply

Set continue-on-error: true on the action step in the calling workflow. Tradeoff: also masks any future legitimate failure of the main step, so it's a temporary unblock, not a fix.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions