test(ui): cover analytics-proxy's allowlist, cookie/IP, and set-cookie stripping (#8387)#8450
Conversation
…e stripping (JSONbored#8387) apps/loopover-ui/src/lib/analytics-proxy.ts relays the cookieless analytics beacon to the Umami-compatible upstream without exposing that host to the browser. Its four security behaviors -- strict path allowlist, first-party cookie stripping (the JSONbored#597 fix), cf-connecting-ip-only x-forwarded-for (anti-geo-spoof), and upstream set-cookie stripping -- had zero coverage; no test referenced handleAnalyticsProxy at all. Adds apps/loopover-ui/src/lib/analytics-proxy.test.ts (vi.stubGlobal fetch, the established pattern in this dir), covering: - an allowed POST forwards to https://tasty.aethereal.dev/api/send with the query preserved and the upstream status/statusText/body relayed - a disallowed method returns 405 + allow header and never fetches - a non-allowlisted path (/stats/admin, /stats/api/collect) returns undefined (SSR fallthrough) and never fetches - the visitor cookie is stripped while unrelated headers pass through - x-forwarded-for is re-derived from cf-connecting-ip and a client-supplied value is dropped; no cf-connecting-ip means no x-forwarded-for - upstream set-cookie is stripped while other response headers are relayed - an upstream fetch throw fails quietly with 502 Test-only, no production change.
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-24 13:57:56 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionPartially addressed Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
Summary
Closes #8387.
apps/loopover-ui/src/lib/analytics-proxy.ts'shandleAnalyticsProxyrelays the app's cookieless analytics beacon (POST /stats/api/send) to the Umami-compatible upstream without ever exposing that host to the browser. The module's own comments spell out four security-sensitive behaviors, and it had zero test coverage -- no test file referencedhandleAnalyticsProxyoranalytics-proxyat all, so a regression in any of them would ship with no signal.Adds
apps/loopover-ui/src/lib/analytics-proxy.test.ts(vi.stubGlobal("fetch", ...)withafterEach(() => vi.unstubAllGlobals()), the established pattern in this directory), covering all four plus the fail-safe:POST /stats/api/sendreacheshttps://tasty.aethereal.dev/api/sendwith the query string preserved, and the upstream's status / statusText / body are relayed back.405with anallowheader and never callsfetch.ROUTES(/stats/admin,/stats/api/collect) returnsundefined(SSR fallthrough) and never callsfetch. This is the load-bearing "must NOT become an open proxy onto the Umami host, whose admin/auth API lives on the same origin" guarantee.cookieis not forwarded (the fix for closed issue [Bug]: Umami analytics reverse-proxy forwards first-party request cookies to the upstream, breaking its "cookieless / strips cookies" guarantee #597's cookieless-guarantee bug), while a non-stripped header still passes through, so the assertion isn't just "drops everything".x-forwarded-foris re-derived from the trustedcf-connecting-ipand a client-suppliedx-forwarded-foris dropped (no geolocation spoofing); with nocf-connecting-ip, nox-forwarded-foris set.set-cookiestripping -- the upstream'sset-cookieis not relayed to the browser, while unrelated response headers still are.fetchthrow yields502rather than taking the page down.Test-only, no production change.
Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Closes #8387).Validation
git diff --checknpm run actionlint- no workflow files touched.npm run ui:typechecknpm --workspace @loopover/ui run test -- --run src/lib/analytics-proxy.test.ts- 8/8 pass.npm run test:coverage/test:workers/build:mcp- not run: this adds one test file underapps/loopover-ui/and touches no backend, worker, or MCP surface.npm audit --audit-level=moderate- no dependency changes.If any required check was skipped, explain why:
apps/**, whichcodecov.ymlignores, socodecov/patchhas no changed lines to score.Safety
set-cookie-strip cases are all negative-path assertions.UI Evidencesection - n/a: test-only, no visible UI difference.Notes
fetchis stubbed via a small typed recorder rather than readingmock.calls, so the forwarded URL/method/headers are inspected without casting through the WorkersRequestInit<CfProperties>type.