Repository navigation
Preserve browser Origin with authenticated proxy forwarding - #1251
Merged
Merged
Conversation
With --rewrite-host the proxy sends Host: TO but forwarded the browser's Origin: https://FROM unchanged, so upstream endpoints that verify a same-origin Origin against their own origin rejected proxied requests. Replace a single same-origin Origin with the TO origin (scheme from --upstream-plaintext, non-default port kept) so Origin and Host name the same authority. Cross-site, null, plain-http and duplicated Origin values pass through unchanged.
When Cookie field multiplicity is not preserved, any comma anywhere in the header made all four trace cookie results unavailable. Google Identity's JSON-valued g_state cookie contains commas and is set on every page load of publishers that use One Tap, so tracing could never activate for those visitors. A comma is now ambiguous only when it could change a reserved result: inside a reserved cookie's own segment, where it could truncate the value, or directly before a reserved name, where it could hide an occurrence inside another cookie's value. Commas inside unrelated values cannot do either. The replacement-character rule is unchanged. Update the four fixtures that relied on the old rule to use a comma that still borders the session cookie, and align the spec and operator guide.
The trace page listed every retained field in one long column, so a reader on a phone had to scroll through many screens of label/value pairs, raw float timings and Unavailable rows to learn whether an ad slot filled. Open the report with a What happened summary: a headline, a short reading computed only from retained fields, count tiles and fill chips. A Needs attention list links to empty, fill-unknown, incomplete or creative-failure slots. Each GPT slot gets a card with its fill state, a proportional response/render/viewable timing bar, its exact server-slot link and a collapsed All details disclosure. Server auctions stay expanded; request, cookie and coverage sections collapse. Unavailable fields fold behind N fields unavailable, timings round to one decimal and capture times read as UTC. The summary never names an auction winner, counts only bidder-role bids so mediator echoes are not double counted, names the outcome of auctions that did not complete and applies no latency thresholds. Timing bars use stylesheet flex-weight classes, not inline styles, so the strict style-src 'self' CSP holds, and the exact milliseconds stay in text and in the bar's accessible label. Light and dark themes follow the system setting. Split the 680-line viewer into a pure, unit-tested summary model (view-model.ts), DOM primitives (report-dom.ts), detail sections (report-details.ts) and the page layout (report-view.ts). Rebuild the v1 trace assets and manifest, drop the setup shell's duplicated instruction, and describe the page in spec section 6.3.
Derive the first-party origin from the inbound Host so non-443 sessions are rewritten too, and apply the rewrite only to Trusted Server's /_ts endpoints, so publisher and integration requests keep the browser's real Origin. Cover the behavior end to end through the proxy.
Document authenticated forwarding and the current dev proxy limitation, pin the Spin runtime checksum, and keep composition tests compatible with ES2020. Refresh the stale trace input digest after verifying rebuilt JS and CSS exactly match the frozen assets.
Resolve documentation overlaps while preserving authenticated forwarding, browser authority validation, and Origin handling. Update the configuration guide and example for the available forwarding credential option.
aram356
added a commit
that referenced
this pull request
Oct 12, 2026
Brings #1107 to b4a20f4, its first revision in this RC that carries the trace implementation rather than only the spec. Integration decisions: - EdgeZero moves to 78439fd4 on spec/pre-dispatch-request-fidelity. It contains v0.0.9 (#1175) and the pre-dispatch ingress hooks #1107 and #1251 pin at 965d482f; no released tag carries both. - scheduleInitialAdInit takes (bids, slots, auctionDiagnostics, traceAuctionTransport). One builder emits both payloads, so the RC's diagnostics-only scripts are unchanged and trace moves to the fourth argument. recordTrustedServerOpportunity likewise takes auctionFacts then traceIdentity; #1107's positional tests and the bootstrap fallback were shifted to match. - The Fastly trace terminal path sends through the timed delivery function without Server-Timing, sandbox counters or access telemetry. - build.rs embeds trace assets from #1214's private bundle directory. The viewer rebuilds byte-identical; the pinned source digest changes only because build-all.mjs gained --out-dir. - The trace projection does not copy the RC's auction evidence fields, so the classification test marks them excluded. - The retained diagnostics toolbar resyncs its filter select after selectRequest. - Shim size guard raised to 55.5 KB for diagnostics plus trace.
aram356
added a commit
that referenced
this pull request
Oct 12, 2026
aram356
added a commit
that referenced
this pull request
Oct 12, 2026
Brings #1222 at 514a617. Integration decisions: - RequestInfo::from_request keeps #1251's source order (authenticated forwarder, immutable ingress, runtime origin, Host) and applies #1222's host syntax check to whichever host is selected. It returns BadRequest for a malformed or non-text selected host. Raw Forwarded and X-Forwarded-Host are never selected in the RC, so #1222's tests for those headers now assert they are ignored instead of rejected. - RC-only callers (DataDome protection, Fastly compat, Spin, forwarder, orchestrator and publisher tests) handle the fallible signature. DataDome only reads RequestInfo behind an authenticated origin and keeps its request_host fallback. - The first-party sign path prefers the authenticated forwarder scheme (#1251) and propagates #1222's host error. - The GTM rewriter takes #1222's per-document GtmScriptState, which supersedes main's ScriptTextAccumulator use from #1179; state still lives in IntegrationDocumentState, and #1179's two-document residue tests remain.
aram356
approved these changes
Oct 13, 2026
aram356
added a commit
that referenced
this pull request
Oct 15, 2026
Brings in the squash-merged #1175 (a0b00c7), #1239 (d2f0d8c) and #1226 (3e85161), replacing the RC's earlier branch revisions. Conflict resolutions: - EdgeZero stays pinned to 78439fd4. Main pins v0.0.9, which 78439fd4 contains; #1107 and #1251 still need its pre-dispatch hooks, and no released tag carries them yet. The lockfile needed no changes. - Fastly main.rs keeps #1107's ingress-capturing signatures, which already carry #1175's logical store selection. - proxy.rs takes #1239's final redirect-limit passthrough test. - AGENTS.md keeps the RC's gate list, which already includes main's wasm clock lint. - getting-started takes main's final #1175/#1213 deploy wording. - Integration-test config.rs and cloudflare.rs keep the RC's trace-aware envelope and readiness-probe helpers, which carry #1226's spawn_with_config_json.
aram356
added a commit
that referenced
this pull request
Oct 21, 2026
prk-Jr
changed the base branch from
spec/mobile-ad-render-trace-endpoint
to
main
October 30, 2026 13:53
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.
Summary
Allow
ts dev proxyto authenticate the browser-facing origin while preserving the browser's original Origin header. This lets trace Enable/End work when the proxy rewrites Host or sends plaintext to its upstream, without forging a trace-specific Origin.Changes
--forwarder-secret-file. Validate a single secret of at least 32 ASCII graphic bytes before listening, redact diagnostics and mark the outgoing credential header sensitive. Credential injection requires a loopback listener.X-Forwarded-Host,X-Forwarded-Proto: httpsandX-TS-Forwarder-Authafter hop-by-hop sanitation. Conflicting or ambiguous authority is rejected; CONNECT fallback is never authenticated.Dependency
Requires the server-side authenticated-forwarder support from #1107, now on
main: optional[trusted_forwarder]configuration, secret-store resolution and shared public-origin handling.Configure the server's authentication header as
x-ts-forwarder-auth; itsshared_secretis a secret-store key, while the CLI file contains the actual matching secret. Deploy the server configuration before using the flag.Validation
All required local CI gates passed before the final merge with
main: all eight lint gates, every adapter suite, parity, JS build/tests and formatting, native build-digest tests/lint, core documentation, native CLI suites and adapter builds including Fastly/Spin release artifacts. The CLI unit, proxy wire and actual proxy-to-server suites pass. Explicit TLS provider setup makes the new shared fixture dependency deterministic; the isolated TLS wire test and serial 111-test proxy unit suite also pass. The actualts config validatecommand accepts the forwarder secret-store key reference. The combined regressions use the production Axum HTTP listener behind the real proxy, covering encrypted/plaintext upstreams, rewritten/preserved Host, a public non-default port, Enable/End cookies, rejected Origins/queries/duplicates, missing credentials, server opt-out and transport fallback. Publisher tests check unchanged Origin, stripped credentials, generated public URLs and HTTPS protocol-relative signing.Independent reviewers checked the CLI implementation, found and verified a streaming trailer credential leak fix, and reviewed the real-server fixture. Server ingress and configured identify CORS are covered by #1107, now on
main.Closes #1250
Spec:
docs/superpowers/specs/2026-06-22-ts-dev-proxy-design.md(updated here), plan:docs/superpowers/plans/2026-10-09-authenticated-forwarder.mdThe new CodeQL alert #204 was independently reviewed and dismissed as a false positive. SHA-256 only creates temporary fixed-size bearer-token digests for comparison; neither digest is stored or exposed. Operator documentation requires cryptographically random token generation and distinguishes minimum length from entropy. This assessment follows CodeQL's guidance for the distinction between password storage and other hashing uses.
Standalone runtime verification: launched the actual
trusted-server-axumserver andts dev proxybinaries, loading server configuration through the normal blob envelope and environment-backed secret store. All 56 live HTTPS requests passed the expected checks across plaintext/TLS upstreams with--rewrite-hoston/off. Enable → separate active-state request → publisher document with active trace context → End → separate inactive-state request succeeded with unchanged Secure/HttpOnly/host-only/SameSite=Lax cookies. Public URLs retain browser HTTPS authority and port; protocol-relative signing uses HTTPS; publisher and custom Didomi routes preserve browser Origin and receive no forwarding credentials. Foreign hosts/Origins, duplicate Origin, action queries, nonempty bodies, missing/wrong credentials, and server opt-out reject without cookie mutation. Browser-to-proxy TLS uses the isolated generated CA; the self-signed local upstream TLS relay uses--insecure. An independent subagent audited the response and recorded upstream evidence. This does not establish physical mobile/browser UI or deployed-runtime acceptance.The standalone run found a TLS-provider startup panic when workspace features enable both providers. The proxy now calls the existing idempotent provider initializer before TLS setup; a fresh-process regression requires a real PAC HTTP response. CI also exposed a redaction-test sentinel collision with a backtrace symbol; the distinct short invalid token retains the complete Report Debug redaction assertion and passes with short/full backtraces.