Make auction creative rewriting optional#916
Conversation
Allow operators to retain sanitizer-accepted external URLs in POST /auction adm while preserving mandatory server-side sanitization and the existing default behavior.
aram356
left a comment
There was a problem hiding this comment.
Summary
The runtime branch itself is well scoped: sanitization remains mandatory, rewriting is gated after sanitization, both modes have substantive tests, and /first-party/proxy remains independent. I am requesting changes for rollback compatibility and two operator-facing configuration/privacy contracts described in the inline comments.
Non-blocking
🏕 camp site
- Update the internal auction README:
crates/trusted-server-core/src/auction/README.md:139,:251, and:382still describe creative rewriting as unconditional. Please consider updating those passages to distinguish mandatory sanitization from default-on, configurable rewriting.
📌 out of scope
- Track the pre-existing
iframe[srcdoc]sanitizer gap: the generic handler atcrates/trusted-server-core/src/creative.rs:385neither removes nor recursively sanitizessrcdoc, while the normal renderer grantsallow-scriptsandallow-same-originatcrates/trusted-server-js/lib/src/core/render.ts:14. This exists at the base SHA and should not block this PR, but it deserves a security follow-up that removessrcdocand adds regression coverage through both rewrite modes.
👍 praise
- The implementation keeps sanitization strictly before the configuration branch, avoids logging creative contents, covers default/disabled behavior and legacy blob loading, and verifies that proxy HTML/CSS rewriting is independent. No new dependency, OS API, or WASM-incompatible construct is introduced.
CI Status
- fmt and all adapter/target clippy checks: PASS
- Rust tests and builds (Fastly, Axum, Cloudflare, Spin, parity, CLI): PASS
- JS formatting and Vitest: PASS
- integration, browser, Fastly EC lifecycle, and CodeQL checks: PASS
|
Implemented and pushed the requested review fixes in Also addressed the non-blocking internal auction README cleanup. The pre-existing nested Validation completed locally:
|
prk-Jr
left a comment
There was a problem hiding this comment.
Summary
Adds a default-true [auction].rewrite_creatives setting: creative sanitization for POST /auction stays mandatory, while first-party resource/click rewriting and TSJS injection become optional. Backward-compatibility handling (default omitted from serialized/legacy blobs, explicit false preserved, legacy schema round-trip, EdgeZero env-overlay pre-existing-leaf quirk) is thorough and well tested. No blocking issues found.
Non-blocking
⛏ nitpick
- "unre-written" wording:
docs/guide/configuration.mdanddocs/guide/creative-processing.mdrepeat the hyphenation "unre-written" (e.g. "sanitized but unre-written HTML") several times. Suggest "not rewritten" or "unrewritten" for readability — no behavior impact.
👍 praise
- Backward-compatibility test coverage: the
skip_serializing_ifdefault-omission design plus tests acrosssettings.rs(TOML omitted/explicit-false),config_payload.rs(legacy JSON blob round-trip and legacy-schema deserialization), and the new CLI integration test (config_env_overlay.rs, proving the EdgeZero "env overlay only overrides pre-existing leaves" quirk is handled) directly cover the real rollback/migration edge cases operators will hit. Theproxy.rstest proving/first-party/proxyrewriting stays independent of the new flag is a good isolation check too.
📝 note
- Change table is stale: the PR description's file table lists 12 files; the actual diff touches 16, including
creative.rs(see inline comment — an independent exclusion-matching bug fix bundled here),crates/trusted-server-cli/tests/config_env_overlay.rs,crates/trusted-server-core/src/auction/README.md, anddocs/guide/cli.md. Worth syncing the table with the real diff before merge.
CI Status
- fmt: PASS
- clippy (fastly/axum/cloudflare native+wasm/spin native+wasm): PASS
- rust tests (fastly/axum/cloudflare/spin/cross-adapter parity/CLI): PASS
- js tests (vitest): PASS
- js/docs format: PASS
aram356
left a comment
There was a problem hiding this comment.
Summary
Narrowly-scoped, backward-compatible feature with strong test coverage (default, explicit false, TOML parse, blob round-trip, legacy-schema acceptance, CLI env overlay, and a regression test proving /first-party/proxy rewriting is unaffected) and careful documentation. Two items need attention before merge: an undeclared drive-by behavior change in to_abs, and the fact that the rollback-critical skip_serializing_if carries no in-code rationale. Both are inline.
Blocking
🔧 wrench
- Undeclared behavior change in
to_abs: moving the exclusion check onto the normalized URL is a real fix —is_excludednever matched protocol-relative URLs becauseurl::Url::parsefails on//host/path— but it is unrelated torewrite_creativesand appears in neither the PR description nor the CHANGELOG. It also silently tightens the/first-party/proxytsurlvalidator (proxy.rs:1633), which is untested. (crates/trusted-server-core/src/creative.rs:53-73) skip_serializing_ifis load-bearing but unexplained:AuctionConfigisdeny_unknown_fields, so omitting the default is what keeps pushed blobs readable by an older binary during rollback. That rationale exists only in docs and a TOML comment, so a future cleanup of the attribute silently breaks rollback. (crates/trusted-server-core/src/auction_config_types.rs:15-19)
❓ question
- Client-side behavior with
rewrite_creatives = false: disabling also dropsdata-tsclickand thetsjs-unified.min.jsruntime injection. The docs frame this purely as a privacy trade-off. Is the creative render bridge tolerant of a missing runtime, or does the creative fail to size/render? If rendering depends on it, that is a functional consequence and belongs in the warning block indocs/guide/creative-processing.md. ts config diffwith the leaf present: raised inline ontrusted-server.example.toml:119.
Non-blocking
♻️ refactor
- Gate the flag inside
creative:crates/trusted-server-core/src/auction/formats.rs:256-268(inline). - Warn when the privacy default is off:
crates/trusted-server-core/src/auction/formats.rs:258(inline).
🤔 thinking
- Hand-mirrored
LegacyAuctionConfigwill drift:crates/trusted-server-core/src/config_payload.rs:52-72(inline). - CLI test does not pin the working directory:
crates/trusted-server-cli/tests/config_env_overlay.rs:36-63(inline).
📌 out of scope
/first-party/proxysign handler bypassesto_absfor protocol-relative URLs: the//-prefixed branch builds the absolute URL inline and never callsto_abs, so it skips the exclusion check entirely — the exact inconsistency this PR fixes on the creative path. Pre-existing; worth a follow-up issue now that the sibling path was corrected. (crates/trusted-server-core/src/proxy.rs:1624-1632)[debug].inject_adm_for_testingembeds raw, unsanitizedadm: correctly documented here as debug-only, but it remains the one creative path with neither sanitization nor rewriting. Follow-up issue. (crates/trusted-server-core/src/publisher.rs:2144-2147)
⛏ nitpick
rewrite_modestring is unnecessary:crates/trusted-server-core/src/auction/formats.rs:264-268(inline).
Verification notes
- The docs change from "env vars baked at build time" to "typed CLI overlay" was verified accurate: no
TRUSTED_SERVER__handling remains incrates/trusted-server-core/build.rs. [debug].inject_adm_for_testingreferenced in the new docs exists as described (settings.rs:1923).convert_to_openrtb_responsehas exactly two production callers, both inauction/endpoints.rs(219, 340), so the new flag's blast radius matches what the docs claim.
CI Status
Taken from the PR's own checks — not re-run locally.
- fmt: PASS
- clippy / CodeQL (
Analyze (rust),Analyze (javascript-typescript),Analyze (actions)): PASS - rust tests (
cargo test, axum native, cloudflare, spin, ts CLI native, cross-adapter parity): PASS - js tests (vitest), format-typescript, format-docs: PASS
- integration tests, Fastly EC lifecycle, browser integration tests: still pending at review time
Summary
Changes
CHANGELOG.mdcrates/trusted-server-cli/tests/config_env_overlay.rscrates/trusted-server-core/src/auction/README.mdcrates/trusted-server-core/src/auction/endpoints.rs/auctionsanitization and rewrite behavior.crates/trusted-server-core/src/auction/formats.rscrates/trusted-server-core/src/auction/orchestrator.rscrates/trusted-server-core/src/auction_config_types.rscrates/trusted-server-core/src/config_payload.rscrates/trusted-server-core/src/creative.rscrates/trusted-server-core/src/proxy.rscrates/trusted-server-core/src/settings.rsdocs/guide/auction-orchestration.mddocs/guide/cli.mddocs/guide/configuration.mddocs/guide/creative-processing.mdtrusted-server.example.tomlCloses
Closes #914
Test plan
cargo test-fastly && cargo test-axumcargo clippy-fastly && cargo clippy-axumcargo fmt --all -- --checkcd crates/trusted-server-js/lib && npx vitest runcd crates/trusted-server-js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute servecargo test-cloudflare,cargo test-spin, all target-matched clippy aliases, and./scripts/test-cli.shChecklist
unwrap()in production code — useexpect("should ...")tracingmacros (notprintln!) — N/A; this project requireslogmacros.