Skip to content

Emit absolute creative rewrite URLs - #917

Open
ChristianPavilonis wants to merge 12 commits into
mainfrom
feature/absolute-creative-rewrite-urls
Open

ChristianPavilonis wants to merge 12 commits into
mainfrom
feature/absolute-creative-rewrite-urls

Conversation

@ChristianPavilonis

@ChristianPavilonis ChristianPavilonis commented Jul 15, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Emit absolute creative proxy, click, CSS, srcset, runtime, sign-response, and rebuild-response URLs using normalized publisher.public_origin. Preserve signing, rewrite policy, legacy signed inputs, credential modes, and the inline renderer's request-origin override.

Closes #915.

Spec

Absolute creative rewrite URLs at the reviewed revision.

Review follow-up

  • Both publisher-page and creative-runtime script tags now stamp data-ts-public-origin. The runtime captures this metadata once to recognize the exact /first-party/proxy path on the configured origin as already proxied, even when the bundle loads from a different origin. Sign/rebuild endpoints remain script-origin-first; metadata does not replace the legacy parent stamp.
  • Source, independent emitted-IIFE, and real Chromium regressions cover split origins, foreign/path/port lookalikes, later DOM mutation, and images/iframes. A real raw-resource control proves the guard is active and selects the script-origin sign endpoint. Signer-minted proxy URLs load successfully without a second sign or nested proxy target; invalid tokens still return 403. Browser security and CORS are unchanged.
  • App-config loading/construction emits static advisory diagnostics for omitted origins, out-of-EC-cookie-scope hosts, and non-loopback HTTP. Matching uses publisher.domain, not cookie_domain, and retains the trailing-dot cookie distinction. Validation itself no longer logs. HTTP and intentional local mismatches remain valid; blob serialization and hashes are unchanged.
  • Rust rewrite boundaries choose the origin explicitly before signing, without base_path.starts_with('/') inference or per-resource public-origin resolution. Inline request-origin precedence and encrypted target tokens/query ordering remain covered.
  • EOF runtime goldens account only for the per-listener script metadata, while asserting the current stamp and retaining exact checks for all other output.
  • All four smoke scripts reuse a named positive listener port. The template lead-in and configuration docs are updated.
  • The earlier merge/CI, quickstart overlay, configuration anchor, forwarded-origin precedence, placeholder, rebuild-token, error-message, port-zero, and logging findings remain addressed. This follow-up preserves their regressions.

Compatibility

An omitted public_origin remains omitted in serialized config but emits general-purpose URLs on https://{publisher.domain}. Verify the browser-facing endpoint and coordinate binary/config upgrade and rollback as described under Publisher configuration.

No signing-format migration, CORS expansion, cross-origin credential change, or identity/consent policy change. Script-origin and metadata capture are not authenticated against earlier creative scripts; the documented pre-capture currentScript spoofing limitation remains.

Verification on this follow-up

Pinned Rust 1.98.1, Node 24.20.0, and Viceroy 0.21.0.

  • Native core library: 3,362 passed, two existing ignored tests.
  • All five adapter/core test aliases, cross-adapter parity, integration config/generator tests, full host CLI suite, and native build-digest tests passed.
  • All eight target-matched Clippy aliases, integration/build-digest lint, and Rust formatting passed. Fastly and Spin release builds passed.
  • Full JS suite: 78 files, 1,891 tests passed with four workers; build, lint, formatting, and emitted-IIFE regressions passed. The unrestricted run hit three timeout-only failures; the four-worker rerun passed without source or timeout changes.
  • Real Chromium full suites: Next.js 57 passed/two intended skips; WordPress 36 passed/23 intended skips. The new configured-origin regression passes on both frameworks. Dedicated trace/auth configs were supplied, and the isolated fixture image leaves shared Docker tags unchanged.
  • Docs lint/format/build, browser formatting/types with the installed JS Node types, bash syntax, and ShellCheck passed.
  • Native EOF harness tests/lint and actual Axum plus Fastly EOF/auction controls passed, including Fastly streaming and timeout controls.
  • Complete Axum and Fastly local smokes passed. Spin reaches the expected 503 but fails its missing-config log assertion; the pre-change script reproduces the same failure. Full Spin smoke coverage remains incomplete. Cloudflare's full smoke was not run because the script requires a Wrangler pin absent from .tool-versions; its common initializer CLI regression and shell checks pass.
  • All 29 GitHub checks pass on 8ed42ab8e, including Rust analysis, both EOF runtime jobs, integration, browser, trace-runtime acceptance, and parity. The first follow-up exposed an EOF test-harness assumption about byte-identical output across different listener ports. The harness now verifies the exact current origin stamp and permits only that controlled field to change in its otherwise exact output comparison.

