Skip to content

Add the permission model with the Privacy Taxonomy vocabulary - #1045

Open
jwrosewell wants to merge 3 commits into
IABTechLab:mainfrom
jwrosewell:split/3-permissions
Open

Add the permission model with the Privacy Taxonomy vocabulary#1045
jwrosewell wants to merge 3 commits into
IABTechLab:mainfrom
jwrosewell:split/3-permissions

Conversation

@jwrosewell

Copy link
Copy Markdown
Contributor

Third of five PRs decomposing #838 (see #1043 for the series description). Stacked on #1044: until predecessors merge, this PR displays the cumulative diff, so review the top commit only.

What this PR contains

  • permissions.rs resolves a per-request PermissionState from the country/region baseline in permissions.yaml, augmented by the session's signals (TCF, GPP, GPC, US Privacy). Permission names follow the Privacy Taxonomy Data Uses presented at the last task force meeting.
  • The Edge Cookie gate moves from raw consent to the permission model: a provider declares required_permissions() and core executes it only when every one is set. Consent is one of several ways a permission is established, alongside country rules and other signals.
  • Withdrawal separates from merely not-permitted: an explicit signal expires the cookie and writes tombstones, while a pre-consent or fail-closed state only strips EC response headers and never destroys an already-issued identifier.
  • Bidstream EIDs gate on the permission model (gate_eids_by_permissions) instead of raw TCF consent.
  • [geo] default_country becomes required and validated at startup: it names the permissions.yaml rule that applies when the geo provider leaves a request unmatched, so there is always a defined permission baseline.

Verification

Full gate green on this branch: fmt, clippy x6 with -D warnings, all four adapters' test suites (1,861 core tests), and cross-adapter parity.

Produced with AI assistance under James Rosewell's direction; needs human review.

…ider

First slice of the PR 838 decomposition (one PR per feature, Edge Cookie
provider first). Introduces the EdgeCookieProvider trait and routes Edge
Cookie minting, cookie read-back, and KV keying through the selected
provider, so a vendor identifier round-trips verbatim instead of being
dropped by the built-in shape check.

- [ec] provider selector with per-provider [ec.providers.<key>] blocks;
  the hmac block carries the passphrase that previously lived on [ec].
  With no provider selected, no Edge Cookie is generated.
- Built-in provider: hmac (HMAC over client IP, preserves today's
  identity). The host-signal provider follows in the device slice,
  which supplies the host fingerprints it needs.
- Request evidence abstraction (crate::evidence) giving providers
  read access to the client IP, headers (including cookies), URL path,
  and query parameters.
- Adapter injection seam: RuntimeServices carries an optional vendor
  provider, so a vendor provider lives in its own crate and core never
  names it.
- Provider-declared identifier semantics: accepts_id gates cookie
  read-back and withdrawal, normalize_id_for_kv controls the KV key, so
  an opaque identifier survives byte for byte as both cookie value and
  storage key. Tests cover the verbatim round-trip with a non-default
  provider, evidence access at generate time, and opaque KV persistence.

Edge Cookie creation and use stay gated by the existing consent context
exactly as before, including with no provider selected; the permission
model replaces that input in a later slice. The client-set resolve path
and the response-header hook are later slices.

Config migration: [ec] passphrase is rejected as an unknown field; move
it to [ec.providers.hmac] and select provider = "hmac" to keep minting.
@jwrosewell
jwrosewell force-pushed the split/3-permissions branch from efc8a56 to 6d20255 Compare August 20, 2026 01:47
…e provider

Second slice of the PR 838 decomposition. Device classification and
geolocation become selectable providers, mirroring the Edge Cookie
provider seam:

- [device] provider selects the classifier. The built-in default reads
  the User-Agent alone and makes no host call; the opt-in fastly
  provider strengthens the browser/bot gate with the host's TLS JA4 and
  HTTP/2 fingerprints (crates/device/fastly).
- [geo] provider selects geolocation. No provider is the default and
  resolves no location; provider = "platform" opts into the host's
  lookup (crates/geo/fastly wraps the Fastly host lookup behind the
  PlatformGeo trait).
- The host-signal Edge Cookie provider arrives with the capability it
  needs: the Fastly adapter injects the TLS/HTTP-2 fingerprints as a
  HostSignals service, and the provider mints from them plus the client
  IP. With no fingerprint at all it defers with a warning rather than
  degrading to an IP-only identifier.
- Device signals move to a field-based DeviceSignals derived in the
  adapter (derive_ua_only for hosts without fingerprints).
- The new crates join the fastly cargo aliases so they build, lint, and
  test in CI rather than compiling only transitively.
Third slice of the PR 838 decomposition. Permissions become the
primitive that gates identity features; consent is one of several ways
a permission is established:

- permissions.rs resolves a per-request PermissionState from the
  country/region baseline in permissions.yaml augmented by the session's
  signals (TCF, GPP, GPC, US Privacy). Permission names follow the
  Privacy Taxonomy Data Uses.
- The Edge Cookie gate moves from raw consent to the permission model:
  a provider declares required_permissions() and core executes it only
  when every one is set. With no provider selected the gate stays
  closed and identifiers are treated as absent, matching the stateless
  contract established in the first slice.
- Withdrawal separates from mere not-permitted: ec_storage_withdrawn
  (an explicit signal) expires the cookie and writes tombstones, while
  a pre-consent or fail-closed state only strips EC response headers.
- Bidstream EIDs gate on the permission model (gate_eids_by_permissions)
  instead of raw TCF consent.
- [geo] default_country becomes required: it names the permissions.yaml
  rule that applies when the geo provider leaves a request unmatched,
  validated at startup, so there is always a defined permission
  baseline.
- The consent module keeps building the ConsentContext; its EC-specific
  gating helpers move behind the permission model.
@jwrosewell
jwrosewell force-pushed the split/3-permissions branch from 6d20255 to 760b921 Compare August 20, 2026 02:22
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.

1 participant