Skip to content

Detect non-main default branches in single-branch CI checkouts - #383

Merged
Martin Torp (mtorp) merged 4 commits into
mainfrom
martin/python-cli-default-branch-issue
Sep 30, 2026
Merged

Martin Torp (mtorp) merged 4 commits into
mainfrom
martin/python-cli-default-branch-issue

Conversation

@mtorp

@mtorp Martin Torp (mtorp) commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Nightly socketcli --reach scans on repos whose default branch isn't main or master stopped becoming the branch head from 2.6.6 onward. Webflow's dev and development repos have only shown GitHub App results on the Alerts page since August.

Root Cause

#301 removed the git fetch --all from Git.__init__. On git 2.48 and later that fetch also created refs/remotes/origin/HEAD when it was missing, and that side effect was the only way the CLI learned the default branch in CI.

actions/checkout fetches a single branch and leaves no origin/HEAD. Without the fetch, get_default_branch_name() fell back to main/master/main. So GITHUB_REF=refs/heads/dev never matched, is_default_branch was False, and the scan was never made the head. Repos on main or master kept working because the fallback guessed right. A plain git clone also worked because clone writes origin/HEAD.

Fix

get_default_branch_name() first reads GitLab's CI_DEFAULT_BRANCH or Buildkite's BUILDKITE_PIPELINE_DEFAULT_BRANCH when set, then origin/HEAD. Those two variables used to feed only the final branch comparison, so the commit-on-default check ignored them. When neither gives an answer, it checks, in order:

  1. repository.default_branch from the GitHub event payload at GITHUB_EVENT_PATH. No network needed.
  2. git ls-remote --symref origin HEAD. It's one round trip and downloads no objects, so it does not restore the broad fetch removed in Reduce scan startup time in large repositories #301. It runs with GIT_TERMINAL_PROMPT=0 and a 30s timeout. The command runs in its own session, and a timeout kills the whole group (taskkill /T walks the tree on Windows). That matters because git's HTTP helper otherwise keeps the output pipe open after git itself is killed, which kept startup blocked on a stalled remote.
  3. The existing main/master fallback.

Known GitHub, Buildkite, GitLab, and Bitbucket PR/MR runs, plus non-branch GitHub refs, return before default-branch lookup and make no ls-remote call. Branch runs use CI metadata, origin/HEAD, and the GitHub event payload before querying the remote. The result is cached, since branch detection can call it twice. Branch names with slashes now resolve correctly from origin/HEAD too.

Tests cover an actions/checkout-style single-branch checkout of a dev-default repo; GitHub event metadata and GitLab/Buildkite default-branch variables; no remote default-branch query on GitHub, Buildkite, GitLab, and Bitbucket PR/MR runs; stalled HTTP remote timeout; and Windows process-tree cleanup. All 605 unit tests pass locally.

Until this ships, passing --default-branch on the nightly job works around it.

Public Changelog

Fixed default-branch detection for repositories whose default branch isn't main or master when scanning from a single-branch CI checkout such as actions/checkout.

Fixes CE-482


Note

Medium Risk
Changes when scans become the default-branch head and may run git ls-remote during CLI startup; logic is well-tested but affects core CI git behavior.

Overview
Fixes default-branch detection when CI uses shallow single-branch checkouts (e.g. actions/checkout) without origin/HEAD, so repos whose default is not main/master can mark scans as the branch head again.

get_default_branch_name() now caches the result and resolves in order: GitLab CI_DEFAULT_BRANCH / Buildkite BUILDKITE_PIPELINE_DEFAULT_BRANCH, then origin/HEAD (via remote_head, including names with slashes), then repository.default_branch from the GitHub event at GITHUB_EVENT_PATH, then a timed git ls-remote --symref origin HEAD (30s, kills the process tree on timeout—including Windows taskkill /T), then the existing main/master fallbacks.

_is_commit_and_branch_default() rejects PR/MR/non-branch refs before any default-branch lookup, and all CI providers now compare against get_default_branch_name() so the CI default-branch env vars apply to commit-on-default checks too.

Release 2.10.6 with changelog and expanded unit tests (single-branch dev checkout, event payload, stalled remote timeout).

Reviewed by Cursor Bugbot for commit 6a8162a. Configure here.

actions/checkout fetches one branch and leaves no origin/HEAD. Since 2.6.6
dropped the git fetch --all that recreated origin/HEAD, default-branch
detection fell back to main/master, so scans on repos whose default branch
is dev never became the branch head.

When origin/HEAD is missing, read the default branch from the GitHub event
payload, then from git ls-remote --symref origin HEAD, before the
main/master fallback.
GitPython's kill_after_timeout is rejected on Windows and relies on
ps --ppid, which macOS lacks. It also leaves git-remote-https holding the
output pipe after the parent dies, so a stalled remote blocked startup past
the timeout.

Run git ls-remote in its own process group and kill the whole group on
timeout, with taskkill /T on Windows.
GitLab's CI_DEFAULT_BRANCH and Buildkite's BUILDKITE_PIPELINE_DEFAULT_BRANCH
only fed the final branch comparison. The commit-on-default check still
went to the remote, so single-branch checkouts on those CIs paid for a
git ls-remote call even when CI already knew the answer. Both variables
now come first in get_default_branch_name.

Also simplifies the remote lookup. start_new_session works on every
platform because Windows ignores it and taskkill walks the tree by PID.
The stalled-remote fixture is now a listener that never accepts, and the
test clears proxy variables so it really waits for the timeout.
@mtorp
Martin Torp (mtorp) marked this pull request as ready for review September 29, 2026 14:51
@mtorp
Martin Torp (mtorp) requested a review from a team as a code owner September 29, 2026 14:51
@lelia lelia self-assigned this Sep 29, 2026
@lelia
lelia deployed to socket-firewall September 29, 2026 22:19 — with GitHub Actions Active
@lelia

lelia commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 6a8162a. Configure here.

@mtorp
Martin Torp (mtorp) merged commit 3eb5433 into main Sep 30, 2026
33 checks passed

This branch was successfully deployed

1 active deployment
socket-firewall — 6a8162af Deployed Sep 29, 2026 by lelia via python-sfw-smoke-enterprise #445
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants