Repository navigation
Attribute adagents.json properties to a publisher domain, gate permissive resolution, and verify cross-domain claims #1697
Description
Problem
get_properties_by_agent / resolve_properties_for_agent tell a sales agent which properties it is authorized for in one adagents.json. A sales agent syncing that file for a given publisher domain has to make three more decisions that the SDK leaves to it. Each implementation makes them differently, so the same file gives different answers from different agents.
We hit this in a sales agent built on this SDK. It kept a property only when its domain identifier equaled the publisher domain after stripping www./m./mobile.. So a publisher that authorized shop.example.org and ctv.example.org by property_ids in example.org's file lost both: the agent believed it sold only example.org. That rule was our own; the SDK's domain_matches would have handled it with *.example.org. We've moved the agent onto domain_matches, but the remaining decisions belong in the SDK so every agent gets them right.
Requests
1. Attribute a file's properties to a publisher domain
One file is often served at several publisher domains (a media group's shared file), or names a network's publishers. When syncing it for publisher domain D, an agent needs "which of these authorized properties are D's". Suggested helper:
def properties_for_publisher_domain(properties: list[dict], publisher_domain: str) -> list[dict]Proposed rules, using domain_matches:
- A property that declares
publisher_domainbelongs toDwhen that value namesD. - Otherwise it belongs to
Dwhen atype=domainidentifier namesD, itswww./m.forms, or any subdomain (*.D). A publisher entered aswww.Dis treated asD. - A property with no domain at all (an app identified only by bundle id) is kept, or reported separately for the caller to decide.
2. A domain gate for permissive (bare-entry) resolution
resolve_properties_for_agent(mode="permissive") returns every top-level property when the agent's entry is bare. Without a typed binding, nothing stops a file on attacker.example from bare-listing an agent and claiming another publisher's site, an app bundle or a DOOH venue. Every agent has to add its own gate. Suggestion: an optional publisher_domain= on the permissive mode. It keeps only properties with a type=domain identifier naming that domain or a subdomain, and ignores a property's own publisher_domain claim, since the file isn't attested.
3. Verify cross-domain claims at resolution time
When a file served at A authorizes an agent for a property on another domain B, nothing during resolution confirms that B vouches for it. Vouching would mean B's own adagents.json authorizes the agent, or points to A through authoritative_location or ads.txt MANAGERDOMAIN. fetch_agent_authorizations_from_directory and detect_publisher_properties_divergence cover this from the directory side. A resolver-side option would let sync paths enforce it without depending on a directory. That could be a verify_cross_domain=True flag or a helper that takes a fetcher and returns the verified subset.
Why in the SDK
These are spec-level rules: domain matching, delegation and revocation. The SDK already owns them in domain_matches, identifiers_match, authoritative_location following and revoked_publisher_domains. Keeping attribution, the permissive gate and cross-domain verification next to them means every sales agent applies the same rules.
Activity