fix: fall back to repo default_branch instead of hardcoded "main"#1143
fix: fall back to repo default_branch instead of hardcoded "main"#1143ashwin-ant merged 2 commits intomainfrom
Conversation
When no explicit base_branch input is provided, the action previously fell back to a hardcoded "main", which fails on repositories whose default branch is named differently (e.g. "master", "develop"). This reads repository.default_branch from the GitHub event payload (populated once in parseGitHubContext) and uses it as the fallback in all three callsites: agent/index.ts, run.ts, and update-comment-link.ts. Explicit env/input precedence is preserved; "main" remains only as a last-resort defensive fallback if the payload somehow lacks the field.
agent/index.ts no longer reads process.env.BASE_BRANCH directly (it now goes through context.inputs.baseBranch which is set on the mock context), so saving/clearing/restoring that env var in the regression test is dead code.
There was a problem hiding this comment.
LGTM — clean, focused fix with consistent changes across all three callsites and a regression test.
Extended reasoning...
Overview
This PR adds default_branch to the repository field in BaseContext, populates it from context.payload.repository?.default_branch in parseGitHubContext(), and uses it as the fallback (before the hard-coded "main" last resort) in three places: agent/index.ts, run.ts, and update-comment-link.ts. It also removes a redundant process.env.BASE_BRANCH read in agent/index.ts since context.inputs.baseBranch already mirrors that env var. A regression test exercises the default_branch: "develop" path.
Security risks
No security concerns. repository.default_branch comes from the same GitHub event payload already used for owner, repo, and full_name — all trusted values. The "main" last-resort fallback is preserved for edge cases where the field is absent.
Level of scrutiny
Low — this is a narrow bug fix that only changes the default-branch fallback logic. No new API calls, no auth/permission changes, no architectural decisions. The change is mechanical and consistent across all affected callsites.
Other factors
The PR correctly notes the accepted-risk edge case (issue_comment-on-PR using repo default branch instead of PR base ref) and acknowledges it as a known pre-existing trade-off. Test coverage is solid: the new test clears all overriding env vars and asserts "develop" flows through to branchInfo.
There was a problem hiding this comment.
LGTM — clean, consistent fix across all three callsites with a defensive || "main" fallback retained.
Extended reasoning...
Overview
This PR adds default_branch to the repository context object (parsed once from the GitHub event payload) and threads it through three fallback callsites in agent/index.ts, run.ts, and update-comment-link.ts, replacing a hardcoded "main". A new regression test asserts the develop case propagates correctly.
Security risks
No security concerns. default_branch is sourced from the trusted GitHub event payload, gated behind ?. optional chaining, and always has || "main" as a last-resort defensive fallback. The comment in run.ts correctly documents the accepted-risk edge case for issue_comment-on-PR where the restore uses the repo default branch rather than the PR base ref.
Level of scrutiny
Low — this is a straightforward bug fix. Each change is a one-liner substituting an existing || "main" sentinel with || context.repository.default_branch || "main". No logic changes, no new API calls, no auth/permission paths touched.
Other factors
The sole bug reported (missing CLAUDE_ARGS save/restore in the new test) is a nit: it only manifests if the preceding test fails mid-body before its inline cleanup, and even then the leaked value does not affect the new test's assertions (which only check branchInfo fields). The inline comments already capture this. The PR is well-scoped, drops a redundant process.env.BASE_BRANCH read that was shadowed by context.inputs.baseBranch, and includes a regression test to guard against reversion.
| eventName: "workflow_dispatch", | ||
| repository: { | ||
| owner: "test-owner", | ||
| repo: "test-repo", | ||
| full_name: "test-owner/test-repo", | ||
| default_branch: "develop", | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🟡 The new test "prepare falls back to repository.default_branch when not 'main'" does not save/restore CLAUDE_ARGS, unlike the adjacent test that explicitly manages it. If the preceding test fails at an assertion before its delete process.env.CLAUDE_ARGS cleanup (line 104), the leaked value would flow into prepareAgentMode and appear in claudeArgs output — though the test assertions only cover branchInfo fields so they would still pass.
Extended reasoning...
Analysis
The new test added at lines 113-163 of test/modes/agent.test.ts does not save or restore CLAUDE_ARGS, unlike the immediately preceding test "prepare passes through claude_args" which explicitly sets process.env.CLAUDE_ARGS = "--model claude-sonnet-4 --max-turns 10" and cleans it up with delete process.env.CLAUDE_ARGS at the end of the test body.
How the bug manifests
In src/modes/agent/index.ts, CLAUDE_ARGS is read unconditionally: const userClaudeArgs = process.env.CLAUDE_ARGS || "";. This value flows into the claudeArgs return field. If the preceding test fails mid-execution — for example, if one of its expect() assertions throws before reaching the cleanup block — CLAUDE_ARGS remains set in the process environment and is inherited by the new test.
Why existing code doesn't prevent it
The test cleanup for CLAUDE_ARGS in the preceding test is done inline in the test body (not in afterEach), so it is not guaranteed to run on failure. The afterEach hook only restores spies, not environment variables. This is a gap that the new test inherits rather than defending against.
Impact
If the leak occurs, prepareAgentMode will include --model claude-sonnet-4 --max-turns 10 in its claudeArgs output instead of an empty string. The new test only asserts on result.branchInfo.baseBranch and result.branchInfo.currentBranch, which are derived from context.repository.default_branch — completely unaffected by CLAUDE_ARGS. So the test passes even with leaked state, silently masking the unexpected behavior. This is a test quality/robustness issue, not a correctness issue for production code.
Addressing the refutation
The refutation correctly notes that (a) the prior test does clean up CLAUDE_ARGS under normal execution, and (b) the new test's assertions are unaffected by CLAUDE_ARGS. Both points are true. However, the fragility comes from the failure path: if the prior test throws before line 104, cleanup is skipped. The refutation does not address this failure-path scenario. The inconsistency with the surrounding cleanup pattern is also a readability/maintenance concern — future readers may not realize this test is not defensive against env leakage.
Proof of fragility
Step-by-step: (1) Prior test sets process.env.CLAUDE_ARGS = "--model claude-sonnet-4 --max-turns 10". (2) An assertion in the prior test fails, throwing before delete process.env.CLAUDE_ARGS at line 104. (3) The new test runs with CLAUDE_ARGS still set. (4) prepareAgentMode reads CLAUDE_ARGS and builds claudeArgs = "--model claude-sonnet-4 --max-turns 10". (5) The new test assertions expect(result.branchInfo.baseBranch).toBe("develop") and expect(result.branchInfo.currentBranch).toBe("develop") both pass since CLAUDE_ARGS does not affect branch info. (6) The test suite reports a passing test, but the behavior being tested has unexpected side effects that go undetected.
Fix
Add const originalClaudeArgs = process.env.CLAUDE_ARGS; before the test body and restore/delete it in the cleanup block alongside the other env var restorations, matching the pattern used in the same test for CLAUDE_BRANCH, GITHUB_HEAD_REF, and GITHUB_REF_NAME.
Bumps the github-actions group with 2 updates: [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) and [docker/login-action](https://github.com/docker/login-action). Updates `anthropics/claude-code-action` from 1.0.82 to 1.0.88 Release notes *Sourced from [anthropics/claude-code-action's releases](https://github.com/anthropics/claude-code-action/releases).* > v1.0.88 > ------- > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.88> > > v1.0.87 > ------- > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.87> > > v1.0.86 > ------- > > What's Changed > -------------- > > * Fix subprocess isolation install step not running by [`@OctavianGuzu`](https://github.com/OctavianGuzu) in [anthropics/claude-code-action#1148](https://redirect.github.com/anthropics/claude-code-action/pull/1148) > * Pass env to execFileSync git calls by [`@OctavianGuzu`](https://github.com/OctavianGuzu) in [anthropics/claude-code-action#1151](https://redirect.github.com/anthropics/claude-code-action/pull/1151) > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.86> > > v1.0.85 > ------- > > What's Changed > -------------- > > * fix: fall back to repo default\_branch instead of hardcoded "main" by [`@ashwin-ant`](https://github.com/ashwin-ant) in [anthropics/claude-code-action#1143](https://redirect.github.com/anthropics/claude-code-action/pull/1143) > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.85> > > v1.0.84 > ------- > > What's Changed > -------------- > > * Pin Claude Code to 2.1.87 by [`@ashwin-ant`](https://github.com/ashwin-ant) in [anthropics/claude-code-action#1142](https://redirect.github.com/anthropics/claude-code-action/pull/1142) > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.84> > > v1.0.83 > ------- > > What's Changed > -------------- > > * Add subprocess isolation setup and git credential helper by [`@OctavianGuzu`](https://github.com/OctavianGuzu) in [anthropics/claude-code-action#1132](https://redirect.github.com/anthropics/claude-code-action/pull/1132) > > **Full Changelog**: <anthropics/claude-code-action@v1...v1.0.83> Commits * [`1eddb33`](anthropics/claude-code-action@1eddb33) chore: bump Claude Code to 2.1.92 and Agent SDK to 0.2.92 * [`0432df8`](anthropics/claude-code-action@0432df8) chore: bump Claude Code to 2.1.91 and Agent SDK to 0.2.91 * [`ba026a3`](anthropics/claude-code-action@ba026a3) Pass env to execFileSync git calls ([#1151](https://redirect.github.com/anthropics/claude-code-action/issues/1151)) * [`c95e735`](anthropics/claude-code-action@c95e735) Fix subprocess isolation install step never running ([#1148](https://redirect.github.com/anthropics/claude-code-action/issues/1148)) * [`58dbe8e`](anthropics/claude-code-action@58dbe8e) chore: bump Claude Code to 2.1.90 and Agent SDK to 0.2.90 * [`c281e17`](anthropics/claude-code-action@c281e17) fix: fall back to repo default\_branch instead of hardcoded "main" ([#1143](https://redirect.github.com/anthropics/claude-code-action/issues/1143)) * [`408a40e`](anthropics/claude-code-action@408a40e) Pin Claude Code to 2.1.87 ([#1142](https://redirect.github.com/anthropics/claude-code-action/issues/1142)) * [`bee87b3`](anthropics/claude-code-action@bee87b3) chore: bump Claude Code to 2.1.89 and Agent SDK to 0.2.89 * [`32156b1`](anthropics/claude-code-action@32156b1) Add subprocess isolation setup and git credential helper ([#1132](https://redirect.github.com/anthropics/claude-code-action/issues/1132)) * [`7225f04`](anthropics/claude-code-action@7225f04) chore: bump Claude Code to 2.1.88 and Agent SDK to 0.2.88 * See full diff in [compare view](anthropics/claude-code-action@88c168b...1eddb33) Updates `docker/login-action` from 4.0.0 to 4.1.0 Release notes *Sourced from [docker/login-action's releases](https://github.com/docker/login-action/releases).* > v4.1.0 > ------ > > * Fix scoped Docker Hub cleanup path when registry is omitted by [`@crazy-max`](https://github.com/crazy-max) in [docker/login-action#945](https://redirect.github.com/docker/login-action/pull/945) > * Bump `@aws-sdk/client-ecr` and `@aws-sdk/client-ecr-public` to 3.1020.0 in [docker/login-action#930](https://redirect.github.com/docker/login-action/pull/930) > * Bump `@docker/actions-toolkit` from 0.77.0 to 0.86.0 in [docker/login-action#932](https://redirect.github.com/docker/login-action/pull/932) [docker/login-action#936](https://redirect.github.com/docker/login-action/pull/936) > * Bump brace-expansion from 1.1.12 to 1.1.13 in [docker/login-action#952](https://redirect.github.com/docker/login-action/pull/952) > * Bump fast-xml-parser from 5.3.4 to 5.3.6 in [docker/login-action#942](https://redirect.github.com/docker/login-action/pull/942) > * Bump flatted from 3.3.3 to 3.4.2 in [docker/login-action#944](https://redirect.github.com/docker/login-action/pull/944) > * Bump glob from 10.3.12 to 10.5.0 in [docker/login-action#940](https://redirect.github.com/docker/login-action/pull/940) > * Bump handlebars from 4.7.8 to 4.7.9 in [docker/login-action#949](https://redirect.github.com/docker/login-action/pull/949) > * Bump http-proxy-agent and https-proxy-agent to 8.0.0 in [docker/login-action#937](https://redirect.github.com/docker/login-action/pull/937) > * Bump lodash from 4.17.23 to 4.18.1 in [docker/login-action#958](https://redirect.github.com/docker/login-action/pull/958) > * Bump minimatch from 3.1.2 to 3.1.5 in [docker/login-action#941](https://redirect.github.com/docker/login-action/pull/941) > * Bump picomatch from 4.0.3 to 4.0.4 in [docker/login-action#948](https://redirect.github.com/docker/login-action/pull/948) > * Bump undici from 6.23.0 to 6.24.1 in [docker/login-action#938](https://redirect.github.com/docker/login-action/pull/938) > > **Full Changelog**: <docker/login-action@v4.0.0...v4.1.0> Commits * [`4907a6d`](docker/login-action@4907a6d) Merge pull request [#930](https://redirect.github.com/docker/login-action/issues/930) from docker/dependabot/npm\_and\_yarn/aws-sdk-dependenc... * [`1e233e6`](docker/login-action@1e233e6) chore: update generated content * [`6c24ead`](docker/login-action@6c24ead) build(deps): bump the aws-sdk-dependencies group with 2 updates * [`ee034d7`](docker/login-action@ee034d7) Merge pull request [#958](https://redirect.github.com/docker/login-action/issues/958) from docker/dependabot/npm\_and\_yarn/lodash-4.18.1 * [`1527209`](docker/login-action@1527209) Merge pull request [#937](https://redirect.github.com/docker/login-action/issues/937) from docker/dependabot/npm\_and\_yarn/proxy-agent-depen... * [`d39362a`](docker/login-action@d39362a) build(deps): bump lodash from 4.17.23 to 4.18.1 * [`a6f092b`](docker/login-action@a6f092b) chore: update generated content * [`60953f0`](docker/login-action@60953f0) build(deps): bump the proxy-agent-dependencies group with 2 updates * [`62c6885`](docker/login-action@62c6885) Merge pull request [#936](https://redirect.github.com/docker/login-action/issues/936) from docker/dependabot/npm\_and\_yarn/docker/actions-to... * [`102c0e6`](docker/login-action@102c0e6) chore: update generated content * Additional commits viewable in [compare view](docker/login-action@b45d80f...4907a6d) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- Dependabot commands and options You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Fixes #1080
Fixes #1085
Supersedes #1083
When no explicit
base_branchinput is provided, the action previously fell back to a hardcoded"main", causingrestoreConfigFromBase(and PR-link generation) to fail on repositories whose default branch is named differently (e.g.master,develop).This reads
repository.default_branchfrom the GitHub event payload — populated once inparseGitHubContext()so no extra API call is needed — and uses it as the fallback in all three callsites:src/modes/agent/index.tssrc/entrypoints/run.tssrc/entrypoints/update-comment-link.ts(#1083 only patched
agent/index.ts.)Explicit env/input precedence is preserved;
"main"remains only as a last-resort defensive fallback if the payload somehow lacks the field. Also drops the redundantprocess.env.BASE_BRANCHread inagent/index.tssincecontext.inputs.baseBranchalready mirrors it.A regression test in
test/modes/agent.test.tsasserts adefault_branch: "develop"repo flows through tobranchInfo, so CI fails if this fallback is ever reverted.Note: for the
issue_comment-on-PR edge case in agent mode, the restore now uses the repo's default branch rather than the PR's actual base ref — still secure (trusted branch), and matches the existing accepted-risk comment inrun.ts. Fetching the true base ref via API for that case is a possible follow-up.