Skip to content

Use GITHUB_TOKEN (PAT) for branch detection on url_pull repos#3061

Draft
ashwindasr wants to merge 1 commit into
openshift-eng:mainfrom
ashwindasr:cursor-38291-ab7x
Draft

Use GITHUB_TOKEN (PAT) for branch detection on url_pull repos#3061
ashwindasr wants to merge 1 commit into
openshift-eng:mainfrom
ashwindasr:cursor-38291-ab7x

Conversation

@ashwindasr

@ashwindasr ashwindasr commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • When url_pull is configured in image metadata (pointing to a personal fork), branch detection via git ls-remote fails because the GitHub App is not installed on personal accounts. The build then errors with "branch does not exist" even though the branch is present.
  • This PR uses PAT-based auth (GITHUB_TOKEN) instead of GitHub App tokens when checking branches against url_pull repositories.
  • If the PAT check also fails (e.g. GITHUB_TOKEN is not set), it falls back to checking the push url (where the GitHub App is installed).

Context

Build #6119 of build/layered-products failed to rebase acm-cli because:

  1. url_pull pointed to git@github.com:dhaiducek/acm-cli.git (personal fork)
  2. GitHub App token generation failed: "No GitHub App installation found for org 'dhaiducek'"
  3. GITHUB_TOKEN was not set, so git ls-remote ran unauthenticated
  4. The branch check returned empty, causing Requested target branch release-2.16 does not exist

Test plan

  • All existing test_source_resolver.py tests pass
  • New test: test_get_remote_branch_ref_use_pat verifies PAT auth is used when use_pat=True
  • New test: test_detect_remote_source_branch_uses_pull_url_with_pat verifies PAT auth for url_pull
  • New test: test_detect_remote_source_branch_pull_url_fallback_to_push_url verifies fallback to push url when url_pull check fails
  • Verify in a layered-products build with a url_pull pointing to a personal fork

Made with Cursor

Summary by CodeRabbit

Release Notes

  • New Features

    • Added PAT-based authentication support for detecting remote branches, improving compatibility with personal fork workflows.
    • Implemented automatic fallback mechanism that retries branch detection against alternate remote URLs when initial checks fail.
  • Tests

    • Enhanced test coverage for authentication behavior in branch detection logic.

When url_pull points to a personal fork, the GitHub App is not
installed there and branch detection fails silently (returning no
results from git ls-remote).  This causes the build to error with
"branch does not exist" even though the branch is present.

Use PAT-based auth (GITHUB_TOKEN) for url_pull repositories, and
fall back to checking the push url (where the App is installed)
if the PAT check also fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
@openshift-ci

openshift-ci Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign locriandev for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

SourceResolver now supports detecting remote branch existence using PAT-based GitHub auth when a url_pull is present (personal fork scenarios), automatically retrying against the push URL with GitHub App auth if pull URL checks fail. The _get_remote_branch_ref helper accepts a use_pat flag to select the appropriate auth environment, and this logic is applied to stage, target, and fallback branch detection with comprehensive test coverage.

Changes

Remote branch detection with PAT authentication and fallback

