The download_job_log MCP tool called
client.actions.downloadJobLogsForWorkflowRun() with no timeout and no
AbortController. @octokit/rest@21 runs on Node's native fetch, which has
no default timeout, and Octokit only cancels a request when the caller
passes request.signal. If the log blob fetch stalls, that await never
resolves and never rejects.
This tool is always enabled in tag mode (src/modes/tag/index.ts), so a
"fix the failing CI" run that calls get_ci_status -> get_workflow_run_details
-> download_job_log can hang on this one await with nothing to recover it.
It's headless, so the run only ends when the Actions job-level
timeout-minutes kills it, burning the whole job budget with the tracking
comment stuck at "Claude Code is working...".
Sibling fetch in src/github/utils/image-downloader.ts (fetchImage) already
got this treatment in #1625 via a timeout-driven AbortController. Same
shape of call: fetch a GitHub-hosted resource by ID from untrusted PR/CI
content. This mirrors that fix for github-actions-server.ts.
Extracted the download+write logic into an exported downloadJobLog()
function (with an injectable timeoutMs) so the timeout path is directly
testable, and guarded the module's entrypoint side effects with
import.meta.main, matching the pattern already used by the other
entrypoints in src/entrypoints/.
* fix: use paths param in delete_files prompt example
The tag-mode prompt told the model to call delete_files with
"files", but the MCP tool schema and handler expect "paths".
Co-authored-by: Cursor <cursoragent@cursor.com>
* test: prove delete_files prompt against the live MCP schema
The old {files} payload is rejected by the same Zod shape the
tool registers; the generated prompt example now parses cleanly.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test: cover delete_files schema edges and the sibling commit_files tool
Confirm the old files-only payload still fails, types and required
fields are enforced, and commit_files was not inverted by the fix.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: RESILIENCE Agentic Solutions <286555414+WeAreResilience@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
On Windows, git's default core.autocrlf=true checks out CRLF, and the contributor commands in CONTRIBUTING.md then fail: bun run format:check reports 191 files because Prettier defaults to endOfLine "lf", and three tests that match LF-terminated content fail.
All tracked blobs are already LF, so this changes checkout behavior only and produces no renormalization diff. Every CI job runs on ubuntu-latest, where it is a no-op.
restoreConfigFromBase replaces .claude/, CLAUDE.md and the other sensitive
paths with the PR base branch's versions, then deliberately unstages them so
the revert does not reach a commit. checkAndCommitOrDeleteBranch then ran a
bare `git add -A`, which staged them again and pushed a silent revert of the
PR author's own config onto their branch, under a commit message that says
only "Auto-commit: Save uncommitted changes from Claude".
restoreConfigFromBase now returns the paths it restored. run.ts threads them
through updateCommentLink into checkAndCommitOrDeleteBranch, which excludes
them via pathspec from both the staging and the git status check.
The exclusion is driven by what was actually restored rather than applied
unconditionally. This path also runs for issues, where no restore happens and
Claude may legitimately have been asked to edit CLAUDE.md or
.claude/settings.json; excluding those there would silently drop the work —
trading one silent-data-loss bug for another. Reverting the fix, dropping the
status scoping, and switching to an unconditional exclusion each fail the new
tests.
The status check is scoped the same way as the staging: when the reverted
config is the only dirty entry there is no real work, so the branch is now
correctly treated as empty and deleted instead of receiving a pure revert.
Reachable on a closed or merged PR where Claude left uncommitted changes with
use_commit_signing false — the only combination where a restore has run and
claudeBranch is set.
Fixes#1669
The REST client honors GITHUB_API_URL, but the GraphQL client derived its
base URL from GITHUB_API_URL as well and ignored the standard
GITHUB_GRAPHQL_URL variable that GitHub Actions provides. On standard GitHub
Enterprise Server this still worked because @octokit/graphql rewrites a
".../api/v3" REST base to ".../api/graphql", but any deployment whose GraphQL
endpoint is not derivable from the REST base (custom proxy, separate host)
sent GraphQL requests to the wrong URL.
Honor GITHUB_GRAPHQL_URL independently and fall back to GITHUB_API_URL when it
is unset, so behavior is unchanged for github.com and standard GHES. A single
trailing "/graphql" is stripped because @octokit/graphql appends its own.
Add wire-level regression tests that run the real client factory in a fresh
process and assert the final request URLs and Authorization headers;
constructor-option assertions are insufficient because @octokit/graphql
rewrites the path after the client is constructed.
configureGitAuth() removed the actions/checkout auth header with
`git config --unset-all http.<server>/.extraheader`, which only edits the
repo-local config. Since actions/checkout v6.0.0 (backported to v5.0.1 and
v4.3.1) the header is written to a separate file under RUNNER_TEMP and
pulled in via include.path, so --unset-all on the local config is a no-op:
the code logged "No existing authentication headers to remove" while the
checkout credential (usually the workflow GITHUB_TOKEN) stayed usable by
git for the rest of the job.
Also clear the header from every included file, so it is neutralized under
both the pre-v6 (local) and v6+ (include) layouts. Includes that do not
define the header are left untouched.
Fixes#1510
`exclude_comments_by_actor` and `include_comments_by_actor` never matched
any bot. Both the documented `*[bot]` wildcard and exact entries such as
`dependabot[bot]` silently did nothing.
GitHub's GraphQL API returns the bare login for App actors ("dependabot"),
while REST and the GitHub UI append a suffix ("dependabot[bot]"). Filter
patterns are written in the suffixed form, so matching a GraphQL login
against them could never succeed and `actor.endsWith("[bot]")` was dead
code.
Request `__typename` on the Actor-typed author selections and normalize
App actors to their suffixed name via `resolveActorName()` before matching.
Normalizing at the filter boundary fixes the wildcard and exact-match cases
together, and leaves the author names shown in the prompt unchanged.
The existing test mocked `login: "scanner[bot]"`, a payload GraphQL never
produces, which is why the gap was invisible. It now mocks the real shape
(`__typename: "Bot", login: "scanner"`) and fails without this fix.
The commit author selection is left alone: it is a GitCommit, not an Actor.
Fixes#1514
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Ensure all public issue, PR, and inline comments apply redactSecrets() in addition to sanitizeContent() before submitting payloads to the GitHub API. This aligns public comment output with error log and step-summary redaction policies, preventing potential leakage of Anthropic API keys, AWS credentials, Slack tokens, JWTs, and GitHub tokens.
shell-quote 1.8.3 (root and base-action dependency) is affected by
CVE-2026-9277, a CRITICAL severity vulnerability. 1.8.4 contains the fix.
Co-authored-by: Ashwin Bhat <ashwin@anthropic.com>