Skip to content

feat(auth): add URL-dispatched session auth for GitHub and GitLab#1173

Merged
mergify[bot] merged 1 commit into
python-wheel-build:mainfrom
tiran:session-auth
May 28, 2026
Merged

feat(auth): add URL-dispatched session auth for GitHub and GitLab#1173
mergify[bot] merged 1 commit into
python-wheel-build:mainfrom
tiran:session-auth

Conversation

@tiran
Copy link
Copy Markdown
Collaborator

@tiran tiran commented May 27, 2026

Pull Request Description

What

Add SessionAuth class that dispatches authentication by (scheme, hostname). Lazy callbacks resolve credentials from netrc or environment variables on first request and cache the result. create_session() returns the session and auth handler so callers can register additional hosts.

Move authentication documentation to docs/how-tos/authentication.md and update http-retry.md to reference the new guide.

Why

see #1168

@tiran tiran requested a review from a team as a code owner May 27, 2026 12:06
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR refactors Fromager's GitHub and GitLab API authentication from scattered caller-side token management to a centralized SessionAuth class. The new SessionAuth implements requests.auth.AuthBase and registers per-host credential resolver callbacks that check netrc credentials first, then environment variables (GITHUB_TOKEN, CI_JOB_TOKEN, GITLAB_PRIVATE_TOKEN). A new create_session() factory initializes the shared session, mounts the retry adapter, registers GitHub and GitLab resolvers, and exports both the session and auth handler. The resolver's inline GitHub token logic is removed. Tests validate auth dispatch, caching, credential precedence, and wiring. Documentation adds a new authentication how-to and updates existing guides to reference the centralized approach.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: introducing a SessionAuth class for URL-dispatched authentication handling for GitHub and GitLab.
Description check ✅ Passed The description clearly relates to the changeset, explaining what SessionAuth does, why it was added (issue #1168), and documenting the related changes to authentication documentation.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@tiran tiran requested review from EmilienM and ryanpetrello May 27, 2026 12:09
@mergify mergify Bot added the ci label May 27, 2026
@tiran
Copy link
Copy Markdown
Collaborator Author

tiran commented May 27, 2026

The new code generalized authentication for GitHub and GitLab. We can drop a bunch of custom code from downstream.

Copy link
Copy Markdown
Contributor

@ryanpetrello ryanpetrello left a comment

Choose a reason for hiding this comment

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

The caching/lazy mechanism makes sense to me as I read it, but I'm wondering if the complexity is worth it in terms of what we're saving/avoiding here. I had to step through this and think about it to make sure I understood - for example - the cache invalidation.

Without the caching, we're basically re-reading a .netrc on every request. Is that it?

If so, would it be simpler to just make that file read a singleton and change our callback signature so that we pass in the parsed netrc as a parameter (psuedo-code ahead)

class SessionAuth(requests.auth.AuthBase):

    def __init__(self) -> None:
        self._netrc = get_netrc_auth()

    def get(self, url: str) -> dict[str, str]:
        ...
        callback = self._callbacks.get(key)
        return callback(*key, self._netrc) if callback else {}

@ryanpetrello
Copy link
Copy Markdown
Contributor

ryanpetrello commented May 27, 2026

I should also say, @tiran I don't feel particularly strongly about #1173 (review)

If you're happy with the implementation as-is, I'm happy to give a thumbs up 👍 (though my approval is non-voting on merge).

This in particular:

We can drop a bunch of custom code from downstream.

...makes me inclined to say "ship it".

Copy link
Copy Markdown
Contributor

@rd4398 rd4398 left a comment

Choose a reason for hiding this comment

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

Looks overall good. I have left a couple of comments

Comment thread src/fromager/request_session.py
Comment thread docs/http-retry.md
@tiran
Copy link
Copy Markdown
Collaborator Author

tiran commented May 27, 2026

The caching/lazy mechanism makes sense to me as I read it, but I'm wondering if the complexity is worth it in terms of what we're saving/avoiding here. I had to step through this and think about it to make sure I understood - for example - the cache invalidation.

Without the caching, we're basically re-reading a .netrc on every request. Is that it?

Kind of. The two callbacks use requests' utils to locate, load, and parse a netrc file, then find a matching entry for an URL. In the future, callbacks may do other things that do not involve a netrc file.

@rd4398
Copy link
Copy Markdown
Contributor

rd4398 commented May 27, 2026

The caching/lazy mechanism makes sense to me as I read it, but I'm wondering if the complexity is worth it in terms of what we're saving/avoiding here. I had to step through this and think about it to make sure I understood - for example - the cache invalidation.

Without the caching, we're basically re-reading a .netrc on every request. Is that it?

If so, would it be simpler to just make that file read a singleton and change our callback signature so that we pass in the parsed netrc as a parameter (psuedo-code ahead)

class SessionAuth(requests.auth.AuthBase):

    def __init__(self) -> None:
        self._netrc = get_netrc_auth()

    def get(self, url: str) -> dict[str, str]:
        ...
        callback = self._callbacks.get(key)
        return callback(*key, self._netrc) if callback else {}

+1 to what @ryanpetrello commented.

Alternate suggestion:

drop ` _cache`  entirely and call the callback on every request. If profiling later shows netrc parsing is consuming resources, we could add caching then.

@tiran
Copy link
Copy Markdown
Collaborator Author

tiran commented May 27, 2026

What profiling? We don't do performance profiling regularly.

@rd4398
Copy link
Copy Markdown
Contributor

rd4398 commented May 27, 2026

What profiling? We don't do performance profiling regularly.

Yeah, I missed that part.

Copy link
Copy Markdown
Contributor

@rd4398 rd4398 left a comment

Choose a reason for hiding this comment

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

LGTM!

@tiran
Copy link
Copy Markdown
Collaborator Author

tiran commented May 28, 2026

@Mergifyio rebase

Add `SessionAuth` class that dispatches authentication by
(scheme, hostname). Lazy callbacks resolve credentials from
netrc or environment variables on first request and cache
the result. `create_session()` returns the session and auth
handler so callers can register additional hosts.

Move authentication documentation to docs/how-tos/authentication.md
and update http-retry.md to reference the new guide.

Co-Authored-By: Claude <claude@anthropic.com>
Signed-off-by: Christian Heimes <cheimes@redhat.com>
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 28, 2026

Deprecation notice: This pull request comes from a fork and was rebased using bot_account impersonation. This capability will be removed on July 1, 2026. After this date, the rebase action will no longer be able to rebase fork pull requests with this configuration. Please switch to the update action/command to ensure compatibility going forward.

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 28, 2026

rebase

✅ Branch has been successfully rebased

@mergify mergify Bot merged commit fa05ad2 into python-wheel-build:main May 28, 2026
38 of 39 checks passed
@tiran tiran deleted the session-auth branch May 28, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants