Repository navigation
fix(actions): run Claude Code directly in beta-notes - #40
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a209234a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| notes="$NOTES" | ||
| source=manual | ||
| elif [ "$CONCLUSION" = success ] && [ -n "$STRUCTURED" ]; then | ||
| elif [ -s "$RESULT" ]; then |
There was a problem hiding this comment.
Use an invocation-specific result file
When this composite action is invoked more than once in the same job, every invocation uses the same $RUNNER_TEMP/beta-notes-result.json. If a later invocation skips the Claude step because its range has no qualifying commits, or exits before the final redirected command, this condition consumes the earlier invocation's still-populated file and emits stale notes with source=claude instead of the promised fallback. Clear the result before planning or give each invocation a unique result path.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: plan.sh clears the result file on every invocation.
| --max-turns "$MAX_TURNS" \ | ||
| --allowedTools Read Grep Glob "Bash(git log:*)" "Bash(git show:*)" "Bash(git diff:*)" "Bash(gh pr view:*)" \ | ||
| --json-schema "$(cat "$GITHUB_ACTION_PATH/schema.json")" \ | ||
| --output-format json < /dev/null > "$RESULT" |
There was a problem hiding this comment.
Update the federation smoke for the new result output
Writing the direct CLI response only to $RESULT leaves .github/workflows/federation-smoke.yml:46 reading the removed $RUNNER_TEMP/claude-execution-output.json file. Whenever that smoke workflow runs, its always-running diagnostic step therefore fails after the action, and the subsequent Require notes from Claude step is skipped under the default success condition, so the workflow can no longer validate federation. Update the smoke step to read and parse the new single-object result format.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: the smoke's diagnostic step is gone; finish.sh now logs the failure reason.
| claude -p "$(cat "$PROMPT")" \ | ||
| --model "$MODEL" \ | ||
| --max-turns "$MAX_TURNS" \ | ||
| --allowedTools Read Grep Glob "Bash(git log:*)" "Bash(git show:*)" "Bash(git diff:*)" "Bash(gh pr view:*)" \ |
There was a problem hiding this comment.
Strip OIDC request credentials before launching Claude
In federation mode, the claude subprocess inherits ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, allowing any Claude-executed tool or project hook influenced by the repository or summarized PR content to mint fresh GitHub OIDC tokens for arbitrary audiences. The replaced base action explicitly removed these variables before starting the model process (pinned source); unset them after fetching the Anthropic identity token and before invoking Claude.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: the OIDC request variables move into unexported shell variables and are unset before Claude starts.
| export ANTHROPIC_IDENTITY_TOKEN_FILE="$dir/identity-token" | ||
| curl -fsS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ | ||
| "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \ | ||
| | jq -er .value > "$ANTHROPIC_IDENTITY_TOKEN_FILE" |
There was a problem hiding this comment.
Refresh the identity token during long Claude runs
Federation writes one GitHub OIDC JWT to this file and never updates it while Claude runs. Anthropic caps the access token's lifetime based on the IdP JWT's remaining lifetime and begins refreshing before expiry (WIF token lifetime and refresh), so a sufficiently long run eventually tries to exchange the same expired or already-consumed JWT and fails even though the job still has id-token: write; the previous base action refreshed the identity-token file in the background. Keep renewing the GitHub token until the Claude process exits.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: a background loop rewrites the identity token every 4 minutes until Claude exits.
| set -euo pipefail | ||
|
|
||
| version=2.1.309 | ||
| for attempt in 1 2 3; do |
There was a problem hiding this comment.
Verify the installer before executing it
Every invocation executes the current, mutable contents of https://claude.ai/install.sh while the step environment already contains GH_TOKEN and, for static authentication, ANTHROPIC_API_KEY. Passing 2.1.309 only asks that unverified script which payload to install; it does not pin or authenticate the code being piped into Bash, so an upstream installer change or compromise gains arbitrary code execution with those credentials. Use a pinned installer artifact or download the versioned CLI directly and verify its checksum before execution.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: the action downloads the 2.1.309 binary for its platform directly and checks a pinned sha256; the installer script is gone.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d71b48830
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| request_token="$ACTIONS_ID_TOKEN_REQUEST_TOKEN" | ||
| unset ACTIONS_ID_TOKEN_REQUEST_URL ACTIONS_ID_TOKEN_REQUEST_TOKEN | ||
|
|
||
| dir="$RUNNER_TEMP/beta-notes-federation" |
There was a problem hiding this comment.
Give each federation invocation its own cache
When a job invokes beta-notes more than once with different federation rule, service-account, or workspace inputs, every invocation reuses this directory and the default profile, so the second run can consume the still-valid credentials/default.json written by the first instead of exchanging its new identity token. Anthropic documents that this file stores the profile's cached access token and that a federated token is scoped to a workspace when exchanged (WIF reference); consequently, the second summary can run under the first invocation's identity or fail authorization. Use an invocation-specific config directory or clear the cached credential before launching Claude.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed: each invocation removes the federation directory before writing its token and profile.
beta-notesnow runsclaude -pitself instead of claude-code-action's base action, whose Agent SDK launch is rejected as "Credit balance is too low" on funded orgs (anthropics/claude-code-action#1901).claude -pbeta-notes: Claude failed: <reason>in the logmain: the rule only trustsmain.