Expose UpstreamFilter through authserver.New facade#5733
Conversation
WithUpstreamFilter (added in #5725) was only reachable via the low-level handlers.NewHandler constructor, so a caller using the public authserver.New facade had no way to install a filter. Add Config.UpstreamFilter and thread it into the handler options built for handlers.NewHandler, mirroring the existing refresher wiring. A nil filter preserves current behavior.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5733 +/- ##
==========================================
+ Coverage 70.68% 70.74% +0.05%
==========================================
Files 682 682
Lines 68949 68958 +9
==========================================
+ Hits 48736 48783 +47
+ Misses 16665 16619 -46
- Partials 3548 3556 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tgrunnagle
left a comment
There was a problem hiding this comment.
Multi-Agent Consensus Review
Agents consulted: architecture-api-design, security, test-coverage, general-code-quality
Consensus Summary
| # | Finding | Consensus | Severity | Action |
|---|---|---|---|---|
| 1 | Config.Validate() doesn't guard against UpstreamFilter set with fewer than 2 upstreams | 9/10 | MEDIUM | Fix |
| 2 | withUpstreamFilter test option is silently ignored by 4 of 5 setup helpers | 8/10 | MEDIUM | Fix |
| 3 | Typed-nil interface value can defeat the nil-filter fast path | 7/10 | LOW | Fix |
| 4 | New test duplicates leg-1 HTTP flow boilerplate | 7/10 | LOW | Fix |
| 5 | Doc comment overstates a "second failure signal" that can't occur | 7/10 | LOW | Fix |
Overall
This threads the UpstreamFilter hook added in #5725 through the public authserver.Config/authserver.New facade, mirroring the existing UpstreamTokenRefresher wiring pattern exactly. The approach is sound: buildHandlerOptions preserves nil-filter backward compatibility byte-for-byte, there's no import cycle, and the new integration test proves the wiring with two independent signals (an HTTP status code and a storage-level assertion) rather than a shallow check.
The findings below are validation-gap and test-hygiene polish, not correctness defects. The one worth prioritizing is the Config.Validate() gap: a caller can set UpstreamFilter with a single configured upstream and get a silent no-op instead of a startup error, which cuts against this repo's own "fail loudly on invalid input" convention. The test-option no-op (a withUpstreamFilter option only 1 of 5 setup helpers actually honors) is a real footgun for future test authors, even though it doesn't touch production code. The rest are comment-accuracy and DRY nits in the new test.
Nothing here should block merge.
Generated with Claude Code
Addresses #5733 review comments: - MEDIUM pkg/authserver/config.go (3533389467): Validate() now rejects UpstreamFilter set with fewer than 2 upstreams, since computeChain never consults the filter in that case and it would silently no-op. - LOW pkg/authserver/config.go (3533389470): doc comment now warns that a typed-nil concrete pointer is a non-nil interface value and will still be wired in.
Addresses #5733 review comments: - MEDIUM pkg/authserver/integration_test.go (3533389480): wire options.upstreamFilter into setupTestServer and setupTestServerWithOIDCProvider's Config literals so withUpstreamFilter no longer silently no-ops when applied to those helpers (or to setupTestServerWithMockOIDC, which delegates to setupTestServer). - LOW pkg/authserver/integration_test.go (3533389475): extract the shared client->authorize->first-upstream->callback boilerplate into runFirstLeg, reused by runChainFlow and the new filter test. - LOW pkg/authserver/integration_test.go (3533389477): reword the new test's doc comment, which overstated a "second failure signal" from mockoidc that can't actually occur given the test's control flow.
Summary
WithUpstreamFilter(added in #5725) let a caller narrow the upstream authorization chain, but it was only reachable through the low-levelhandlers.NewHandlerconstructor. The publicpkg/authserver.Newfacade and itsConfighad no way to inject anUpstreamFilter, so any caller embedding the auth server through the facade could not install a filter at all.This adds an
UpstreamFilterfield toauthserver.Configand threads it into the handler options assembled innewServer, mirroring how the existing upstream-token refresher is already wired. Anilfilter (the default) preserves current behavior of walking every configured upstream, so the change is fully backward-compatible.Closes #5732
Type of change
Test plan
task test)task lint-fix)pkg/authserver/integration_test.gogainsTestIntegration_MultiUpstreamChain_ConfigUpstreamFilter, which drives a two-upstream chain end-to-end throughauthserver.Newwith aConfig.UpstreamFilterthat drops the second provider, and asserts the handler redirects straight to the client after the first callback instead of continuing on to provider-2. The pre-existingTestIntegration_MultiUpstreamSequentialChainis unmodified and now implicitly covers thenil-filter (no-behavior-change) path through the same facade wiring. The fullpkg/authserversuite passes, andgofmt/lint are clean on all three changed files.Does this introduce a user-facing change?
No end-user or CLI-facing change. It adds a new optional field,
Config.UpstreamFilter, to the publicpkg/authserver.Configstruct for Go callers that embed the auth server; existing callers are unaffected since anilfilter preserves today's behavior.Special notes for reviewers
handlers.UpstreamFilter/WithUpstreamFilterat the handler level but left them unreachable from theauthserver.Newfacade.server_impl.gogains a smallbuildHandlerOptionshelper so thehandlers.Optionslice is assembled once, appending the filter option only whencfg.UpstreamFilteris non-nil.integration_test.gorather than next tohandler_chain_test.goas the issue suggested, since it specifically exercises theConfig→authserver.New→handlers.NewHandlerwiring; the lower-level chain-narrowing logic (computeChain) is already unit-tested inhandler_chain_test.go.Config.UpstreamFilter— wiring an actual filter policy for a real caller is out of scope for this issue and left as follow-up work.Generated with Claude Code