Skip to content

fix: refresh GitHub App tokens before push/reply in review-agent - #82494

Open
bryan-cox wants to merge 1 commit into
openshift:mainfrom
bryan-cox:fix-review-agent-token-refresh
Open

fix: refresh GitHub App tokens before push/reply in review-agent#82494
bryan-cox wants to merge 1 commit into
openshift:mainfrom
bryan-cox:fix-review-agent-token-refresh

Conversation

@bryan-cox

@bryan-cox bryan-cox commented Jul 27, 2026

Copy link
Copy Markdown
Member

Summary

  • Store GitHub App tokens in files (/tmp/.github-token-{fork,upstream}) instead of baking them into env vars and git config
  • Git credential helper reads from file each invocation, so refreshed tokens are picked up automatically
  • Switch from export GITHUB_TOKEN to gh auth login --with-token so stored auth can be updated mid-session
  • Write /tmp/refresh-github-tokens.sh that Claude can call to regenerate both tokens (~2-3s)

Problem

GitHub App installation tokens expire after 1 hour. When Claude sessions run longer (e.g. PR #9102 session ran 1h17m), push and reply operations fail with 401 Bad credentials. The agent processes the review comments correctly but can't post replies or push code changes.

Test plan

  • Trigger a review-agent run against a PR with review comments
  • Verify /tmp/refresh-github-tokens.sh is created with correct credentials
  • Verify gh auth status shows valid auth after initial setup
  • Verify token refresh works: manually call /tmp/refresh-github-tokens.sh after setup
  • Verify push and reply succeed after a session >1 hour

/cc @openshift/hypershift-team-psa

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved comment analysis to account for all available issue and review comments, including paginated results.
    • Increased reliability of GitHub authentication by supporting automatic token refresh during processing.
  • Improvements

    • Added safeguards to prevent duplicate replies within the same review session, helping ensure comments are addressed only once.

@openshift-ci

openshift-ci Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@bryan-cox: GitHub didn't allow me to request PR reviews from the following users: openshift/hypershift-team-psa.

Note that only openshift members and repo collaborators can review this PR, and authors cannot review their own PRs.

Details

In response to this:

Summary

  • Store GitHub App tokens in files (/tmp/.github-token-{fork,upstream}) instead of baking them into env vars and git config
  • Git credential helper reads from file each invocation, so refreshed tokens are picked up automatically
  • Switch from export GITHUB_TOKEN to gh auth login --with-token so stored auth can be updated mid-session
  • Write /tmp/refresh-github-tokens.sh that Claude can call to regenerate both tokens (~2-3s)

Problem

GitHub App installation tokens expire after 1 hour. When Claude sessions run longer (e.g. PR #9102 session ran 1h17m), push and reply operations fail with 401 Bad credentials. The agent processes the review comments correctly but can't post replies or push code changes.

Test plan

  • Trigger a review-agent run against a PR with review comments
  • Verify /tmp/refresh-github-tokens.sh is created with correct credentials
  • Verify gh auth status shows valid auth after initial setup
  • Verify token refresh works: manually call /tmp/refresh-github-tokens.sh after setup
  • Verify push and reply succeed after a session >1 hour

/cc @openshift/hypershift-team-psa

🤖 Generated with Claude Code

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The review agent now retrieves paginated issue comments, stores and refreshes GitHub App tokens through temporary files and a generated script, and adds prompt instructions for tracking posted replies within a session.

Changes

Review agent updates

Layer / File(s) Summary
Paginated comment retrieval
ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh
Both review-body and issue-comment analysis requests now use GitHub REST pagination.
Refreshable GitHub authentication
ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh
Fork and upstream tokens are written to temporary files; the credential helper reads the fork token dynamically, and a refresh script regenerates tokens and re-authenticates gh.
Session duplicate prevention
ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh
Claude receives instructions to check and record posted replies using comment or thread IDs.ف

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReviewAgent
  participant GitHubRESTAPI
  participant Claude
  ReviewAgent->>GitHubRESTAPI: Fetch paginated issue comments
  GitHubRESTAPI-->>ReviewAgent: Return all comment pages
  ReviewAgent->>Claude: Provide comments and duplicate-prevention instructions
  Claude-->>ReviewAgent: Produce review replies
Loading

Suggested reviewers: enxebre

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: refreshing GitHub App tokens for push and reply operations in the review-agent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed PASS: The PR only changes a shell script; no Ginkgo test definitions or titles were added or modified.
Test Structure And Quality ✅ Passed PR only changes a shell script; no Ginkgo tests were added or modified, so the test-structure checklist is not applicable.
Microshift Test Compatibility ✅ Passed Only a shell-script step changed; no new Ginkgo e2e tests, It/Describe/Context/When blocks, or MicroShift-sensitive APIs were added.
Single Node Openshift (Sno) Test Compatibility ✅ Passed Only a shell script changed; no new Ginkgo tests or SNO-relevant node assumptions were added.
Topology-Aware Scheduling Compatibility ✅ Passed Diff only changes token refresh/auth logic in a shell script; no manifests, controllers, node selectors, affinity, or topology constraints were added.
Ote Binary Stdout Contract ✅ Passed Only a step-registry shell script changed; no OTE binary/main/TestMain/setup code was touched, so the stdout contract isn’t implicated.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Only a shell/process script changed; no new Ginkgo e2e tests or IP/network-sensitive test code were added.
No-Weak-Crypto ✅ Passed No weak ciphers/hashes or secret comparisons found; only standard SHA-256 JWT signing and token-file refresh logic.
Container-Privileges ✅ Passed Only a shell script changed; no privileged, hostPID/network/IPC, SYS_ADMIN, runAsUser=0, or allowPrivilegeEscalation settings were added.
No-Sensitive-Data-In-Logs ✅ Passed No direct logging of secrets/PII found; token values are written to files or stdin, and logs only emit status messages/usernames, not token contents.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 27, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

@bryan-cox, pj-rehearse: unable to determine affected jobs. This could be due to a branch that needs to be rebased. ERROR:

couldn't prepare candidate: couldn't rebase candidate onto 756999cafef5b31f85d3bf5b1d3944b9816a8728 due to conflicts
Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh (2)

623-627: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Token files are world-readable for a brief window before chmod 600.

echo ... > /tmp/.github-token-fork/upstream writes with default umask permissions, and chmod 600 only runs afterward, leaving a short window where the token content is more widely readable. Given the retrieved learning that these step-registry scripts run in ephemeral, single-tenant containers with no other local users, the symlink/TOCTOU angle flagged by static analysis doesn't really apply here (and mktemp isn't viable since the credential helper and refresh script need this exact predictable path). Still, tightening the write itself (e.g. (umask 077; echo "$TOKEN" > file) or install -m 600 /dev/null file && echo ... > file) is a trivial defense-in-depth improvement for token material.

🔒 Optional tightening
-echo "$GITHUB_TOKEN_FORK" > /tmp/.github-token-fork
-echo "$GITHUB_TOKEN_UPSTREAM" > /tmp/.github-token-upstream
-chmod 600 /tmp/.github-token-fork /tmp/.github-token-upstream
+(umask 077; echo "$GITHUB_TOKEN_FORK" > /tmp/.github-token-fork)
+(umask 077; echo "$GITHUB_TOKEN_UPSTREAM" > /tmp/.github-token-upstream)

Based on learnings, "assume they run in ephemeral containers created at execution time with no pre-existing filesystem/symlinks from the image... the 'pre-existing-path symlink' concern should not be raised for predictable /tmp paths in these scripts."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh`
around lines 623 - 627, Update the token writes near the refresh-file setup to
create both /tmp token files with restrictive permissions from the outset, using
a scoped umask or equivalent approach before writing their contents. Preserve
the existing predictable paths required by the credential helper and refresh
script; the subsequent chmod may remain as defense in depth.

Source: Learnings


636-686: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Generated refresh script isn't permission-restricted, and duplicates JWT-signing logic.

Two independent points:

  1. /tmp/refresh-github-tokens.sh only gets chmod +x (line 685); unlike the token files it doesn't get a 600/700 restriction, so its content — including $PRIVATE_KEY_FILE's path and both installation IDs — is left at default umask readability.
  2. The JWT-minting logic inside this heredoc (lines 646-661) is a near-verbatim duplicate of generate_github_token() (lines 583-603). Any future change to the signing algorithm or claims would need to be kept in sync in two places.
🔒 Restrict permissions on the generated script
 chmod +x /tmp/refresh-github-tokens.sh
+chmod 700 /tmp/refresh-github-tokens.sh
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh`
around lines 636 - 686, Restrict the generated /tmp/refresh-github-tokens.sh
permissions to owner-only access by applying 700 (or stricter) instead of only
making it executable. Remove the duplicated generate_token JWT-signing
implementation from the heredoc and have the refresh script reuse the existing
generate_github_token() logic, preserving the current fork and upstream token
refresh behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh`:
- Around line 623-627: Update the token writes near the refresh-file setup to
create both /tmp token files with restrictive permissions from the outset, using
a scoped umask or equivalent approach before writing their contents. Preserve
the existing predictable paths required by the credential helper and refresh
script; the subsequent chmod may remain as defense in depth.
- Around line 636-686: Restrict the generated /tmp/refresh-github-tokens.sh
permissions to owner-only access by applying 700 (or stricter) instead of only
making it executable. Remove the duplicated generate_token JWT-signing
implementation from the heredoc and have the refresh script reuse the existing
generate_github_token() logic, preserving the current fork and upstream token
refresh behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4c1abc2e-774d-466c-9a04-834a97232037

📥 Commits

Reviewing files that changed from the base of the PR and between 756999c and 37f8fd9.

📒 Files selected for processing (1)
  • ci-operator/step-registry/hypershift/review-agent/process/hypershift-review-agent-process-commands.sh

bryan-cox added a commit to bryan-cox/ai-helpers that referenced this pull request Jul 27, 2026
Add a pre-step to address-review-pr that calls /tmp/refresh-github-tokens.sh
(written by the CI process step) before posting replies or pushing. This
ensures tokens are valid after long sessions that outlast the 1-hour GitHub
App token lifetime.

Companion to openshift/release#82494.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GitHub App installation tokens expire after 1 hour. When Claude sessions
run longer than that (the PR openshift#9102 session ran 1h17m), push and reply
operations fail with 401 Bad credentials.

Store tokens in files instead of baking them into env vars and git config.
Write a refresh script to /tmp that Claude can call before push/reply to
regenerate both fork and upstream tokens (~2-3s). Switch from
`export GITHUB_TOKEN` to `gh auth login --with-token` so the stored token
can be updated mid-session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bryan-cox
bryan-cox force-pushed the fix-review-agent-token-refresh branch from 37f8fd9 to 6c0d2b0 Compare July 27, 2026 15:07
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 27, 2026
@openshift-ci

openshift-ci Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bryan-cox

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

[REHEARSALNOTIFIER]
@bryan-cox: the pj-rehearse plugin accommodates running rehearsal tests for the changes in this PR. Expand 'Interacting with pj-rehearse' for usage details. The following rehearsable tests have been affected by this change:

Test name Repo Type Reason
periodic-ci-openshift-hypershift-main-periodic-review-agent N/A periodic Registry content changed
periodic-ci-openshift-installer-main-periodic-review-agent N/A periodic Registry content changed
Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@openshift-ci

openshift-ci Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@bryan-cox: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

$_was_tracing && set -x || true

# Write a refresh script that Claude can call before push/reply operations
cat > /tmp/refresh-github-tokens.sh << REFRESH_EOF

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants