Skip to content

Rename pkg/oauth to pkg/oauthproto and move DCR primitives - #5036

Merged
tgrunnagle merged 1 commit into
mainfrom
worktree-issue_4977
Apr 27, 2026
Merged

tgrunnagle merged 1 commit into
mainfrom
worktree-issue_4977

Conversation

@tgrunnagle

@tgrunnagle tgrunnagle commented Apr 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • The authserver could not import pkg/auth/oauth to reuse the Dynamic Client Registration (DCR) client because doing so would create an import cycle. This blocked Phase 2 of the DCR story (Authserver DCR integration (Phase 2, Steps 2a-2g) #4978), which wires the authserver to upstream OAuth providers.
  • This PR renames pkg/oauth to pkg/oauthproto, moves the RFC 7591 DCR primitives from pkg/auth/oauth/dynamic_registration.go into pkg/oauthproto/dcr.go, and relocates the loopback-host helper into pkg/oauthproto so the package remains a true leaf with no pkg/networking dependency.

Implements (most of) #4977 (the authserver still defines its own DCRRequest/DCRResponse in pkg/authserver/server/registration/dcr.go alongside the new types in pkg/oauthproto. Reconciling Scope string vs ScopeList is the blocking work, so it doesn't belong in this PR).

Type of change

  • Refactoring (no behavior change)

Test plan

  • Unit tests (task test)
  • Linting (task lint-fix)

Unit tests for all moved DCR logic now live in pkg/oauthproto/dcr_test.go (package oauthproto_test), covering RegisterClientDynamically happy paths, nil-client default, endpoint validation, validateAndSetDefaults, handleHTTPResponse error mapping (including regression guard that the CLI-flag hint is absent), ScopeList marshal/unmarshal, isLoopbackHost, and the 1 MB body-cap via io.LimitReader.

Changes

File Change
pkg/oauth/ (all files) Renamed directory to pkg/oauthproto/; package oauth → package oauthproto
pkg/oauthproto/dcr.go DCR types, RegisterClientDynamically, and helpers moved from pkg/auth/oauth/dynamic_registration.go; getHTTPClient/registerClientDynamicallyWithClient removed; *http.Client parameter replaces the networking.HTTPClient interface indirection
pkg/oauthproto/dcr_test.go New file — DCR unit tests relocated from pkg/auth/oauth/dynamic_registration_test.go; mock-client tests rewritten using httptest.NewServer
pkg/oauthproto/locality.go New file — IsLoopbackHost (exported) hosts the canonical loopback check; keeps pkg/oauthproto free of any pkg/networking import
pkg/oauthproto/constants.go UserAgent = "ToolHive/1.0" moved here from pkg/auth/oauth/oidc.go
pkg/oauthproto/doc.go Updated to document the expanded (still leaf-package) surface including DCR and the leaf-package invariant
pkg/networking/utilities.go IsLocalhost made a thin wrapper over oauthproto.IsLoopbackHost — all existing callers unchanged
pkg/auth/discovery/dcr_request.go New file — NewDynamicClientRegistrationRequest factory (CLI-specific loopback redirect URI assumption) extracted here from pkg/auth/oauth/dynamic_registration.go
pkg/auth/discovery/discovery.go registerDynamicClient updated to call the local factory and oauthproto.RegisterClientDynamically
pkg/auth/oauth/dynamic_registration.go Deleted
pkg/auth/oauth/dynamic_registration_test.go Deleted (tests moved to pkg/oauthproto/dcr_test.go)
17 import sites pkg/oauth → pkg/oauthproto; the 8 sites that already aliased as oauthproto drop the alias

Implementation Details

  • pkg/oauthproto is a leaf package: it depends only on the standard library and fosite (already pulled in by redirect.go). pkg/networking now imports pkg/oauthproto for the loopback check, not the other way around. This is the structural change that unblocks pkg/authserver from importing the DCR client in Phase 2.
  • RegisterClientDynamically now takes *http.Client directly (nil means "use the 30 s / 10 s / 10 s default"). The former networking.HTTPClient interface indirection and the private registerClientDynamicallyWithClient entry point are removed, eliminating a layer of unnecessary abstraction.
  • The CLI-specific error hint ("Please configure OAuth client credentials using --remote-auth-client-id…") in handleHTTPResponse is replaced with a protocol-neutral message before the function moves into the protocol package.
  • NewDynamicClientRegistrationRequest remains in pkg/auth/discovery/ because it hardcodes http://localhost:<port>/callback — a CLI assumption that must not leak into a protocol-level package.

Does this introduce a user-facing change?

No.

Special notes for reviewers

  • Import cycle elimination is the core goal. go list -deps ./pkg/oauthproto/... should show no pkg/networking path. A grep -r "pkg/networking" pkg/oauthproto returns no hits.
  • The pkg/auth/oauth/dynamic_registration_test.go → pkg/oauthproto/dcr_test.go rename is a large hunk in the diff but is mostly a structural move; the test logic is equivalent with mock-based tests converted to httptest.NewServer.
  • pkg/oauth/doc.go is deleted; pkg/oauthproto/doc.go replaces it with updated content reflecting the expanded surface area.
  • Phase 2 (Authserver DCR integration (Phase 2, Steps 2a-2g) #4978) is blocked on this PR landing first.

Generated with Claude Code

Large PR Justification

  • Refactor has to be done in one PR

jhrozek
jhrozek previously approved these changes Apr 23, 2026

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

Looks good. One follow-up worth tracking under #4977 before we close it out: the authserver still defines its own DCRRequest/DCRResponse in pkg/authserver/server/registration/dcr.go alongside the new types in pkg/oauthproto. Reconciling Scope string vs ScopeList is the blocking work, so it doesn't belong in this PR, but it's worth a line in the #4977 plan so the two don't drift.

Minor aside, not blocking: the doc.go surface-area bullet says "RFC 7591 Dynamic Client Registration: request/response types" which overclaims slightly while the authserver still has its own. Tightening the wording to make it clear these are the client-side types would avoid future confusion.

@tgrunnagle
tgrunnagle force-pushed the worktree-issue_4977 branch from 3cb8de5 to 5e365c9 Compare April 27, 2026 13:16
@tgrunnagle
tgrunnagle marked this pull request as ready for review April 27, 2026 13:16
@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Apr 27, 2026

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

Large PR Detected

This PR exceeds 1000 lines of changes and requires justification before it can be reviewed.

How to unblock this PR:

Add a section to your PR description with the following format:

## Large PR Justification

[Explain why this PR must be large, such as:]
- Generated code that cannot be split
- Large refactoring that must be atomic
- Multiple related changes that would break if separated
- Migration or data transformation

Alternative:

Consider splitting this PR into smaller, focused changes (< 1000 lines each) for easier review and reduced risk.

See our Contributing Guidelines for more details.


This review will be automatically dismissed once you add the justification section.

jhrozek
jhrozek previously approved these changes Apr 27, 2026
@github-actions github-actions Bot removed the size/XL Extra large PR: 1000+ lines changed label Apr 27, 2026
@github-actions
github-actions Bot dismissed their stale review April 27, 2026 13:20

Large PR justification has been provided. Thank you!

@github-actions

Copy link
Copy Markdown
Contributor

✅ Large PR justification has been provided. The size review has been dismissed and this PR can now proceed with normal review.

@github-actions github-actions Bot added the size/XL Extra large PR: 1000+ lines changed label Apr 27, 2026
Implements Phase 1 of issue #4977:
- Rename pkg/oauth/ -> pkg/oauthproto/; update all 17 import sites
  (8 with alias can now drop the alias since pkg name matches)
- Move DCR types, ScopeList, RegisterClientDynamically, and helpers
  from pkg/auth/oauth/dynamic_registration.go into pkg/oauthproto/dcr.go
- RegisterClientDynamically now takes *http.Client directly (nil builds
  a default); drop registerClientDynamicallyWithClient and HTTPClient iface
- Relocate IsLocalhost logic into pkg/oauthproto/IsLoopbackHost; pkg/networking
  keeps its IsLocalhost as a thin wrapper to avoid touching all callers
- Move UserAgent constant from pkg/auth/oauth/oidc.go to pkg/oauthproto/constants.go
- Generalize handleHTTPResponse error string (remove CLI-flag hints)
- Host NewDynamicClientRegistrationRequest in pkg/auth/discovery/dcr_request.go
  (sole caller; loopback redirect-URI assumption stays out of protocol pkg)
- Add tests in pkg/oauthproto/dcr_test.go covering the moved behaviour
- Update pkg/oauthproto/doc.go to document the expanded surface area

Address code review feedback

Fixed issues from code review:
- CRITICAL: Delete orphaned pkg/oauth/ directory (7 files); no importers remain
- HIGH: Copy request in RegisterClientDynamically before validateAndSetDefaults
  to avoid mutating the caller's struct; nil guard moved up before the deref
- HIGH: Drop redundant oauthproto alias from 4 test files (token_test.go,
  oidc_test.go, discovery_test.go, upstream/oidc_test.go)
- MEDIUM: Remove isLoopbackHost private wrapper; dcr.go calls IsLoopbackHost directly
- MEDIUM: Replace 13-line Apache header in pkg/oauthproto/doc.go with 2-line SPDX
- MEDIUM: Add comment in registerDynamicClient clarifying CLI-flag hint is
  intentional; reference #4978 for future structured error handling

Address second round of code review feedback

Fixed issues from code review:
- HIGH: Replace 13-line Apache header and redundant package doc comment in
  pkg/oauthproto/constants.go with the 2-line SPDX form; the file was
  substantially rewritten (UserAgent added, original URN constants removed)
  so it qualifies as "rewritten in full" per the project header rule
- MEDIUM: Drain response body with io.Copy(io.Discard) before returning the
  content-type error in handleHTTPResponse, allowing net/http to reuse the
  underlying TCP connection per the project drain-before-close style rule

Add missing io.LimitReader body-cap test for handleHTTPResponse

The Testing Strategy in issue #4977 requires that handleHTTPResponse is
tested for its 1 MB io.LimitReader cap. The non-JSON content-type and
missing client_id cases were already covered; this commit adds the cap
test. The test sends a body padded well past 1 MB and verifies the call
returns promptly without hanging or panicking — a future refactor that
removes or raises the cap would break the JSON decode and surface the
regression immediately.
@tgrunnagle
tgrunnagle force-pushed the worktree-issue_4977 branch from 5e365c9 to 16e2153 Compare April 27, 2026 13:21
@github-actions github-actions Bot added size/XL Extra large PR: 1000+ lines changed and removed size/XL Extra large PR: 1000+ lines changed labels Apr 27, 2026
@codecov

codecov Bot commented Apr 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.55556% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.75%. Comparing base (68d29fb) to head (16e2153).

Files with missing lines Patch % Lines
pkg/auth/discovery/dcr_request.go 0.00% 9 Missing ⚠️
pkg/auth/discovery/discovery.go 25.00% 3 Missing ⚠️
pkg/oauthproto/dcr.go 93.10% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5036      +/-   ##
==========================================
- Coverage   69.81%   69.75%   -0.06%     
==========================================
  Files         562      564       +2     
  Lines       56647    56649       +2     
==========================================
- Hits        39548    39518      -30     
- Misses      14063    14101      +38     
+ Partials     3036     3030       -6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tgrunnagle
tgrunnagle merged commit d82a03b into main Apr 27, 2026
43 checks passed
@tgrunnagle
tgrunnagle deleted the worktree-issue_4977 branch April 27, 2026 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Extra large PR: 1000+ lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants