Skip to content

Add EC module with EcContext lifecycle and cookie domain computation#546

Draft
ChristianPavilonis wants to merge 7 commits intofeature/ssc-updatefrom
feature/edge-cookies
Draft

Add EC module with EcContext lifecycle and cookie domain computation#546
ChristianPavilonis wants to merge 7 commits intofeature/ssc-updatefrom
feature/edge-cookies

Conversation

@ChristianPavilonis
Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis commented Mar 20, 2026

Summary

  • Implements Story 1 (EC generation and request context #533) and Story 2a (EC cookie helpers #535) of the Edge Cookie epic (Implement Edge Cookie (EC) identity system #532): introduces a new ec/ module with two-phase EcContext lifecycle (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.
  • EC cookies derive their domain as .{publisher.domain} per spec §5.2. The cookie_domain config field is retained for non-EC cookies. EC cookie helpers moved from cookies.rs to ec/cookies.rs.
  • Removes fresh_id / ec_fresh / X-ts-ec-fresh per spec §12.1 — this was a SyntheticID artifact not carried forward in the EC spec.
  • Updates all call sites, TOML fixtures, integration test configs, and documentation.

Closes #533, Closes #535

Changes

File Change
ec/mod.rs New. EcContext struct with read_from_request() and generate_if_needed(), shared parse_ec_from_request() helper, get_ec_id() public API
ec/generation.rs New. HMAC-based ID generation, IPv4/v6 normalization, ec_hash(), is_valid_ec_id(), extract_client_ip()
ec/consent.rs New. ec_consent_granted() wrapper delegating to consent module
ec/cookies.rs New. create_ec_cookie, set_ec_cookie, expire_ec_cookie — uses ec_cookie_domain() per spec §5.2
edge_cookie.rs Reduced to thin re-export shim for backward compat
consent/mod.rs Jurisdiction::Unknown now blocks EC (fail-closed); GPC independently blocks in US states
cookies.rs Removed EC-specific cookie helpers (moved to ec/cookies.rs)
settings.rs Added ec_cookie_domain() method (computed .{domain} for EC); cookie_domain field retained for non-EC use
publisher.rs Migrated to EcContext API with full consent-gated revocation
integrations/registry.rs Migrated to EcContext; added consent-gated cookie setting AND revocation on withdrawal
auction/endpoints.rs Migrated to EcContext; EC value gated behind ec_allowed() before forwarding to bidders
auction/formats.rs Removed fresh_id generation; removed X-ts-ec-fresh response header
auction/types.rs Removed fresh_id from UserInfo struct
openrtb.rs Removed ec_fresh field from UserExt
constants.rs Removed HEADER_X_TS_EC_FRESH constant and internal header entry
integrations/prebid.rs Removed ec_fresh population in Prebid adapter
proxy.rs, testlight.rs Import updated from edge_cookieec
Docs Updated configuration.md, first-party-proxy.md, error-reference.md, PUBLISHER_IDS_AUDIT.md

Breaking changes

  1. Missing client IP now errorsgenerate_ec_id() takes a &str client IP; no "unknown" fallback
  2. Jurisdiction::Unknown blocks EC creation — fail-closed when geo unavailable
  3. GPC independently blocks in US states — even if us_privacy string allows
  4. IPv6 normalization format change"2001:db8:85a3:0::""20010db885a30000" (existing IPv6 EC IDs invalidated)
  5. Integration proxy now consent-gates cookie setting — was unconditional (bug fix)
  6. Integration proxy now expires cookie on consent withdrawal — matches publisher proxy behavior
  7. EC cookie domain computed from publisher.domaincookie_domain config retained for non-EC cookies only
  8. fresh_id / ec_fresh / X-ts-ec-fresh removed — SyntheticID artifact not in EC spec (§12.1)
  9. Auction strips revoked EC IDsuser.id is empty when consent denied, preventing leaked identifiers to bidders

Verification

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets --all-features -- -D warnings — zero warnings
  • cargo test --workspace715 tests passed, 0 failed

@ChristianPavilonis ChristianPavilonis self-assigned this Mar 20, 2026
@ChristianPavilonis ChristianPavilonis changed the base branch from main to feature/ssc-update March 23, 2026 17:10
@ChristianPavilonis ChristianPavilonis changed the base branch from feature/ssc-update to main March 23, 2026 17:11
@ChristianPavilonis ChristianPavilonis marked this pull request as draft March 23, 2026 17:11
- 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.
@ChristianPavilonis ChristianPavilonis changed the base branch from main to feature/ssc-update March 23, 2026 18:50
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.

EC cookie helpers EC generation and request context

1 participant