Skip to content

Commit 6a1e9f6

Browse files
committed
deploy: ef55dcb
1 parent 1411651 commit 6a1e9f6

3 files changed

Lines changed: 58 additions & 102 deletions

File tree

adagents.html

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,21 @@ <h2 id="returns">Returns</h2>
165165
# Track visited URLs to detect loops
166166
visited_urls: set[str] = set()
167167

168+
is_redirect = False
169+
168170
for depth in range(MAX_REDIRECT_DEPTH + 1):
169171
# Check for redirect loop
170172
if url in visited_urls:
171-
raise AdagentsValidationError(f&#34;Circular redirect detected: {url} already visited&#34;)
173+
raise AdagentsValidationError(
174+
&#34;Circular redirect detected in authoritative_location chain&#34;
175+
)
172176
visited_urls.add(url)
173177

174-
data = await _fetch_adagents_url(url, timeout, user_agent, client)
178+
# Use the caller&#39;s client for the initial fetch only. Redirect targets
179+
# use a fresh client to avoid leaking credentials to third-party URLs.
180+
fetch_client = None if is_redirect else client
181+
182+
data = await _fetch_adagents_url(url, timeout, user_agent, fetch_client)
175183

176184
# Check if this is a redirect. A response with authoritative_location but no
177185
# authorized_agents indicates a redirect. If both are present, authorized_agents
@@ -187,6 +195,9 @@ <h2 id="returns">Returns</h2>
187195
f&#34;authoritative_location must be an HTTPS URL, got: {authoritative_url!r}&#34;
188196
)
189197

