Repository navigation
Conversation
Spec and implementation plan for #1234: an [auction] rewrite_clicks switch that follows rewrite_creatives when unset, so click wrapping can be controlled independently of asset rewriting. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Describe the review fixes: the extended shared-step CHANGELOG entry and the sign status change, rollback in both directions, the reworded Auction Rewrite Control docs and renderGuard note, the fuller body-less matrix fixture, the exact default-output pin, and the stronger proxied-HTML test. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Replace to_abs with normalize_creative_url and move exclusion policy to Rewrite::should_proxy_asset and Rewrite::should_wrap_click, sharing the case-insensitive proxy host matcher. Normalize exclude_domains at load. This is the shared step for #1231 and #1234. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…when unset Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
The rewrite pass registers asset handlers only when rewrite_creatives is on and the anchor handler only when click rewriting resolves on. Base removal and TSJS injection run whenever either is on. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…rty proxy Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…avior Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Correct the renderGuard caveat for the sandboxed /auction renderer, list the operator docs that become false, keep a bidder <base target> while dropping its href, and warn on the public rewrite wrappers. Also fix citations, the shared CHANGELOG Fixed wording, red-step ordering, the Step 5 grep, rollout and staged rollback notes, and other precision items. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…-creative-click-rewrite-switch Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Restore the example2.com.fake.com style case dropped in the port of test_rewrite_is_excluded, and point the should_proxy_asset docs at is_host_allowed in code text so cargo doc stops warning about a link to a private item. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
rewrite_creative_html and rewrite_inline_creative_html rewrite assets and clicks unconditionally. Document that production code must use the auction processing entry points, which honor both switches. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
The rewrite pass removed every <base>, which also dropped target="_blank" so raw links opened inside the creative iframe. Drop only the href, which is what can rebase first-party URLs, and remove a <base> left without a target as before, so default output is unchanged. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Name rewrite_clicks in the orchestration example, environment overrides and rollback note, fix the rewrite_creatives = false summary, correct the renderGuard caveat for the sandboxed renderer, and document base target handling and the inert click guard. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
List the CSS re-quoting, https: prefixing and sign error text changes in the Fixed entry, and note that a bidder base target is now kept. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
|
@prk-Jr Your review comments on the spec PRs (#1248 and #1249) are addressed in the spec branches. Those changes are merged here, along with the matching code changes: the |
Brings #1252 at 7c5eca0, including the design spec and plan from its spec/1234-creative-click-rewrite-switch base. Integration decisions: - Settings normalization runs #1252's rewrite.normalize() and keeps main's fallible image_optimizer.normalize()? from #1221. - CHANGELOG.md keeps the RC's entries and replaces the older rewrite_creatives entry with #1252's version, which defers click wrapping to rewrite_clicks.
Brings #1253 at e210f62, including the design spec and plan from its spec/1231-creative-asset-host-allowlist base. #1253 carries its own copy of #1252's rewrite_clicks commits plus the include_domains allowlist, so its conflicts with #1252 are two versions of the same change. Integration decisions: - proxy.rs, creative.rs and settings.rs take a clean three-way merge of #1253 against the RC before #1252. #1253's versions of the shared rewrite_clicks code supersede #1252's, and they also carry #1252's suffix-spoofing test case and doc-link fix. Every other file #1253 touches matches that re-merge exactly, so nothing is duplicated. - Settings normalization keeps main's fallible image_optimizer normalize()? beside rewrite.normalize(). - CHANGELOG.md keeps the RC's entries and takes #1253's exclude_domains, include_domains, rewrite_clicks and rewrite_creatives entries.
aram356
left a comment
There was a problem hiding this comment.
Summary
Splits click wrapping into [auction] rewrite_clicks and narrows rewrite_creatives to assets, with a shared URL normalizer and host policy. The core logic holds up. For every parseable URL in a 40-input edge corpus, the new normalizer produces signed proxy and click URLs byte-identical to the old to_abs path. 26 of 29 mutants against the new logic are killed, and the tree merged with current main passes clippy-fastly, test-fastly, test-axum and the CLI overlay tests. What blocks is the merge conflict with main, operator docs left contradicting the switch, and release notes that miss a default-config <base target> change.
6 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. Each one was applied in a scratch tree and checked with the pinned docs prettier (3.8.1), or withcargo fmt --check,cargo clippy-fastlyand the targeted test for the Rust one. The remaining comments describe the fix in prose because it touches lines outside the diff.
Blocking
🔧 wrench
- Conflicts with
main: see the cross-cutting section below - Operator docs left contradicting the switch: see inline at
docs/guide/auction-orchestration.md:641 - Default-config
<base target>change described as no change: see inline atCHANGELOG.md:44 /first-party/signerror-string claim, missing one-time push diff: see inline atCHANGELOG.md:36<base>removal and TSJS wording: see inline attrusted-server.example.toml:267- Click-guard sentence needs the
rewrite_creativesqualifier: see inline atdocs/guide/creative-processing.md:121 - Spec status and rollout are stale: see inline at
docs/superpowers/specs/2026-10-07-1234-creative-click-rewrite-switch-design.md:9 - No test for non-http(s) schemes that carry a host: see inline at
crates/trusted-server-core/src/creative.rs:2063 - Stale prose outside the diff and smaller precision items: see the cross-cutting section below
Non-blocking
🤔 thinking
- The
/auctionclick guard ignores the kept<base target>: see inline atcrates/trusted-server-core/src/creative.rs:1288
🌱 seedling
exclude_domainsstill misses trailing-dot hosts and IDN entries: see inline atcrates/trusted-server-core/src/settings.rs:681
Cross-cutting / body-level findings
-
🔧 Conflicts with
main. GitHub reports the branch as conflicting withmain(d2f0d8c), and both conflicts are mechanical. InCHANGELOG.md, both sides add### Fixedbullets, so keep all of them. InSettings::normalize_deserialized(settings.rs), #1221 made the function returnResultand callself.image_optimizer.normalize()?;. Keep that and add this PR's call above it:self.proxy.normalize(); self.rewrite.normalize(); self.image_optimizer.normalize()?;
With that resolution, a scratch merge of
maininto this head passes:cargo fmt --all -- --check;cargo clippy-fastly;cargo test-fastly(core lib 2949 passed, all 18 new core tests included);cargo test-axum;- the CLI
config_env_overlaytests (10 passed, both newrewrite_clickstests included).
None of the 13
maincommits interact with this change semantically: -
🔧 Stale prose outside the diff. These predate this PR, but they now sit next to the new text and disagree with it:
docs/guide/creative-processing.md:704-705says*.cdn.example.comdoes not matchcdn.example.com("no subdomain").is_host_allowedmatches the apex (proxy.rs:1246-1250), this PR'srewrite_policy_matches_exclude_patterns_case_insensitivelyasserts it, andconfiguration.md:1025already says ✅. While there, note that matching is case-insensitive.docs/guide/creative-processing.md:968-970troubleshooting says "Ensure origin response includes proper<base>tag". The rewriter drops<base href>whenever it runs.crates/trusted-server-core/src/settings.rs:640-641: theexclude_domainsdoc says matching hosts "will not be proxied through first-party endpoints".should_wrap_clickuses the same list, so they are not click-wrapped either.crates/trusted-server-core/src/proxy.rs:1621-1624: the# Errorssection ofhandle_first_party_proxy_signdoes not list rejection of hosts matched byrewrite.exclude_domains.crates/trusted-server-js/lib/src/shared/origin.ts:56-57: says the server-side rewriter "strips<base>from creative markup whenever rewriting is enabled". It now drops thehref(keepingtarget) when asset or click rewriting is on.
-
🔧 Smaller precision items in operator docs:
docs/guide/configuration.md:1950-1951:- "so existing configs keep their current behavior" is followed directly by the
<base target>change, which applies to existing configs. - The
<base>sentence does not mention thatsanitize_creatives = trueremoves<base>entirely before the rewrite pass (creative.rs:898). - The same sanitizer caveat applies to the
<base>column of the Assets and clicks table (creative-processing.md:107-112) and tocreative-processing.md:129-130.
- "so existing configs keep their current behavior" is followed directly by the
docs/guide/configuration.md:2185: "links still followrewrite_clicks" reads as if links stay wrapped. With it unset they turn off too. Suggest "links are wrapped only whenrewrite_clicks = true".docs/guide/auction-orchestration.md:861-862: "rolling back also changes link wrapping whenrewrite_clickswas set" is only true when it differed fromrewrite_creativeson the auction paths, or wasfalse, which also changes proxied HTML.
CI Status
- CLAUDE.md symlink guard: 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
- format-docs: PASS (required)
- format-typescript: PASS (required)
- integration tests: PASS
- integration tests (Fastly EC lifecycle): PASS
- prepare integration artifacts: PASS
- vitest: PASS
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Please update the remaining processing tables and prose to reflect the separate rewrite_clicks switch. They currently give contradictory expectations for direct links, click-guard attributes, TSJS injection, and proxied HTML. Distinguish the inline path and document the explicit proxied-HTML override so operators can configure tracking correctly; no runtime change is needed.
Non-blocking: reuse the new push helper in the two existing auction-overlay tests to avoid maintaining duplicate push and decoding flows.
…ick-rewrite-switch Signed-off-by: dhruv8sh <dhruv8sh@proton.me> # Conflicts: # CHANGELOG.md # crates/trusted-server-core/src/settings.rs
Describe rewrite_clicks separately from asset rewriting across the operator guides, state the default-config <base target> change in the CHANGELOG, refresh the spec status and rollout, and correct stale exclude_domains and <base> prose. Add non-http(s) host-bearing schemes to the URL normalizer test and reuse the push helper in the existing auction overlay CLI tests. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
ChristianPavilonis
left a comment
There was a problem hiding this comment.
Approved. Separating rewrite_clicks from asset rewriting gives operators independent control, with unset behavior preserving existing click-rewriting defaults.
Summary
[auction] rewrite_clickscontrols<a href>and<area href>wrapping into signed/first-party/clickredirects, andrewrite_creativesnow controls asset URLs only. Operators can keep first-party click tracking with assets left direct, or proxy assets with landing links left alone.rewrite_clicksis anOption<bool>, and unset is the default:rewrite_creatives, so existing configs keep their asset and link behavior./first-party/proxykeeps wrapping links as it does today.<base>handling and TSJS injection (onPOST /auctiononly) run when either switch is on.<base target>is now kept with itshrefdropped, instead of the whole element being removed, so raw links keep opening where the bidder intended.to_absis replaced bynormalize_creative_urlplusRewrite::should_proxy_assetandRewrite::should_wrap_click.exclude_domainsmatching is now case-insensitive and trimmed.Implements the approved design in #1249:
docs/superpowers/specs/2026-10-07-1234-creative-click-rewrite-switch-design.md.#1249 was closed without merging, so this PR targets
mainand carries the spec itself. Usegit diff -wwhen readingcreative.rs, because gating the handlers re-indents a large block.Changes
crates/trusted-server-core/src/auction_config_types.rsrewrite_clicks: Option<bool>(left out of the blob when unset),rewrites_auction_clicks(),rewrites_proxied_clicks(), testscrates/trusted-server-core/src/creative.rsnormalize_creative_url,asset_target/click_target,CreativeFeatures. Asset and anchor handlers are registered only when their switch is on. Caller wiring, module docs, the four-combination matrix tests, and a byte-for-byte pin againstmain's outputcrates/trusted-server-core/src/settings.rsRewrite::should_proxy_asset,should_wrap_clickandnormalize(trim, lowercase, drop inert entries); removesis_excluded; testscrates/trusted-server-core/src/proxy.rs/first-party/signuses the normalizer and policy; proxied-HTML click testscrates/trusted-server-core/src/config_payload.rscrates/trusted-server-core/src/auction/formats.rs,publisher.rs/auctionand inline tests; doc and log updatescrates/trusted-server-core/src/auction/orchestrator.rsAuctionConfigliteralcrates/trusted-server-core/src/auction/endpoints.rs,auction/README.mdcrates/trusted-server-cli/tests/config_env_overlay.rsTRUSTED_SERVER__AUCTION__REWRITE_CLICKSoverride behavior, with and without the TOML leaftrusted-server.example.tomlrewrite_creativescomment narrowed to assets; commented-outrewrite_clicksline with rollout notesdocs/guide/configuration.md,creative-processing.md,auction-orchestration.md,api-reference.mdclickGuardvsrewrite_clicks, rollout and rollbackCHANGELOG.mdrewrite_clicks; Fixed case-insensitiveexclude_domainsand the related edge casesCloses
Closes #1234
Test plan
cargo test-fastly && cargo test-axum. Alsocargo test-fastly-reuse,cargo test-cloudflare,cargo test-spin,./scripts/test-cli.shand the parity tests.cargo clippy-fastly && cargo clippy-axum. All 8 clippy aliases pass, and every intermediate commit passesclippy-fastly.cargo fmt --all -- --checkcd crates/trusted-server-js/lib && npx vitest run(no JS changes)cd crates/trusted-server-js/lib && npm run format(no JS changes)cd docs && npm run format, plus the markdown prettier check outsidedocs/cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute serveRollout: deploy the binary first; while
rewrite_clicksis unset, asset and link behavior is unchanged (apart from the<base target>change above). Then push a config that sets it. Rollback: remove any explicitrewrite_clicksand push first, then roll back the binary.Checklist
unwrap()in production code — useexpect("should ...")tracingmacros (notprintln!)Follow-ups
<base target>