1010import os
1111import time
1212import warnings
13- from collections .abc import Callable , Iterator
13+ from collections .abc import Callable , Iterator , Mapping
1414from datetime import datetime , timezone
1515from typing import TYPE_CHECKING , Any , TypedDict , cast
1616from uuid import uuid4
@@ -578,6 +578,9 @@ def __init__(
578578 """
579579 self ._adcp_version : str = resolve_adcp_version (adcp_version )
580580 self ._server_version : str | None = _resolve_server_version (server_version )
581+ if type (allow_unauthenticated_webhooks ) is not bool :
582+ raise TypeError ("allow_unauthenticated_webhooks must be a bool" )
583+
581584 self .agent_config = agent_config
582585 self .webhook_url_template = webhook_url_template
583586 self .webhook_secret = webhook_secret
@@ -5087,7 +5090,18 @@ async def _handle_mcp_webhook(
50875090 f"Webhook signature verification failed for agent { self .agent_config .id } "
50885091 )
50895092 raise ADCPWebhookSignatureError ("Invalid webhook signature" )
5090- elif not self .allow_unauthenticated_webhooks :
5093+ if raw_body is None : # Defensive type narrowing; verifier rejects this above.
5094+ raise ADCPWebhookSignatureError ("Signed webhook raw body is required" )
5095+ try :
5096+ authenticated_payload = json .loads (raw_body )
5097+ except (TypeError , ValueError , UnicodeDecodeError ) as exc :
5098+ raise ADCPWebhookSignatureError ("Invalid signed webhook body" ) from exc
5099+ if not isinstance (authenticated_payload , dict ):
5100+ raise ADCPWebhookSignatureError ("Signed webhook body must be a JSON object" )
5101+ # Process the bytes that were authenticated, not a separately
5102+ # supplied parsed object that middleware could have transformed.
5103+ payload = cast (dict [str , Any ], authenticated_payload )
5104+ elif self .allow_unauthenticated_webhooks is not True :
50915105 raise ADCPWebhookSignatureError (
50925106 "MCP webhook cannot be authenticated because webhook_secret is not configured; "
50935107 "configure a secret or explicitly set allow_unauthenticated_webhooks=True only "
@@ -5106,11 +5120,8 @@ async def _handle_mcp_webhook(
51065120 task_type = task_type ,
51075121 timestamp = datetime .now (timezone .utc ).isoformat (),
51085122 metadata = {
5109- "payload" : (
5110- payload
5111- if preserve_legacy_identity
5112- else strip_legacy_creative_identity (payload )
5113- ),
5123+ "task_id" : webhook .task_id ,
5124+ "status" : webhook .status .value ,
51145125 "protocol" : "mcp" ,
51155126 },
51165127 )
@@ -5479,7 +5490,7 @@ def __init__(
54795490 adcp_version : str | dict [str , str ] | None = None ,
54805491 legacy_format_converter : LegacyFormatConverter | None = None ,
54815492 canonical_format_legacy_resolver : CanonicalFormatLegacyResolver | None = None ,
5482- allow_unauthenticated_webhooks : bool = False ,
5493+ allow_unauthenticated_webhooks : bool | Mapping [ str , bool ] = False ,
54835494 ):
54845495 """
54855496 Initialize multi-agent client.
@@ -5493,8 +5504,10 @@ def __init__(
54935504 signing: Optional RFC 9421 signing config forwarded to every
54945505 per-agent ADCPClient. The same identity signs traffic to
54955506 all agents. See ADCPClient.__init__ for details.
5496- allow_unauthenticated_webhooks: Explicit compatibility escape
5497- forwarded to each client. Defaults to False.
5507+ allow_unauthenticated_webhooks: Explicit compatibility escape.
5508+ A mapping scopes the opt-in by agent ID; omitted IDs remain
5509+ protected. A uniform True is accepted only for a single-agent
5510+ collection. Defaults to False.
54985511 adcp_version: AdCP protocol release pin. Three forms:
54995512
55005513 - ``None`` (default): every per-agent ADCPClient resolves
@@ -5510,6 +5523,31 @@ def __init__(
55105523 See ADCPClient.__init__ for per-instance semantics.
55115524 Cross-major pins raise ConfigurationError at construction.
55125525 """
5526+ agent_ids = {agent .id for agent in agents }
5527+ if isinstance (allow_unauthenticated_webhooks , Mapping ):
5528+ unknown_ids = set (allow_unauthenticated_webhooks ) - agent_ids
5529+ if unknown_ids :
5530+ unknown = ", " .join (sorted (unknown_ids ))
5531+ raise ValueError (
5532+ "allow_unauthenticated_webhooks contains unknown agent IDs: " + unknown
5533+ )
5534+ if any (type (value ) is not bool for value in allow_unauthenticated_webhooks .values ()):
5535+ raise TypeError ("allow_unauthenticated_webhooks mapping values must be bools" )
5536+ per_agent_unauthenticated = dict (allow_unauthenticated_webhooks )
5537+ else :
5538+ if type (allow_unauthenticated_webhooks ) is not bool :
5539+ raise TypeError (
5540+ "allow_unauthenticated_webhooks must be a bool or mapping of agent IDs to bools"
5541+ )
5542+ if allow_unauthenticated_webhooks is True and len (agents ) > 1 :
5543+ raise ValueError (
5544+ "allow_unauthenticated_webhooks=True cannot be applied to multiple agents; "
5545+ "pass a mapping keyed by the isolated agent IDs"
5546+ )
5547+ per_agent_unauthenticated = {
5548+ agent .id : allow_unauthenticated_webhooks for agent in agents
5549+ }
5550+
55135551 # Per-agent map → resolve each pin individually for the dict form;
55145552 # otherwise use the uniform pin for all agents.
55155553 if isinstance (adcp_version , dict ):
@@ -5528,7 +5566,7 @@ def __init__(
55285566 adcp_version = self ._per_agent_versions .get (agent .id , default_pin ),
55295567 legacy_format_converter = legacy_format_converter ,
55305568 canonical_format_legacy_resolver = canonical_format_legacy_resolver ,
5531- allow_unauthenticated_webhooks = allow_unauthenticated_webhooks ,
5569+ allow_unauthenticated_webhooks = per_agent_unauthenticated . get ( agent . id , False ) ,
55325570 )
55335571 for agent in agents
55345572 }
@@ -5545,7 +5583,7 @@ def __init__(
55455583 adcp_version = self ._adcp_version ,
55465584 legacy_format_converter = legacy_format_converter ,
55475585 canonical_format_legacy_resolver = canonical_format_legacy_resolver ,
5548- allow_unauthenticated_webhooks = allow_unauthenticated_webhooks ,
5586+ allow_unauthenticated_webhooks = per_agent_unauthenticated . get ( agent . id , False ) ,
55495587 )
55505588 for agent in agents
55515589 }
0 commit comments