198+
# Validate the redirect target is not a private/reserved address
199+
_validate_redirect_url(authoritative_url)
200+
190201
# Check if we&#39;ve exceeded max depth
191202
if depth &gt;= MAX_REDIRECT_DEPTH:
192203
raise AdagentsValidationError(
@@ -195,6 +206,7 @@ <h2 id="returns">Returns</h2>
195206

196207
# Follow the redirect
197208
url = authoritative_url
209+
is_redirect = True
198210
continue
199211

200212
# We have the final data with authorized_agents (or both fields present,
@@ -367,6 +379,9 @@ <h2 id="notes">Notes</h2>
367379
<pre><code class="python">def get_all_properties(adagents_data: dict[str, Any]) -&gt; list[dict[str, Any]]:
368380
&#34;&#34;&#34;Extract all properties from adagents.json data.
369381

382+
Handles all authorization types: inline_properties, property_ids,
383+
property_tags, and publisher_properties.
384+
370385
Args:
371386
adagents_data: Parsed adagents.json data
372387

@@ -383,6 +398,10 @@ <h2 id="notes">Notes</h2>
383398
if not isinstance(authorized_agents, list):
384399
raise AdagentsValidationError(&#34;adagents.json must have &#39;authorized_agents&#39; array&#34;)
385400

401+
top_level_properties = adagents_data.get(&#34;properties&#34;, [])
402+
if not isinstance(top_level_properties, list):
403+
top_level_properties = []
404+
386405
properties = []
387406
for agent in authorized_agents:
388407
if not isinstance(agent, dict):
@@ -392,20 +411,17 @@ <h2 id="notes">Notes</h2>
392411
if not agent_url:
393412
continue
394413

395-
agent_properties = agent.get(&#34;properties&#34;, [])
396-
if not isinstance(agent_properties, list):
397-
continue
414+
agent_properties = _resolve_agent_properties(agent, top_level_properties)
398415

399-
# Add each property with the agent URL for reference
400416
for prop in agent_properties:
401-
if isinstance(prop, dict):
402-
# Create a copy and add agent_url
403-
prop_with_agent = {**prop, &#34;agent_url&#34;: agent_url}
404-
properties.append(prop_with_agent)
417+
prop_with_agent = {**prop, &#34;agent_url&#34;: agent_url}
418+
properties.append(prop_with_agent)
405419

406420
return properties</code></pre>
407421
</details>
408422
<div class="desc"><p>Extract all properties from adagents.json data.</p>
423+
<p>Handles all authorization types: inline_properties, property_ids,
424+
property_tags, and publisher_properties.</p>
409425
<h2 id="args">Args</h2>
410426
<dl>
411427
<dt><strong><code>adagents_data</code></strong></dt>
@@ -500,12 +516,10 @@ <h2 id="raises">Raises</h2>
500516
if not isinstance(authorized_agents, list):
501517
raise AdagentsValidationError(&#34;adagents.json must have &#39;authorized_agents&#39; array&#34;)
502518

503-
# Get top-level properties for reference-based authorization types
504519
top_level_properties = adagents_data.get(&#34;properties&#34;, [])
505520
if not isinstance(top_level_properties, list):
506521
top_level_properties = []
507522

508-
# Normalize the agent URL for comparison
509523
normalized_agent_url = normalize_url(agent_url)
510524

511525
for agent in authorized_agents:
@@ -516,48 +530,10 @@ <h2 id="raises">Raises</h2>
516530
if not agent_url_from_json:
517531
continue
518532

519-
# Match agent URL (protocol-agnostic)
520533
if normalize_url(agent_url_from_json) != normalized_agent_url:
521534
continue
522535

523-
# Found the agent - determine authorization type
524-
authorization_type = agent.get(&#34;authorization_type&#34;, &#34;&#34;)
525-
526-
# Handle inline_properties (properties array directly on agent)
527-
if authorization_type == &#34;inline_properties&#34; or &#34;properties&#34; in agent:
528-
properties = agent.get(&#34;properties&#34;, [])
529-
if not isinstance(properties, list):
530-
return []
531-
return [p for p in properties if isinstance(p, dict)]
532-
533-
# Handle property_ids (filter top-level properties by property_id)
534-
if authorization_type == &#34;property_ids&#34;:
535-
authorized_ids = set(agent.get(&#34;property_ids&#34;, []))
536-
return [
537-
p
538-
for p in top_level_properties
539-
if isinstance(p, dict) and p.get(&#34;property_id&#34;) in authorized_ids
540-
]
541-
542-
# Handle property_tags (filter top-level properties by tags)
543-
if authorization_type == &#34;property_tags&#34;:
544-
authorized_tags = set(agent.get(&#34;property_tags&#34;, []))
545-
return [
546-
p
547-
for p in top_level_properties
548-
if isinstance(p, dict) and set(p.get(&#34;tags&#34;, [])) &amp; authorized_tags
549-
]
550-
551-
# Handle publisher_properties (cross-domain references)
552-
# Returns the selector objects; caller must resolve against other domains
553-
if authorization_type == &#34;publisher_properties&#34;:
554-
publisher_props = agent.get(&#34;publisher_properties&#34;, [])
555-
if not isinstance(publisher_props, list):
556-
return []
557-
return [p for p in publisher_props if isinstance(p, dict)]
558-
559-
# No recognized authorization type - return empty
560-
return []
536+
return _resolve_agent_properties(agent, top_level_properties)
561537

562538
return []</code></pre>
563539
</details>

index.html

Lines changed: 27 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -903,13 +903,21 @@ <h2 id="examples">Examples</h2>
903903
# Track visited URLs to detect loops
904904
visited_urls: set[str] = set()
905905

906+
is_redirect = False
907+
906908
for depth in range(MAX_REDIRECT_DEPTH + 1):
907909
# Check for redirect loop
908910
if url in visited_urls:
909-
raise AdagentsValidationError(f&#34;Circular redirect detected: {url} already visited&#34;)
911+
raise AdagentsValidationError(
912+
&#34;Circular redirect detected in authoritative_location chain&#34;
913+
)
910914
visited_urls.add(url)
911915

912-
data = await _fetch_adagents_url(url, timeout, user_agent, client)
916+
# Use the caller&#39;s client for the initial fetch only. Redirect targets
917+
# use a fresh client to avoid leaking credentials to third-party URLs.
918+
fetch_client = None if is_redirect else client
919+
920+
data = await _fetch_adagents_url(url, timeout, user_agent, fetch_client)
913921

914922
# Check if this is a redirect. A response with authoritative_location but no
915923
# authorized_agents indicates a redirect. If both are present, authorized_agents
@@ -925,6 +933,9 @@ <h2 id="examples">Examples</h2>
925933
f&#34;authoritative_location must be an HTTPS URL, got: {authoritative_url!r}&#34;
926934
)
927935

936+
# Validate the redirect target is not a private/reserved address
937+
_validate_redirect_url(authoritative_url)
938+
928939
# Check if we&#39;ve exceeded max depth
929940
if depth &gt;= MAX_REDIRECT_DEPTH:
930941
raise AdagentsValidationError(
@@ -933,6 +944,7 @@ <h2 id="examples">Examples</h2>
933944

934945
# Follow the redirect
935946
url = authoritative_url
947+
is_redirect = True
936948
continue
937949

938950
# We have the final data with authorized_agents (or both fields present,
@@ -1315,6 +1327,9 @@ <h2 id="raises">Raises</h2>
13151327
<pre><code class="python">def get_all_properties(adagents_data: dict[str, Any]) -&gt; list[dict[str, Any]]:
13161328
&#34;&#34;&#34;Extract all properties from adagents.json data.
13171329

1330+
Handles all authorization types: inline_properties, property_ids,
1331+
property_tags, and publisher_properties.
1332+
13181333
Args:
13191334
adagents_data: Parsed adagents.json data
13201335

@@ -1331,6 +1346,10 @@ <h2 id="raises">Raises</h2>
13311346
if not isinstance(authorized_agents, list):
13321347
raise AdagentsValidationError(&#34;adagents.json must have &#39;authorized_agents&#39; array&#34;)
13331348

1349+
top_level_properties = adagents_data.get(&#34;properties&#34;, [])
1350+
if not isinstance(top_level_properties, list):
1351+
top_level_properties = []
1352+
13341353
properties = []
13351354
for agent in authorized_agents:
13361355
if not isinstance(agent, dict):
@@ -1340,20 +1359,17 @@ <h2 id="raises">Raises</h2>
13401359
if not agent_url:
13411360
continue
13421361

1343-
agent_properties = agent.get(&#34;properties&#34;, [])
1344-
if not isinstance(agent_properties, list):
1345-
continue
1362+
agent_properties = _resolve_agent_properties(agent, top_level_properties)
13461363

1347-
# Add each property with the agent URL for reference
13481364
for prop in agent_properties:
1349-
if isinstance(prop, dict):
1350-
# Create a copy and add agent_url
1351-
prop_with_agent = {**prop, &#34;agent_url&#34;: agent_url}
1352-
properties.append(prop_with_agent)
1365+
prop_with_agent = {**prop, &#34;agent_url&#34;: agent_url}
1366+
properties.append(prop_with_agent)
13531367

13541368
return properties</code></pre>
13551369
</details>
13561370
<div class="desc"><p>Extract all properties from adagents.json data.</p>
1371+
<p>Handles all authorization types: inline_properties, property_ids,
1372+
property_tags, and publisher_properties.</p>
13571373
<h2 id="args">Args</h2>
13581374
<dl>
13591375
<dt><strong><code>adagents_data</code></strong></dt>
@@ -1597,12 +1613,10 @@ <h2 id="example">Example</h2>
15971613
if not isinstance(authorized_agents, list):
15981614
raise AdagentsValidationError(&#34;adagents.json must have &#39;authorized_agents&#39; array&#34;)
15991615

1600-
# Get top-level properties for reference-based authorization types
16011616
top_level_properties = adagents_data.get(&#34;properties&#34;, [])
16021617
if not isinstance(top_level_properties, list):
16031618
top_level_properties = []
16041619

1605-
# Normalize the agent URL for comparison
16061620
normalized_agent_url = normalize_url(agent_url)
16071621

16081622
for agent in authorized_agents:
@@ -1613,48 +1627,10 @@ <h2 id="example">Example</h2>
16131627
if not agent_url_from_json:
16141628
continue
16151629

1616-
# Match agent URL (protocol-agnostic)
16171630
if normalize_url(agent_url_from_json) != normalized_agent_url:
16181631
continue
16191632

1620-
# Found the agent - determine authorization type
1621-
authorization_type = agent.get(&#34;authorization_type&#34;, &#34;&#34;)
1622-
1623-
# Handle inline_properties (properties array directly on agent)
1624-
if authorization_type == &#34;inline_properties&#34; or &#34;properties&#34; in agent:
1625-
properties = agent.get(&#34;properties&#34;, [])
1626-
if not isinstance(properties, list):
1627-
return []
1628-
return [p for p in properties if isinstance(p, dict)]
1629-
1630-
# Handle property_ids (filter top-level properties by property_id)
1631-
if authorization_type == &#34;property_ids&#34;:
1632-
authorized_ids = set(agent.get(&#34;property_ids&#34;, []))
1633-
return [
1634-
p
1635-
for p in top_level_properties
1636-
if isinstance(p, dict) and p.get(&#34;property_id&#34;) in authorized_ids
1637-
]
1638-
1639-
# Handle property_tags (filter top-level properties by tags)
1640-
if authorization_type == &#34;property_tags&#34;:
1641-
authorized_tags = set(agent.get(&#34;property_tags&#34;, []))
1642-
return [
1643-
p
1644-
for p in top_level_properties
1645-
if isinstance(p, dict) and set(p.get(&#34;tags&#34;, [])) &amp; authorized_tags
1646-
]
1647-
1648-
# Handle publisher_properties (cross-domain references)
1649-
# Returns the selector objects; caller must resolve against other domains
1650-
if authorization_type == &#34;publisher_properties&#34;:
1651-
publisher_props = agent.get(&#34;publisher_properties&#34;, [])
1652-
if not isinstance(publisher_props, list):
1653-
return []
1654-
return [p for p in publisher_props if isinstance(p, dict)]
1655-
1656-
# No recognized authorization type - return empty
1657-
return []
1633+
return _resolve_agent_properties(agent, top_level_properties)
16581634

16591635
return []</code></pre>
16601636
</details>

types/base.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,8 @@ <h2 id="args">Args</h2>
966966
a [<code>PydanticSerializationError</code>][pydantic_core.PydanticSerializationError] error is raised.</dd>
967967
<dt><strong><code>serialize_as_any</code></strong></dt>
968968
<dd>Whether to serialize fields with duck-typing serialization behavior.</dd>
969+
<dt><strong><code>polymorphic_serialization</code></strong></dt>
970+
<dd>Whether to use model and dataclass polymorphic serialization for this call.</dd>
969971
</dl>
970972
<h2 id="returns">Returns</h2>
971973
<p>A dictionary representation of the model.</p></div>
@@ -1023,6 +1025,8 @@ <h2 id="args">Args</h2>
10231025
a [<code>PydanticSerializationError</code>][pydantic_core.PydanticSerializationError] error is raised.</dd>
10241026
<dt><strong><code>serialize_as_any</code></strong></dt>
10251027
<dd>Whether to serialize fields with duck-typing serialization behavior.</dd>
1028+
<dt><strong><code>polymorphic_serialization</code></strong></dt>
1029+
<dd>Whether to use model and dataclass polymorphic serialization for this call.</dd>
10261030
</dl>
10271031
<h2 id="returns">Returns</h2>
10281032
<p>A JSON string representation of the model.</p></div>

0 commit comments

Comments
 (0)