fix: forward browser User-Agent + ADC Local Test Run 4 defects - #495
Merged
Merged
Conversation
The server-side "APIClient" handler from AddCommonServerTokenStorage() now stamps User-Agent with the visitor's user-agent next to X-Forwarded-For (same source and semantics as the cookie-session refresh), so a sign-in or registration on the Blazor Server path records the browser's device on the signed-in devices page instead of "Unrecognized device". Verified in production after v1.225.0: a server-path sign-in recorded the public IP but no device name. The internal handler is renamed BrowserForwardedForHandler -> BrowserOriginHandler since it now forwards both values. A blank user-agent is not forwarded; an existing value is replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sDGvYdTD88ZjjD7if2SMW
…g, cancel toast, Spanish accents) - LoginProtectionService reads the per-IP registration counter from the shared store (GetFromSharedStoreAsync): the hybrid cache served a 30 s in-process copy the increment never refreshed, so a burst of registrations from one IP was never refused (U-23). - Gateway downstream health checks: one keyed-singleton check per downstream so the latched HTTP version survives between polls, and no resilience handler on the probe clients, whose retry backoff ate the 2 s probe budget; /health no longer flaps to 503 while every route works. - DataGridListPageBase toasts "Loading cancelled." only for the current load of a live component: a load superseded by a newer one, or cancelled by disposal, is silent; a user Cancel still toasts (O-39). - Spanish: role administration and the OAuth completion strings regain their accents; new SpanishAccentTestsBase fitness test (Testing.Architecture Governance) fails the build on an unaccented Spanish word in any .es.resx. - INotificationScopeProvider docs: the scope tags the inbox view; delivery goes to every recipient. Tests for each fix were written in a separate pass before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ke2CLcwmJVENRiYrRVmGKw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ke2CLcwmJVENRiYrRVmGKw
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #492 (v1.225.0), found while verifying it in production.
What production showed: after the ADC deploy, a sign-in through the Blazor Server path recorded the visitor's real public IP on the Signed-in devices page (so the #492
X-Forwarded-Forforwarding works), but the device column read "Unrecognized device": the server-side"APIClient"call carried no user-agent of the browser, only the host's empty one.Fix: the handler that
AddCommonServerTokenStorage()composes onto"APIClient"now also stampsUser-Agentwith the visitor's user-agent, from the same request and with the same semanticsCookieSessionRefresher.BrowserOriginalready uses for the refresh call. A blank user-agent is not forwarded; an existing value is replaced, never appended. The internal handler is renamedBrowserForwardedForHandler->BrowserOriginHandler(internal, no public API change).Tests:
BrowserOriginHandlerTestskeeps the six address tests and adds: user-agent forwarded, an existing user-agent replaced, a blank user-agent not sent (address still sent), and the DI wiring asserting both headers.MMCA.Common.UI.Web.Tests208/208 locally; Release build 0 warnings.Ships in the next Common release; consumers pick it up with no code change (ADC and Store already call
AddCommonServerTokenStorage()).Also in this PR: ADC Local Test Run 4 defects (found 2026-10-03/04 by a 231-case manual run on a fresh local ADC stack; each confirmed in source by an independent reviewer; the tests were written in a separate pass before the fixes):
LoginProtectionServiceread the per-IP registration count through the hybrid cache, whose 30 s in-process copyIncrementAsyncnever refreshes, so 11 registrations from one IP within a few seconds all succeeded. It now reads the shared store (GetFromSharedStoreAsync), as 2FA and password reset already do. Test:LoginProtectionServiceHybridCacheTestsover the real hybrid cache./healthflapping (low): the health-check factory built a newDownstreamServiceHealthCheckper poll, losing the latched HTTP version, and the probe clients carried the standard Polly retry inside the 2 s budget, so a mixed-profile downstream (Notification) flapped Unhealthy while every route worked. Now one keyed-singleton check per downstream, and no resilience handler on the probe clients (written against the stableConfigureAdditionalHttpMessageHandlers;RemoveAllResilienceHandlersis still EXTEXP0001). Test:GatewayDownstreamHealthCheckPollingTests.DataGridListPageBasetoasted anyOperationCanceledException, including a load superseded by a newer one. It now toasts only for the current load of a live component; a user Cancel still toasts. Tests: three new facts inDataGridListPageBaseTests(the existing O-72 test now waits on load completion instead of the toast; no assertion changed).SpanishAccentTestsBase(Testing.Architecture, Governance) fails the build on an unaccented Spanish word in any.es.resx; Common subclasses it, and ADC will in its bump PR (ivanball/ADC#248).INotificationScopeProviderno longer claims the targeting caption shows who a notification reaches; the scope tags the inbox view and delivery goes to every recipient.Local:
dotnet build MMCA.Common.slnx -c Release0 warnings; Architecture 318/318, Aspire 293/293, UI 1232/1232, Infrastructure 1725/1725.Release plan: this PR -> v1.226.0 -> one bump PR per consumer (ADC #248 carries its own fixes too, so one deploy; Store and Helpdesk bump PRs).
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ke2CLcwmJVENRiYrRVmGKw