Plain browser TypeScript checking lacks Node types in the existing browser dependency installation; checking with the installed JS package's Node type roots passes without dependency changes. Default browser suites retain the opt-in mobile trace-runtime skips. Viceroy logs some canceled-response worker panics while browser tests still pass; this follow-up does not claim to fix simulator cancellation handling.

Tracked maintenance

The cookie-scope warning is implemented here rather than deferred. Sharing the two Viceroy fixture retargeting helpers remains separate in #1514, preserving their custom-resource, envelope verification, timestamp, upstream, and error contracts.

Retain main's sanitization controls, bounded CSS rewriting and opaque-origin
click recovery while keeping configured absolute creative URLs.

Keep the inline renderer's explicit origin override and both branches'
regression coverage. Adapt root-relative test assumptions to absolute
signing responses.
@ChristianPavilonis
ChristianPavilonis marked this pull request as ready for review October 29, 2026 18:26

@aram356 aram356 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds [publisher].public_origin and emits absolute proxy, click, runtime, sign, and rebuild URLs on it, with the creative runtime capturing its script origin for endpoints. The template's new active public_origin placeholder bypasses the deploy placeholder guard, so an operator following the guard's error message ships a config that points every rewritten creative at ads.example.com. The absent-key fallback and the new currentScript precedence also deserve a second look.

4 of the inline comments below carry a one-click GitHub suggestion. Use Commit suggestion (or Add suggestion to batch for several at once) to apply them as commits on the PR branch. The remaining comments describe the fix in prose because the change touches multiple files or lines outside the diff and can't be auto-applied.

Blocking

🔧 wrench

  • Template public_origin placeholder escapes the deploy guard: see inline at trusted-server.example.toml:70

Non-blocking

🤔 thinking

  • Absent-key fallback moves every existing deployment to https://{apex}: see inline at crates/trusted-server-core/src/settings.rs:275
  • currentScript precedence bypasses the pinned-stamp hardening: see inline at crates/trusted-server-js/lib/src/integrations/creative/first_party.ts:8

♻️ refactor

  • public_origin errors drop the reason: see inline at crates/trusted-server-core/src/settings.rs:158
  • Rebuild // guard is bypassable and its test is vacuous: see inline at crates/trusted-server-core/src/proxy.rs:1931
  • EC cookie scope constraint is undocumented: see inline at docs/guide/configuration.md:418
  • tsjs_unified_script_tag is now dead and duplicated: see inline at crates/trusted-server-core/src/creative.rs:609

⛏ nitpick

  • Port 0 accepted: see inline at crates/trusted-server-core/src/settings.rs:3845

Cross-cutting / body-level findings

  • ♻️ Inline fallback ignores public_origin (crates/trusted-server-core/src/publisher.rs:6140-6144, outside the diff). build_bid_map_with_auction_id still falls back to format!("https://{}", settings.publisher.domain) when the request origin is empty. With public_origin = "https://ads.example.com:8443", domain = "example.com", and an empty request origin, the inline adm comes out as https://example.com/first-party/proxy?... (verified through build_bid_map(..., "", ...), the branch build_bid_map_rewrites_inline_adm_to_absolute_first_party_urls exercises). Use the configured origin:

    let base_origin = if request_origin.is_empty() {
        settings.publisher.effective_public_origin()
    } else {
        request_origin.to_owned()
    };
  • ⛏ The rollout caveat is repeated in many places. The "omission keeps old configs deserializable, not the serving page's scheme, host, or port" text, plus upgrade and rollback sequencing, appears in the CHANGELOG, the template, configuration.md (twice), auction/README.md, creative-processing.md, first-party-proxy.md, auction-orchestration.md, api-reference.md, and testing.md. Keep the full text in configuration.md#public_origin and link to it elsewhere, so a later change (for example an opt-in default) edits one place. The new testing.md section is guidance for this one feature's tests rather than the general testing guide, so it fits better in the spec or as test comments.