Layer / File(s) Summary
PAT authentication support for remote branch checks
doozer/doozerlib/source_resolver.py
Import get_github_git_pat_env helper and extend _get_remote_branch_ref with a use_pat=False parameter that switches between PAT auth and GitHub App auth when selecting the git environment.
Stage branch detection with PAT and fallback
doozer/doozerlib/source_resolver.py
detect_remote_source_branch derives git_url from url_pull when available, sets use_pat accordingly, and retries the stage branch existence check against the push URL if the pull-URL-based call returns no result.
Target and fallback branch detection with PAT and fallback
doozer/doozerlib/source_resolver.py
Main target branch and fallback branch existence checks follow the same pattern: attempt PAT-based pull URL check first, then fall back to push URL with GitHub App auth if needed.
Tests for PAT authentication and branch detection fallbacks
doozer/tests/test_source_resolver.py
New and updated unit tests verify that _get_remote_branch_ref uses get_github_git_pat_env when use_pat=True, and that detect_remote_source_branch correctly executes the pull-URL-then-push-URL fallback flow with the appropriate auth flags.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant detect_remote_source_branch
  participant _get_remote_branch_ref
  participant get_github_git_pat_env
  participant get_github_git_auth_env
  Caller->>detect_remote_source_branch: check branch with url_pull present
  detect_remote_source_branch->>_get_remote_branch_ref: branch, url_pull, use_pat=True
  _get_remote_branch_ref->>get_github_git_pat_env: request PAT auth environment
  get_github_git_pat_env-->>_get_remote_branch_ref: PAT credentials
  _get_remote_branch_ref-->>detect_remote_source_branch: None (branch not found on pull URL)
  detect_remote_source_branch->>_get_remote_branch_ref: branch, url_push, use_pat=False
  _get_remote_branch_ref->>get_github_git_auth_env: request GitHub App auth environment
  get_github_git_auth_env-->>_get_remote_branch_ref: GitHub App credentials
  _get_remote_branch_ref-->>detect_remote_source_branch: commit hash (found on push URL)
  detect_remote_source_branch-->>Caller: branch exists, commit hash
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error source_resolver.py logs full pull_url/push_url and git_url in LOGGER.info (e.g., lines ~323, 345, 356, 393), which could contain token/credentials if present in metadata. Sanitize/redact credentials from any git URLs before logging (e.g., strip user/token@ or use only host+repo), and avoid logging full pull_url/push_url/raw git_url.
No-Hardcoded-Secrets ❌ Error doozer/tests/test_source_resolver.py hardcodes password/token strings: GIT_PASSWORD "pat-token" and "token123" in patched return_value/expected_env. Update tests to avoid hardcoded secret-like literals (use mock.ANY or a clearly non-secret placeholder without token/password semantics).
Ai-Attribution ⚠️ Warning Local PR commit message includes "Co-authored-by: Cursor cursoragent@cursor.com" and no "Assisted-by" or "Generated-by" trailers. Replace the AI "Co-authored-by" trailer with a Red Hat "Assisted-by" or "Generated-by" trailer for Cursor (and remove the Co-authored-by line).
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically summarizes the main change: using GitHub PAT authentication for branch detection on url_pull repositories, which directly addresses the core problem of branch detection failures on personal forks.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
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.
No-Weak-Crypto ✅ Passed Scanned PR files (doozerlib/source_resolver.py, tests/test_source_resolver.py) for MD5/SHA1/DES/RC4/3DES/Blowfish/ECB and crypto/timing compare patterns; none found.
Container-Privileges ✅ Passed PR diff vs origin/main contains only doozer/doozerlib/source_resolver.py and doozer/tests/test_source_resolver.py; these files have no hostPID/hostNetwork/hostIPC/SYS_ADMIN/allowPrivilegeEscalation...
No-Injection-Vectors ✅ Passed Scanned doozer/doozerlib/source_resolver.py and doozer/tests/test_source_resolver.py for forbidden patterns (shell=True, eval/exec, pickle.loads, yaml.load, os.system, SQL/SELECT); none found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@ashwindasr ashwindasr marked this pull request as draft June 12, 2026 21:05
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 12, 2026

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@doozer/doozerlib/source_resolver.py`:
- Around line 309-315: The current logic sets use_pat = bool(pull_url) which
enables injecting the GitHub PAT for any pull URL (including non-GitHub hosts)
and can leak credentials; change the gating so use_pat is true only when
url_pull is a GitHub HTTPS remote. Update the code around
source_details["url_pull"], source_details["url"], git_url and use_pat to detect
GitHub hosts (e.g. by validating the URL's hostname or using the same
GitHub-detection used by get_github_git_auth_env) before setting use_pat, and
leave use_pat False for non-GitHub remotes so _get_remote_branch_ref(...) will
not call get_github_git_pat_env for foreign hosts; apply the same fix to the
other occurrence at the later block (around line 392) that uses use_pat.
- Around line 321-324: _source_resolver.py currently treats "no such ref" and
"probe failed" the same because SourceResolver._get_remote_branch_ref returns
falsy for both; change its contract to return a two-tuple (ref, error) where ref
is the ref string or None when not present, and error is None on a successful
probe (even if ref is missing) or an Exception/str when the git ls-remote call
failed; then update callers (the blocks that call
SourceResolver._get_remote_branch_ref, e.g. the snippet where result =
SourceResolver._get_remote_branch_ref(git_url, stage_branch, use_pat=use_pat)
and the similar calls around the other mentions) to only attempt the retry
against push_url when error is non-None, and treat ref==None with error==None as
authoritative "branch missing on url_pull" (no retry). Ensure any call sites
that expected a single return value are adjusted to unpack the tuple and
propagate/handle errors appropriately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: f341f50e-f028-4866-8108-884e2e5090f5

📥 Commits

Reviewing files that changed from the base of the PR and between 3b263c1 and f247bf4.

📒 Files selected for processing (2)
  • doozer/doozerlib/source_resolver.py
  • doozer/tests/test_source_resolver.py

Comment on lines +309 to +315
pull_url = source_details.get("url_pull")
push_url = source_details["url"]
git_url = pull_url or push_url
# When url_pull points to a personal fork, the GitHub App won't have
# access. Use GITHUB_TOKEN (PAT) for branch detection against url_pull
# and fall back to the push url (where the App is installed) if needed.
use_pat = bool(pull_url)

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Gate PAT auth to GitHub pull remotes only.

use_pat = bool(pull_url) is too broad here. If url_pull points at GitLab or another non-GitHub HTTPS host, _get_remote_branch_ref(..., use_pat=True) will inject GITHUB_TOKEN via get_github_git_pat_env(). Unlike get_github_git_auth_env(url=...), that helper does not suppress credentials for non-GitHub remotes, so this can leak the GitHub PAT to the foreign host during git ls-remote.

Suggested direction
-        use_pat = bool(pull_url)
+        normalized_pull_url = art_util.convert_remote_git_to_https(pull_url) if pull_url else ""
+        use_pat = normalized_pull_url.startswith("https://github.com/")

Also applies to: 392-392

🤖 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 `@doozer/doozerlib/source_resolver.py` around lines 309 - 315, The current
logic sets use_pat = bool(pull_url) which enables injecting the GitHub PAT for
any pull URL (including non-GitHub hosts) and can leak credentials; change the
gating so use_pat is true only when url_pull is a GitHub HTTPS remote. Update
the code around source_details["url_pull"], source_details["url"], git_url and
use_pat to detect GitHub hosts (e.g. by validating the URL's hostname or using
the same GitHub-detection used by get_github_git_auth_env) before setting
use_pat, and leave use_pat False for non-GitHub remotes so
_get_remote_branch_ref(...) will not call get_github_git_pat_env for foreign
hosts; apply the same fix to the other occurrence at the later block (around
line 392) that uses use_pat.

Comment on lines +321 to +324
result = SourceResolver._get_remote_branch_ref(git_url, stage_branch, use_pat=use_pat)
if not result and pull_url:
LOGGER.info("Branch check against url_pull %s failed, retrying with push url %s", pull_url, push_url)
result = SourceResolver._get_remote_branch_ref(push_url, stage_branch)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don't treat "branch missing on url_pull" the same as "couldn't query url_pull".

Right now _get_remote_branch_ref() returns None both when git ls-remote errors and when the branch genuinely does not exist. These sites retry push_url on any falsy result, so a branch that exists only on push_url can be selected even though resolve_source() will still clone from pull_url. That makes branch resolution succeed and the later clone fail. Only retry push_url when the url_pull probe itself failed; a clean "no such ref" result should stay authoritative for the fork.

Also applies to: 343-346, 354-357

🤖 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 `@doozer/doozerlib/source_resolver.py` around lines 321 - 324,
_source_resolver.py currently treats "no such ref" and "probe failed" the same
because SourceResolver._get_remote_branch_ref returns falsy for both; change its
contract to return a two-tuple (ref, error) where ref is the ref string or None
when not present, and error is None on a successful probe (even if ref is
missing) or an Exception/str when the git ls-remote call failed; then update
callers (the blocks that call SourceResolver._get_remote_branch_ref, e.g. the
snippet where result = SourceResolver._get_remote_branch_ref(git_url,
stage_branch, use_pat=use_pat) and the similar calls around the other mentions)
to only attempt the retry against push_url when error is non-None, and treat
ref==None with error==None as authoritative "branch missing on url_pull" (no
retry). Ensure any call sites that expected a single return value are adjusted
to unpack the tuple and propagate/handle errors appropriately.

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

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant