Add EC module with EcContext lifecycle and cookie domain computation#546
Draft
ChristianPavilonis wants to merge 7 commits intofeature/ssc-updatefrom
Draft
Add EC module with EcContext lifecycle and cookie domain computation#546ChristianPavilonis wants to merge 7 commits intofeature/ssc-updatefrom
ChristianPavilonis wants to merge 7 commits intofeature/ssc-updatefrom
Conversation
- Rename all external identifiers: x-synthetic-id → x-ts-ec, synthetic_id cookie → ts-ec, synthetic_fresh → ec_fresh - Simplify hash generation to use only client IP with HMAC-SHA256, removing User-Agent, Accept-Language, Accept-Encoding, and template rendering - Rename config section [synthetic] → [ec] with backward-compat alias - Rename ec.rs to edge_cookie.rs for clarity - Remove handlebars dependency (and transitive deps) - Add x-ts-ec-fresh to internal headers blocklist - Update all docs with new Edge Cookie (EC) terminology - Fix review findings: remove redundant serde rename, stale optimization entry, leftover 'synthetic' references in agent configs and docs Closes #462
Introduce a new ec/ module that owns the Edge Cookie lifecycle with a two-phase design: read_from_request() extracts existing EC state pre-routing, generate_if_needed() creates new IDs only in organic handlers when consent permits. Fixes and behavioral changes: - Jurisdiction::Unknown now blocks EC creation (fail-closed) - GPC independently blocks EC in US states regardless of us_privacy - Missing client IP returns an error instead of using "unknown" fallback - IPv6 normalization uses zero-padded hex without separators - Integration proxy now consent-gates cookie setting (was unconditional) The old edge_cookie module is reduced to a thin re-export shim.
…535) Remove the cookie_domain config field from Publisher and compute it as .{domain} automatically. This eliminates a redundant setting that was always expected to be the dot-prefixed publisher domain. Move create_ec_cookie, set_ec_cookie, and expire_ec_cookie from the generic cookies module into ec/cookies where they belong alongside the rest of the EC subsystem. Update all TOML fixtures, integration test configs, and documentation to remove cookie_domain references.
Address PR review findings: - Strip revoked EC IDs before building auction requests: gate ec_value behind ec_allowed() so withdrawn-consent users don't leak their EC to bidders (#533) - Make fresh_id generation best-effort: auction proceeds without a fresh EC when client IP is unavailable instead of hard-failing - Restore cookie_domain field on Publisher for non-EC cookie use; rename computed method to ec_cookie_domain() per spec §5.2 which says EC cookies derive domain from publisher.domain independently while cookie_domain continues serving its existing purpose
- Add cookie expiration on consent withdrawal in handle_proxy,
matching the publisher proxy revocation path
- Extract parse_ec_from_request() shared helper so get_ec_id and
EcContext::read_from_request use a single cookie-parsing pass
- Replace ec_hash unwrap_or with explicit find('.') match for clarity
The fresh_id concept was a SyntheticID artifact for per-request freshness detection. The EC spec explicitly removes it: - §12.1: Remove ext.synthetic_fresh from openrtb.rs - §12.5: Auction response headers include only X-ts-ec (no X-ts-ec-fresh) Removed: - UserInfo.fresh_id field (types.rs) - fresh_id generation in convert_tsjs_to_auction_request (formats.rs) - HEADER_X_TS_EC_FRESH constant and internal header entry - UserExt.ec_fresh field and serialization test (openrtb.rs) - ec_fresh population in Prebid adapter - All test fixture fresh_id values
Rename EdgeCookie struct to Ec, secret_key field to passphrase, and the TOML section from [edge_cookie] to [ec] to align with the spec's configuration schema. Add optional ec_store and partner_store fields to the Ec struct in preparation for Story 3 (KV identity graph) and Story 4 (partner registry). Remove the edge_cookie.rs legacy re-export shim — no consumers remain after the ec/ module migration.
31fc460 to
fbf83bc
Compare
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
ec/module with two-phaseEcContextlifecycle (read_from_request+generate_if_needed), fixes consent gating to fail-closed for unknown jurisdictions and GPC in US states, and removes the"unknown"client IP fallback..{publisher.domain}per spec §5.2. Thecookie_domainconfig field is retained for non-EC cookies. EC cookie helpers moved fromcookies.rstoec/cookies.rs.fresh_id/ec_fresh/X-ts-ec-freshper spec §12.1 — this was a SyntheticID artifact not carried forward in the EC spec.Closes #533, Closes #535
Changes
ec/mod.rsEcContextstruct withread_from_request()andgenerate_if_needed(), sharedparse_ec_from_request()helper,get_ec_id()public APIec/generation.rsec_hash(),is_valid_ec_id(),extract_client_ip()ec/consent.rsec_consent_granted()wrapper delegating to consent moduleec/cookies.rscreate_ec_cookie,set_ec_cookie,expire_ec_cookie— usesec_cookie_domain()per spec §5.2edge_cookie.rsconsent/mod.rsJurisdiction::Unknownnow blocks EC (fail-closed); GPC independently blocks in US statescookies.rsec/cookies.rs)settings.rsec_cookie_domain()method (computed.{domain}for EC);cookie_domainfield retained for non-EC usepublisher.rsEcContextAPI with full consent-gated revocationintegrations/registry.rsEcContext; added consent-gated cookie setting AND revocation on withdrawalauction/endpoints.rsEcContext; EC value gated behindec_allowed()before forwarding to biddersauction/formats.rsfresh_idgeneration; removedX-ts-ec-freshresponse headerauction/types.rsfresh_idfromUserInfostructopenrtb.rsec_freshfield fromUserExtconstants.rsHEADER_X_TS_EC_FRESHconstant and internal header entryintegrations/prebid.rsec_freshpopulation in Prebid adapterproxy.rs,testlight.rsedge_cookie→ecconfiguration.md,first-party-proxy.md,error-reference.md,PUBLISHER_IDS_AUDIT.mdBreaking changes
generate_ec_id()takes a&strclient IP; no"unknown"fallbackJurisdiction::Unknownblocks EC creation — fail-closed when geo unavailableus_privacystring allows"2001:db8:85a3:0::"→"20010db885a30000"(existing IPv6 EC IDs invalidated)publisher.domain—cookie_domainconfig retained for non-EC cookies onlyfresh_id/ec_fresh/X-ts-ec-freshremoved — SyntheticID artifact not in EC spec (§12.1)user.idis empty when consent denied, preventing leaked identifiers to biddersVerification
cargo fmt --all -- --check— cleancargo clippy --workspace --all-targets --all-features -- -D warnings— zero warningscargo test --workspace— 715 tests passed, 0 failed