CI Status

  • .github/dependabot.yml: PASS
  • Analyze (actions): PASS
  • Analyze (javascript-typescript): PASS (both runs)
  • Analyze (python): PASS
  • Analyze (rust): PASS
  • browser integration tests: PASS
  • cargo check (cloudflare native + wasm32-unknown-unknown): PASS
  • cargo check/build/test (spin native + wasm32-wasip1): PASS
  • cargo fmt: PASS (required)
  • cargo test: PASS (required)
  • cargo test (axum native): PASS
  • cargo test (cross-adapter parity): PASS
  • cargo test (ts CLI, native) (macos-latest): PASS
  • cargo test (ts CLI, native) (ubuntu-latest): PASS
  • CI Node pin guard: PASS
  • CLAUDE.md symlink guard: PASS
  • CodeQL: PASS
  • docs-proposal scripts: PASS
  • format-docs: PASS (required)
  • format-typescript: PASS (required)
  • HTML EOF runtime (Fastly): PASS
  • integration tests: PASS
  • integration tests (Fastly EC lifecycle): PASS
  • prepare integration artifacts: PASS
  • ts dev lint domains (changed lines): PASS
  • vitest: PASS

Comment thread trusted-server.example.toml Resolved
Comment thread crates/trusted-server-core/src/proxy.rs Resolved
Comment thread docs/guide/configuration.md Resolved
Reject the public-origin template placeholder, warn on the retained domain fallback, preserve validation reasons, and reject port zero.\n\nRemove the redundant rebuild authority guard and unused script-tag helper. Retain script-origin precedence with explicit spoofing-limit coverage, use the configured inline fallback, and centralize rollout and EC-cookie guidance.\n\nRetarget template-based audit generators and test harnesses to their actual public endpoints.
@ChristianPavilonis

Copy link
Copy Markdown
Collaborator Author

Addressed the requested changes in a35fef4 and replied to/resolved all eight inline threads.

The two body-level findings are fixed too:

  • Inline bid-map rendering now uses the configured public origin when the request origin is empty. A nonempty request origin still wins, and inline creatives still do not inject the runtime.
  • The full fallback/upgrade/rollback warning now lives at configuration.md#public_origin, with links elsewhere. Feature-specific testing guidance moved into the spec, and configuration examples stay inside the EC cookie scope.

We explicitly reviewed and retained the always-absolute HTTPS/domain fallback and script-origin-first endpoint selection. The CLI now warns about an omitted public_origin. The runtime documentation/tests explicitly acknowledge pre-capture currentScript spoofing; this change does not claim to fix it. The unused script-tag helper was deleted after confirming there are no external consumers.

The placeholder guard also exposed template consumers that only replaced the previous three publisher fields. Audit-generated drafts, CLI test fixtures, EOF runtime fixtures, and the template-cache fixture generator now supply the appropriate public endpoint. EOF fixtures distinguish the runtime listener from the upstream origin.

Validation on the revised sources:

  • All five Rust adapter test aliases and cross-adapter parity passed.
  • All eight Clippy aliases, Rust formatting, native build-digest test/lint, integration lint, and Wasm clock lint passed.
  • Full CLI suite passed, including all 14 environment/config tests and real validate/push placeholder and warning regressions.
  • JS build/lint/format and all 52 Vitest files passed: 1,261 tests, no type errors.
  • Real Chromium focused suites passed all four before/after-spoofing and first-party/foreign-parent cases on both frameworks. Full Next.js: 25 passed, 1 framework skip. Full WordPress: 15 passed, 11 framework skips.
  • Native EOF harness tests/lint and actual Axum/Fastly EOF plus auction controls passed.
  • Docs lint/format/build, root Markdown formatting, documentation-proposal checks, CI Node-pin guard, and committed-state URL-host lint passed.
  • Template-cache inline/ESI fixture generation and real CLI validation passed; the full template-cache runtime harness was not rerun.

Fresh GitHub CI is running for the pushed commit. Requesting re-review from @aram356.

@aram356 aram356 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

All ten round-1 findings are resolved at a35fef44f. I re-ran the round-1 repros:

  • Placeholder guard: with the real ts binary, ts config init, then editing only domain, cookie_domain, and origin_url, now fails config push with Insecure default value for: publisher.public_origin and publishes nothing.
  • Omitted-origin warning: the warning prints once per command.
  • Mutation checks: removing each new guard (deploy and runtime placeholder checks, inline fallback, rebuild scheme and path checks, port 0, error reason) fails the new tests, so none of them is vacuous.

The PR can't merge yet: it conflicts with main, and CI has not run on this head.

Blocking

🔧 wrench

  • Merge main and get CI to run on the head: see the body-level section below

Non-blocking

🌱 seedling

  • Warn when public_origin is outside the EC cookie scope: see inline at crates/trusted-server-core/src/config.rs:126

⛏ nitpick

  • {#public_origin} anchor doesn't resolve on GitHub: see inline at docs/guide/configuration.md:414

Cross-cutting / body-level findings

  • 🔧 Merge main and get CI to run on the head. GitHub reports the PR as dirty (mergeable: false), so the pull_request workflows did not run on a35fef44f. Only the two CodeQL Analyze checks exist. A trial merge with current main (6459e9470) conflicts in:

    • CHANGELOG.md
    • crates/trusted-server-integration-tests/src/bin/generate-viceroy-config.rs
    • crates/trusted-server-integration-tests/tests/common/config.rs
    • crates/trusted-server-integration-tests/tests/environments/axum.rs
    • crates/trusted-server-integration-tests/tests/environments/cloudflare.rs

    The integration-test conflicts change behavior, not just text. They come from #1107, which:

    • added --bidder-origin-url to generate-viceroy-config;
    • added a trace parameter and integration_app_config_envelope_with_trace, used by the new tests/common/trace_boundary.rs, which merges cleanly;
    • moved port selection into AxumDevServer::spawn_with_app_config(&envelope) and CloudflareWorkers::spawn_with_readiness(ready).

    Those spawn helpers now receive a finished envelope and pick the listener port themselves. The listener public_origin therefore has to be applied there, after the port is chosen, by retargeting the envelope the way spawn_with_config_json now does with cloudflare_config_with_public_origin (or a shared envelope_with_public_origin). Otherwise the trace runtimes fall back to https://localhost. Keep both CLI flags, and both fields in Args, in the generator. Then re-run the full CI: the parity, integration, and browser jobs cover exactly these files.

CI Status

  • Analyze (javascript-typescript): PASS
  • Analyze (python): PASS
  • All other checks (cargo fmt, cargo test, format-docs, format-typescript, vitest, integration, browser, parity, lint-domains, and the rest): not run. GitHub does not trigger pull_request workflows while the PR has merge conflicts.
  • Run locally on a35fef44f: cargo fmt --check, JS prettier, docs prettier, and Markdown prettier clean; vitest 1261/1261 pass.

Comment thread docs/guide/configuration.md Resolved

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds publisher.public_origin and emits absolute proxy, click, sign, rebuild, and runtime URLs on it. The code changes look correct, and the round-1 findings are resolved. The PR can't merge yet: it conflicts with main, so CI has not run on this head. Merging main also brings in a second "public origin" concept from #1251, and the merge should settle how the two relate.

Blocking

🔧 wrench

  • Merge main and get CI to run on the head: see the body-level section below

Non-blocking

🤔 thinking

  • Two "public origin" sources after merging #1251: see the body-level section below

Cross-cutting / body-level findings

  • 🔧 Merge main and get CI to run on the head. This is the same open item as the previous review on a35fef44f. A trial merge with current main (d1bb3fa19) still conflicts in CHANGELOG.md, generate-viceroy-config.rs, tests/common/config.rs, tests/environments/axum.rs, and tests/environments/cloudflare.rs. Only the two CodeQL Analyze checks exist on this head. As a data point, the core library merges cleanly: with the integration-test conflicts taken from main's side, cargo test -p trusted-server-core --lib passes (3351 passed). That doesn't exercise the merged integration-test logic, so the parity, integration, and browser jobs still need to run on the merged head.

  • 🤔 Two "public origin" sources after merging #1251. Since this branch's base, main added forwarder.rs. When an authenticated [trusted_forwarder] is configured, it derives a per-request public origin, and configuration.md says that value "supplies URL rewriting". On main, the inline build_bid_map path already takes its request_origin from it, through RequestInfo::from_request. This PR adds a static publisher.public_origin for the other creative paths and documents "Do not derive it from request headers."

    With a forwarder configured and publisher.public_origin unset, one deployment then emits two authorities. Say the browser is on https://www.publisher.example: inline SSAT creatives use https://www.publisher.example, while /auction creatives, sign and rebuild responses, and the injected runtime use https://publisher.example. configuration.md would also use "public origin" for two different things.

    When resolving the merge, please state the precedence between the two in the public_origin and [trusted_forwarder] docs, or rename one term. Falling back to the forwarder origin would mean threading the request into the rewrite paths. That is probably out of scope here, so documenting the precedence is the minimal fix.

CI Status

  • Analyze (javascript-typescript): PASS
  • Analyze (python): PASS
  • All other checks: not run. GitHub doesn't trigger pull_request workflows while the PR has merge conflicts.

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds publisher.public_origin and emits absolute proxy, click, sign, rebuild and runtime URLs on it. The core and JS changes look correct, and the round-1 fixes hold up. Two things block the merge. First, the template's new placeholder breaks the documented local quickstart and the smoke scripts, which only overlay the three older publisher placeholders. Second, the PR still conflicts with main, so CI has not run on this head.

None of the inline comments carry a one-click suggestion. The quickstart fix touches .env.dev, docs/guide/getting-started.md and scripts/smoke-common.sh, which are all outside this diff, so it has to be applied by hand.

Blocking

🔧 wrench

  • Template public_origin placeholder breaks the .env.dev quickstart and the smoke scripts: see inline at trusted-server.example.toml:68
  • Merge main and get CI to run on the head: see the body-level section below

Non-blocking

👍 praise

  • Rebuild rejection tests now carry valid tokens: see inline at crates/trusted-server-core/src/proxy.rs:3281

Cross-cutting / body-level findings

  • 🔧 Merge main and get CI to run on the head. This is still open from the two earlier reviews on a35fef44f. git merge-tree against current main (d1bb3fa19) still reports conflicts in CHANGELOG.md, generate-viceroy-config.rs, tests/common/config.rs, tests/environments/axum.rs and tests/environments/cloudflare.rs. GitHub reports the PR as CONFLICTING/DIRTY, and the only checks on this head are the two CodeQL Analyze runs. The PR description's "All GitHub checks passed on 99d2109c2" refers to the previous head. Please update it once CI has run on the merged head.

CI Status

  • Analyze (javascript-typescript): PASS
  • Analyze (python): PASS
  • All other checks (cargo fmt, cargo test, clippy, vitest, format-*, integration, browser, parity, lint-domains and the rest): not run. GitHub does not trigger pull_request workflows while the PR has merge conflicts. No checks are marked required on this branch.
  • Run locally on a35fef44f:
    • cargo fmt --all -- --check: clean
    • cargo test -p trusted-server-core --lib (native host): 3178 passed
    • cargo test -p trusted-server-cli --test config_env_overlay --test config_store_defaults: 14 + 3 passed
    • vitest with the pinned Node 24.20.0: 52 files, 1261/1261 passed

Comment thread trusted-server.example.toml Resolved
Comment thread crates/trusted-server-core/src/proxy.rs Resolved
Resolve base-branch merge conflicts while preserving absolute creative URLs, trace fixtures, and controlled bidder backends.
Merge main while preserving absolute creative URLs, Lockr routing changes, and both changelog notices.
@ChristianPavilonis

Copy link
Copy Markdown
Collaborator Author

Review status at head 7b98c25.

Addressed

  • All ten original findings were handled in a35fef4. The eight inline threads already have replies and are resolved; the two body-level fixes are covered in the previous response. The subsequent review confirmed all ten fixes.
  • The merge/CI blocker raised by @aram356, @prk-Jr and @dhruv8sh is addressed by 68d59c9 and 7b98c25. The integration merge preserves trace/custom app-config fixtures and retargets the listener public origin after port selection. The generator retains both public-origin and bidder-origin options. GitHub now reports the PR as mergeable.
  • All 29 current-head checks pass, including browser integration, integration, cross-adapter parity, trace-runtime/browser acceptance, Rust/CLI/JS tests, formatting and CodeQL. This supersedes the earlier review snapshots where CI had not run and the description's older-head CI reference.
  • The CodeQL logging finding is addressed in fbc861e. Added a reply explaining the fix; that thread was already resolved. Also acknowledged and resolved the rebuild-test praise thread, which requests no further change.

Still open

These are not being marked addressed or deferred by this cleanup:

  1. Blocking: quickstart and smoke scripts still need a non-placeholder PUBLIC_ORIGIN overlay.
  2. GitHub-facing configuration anchors need correction.
  3. Document the precedence and scope of static publisher.public_origin versus the authenticated forwarder's request origin. This is a body-level finding, so it does not appear in the unresolved inline-thread count.
  4. Optional: warn when public_origin is outside the EC cookie scope.

The three actionable inline threads remain unresolved. Review-summary findings cannot be individually resolved, so the completed merge/CI item is recorded here without dismissing anyone's changes-requested review. Re-review has not been requested while the blocking quickstart/smoke item remains open.

@ChristianPavilonis

ChristianPavilonis commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Pushed 6037fa4 to address the remaining blocker and the two documentation follow-ups.

  • Fixed the quickstart/smoke public-origin overlays and replied to/resolved that inline thread.
  • Fixed all three GitHub-facing configuration anchors and replied to/resolved that inline thread.
  • Addressed @prk-Jr's body-level origin-precedence finding in both relevant configuration sections. Static publisher.public_origin controls general creative rewriting, sign/rebuild responses and injected runtime URLs. Inline SSAT/page-bids creatives retain their nonempty request-origin override, including an authenticated forwarder origin, and fall back to the static setting only when that origin is empty. This documents existing behavior; no forwarding, credential or CORS policy changed.
  • Updated the PR description to distinguish the passing previous-head CI from fresh CI on this follow-up.

Verification: both new regressions failed before the fix and now pass; all 19 CLI config tests, both documented quickstart config-push flows, the full Axum first-success smoke, focused CLI Clippy, ShellCheck/bash syntax, Rust/Markdown formatting, docs lint/build and committed-state URL-host lint pass. Full Fastly, Cloudflare and Spin runtime smokes were not rerun.

The optional out-of-cookie-scope warning is deferred to a separate follow-up, not implemented in this PR. Its thread now records that decision and is resolved. The documented cookie-scope guidance remains in place. All inline review threads are now resolved.

Requesting re-review from @aram356, @prk-Jr and @dhruv8sh.

@prk-Jr prk-Jr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both items from my previous review are resolved at 6037fa4a2. The main merges retarget the listener public_origin after port selection for the Axum and Cloudflare runtimes, and all 29 checks pass on this head. The new configuration.md text accurately describes the precedence: build_bid_map prefers the nonempty request origin, which is forwarder-derived when one is authenticated, and falls back to effective_public_origin(); all other creative paths use the static setting. The .env.dev and smoke-script overlays and their CLI regressions look correct.

Comment thread trusted-server.example.toml Resolved

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds publisher.public_origin (validated, normalized, falling back to https://{domain}) and makes generated creative proxy/click/CSS/srcset/runtime/sign/rebuild URLs absolute on it; the creative runtime records its own script origin for endpoints. Well-tested and carefully documented overall, with one blocking issue in JS proxy detection.

Blocking

🔧 wrench

  • Double-proxying when the bundle's origin differs from public_origin — see inline at crates/trusted-server-js/lib/src/integrations/creative/proxy_sign.ts:10

Non-blocking

🤔 thinking

  • public_origin isn't checked against the cookie scope or for HTTPS — see inline at crates/trusted-server-core/src/settings.rs:4018
  • Warning logged from inside Validate::validate — see inline at crates/trusted-server-core/src/config.rs:126

♻️ refactor

  • Origin choice hidden in base_path.starts_with('/') — see inline at crates/trusted-server-core/src/creative.rs:660

⛏ nitpick

  • Positive smoke port hard-coded as BASE_PORT + 4 in four scripts — see inline at scripts/smoke-axum.sh:39

👍 praise

  • Rebuild endpoint ignores the input's host and tests the tricky inputs — see inline at crates/trusted-server-core/src/proxy.rs:1938

CI Status

  • All 29 reported checks: PASS

Comment thread scripts/smoke-axum.sh Resolved
Comment thread crates/trusted-server-core/src/proxy.rs Resolved

@dhruv8sh dhruv8sh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Adds publisher.public_origin (validated, normalized, falling back to https://{domain}) and makes generated creative proxy/click/CSS/srcset/runtime/sign/rebuild URLs absolute on it; the creative runtime records its own script origin for endpoints. Well-tested and carefully documented. One blocking issue in JS proxy detection, plus non-blocking concerns.

Blocking

  • 🔧 Double-proxying when the bundle's origin differs from public_origin — inline at proxy_sign.ts:10

Non-blocking

  • 🤔 public_origin isn't checked against cookie scope or for HTTPS — inline at settings.rs:4018
  • 🤔 Warning logged from inside Validate::validate — inline at config.rs:126
  • ♻️ Origin choice hidden in base_path.starts_with('/') — inline at creative.rs:660
  • ⛏ Positive smoke port hard-coded as BASE_PORT + 4 in four scripts — inline at scripts/smoke-axum.sh:39
  • 📝 Script-origin trust model — honestly documented in first_party.ts:3-21; earlier creative script can influence document.currentScript, but the iframe sandbox remains the boundary and persistRebuiltClick only allows http(s).
  • 👍 Rebuild endpoint ignores input host and tests tricky inputs — inline at proxy.rs:1938

CI Status

All 29 checks: PASS.

Comment thread scripts/smoke-axum.sh Resolved
Comment thread crates/trusted-server-core/src/proxy.rs Resolved
@ChristianPavilonis

ChristianPavilonis commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator Author

Addressed the remaining feedback in 01bcc08 and the EOF fixture follow-up in 8ed42ab.

  • Replied to and resolved all 15 previously open threads, including both copies of duplicate comments and the praise acknowledgments. A fresh fetch verifies all 28 inline threads resolved. Re-review is requested from @aram356, @prk-Jr, and @dhruv8sh; their existing reviews were not dismissed.
  • The split-origin blocker has source, emitted-IIFE, and real browser network regressions. Full Next.js passes 57 tests and WordPress passes 36, with the intended framework skips. The browser control proves signing stays on the script origin; generated image/iframe proxy URLs are not signed or nested again. Browser fixtures support an isolated Next.js image tag without changing shared tags.
  • Fresh CI exposed an additional EOF harness assumption. Each case has a different listener, so its new origin stamp correctly differs. The harness now asserts the current stamp and permits only that field to vary in the otherwise byte-exact baseline. Actual Axum and Fastly EOF/auction controls both pass locally, including Fastly streaming and timeout controls.
  • The final native core suite passes 3,362 tests, WASM config passes 65, and JS passes 1,891. The adapter/CLI/parity/config-generator suites, target-matched Clippy, docs checks, URL-host lint, and Axum/Fastly smokes pass. The Spin smoke's missing-log assertion also fails with the pre-change script; full Spin coverage remains incomplete. Cloudflare's full smoke was not run because its script expects a missing Wrangler pin. These gaps are recorded in the description rather than counted as passing checks.
  • Cookie-scope diagnostics are implemented, not deferred. The distinct fixture-retargeter refactor is tracked in Share Viceroy fixture retargeting mechanics while preserving caller contracts #1514.

All 29 GitHub checks pass on 8ed42ab8e, including Rust analysis, both EOF runtime jobs, integration, browser, trace-runtime acceptance, and parity.

The PR is not merged; human re-review is still needed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Emit absolute URLs when rewriting creative resources

5 participants