@adcp/sdk 13.0.0-rc.4 → 13.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/bin/adcp.js +7 -1
- package/dist/lib/adapters/property-list-adapter.d.mts +5 -1
- package/dist/lib/adapters/property-list-adapter.d.ts +5 -1
- package/dist/lib/adapters/property-list-adapter.d.ts.map +1 -1
- package/dist/lib/adapters/property-list-adapter.js +7 -7
- package/dist/lib/adapters/property-list-adapter.js.map +1 -1
- package/dist/lib/adapters/property-list-adapter.mjs +7 -7
- package/dist/lib/adapters/property-list-adapter.mjs.map +1 -1
- package/dist/lib/auth/oauth/CLIFlowHandler.d.mts +10 -3
- package/dist/lib/auth/oauth/CLIFlowHandler.d.ts +10 -3
- package/dist/lib/auth/oauth/CLIFlowHandler.d.ts.map +1 -1
- package/dist/lib/auth/oauth/CLIFlowHandler.js +40 -4
- package/dist/lib/auth/oauth/CLIFlowHandler.js.map +1 -1
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs +40 -4
- package/dist/lib/auth/oauth/CLIFlowHandler.mjs.map +1 -1
- package/dist/lib/auth/oauth/index.d.mts +1 -1
- package/dist/lib/auth/oauth/index.d.ts +1 -1
- package/dist/lib/auth/oauth/index.d.ts.map +1 -1
- package/dist/lib/auth/oauth/index.js +2 -0
- package/dist/lib/auth/oauth/index.js.map +1 -1
- package/dist/lib/auth/oauth/index.mjs +2 -0
- package/dist/lib/auth/oauth/index.mjs.map +1 -1
- package/dist/lib/auth/oauth/web-flow.d.mts +12 -0
- package/dist/lib/auth/oauth/web-flow.d.ts +12 -0
- package/dist/lib/auth/oauth/web-flow.d.ts.map +1 -1
- package/dist/lib/auth/oauth/web-flow.js +20 -2
- package/dist/lib/auth/oauth/web-flow.js.map +1 -1
- package/dist/lib/auth/oauth/web-flow.mjs +19 -2
- package/dist/lib/auth/oauth/web-flow.mjs.map +1 -1
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.mts +27 -1
- package/dist/lib/core/SingleAgentClient.d.ts +27 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +46 -18
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/core/SingleAgentClient.mjs +46 -18
- package/dist/lib/core/SingleAgentClient.mjs.map +1 -1
- package/dist/lib/net/address-guards.d.ts.map +1 -1
- package/dist/lib/net/address-guards.js +4 -0
- package/dist/lib/net/address-guards.js.map +1 -1
- package/dist/lib/net/address-guards.mjs +4 -0
- package/dist/lib/net/address-guards.mjs.map +1 -1
- package/dist/lib/protocols/a2a.js +2 -2
- package/dist/lib/protocols/a2a.js.map +1 -1
- package/dist/lib/protocols/a2a.mjs +2 -2
- package/dist/lib/protocols/a2a.mjs.map +1 -1
- package/dist/lib/protocols/index.d.ts.map +1 -1
- package/dist/lib/protocols/index.js +28 -7
- package/dist/lib/protocols/index.js.map +1 -1
- package/dist/lib/protocols/index.mjs +28 -7
- package/dist/lib/protocols/index.mjs.map +1 -1
- package/dist/lib/protocols/mcp-modern.d.ts.map +1 -1
- package/dist/lib/protocols/mcp-modern.js +18 -5
- package/dist/lib/protocols/mcp-modern.js.map +1 -1
- package/dist/lib/protocols/mcp-modern.mjs +18 -5
- package/dist/lib/protocols/mcp-modern.mjs.map +1 -1
- package/dist/lib/protocols/mcp-tasks.d.ts.map +1 -1
- package/dist/lib/protocols/mcp-tasks.js +2 -12
- package/dist/lib/protocols/mcp-tasks.js.map +1 -1
- package/dist/lib/protocols/mcp-tasks.mjs +2 -12
- package/dist/lib/protocols/mcp-tasks.mjs.map +1 -1
- package/dist/lib/protocols/mcp.js +2 -2
- package/dist/lib/protocols/mcp.js.map +1 -1
- package/dist/lib/protocols/mcp.mjs +2 -2
- package/dist/lib/protocols/mcp.mjs.map +1 -1
- package/dist/lib/registry/types.generated.d.mts +554 -15
- package/dist/lib/registry/types.generated.d.ts +554 -15
- package/dist/lib/registry/types.generated.d.ts.map +1 -1
- package/dist/lib/registry/types.generated.js.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/account.d.mts +6 -4
- package/dist/lib/server/decisioning/account.d.ts +6 -4
- package/dist/lib/server/decisioning/account.d.ts.map +1 -1
- package/dist/lib/server/decisioning/account.js.map +1 -1
- package/dist/lib/server/decisioning/account.mjs.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.d.mts +6 -5
- package/dist/lib/server/decisioning/manifest-helpers.d.ts +6 -5
- package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -1
- package/dist/lib/server/decisioning/manifest-helpers.mjs.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +4 -2
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +4 -2
- package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
- package/dist/lib/server/decisioning/tenant-store.d.mts +26 -14
- package/dist/lib/server/decisioning/tenant-store.d.ts +26 -14
- package/dist/lib/server/decisioning/tenant-store.d.ts.map +1 -1
- package/dist/lib/server/decisioning/tenant-store.js +6 -1
- package/dist/lib/server/decisioning/tenant-store.js.map +1 -1
- package/dist/lib/server/decisioning/tenant-store.mjs +6 -1
- package/dist/lib/server/decisioning/tenant-store.mjs.map +1 -1
- package/dist/lib/server/pin-and-bind-fetch.d.mts +2 -0
- package/dist/lib/server/pin-and-bind-fetch.d.ts +2 -0
- package/dist/lib/server/pin-and-bind-fetch.d.ts.map +1 -1
- package/dist/lib/server/pin-and-bind-fetch.js +2 -0
- package/dist/lib/server/pin-and-bind-fetch.js.map +1 -1
- package/dist/lib/server/pin-and-bind-fetch.mjs +2 -0
- package/dist/lib/server/pin-and-bind-fetch.mjs.map +1 -1
- package/dist/lib/server/structured-serialize.d.ts.map +1 -1
- package/dist/lib/server/structured-serialize.js +10 -2
- package/dist/lib/server/structured-serialize.js.map +1 -1
- package/dist/lib/server/structured-serialize.mjs +10 -2
- package/dist/lib/server/structured-serialize.mjs.map +1 -1
- package/dist/lib/server/webhook-emitter.d.ts.map +1 -1
- package/dist/lib/server/webhook-emitter.js +4 -2
- package/dist/lib/server/webhook-emitter.js.map +1 -1
- package/dist/lib/server/webhook-emitter.mjs +4 -2
- package/dist/lib/server/webhook-emitter.mjs.map +1 -1
- package/dist/lib/signing/middleware.d.mts +2 -1
- package/dist/lib/signing/middleware.d.ts +2 -1
- package/dist/lib/signing/middleware.d.ts.map +1 -1
- package/dist/lib/signing/middleware.js +26 -4
- package/dist/lib/signing/middleware.js.map +1 -1
- package/dist/lib/signing/middleware.mjs +26 -4
- package/dist/lib/signing/middleware.mjs.map +1 -1
- package/dist/lib/signing/webhook-verifier.d.ts.map +1 -1
- package/dist/lib/signing/webhook-verifier.js +4 -2
- package/dist/lib/signing/webhook-verifier.js.map +1 -1
- package/dist/lib/signing/webhook-verifier.mjs +4 -2
- package/dist/lib/signing/webhook-verifier.mjs.map +1 -1
- package/dist/lib/testing/agent-tester.d.ts.map +1 -1
- package/dist/lib/testing/agent-tester.js +46 -1
- package/dist/lib/testing/agent-tester.js.map +1 -1
- package/dist/lib/testing/agent-tester.mjs +46 -1
- package/dist/lib/testing/agent-tester.mjs.map +1 -1
- package/dist/lib/types/asset-instances.d.mts +8 -6
- package/dist/lib/types/asset-instances.d.ts +8 -6
- package/dist/lib/types/asset-instances.d.ts.map +1 -1
- package/dist/lib/types/asset-instances.js.map +1 -1
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/index.mjs.map +1 -1
- package/dist/lib/utils/capabilities.d.mts +2 -0
- package/dist/lib/utils/capabilities.d.ts +2 -0
- package/dist/lib/utils/capabilities.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.js +2 -1
- package/dist/lib/utils/capabilities.js.map +1 -1
- package/dist/lib/utils/capabilities.mjs +2 -1
- package/dist/lib/utils/capabilities.mjs.map +1 -1
- package/dist/lib/utils/probe-policy.d.mts +0 -16
- package/dist/lib/utils/probe-policy.d.ts +0 -16
- package/dist/lib/utils/probe-policy.d.ts.map +1 -1
- package/dist/lib/utils/probe-policy.js +15 -1
- package/dist/lib/utils/probe-policy.js.map +1 -1
- package/dist/lib/utils/probe-policy.mjs +15 -1
- package/dist/lib/utils/probe-policy.mjs.map +1 -1
- package/dist/lib/utils/redact-args.d.mts +36 -0
- package/dist/lib/utils/redact-args.d.ts +37 -0
- package/dist/lib/utils/redact-args.d.ts.map +1 -0
- package/dist/lib/utils/redact-args.js +46 -0
- package/dist/lib/utils/redact-args.js.map +1 -0
- package/dist/lib/utils/redact-args.mjs +22 -0
- package/dist/lib/utils/redact-args.mjs.map +1 -0
- package/dist/lib/v2/projection/creative-delivery.js +1 -5
- package/dist/lib/v2/projection/creative-delivery.js.map +1 -1
- package/dist/lib/v2/projection/creative-delivery.mjs +1 -5
- package/dist/lib/v2/projection/creative-delivery.mjs.map +1 -1
- package/dist/lib/validation/index.d.mts +15 -1
- package/dist/lib/validation/index.d.ts +15 -1
- package/dist/lib/validation/index.d.ts.map +1 -1
- package/dist/lib/validation/index.js +4 -8
- package/dist/lib/validation/index.js.map +1 -1
- package/dist/lib/validation/index.mjs +4 -8
- package/dist/lib/validation/index.mjs.map +1 -1
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.js.map +1 -1
- package/dist/lib/version.mjs +3 -3
- package/dist/lib/version.mjs.map +1 -1
- package/examples/hello_seller_adapter_multi_tenant.ts +7 -0
- package/package.json +3 -2
- package/skills/build-holdco-agent/SKILL.md +19 -0
- package/skills/cross-cutting.md +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"address-guards.d.ts","sourceRoot":"","sources":["../../../src/lib/net/address-guards.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"address-guards.d.ts","sourceRoot":"","sources":["../../../src/lib/net/address-guards.ts"],"names":[],"mappings":"AA+EA;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIxD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIpD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASvD"}
|
|
@@ -37,6 +37,7 @@ function normalize(address) {
|
|
|
37
37
|
const alwaysBlocked = new import_net.BlockList();
|
|
38
38
|
alwaysBlocked.addSubnet("169.254.0.0", 16, "ipv4");
|
|
39
39
|
alwaysBlocked.addSubnet("fe80::", 10, "ipv6");
|
|
40
|
+
alwaysBlocked.addAddress("192.0.0.192", "ipv4");
|
|
40
41
|
const privateIp = new import_net.BlockList();
|
|
41
42
|
privateIp.addSubnet("0.0.0.0", 8, "ipv4");
|
|
42
43
|
privateIp.addSubnet("10.0.0.0", 8, "ipv4");
|
|
@@ -46,6 +47,9 @@ privateIp.addSubnet("169.254.0.0", 16, "ipv4");
|
|
|
46
47
|
privateIp.addSubnet("172.16.0.0", 12, "ipv4");
|
|
47
48
|
privateIp.addSubnet("192.168.0.0", 16, "ipv4");
|
|
48
49
|
privateIp.addSubnet("224.0.0.0", 4, "ipv4");
|
|
50
|
+
privateIp.addSubnet("192.0.0.0", 24, "ipv4");
|
|
51
|
+
privateIp.addSubnet("192.88.99.0", 24, "ipv4");
|
|
52
|
+
privateIp.addSubnet("240.0.0.0", 4, "ipv4");
|
|
49
53
|
privateIp.addAddress("255.255.255.255", "ipv4");
|
|
50
54
|
privateIp.addAddress("::", "ipv6");
|
|
51
55
|
privateIp.addAddress("::1", "ipv6");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,iBAAgC;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,aAAS,iBAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,qBAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n// Oracle Cloud IMDS lives at 192.0.0.192 (inside RFC 6890's 192.0.0.0/24\n// IETF-protocol assignments) rather than the 169.254.0.0/16 everyone else\n// uses, so it needs its own entry to be refused even under the private opt-in.\nalwaysBlocked.addAddress('192.0.0.192', 'ipv4');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addSubnet('192.0.0.0', 24, 'ipv4'); // RFC 6890 IETF protocol assignments (incl. Oracle IMDS)\nprivateIp.addSubnet('192.88.99.0', 24, 'ipv4'); // 6to4 relay anycast (RFC 7526, deprecated)\nprivateIp.addSubnet('240.0.0.0', 4, 'ipv4'); // reserved for future use\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,iBAAgC;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,aAAS,iBAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,qBAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;AAI5C,cAAc,WAAW,eAAe,MAAM;AAM9C,MAAM,YAAY,IAAI,qBAAU;AAGhC,UAAU,UAAU,WAAW,GAAG,MAAM;AACxC,UAAU,UAAU,YAAY,GAAG,MAAM;AACzC,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,WAAW,mBAAmB,MAAM;AAE9C,UAAU,WAAW,MAAM,MAAM;AACjC,UAAU,WAAW,OAAO,MAAM;AAClC,UAAU,UAAU,UAAU,IAAI,MAAM;AACxC,UAAU,UAAU,UAAU,GAAG,MAAM;AACvC,UAAU,UAAU,UAAU,GAAG,MAAM;AAIvC,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,UAAU,IAAI,MAAM;AAWjC,SAAS,gBAAgB,SAA0B;AACxD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,cAAc,MAAM,EAAE,MAAM,EAAE,MAAM;AAC7C;AAUO,SAAS,YAAY,SAA0B;AACpD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,UAAU,MAAM,EAAE,MAAM,EAAE,MAAM;AACzC;AAeO,SAAS,mBAAmB,KAAsB;AACvD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,OAAO,EAAE,SAAS,QAAQ,YAAY,EAAE,EAAE,YAAY;AAC5D,QAAI,SAAS,YAAa,QAAO;AACjC,WAAO,YAAY,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -12,6 +12,7 @@ function normalize(address) {
|
|
|
12
12
|
const alwaysBlocked = new BlockList();
|
|
13
13
|
alwaysBlocked.addSubnet("169.254.0.0", 16, "ipv4");
|
|
14
14
|
alwaysBlocked.addSubnet("fe80::", 10, "ipv6");
|
|
15
|
+
alwaysBlocked.addAddress("192.0.0.192", "ipv4");
|
|
15
16
|
const privateIp = new BlockList();
|
|
16
17
|
privateIp.addSubnet("0.0.0.0", 8, "ipv4");
|
|
17
18
|
privateIp.addSubnet("10.0.0.0", 8, "ipv4");
|
|
@@ -21,6 +22,9 @@ privateIp.addSubnet("169.254.0.0", 16, "ipv4");
|
|
|
21
22
|
privateIp.addSubnet("172.16.0.0", 12, "ipv4");
|
|
22
23
|
privateIp.addSubnet("192.168.0.0", 16, "ipv4");
|
|
23
24
|
privateIp.addSubnet("224.0.0.0", 4, "ipv4");
|
|
25
|
+
privateIp.addSubnet("192.0.0.0", 24, "ipv4");
|
|
26
|
+
privateIp.addSubnet("192.88.99.0", 24, "ipv4");
|
|
27
|
+
privateIp.addSubnet("240.0.0.0", 4, "ipv4");
|
|
24
28
|
privateIp.addAddress("255.255.255.255", "ipv4");
|
|
25
29
|
privateIp.addAddress("::", "ipv6");
|
|
26
30
|
privateIp.addAddress("::1", "ipv6");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":"AAsBA,SAAS,WAAW,YAAY;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,SAAS,KAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,UAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/net/address-guards.ts"],"sourcesContent":["/**\n * IP address classification for SSRF defense.\n *\n * Two tiers of blocking:\n * - {@link isAlwaysBlocked}: link-local + cloud metadata endpoints (IMDS).\n * Refused even when the caller opts into private networks (dev loops).\n * - {@link isPrivateIp}: RFC 1918, loopback, CGNAT, IPv6 ULA/link-local,\n * multicast, broadcast, unspecified, plus defense-in-depth on IPv6\n * wrappers (NAT64 well-known prefix, 6to4) so a v4-in-v6 address can't\n * sneak a private target past the classifier. Refused by default; allowed\n * when the caller passes `allowPrivateIp: true` (storyboard runner's\n * `--allow-http`).\n *\n * Classifiers normalize before matching:\n * - Zone IDs (`%eth0`) are stripped — they're a host-local concept, not part\n * of the address, and Node's IP parsers don't accept them.\n * - Surrounding URL brackets (`[::1]`) are stripped — `URL.hostname` returns\n * bracketed form for IPv6 literals; classifiers need bare input.\n * - IPv4-mapped IPv6 is resolved natively by `BlockList` — `::ffff:10.0.0.1`\n * matches the `10.0.0.0/8` subnet regardless of textual form\n * (`0:0:0:0:0:ffff:a.b.c.d` works too).\n */\nimport { BlockList, isIP } from 'net';\n\nfunction normalize(address: string): { addr: string; family: 'ipv4' | 'ipv6' } | null {\n // Strip surrounding brackets (URL-hostname form) and zone ID.\n let bare = address;\n if (bare.startsWith('[') && bare.endsWith(']')) bare = bare.slice(1, -1);\n const pctIdx = bare.indexOf('%');\n if (pctIdx >= 0) bare = bare.slice(0, pctIdx);\n const family = isIP(bare);\n if (family === 4) return { addr: bare, family: 'ipv4' };\n if (family === 6) return { addr: bare, family: 'ipv6' };\n return null;\n}\n\n// Addresses blocked even when the dev opt-in `allowPrivateIp` is set. Cloud\n// metadata services live at 169.254.169.254 and leak credentials if reached;\n// IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the host's\n// local segment.\nconst alwaysBlocked = new BlockList();\nalwaysBlocked.addSubnet('169.254.0.0', 16, 'ipv4');\nalwaysBlocked.addSubnet('fe80::', 10, 'ipv6');\n// Oracle Cloud IMDS lives at 192.0.0.192 (inside RFC 6890's 192.0.0.0/24\n// IETF-protocol assignments) rather than the 169.254.0.0/16 everyone else\n// uses, so it needs its own entry to be refused even under the private opt-in.\nalwaysBlocked.addAddress('192.0.0.192', 'ipv4');\n\n// Private, loopback, multicast, and reserved ranges. Defense-in-depth adds the\n// NAT64 well-known prefix (`64:ff9b::/96`) and 6to4 (`2002::/16`) so a\n// wrapped-v4 address can't bypass the classifier by choosing a representation\n// BlockList doesn't natively canonicalize.\nconst privateIp = new BlockList();\n// v4 — BlockList handles IPv4-mapped IPv6 (`::ffff:a.b.c.d`) against these\n// subnets automatically per Node's check semantics.\nprivateIp.addSubnet('0.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('10.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('127.0.0.0', 8, 'ipv4');\nprivateIp.addSubnet('100.64.0.0', 10, 'ipv4'); // RFC 6598 CGNAT\nprivateIp.addSubnet('169.254.0.0', 16, 'ipv4');\nprivateIp.addSubnet('172.16.0.0', 12, 'ipv4');\nprivateIp.addSubnet('192.168.0.0', 16, 'ipv4');\nprivateIp.addSubnet('224.0.0.0', 4, 'ipv4'); // multicast\nprivateIp.addSubnet('192.0.0.0', 24, 'ipv4'); // RFC 6890 IETF protocol assignments (incl. Oracle IMDS)\nprivateIp.addSubnet('192.88.99.0', 24, 'ipv4'); // 6to4 relay anycast (RFC 7526, deprecated)\nprivateIp.addSubnet('240.0.0.0', 4, 'ipv4'); // reserved for future use\nprivateIp.addAddress('255.255.255.255', 'ipv4'); // limited broadcast\n// v6\nprivateIp.addAddress('::', 'ipv6'); // unspecified\nprivateIp.addAddress('::1', 'ipv6'); // loopback\nprivateIp.addSubnet('fe80::', 10, 'ipv6'); // link-local\nprivateIp.addSubnet('fc00::', 7, 'ipv6'); // ULA\nprivateIp.addSubnet('ff00::', 8, 'ipv6'); // multicast\n// Wrapper prefixes — refuse unconditionally. Tunnels at the caller's edge can\n// translate these into private targets we can't see; safer to refuse than to\n// hope the gateway is configured the way we expect.\nprivateIp.addSubnet('64:ff9b::', 96, 'ipv6'); // NAT64 well-known\nprivateIp.addSubnet('2002::', 16, 'ipv6'); // 6to4\n\n/**\n * Addresses blocked even when `allowPrivateIp` is on. Cloud metadata services\n * (AWS/GCP/Azure IMDS) live at 169.254.169.254 and would exfiltrate\n * credentials if a CI runner or long-lived server followed an attacker URL to\n * them. IPv6 link-local (`fe80::/10`) is the v6 equivalent reach into the\n * host's local segment.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isAlwaysBlocked(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return alwaysBlocked.check(n.addr, n.family);\n}\n\n/**\n * Reject loopback, link-local, RFC 1918 private ranges, CGNAT (RFC 6598),\n * broadcast, multicast, the unspecified address, NAT64/6to4 wrapper prefixes,\n * and IPv6 equivalents. BlockList handles IPv4-mapped IPv6 canonicalization\n * natively so `::ffff:10.0.0.1` is matched against the v4 rule set.\n *\n * Returns `false` for non-IP inputs (hostnames).\n */\nexport function isPrivateIp(address: string): boolean {\n const n = normalize(address);\n if (!n) return false;\n return privateIp.check(n.addr, n.family);\n}\n\n/**\n * Best-effort check that a URL targets a development/private host, without\n * doing a DNS lookup. Matches loopback hostnames (`localhost`) and any IP\n * literal that {@link isPrivateIp} would reject. Public domain names always\n * return `false`.\n *\n * Used by higher layers that need to inherit the operator's \"private is OK\"\n * trust from a primary probe and propagate it to same-origin chain hops —\n * callers that pass this flag into `ssrfSafeFetch` should do so only when\n * they've already decided the target origin is trusted.\n *\n * Returns `false` on unparseable inputs.\n */\nexport function isLikelyPrivateUrl(url: string): boolean {\n try {\n const u = new URL(url);\n const host = u.hostname.replace(/^\\[|\\]$/g, '').toLowerCase();\n if (host === 'localhost') return true;\n return isPrivateIp(host);\n } catch {\n return false;\n }\n}\n"],"mappings":"AAsBA,SAAS,WAAW,YAAY;AAEhC,SAAS,UAAU,SAAmE;AAEpF,MAAI,OAAO;AACX,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE;AACvE,QAAM,SAAS,KAAK,QAAQ,GAAG;AAC/B,MAAI,UAAU,EAAG,QAAO,KAAK,MAAM,GAAG,MAAM;AAC5C,QAAM,SAAS,KAAK,IAAI;AACxB,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,MAAI,WAAW,EAAG,QAAO,EAAE,MAAM,MAAM,QAAQ,OAAO;AACtD,SAAO;AACT;AAMA,MAAM,gBAAgB,IAAI,UAAU;AACpC,cAAc,UAAU,eAAe,IAAI,MAAM;AACjD,cAAc,UAAU,UAAU,IAAI,MAAM;AAI5C,cAAc,WAAW,eAAe,MAAM;AAM9C,MAAM,YAAY,IAAI,UAAU;AAGhC,UAAU,UAAU,WAAW,GAAG,MAAM;AACxC,UAAU,UAAU,YAAY,GAAG,MAAM;AACzC,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,cAAc,IAAI,MAAM;AAC5C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,eAAe,IAAI,MAAM;AAC7C,UAAU,UAAU,aAAa,GAAG,MAAM;AAC1C,UAAU,WAAW,mBAAmB,MAAM;AAE9C,UAAU,WAAW,MAAM,MAAM;AACjC,UAAU,WAAW,OAAO,MAAM;AAClC,UAAU,UAAU,UAAU,IAAI,MAAM;AACxC,UAAU,UAAU,UAAU,GAAG,MAAM;AACvC,UAAU,UAAU,UAAU,GAAG,MAAM;AAIvC,UAAU,UAAU,aAAa,IAAI,MAAM;AAC3C,UAAU,UAAU,UAAU,IAAI,MAAM;AAWjC,SAAS,gBAAgB,SAA0B;AACxD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,cAAc,MAAM,EAAE,MAAM,EAAE,MAAM;AAC7C;AAUO,SAAS,YAAY,SAA0B;AACpD,QAAM,IAAI,UAAU,OAAO;AAC3B,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,UAAU,MAAM,EAAE,MAAM,EAAE,MAAM;AACzC;AAeO,SAAS,mBAAmB,KAAsB;AACvD,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,UAAM,OAAO,EAAE,SAAS,QAAQ,YAAY,EAAE,EAAE,YAAY;AAC5D,QAAI,SAAS,YAAa,QAAO;AACjC,WAAO,YAAY,IAAI;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -35,7 +35,7 @@ var import_client2 = require('../signing/client.js');
|
|
|
35
35
|
var import_agent_fetch = require('../signing/agent-fetch.js');
|
|
36
36
|
var import_fetch = require('../signing/fetch.js');
|
|
37
37
|
var import_fetch_async = require('../signing/fetch-async.js');
|
|
38
|
-
var
|
|
38
|
+
var import_redact_args = require('../utils/redact-args.js');
|
|
39
39
|
var import_rawResponseCapture = require('./rawResponseCapture.js');
|
|
40
40
|
var import_responseSizeLimit = require('./responseSizeLimit.js');
|
|
41
41
|
var import_transportDiagnostics = require('./transportDiagnostics.js');
|
|
@@ -318,7 +318,7 @@ async function callA2AToolImpl(agentUrl, toolName, parameters, authToken, debugL
|
|
|
318
318
|
};
|
|
319
319
|
}
|
|
320
320
|
const payloadSize = JSON.stringify(requestPayload).length;
|
|
321
|
-
const redactedParameters = (0,
|
|
321
|
+
const redactedParameters = (0, import_redact_args.redactArgsForLog)(parameters);
|
|
322
322
|
const redactedPayload = {
|
|
323
323
|
...requestPayload,
|
|
324
324
|
message: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/protocols/a2a.ts"],"sourcesContent":["// Official A2A client implementation - NO FALLBACKS\nimport { A2AClient as A2AClientImpl } from '@a2a-js/sdk/client';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHmac, randomUUID } from 'node:crypto';\nimport type { PushNotificationConfig } from '../types/tools.generated';\nimport type { DebugLogEntry } from '../types/adcp';\nimport { AuthenticationRequiredError, is401Error } from '../errors';\nimport { discoverOAuthMetadata } from '../auth/oauth/discovery';\nimport { probeAuthChallenge } from '../auth/oauth/authorization-required';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { isAgentCardPath, buildCardUrls } from '../utils/a2a-discovery';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport { toSignerKey, isInlineSigningConfig, isProviderSigningConfig } from '../signing/agent-fetch';\nimport { createSigningFetch, type FetchLike } from '../signing/fetch';\nimport { createSigningFetchAsync } from '../signing/fetch-async';\nimport type { AgentConfig } from '../types/adcp';\nimport { redactIdempotencyKeyInArgs } from '../utils/idempotency';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\nimport { DEFAULT_REQUEST_TIMEOUT_MS, resolveRequestTimeoutMs, withAbortSignal } from './abort';\nimport { getLatestA2ADataPartFromResponse } from '../utils/a2a-artifacts';\n\n// The A2A SDK client is used untyped: request/response shapes are validated at\n// runtime against the AdCP wire contract, not against the SDK's exported\n// types. Preserves the prior behaviour of the CommonJS `require` form.\nconst A2AClient: any = A2AClientImpl;\n\nif (!A2AClient) {\n throw new Error('A2A SDK client is required. Please install @a2a-js/sdk');\n}\n\n/**\n * Per-call state flowed through AsyncLocalStorage so concurrent callers\n * that share a cached A2AClient don't clobber each other's debugLogs,\n * customHeaders, or 401 flag.\n */\ninterface A2ACallContext {\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n got401Ref: { value: boolean };\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n}\n\nconst callContextStorage = new AsyncLocalStorage<A2ACallContext>();\n\n/**\n * Cached A2AClient keyed by (agentUrl, authToken hash). Avoids re-fetching\n * /.well-known/agent.json on every tool call. The cached client's fetchImpl\n * reads per-call state from callContextStorage, so concurrent calls to the\n * same cache entry are safe.\n *\n * Process-global singleton — not suitable for multi-tenant servers that\n * want per-tenant isolation (use separate processes or explicit cache keys).\n */\nconst a2aClientCache = new Map<string, InstanceType<typeof A2AClient>>();\nconst pendingA2AClients = new Map<string, Promise<InstanceType<typeof A2AClient>>>();\n\n/**\n * Build the A2A connection-cache key. Mirrors the rationale in\n * `src/lib/protocols/mcp.ts:connectionCacheKey`: when the caller is using a\n * non-bearer scheme (RFC 7617 Basic from the CLI's `--auth-scheme basic`\n * shape, or any future caller-injected `Authorization` header), `authToken`\n * is undefined and the credential rides on the customHeaders bag. Hashing\n * only `authToken` would let two callers with different `user:pass`\n * credentials share a single cached A2AClient — single-CLI-process safe,\n * multi-tenant SDK consumer not safe.\n *\n * `customHeaders` also feed the key so tenant/routing headers cannot reuse a\n * card/client discovered for another caller. Scoped fetch calls bypass this\n * cache entirely (see `getOrCreateA2AClient`).\n */\nfunction a2aCacheKey(\n agentUrl: string,\n authToken?: string,\n signingCacheKey?: string,\n customHeaders?: Record<string, string>\n): string {\n // 64-bit Map-key disambiguator — NOT a password hash. The cached client\n // closes over the full credential, so a hypothetical hash collision still\n // sends the original credential on the wire, just possibly cache-miss\n // and reconnect. Routed via `cacheDisambiguator` (HMAC-SHA256 with empty\n // key) instead of bare `createHash` so CodeQL's\n // `js/insufficient-password-hash` heuristic doesn't misclassify the\n // dataflow — see the helper docstring for the full rationale.\n const fingerprint = authToken ?? extractA2AAuthHeader(customHeaders);\n const tokenSuffix = fingerprint ? `::${cacheDisambiguator(fingerprint)}` : '';\n const headersKey = headersCacheDisambiguator(customHeaders);\n const headersSuffix = headersKey ? `::headers:${headersKey}` : '';\n const signingSuffix = signingCacheKey ? `::${signingCacheKey}` : '';\n return `${agentUrl}${tokenSuffix}${headersSuffix}${signingSuffix}`;\n}\n\n/**\n * Produce a stable 64-bit Map-key disambiguator from credential material.\n * Mirrors the helper in `src/lib/protocols/mcp.ts` — the two protocol\n * modules intentionally don't share runtime imports, so each carries its\n * own copy. See the MCP-side docstring for the full rationale.\n */\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex').slice(0, 16);\n}\n\n/**\n * Case-insensitive lookup of `Authorization` on a header bag. Mirrors the\n * MCP-side helper; A2A keeps its own copy because the two protocol modules\n * intentionally don't share runtime imports.\n */\nfunction extractA2AAuthHeader(headers: Record<string, string> | undefined): string | undefined {\n if (!headers) return undefined;\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === 'authorization' && value) return value;\n }\n return undefined;\n}\n\nfunction headersCacheDisambiguator(headers?: Record<string, string>): string | undefined {\n const entries = Object.entries(headers ?? {})\n .filter(([key]) => {\n const lower = key.toLowerCase();\n return lower !== 'traceparent' && lower !== 'tracestate' && lower !== 'baggage';\n })\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([a], [b]) => a.localeCompare(b));\n return entries.length > 0 ? cacheDisambiguator(JSON.stringify(entries)) : undefined;\n}\n\nfunction redactHeadersForDebug(headers: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.keys(headers).map(key => [key, '***']));\n}\n\nfunction redactPushNotificationConfigForDebug(\n config: PushNotificationConfig | undefined\n): PushNotificationConfig | undefined {\n if (!config) return undefined;\n return {\n ...config,\n ...(config.token && { token: '***' }),\n ...(config.authentication && {\n authentication: {\n ...config.authentication,\n ...(config.authentication.credentials && { credentials: '***' }),\n },\n }),\n };\n}\n\n/**\n * Clear all cached A2A clients. Called by closeConnections('a2a').\n * A2A clients hold no persistent network resources (unlike MCP), so this\n * is just cache eviction.\n */\nexport function closeA2AConnections(): void {\n a2aClientCache.clear();\n pendingA2AClients.clear();\n}\n\n/**\n * Wall-clock cap on a fire-and-forget cancel. A2A sellers that accept the\n * TCP connect but never respond would otherwise pin the event loop past the\n * buyer's abort, which defeats the whole point of fire-and-forget.\n */\nconst CANCEL_TIMEOUT_MS = 5000;\n\n/**\n * Fire-and-forget A2A tasks/cancel for an in-flight task (A2A 0.3.0 §7.4).\n *\n * Sends a raw JSON-RPC 2.0 POST directly to the agent endpoint with the same\n * auth header shape as `callA2AToolImpl` (Bearer + x-adcp-auth). Does NOT\n * enter `callContextStorage` — debug-log capture and 401-cache-eviction are\n * intentionally skipped for best-effort cancellation.\n *\n * **Auth-code OAuth gap:** `authToken` is resolved by `getAuthToken(agent)`,\n * which returns `undefined` for authorization-code-flow sellers (those tokens\n * are managed by the OAuth provider path in `ProtocolClient.callTool`, not\n * accessible here). Cancel calls to those sellers go out unauthenticated and\n * will likely 401 non-fatally.\n *\n * **Phase 2 (adcp-client#1617 follow-up):** when `agent.request_signing` is\n * configured, the cancel POST is signed with the agent's signer key. The\n * `signingContextStorage` ALS scope around `callA2AToolImpl` does NOT extend\n * into `pollTaskCompletion` (sibling promise trees), so we can't replay the\n * captured ALS context — instead we rebuild a one-shot signer fetch from\n * `agent.request_signing` directly and use it for this single POST. Inline\n * keys go through `createSigningFetch` (sync); provider-backed configs use\n * `createSigningFetchAsync`. A `signed-requests` seller that requires\n * signing on `tasks/cancel` (or applies a uniform \"all mutating POSTs must\n * be signed\" policy) now accepts the cancel; one without signing config on\n * the agent gets the Phase 1 unsigned path.\n *\n * The caller is responsible for swallowing errors: cancel failure\n * (TaskNotCancelable, network error, auth rejection, network timeout) is\n * non-fatal because the buyer is already abandoning the task.\n *\n * @param agent The agent config (used for URL, auth token, signing).\n * @param taskId The server-assigned A2A Task.id to cancel.\n */\nexport async function cancelA2ATask(agent: AgentConfig, taskId: string, fetchFn?: typeof fetch): Promise<void> {\n // Defense-in-depth (ad-tech-protocol-expert review of #1640): the cancel\n // POST is JSON-RPC at the bare A2A endpoint. Calling this on an MCP agent\n // would POST `tasks/cancel` JSON-RPC at an MCP endpoint and 404. The\n // single call site (`pollTaskCompletion`) already gates on\n // `agent.protocol === 'a2a'`; this assertion catches future call sites\n // that forget the gate.\n if (agent.protocol !== 'a2a') {\n return;\n }\n const agentUrl = agent.agent_uri;\n const authToken = agent.auth_token;\n\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json',\n };\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n headers['x-adcp-auth'] = authToken;\n }\n // JSON-RPC 2.0 §4.1.3: `id: null` flags the request as a *notification*,\n // and the server MUST NOT respond. A2A 0.3.0 §7.4 defines `tasks/cancel`\n // as a request/response method (returns the canceled `Task` or\n // `TaskNotCancelableError`), so a strict A2A server can legitimately\n // reject `id: null` as a protocol violation. Use a real id and just drop\n // the response on the floor — fire-and-forget is the caller's discipline,\n // not a wire-protocol claim.\n const body = JSON.stringify({\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/cancel',\n params: { id: taskId },\n });\n // Bound the cancel: a hung fetch would orphan-pin the event loop past the\n // buyer's abort, defeating fire-and-forget. AbortSignal.timeout() is the\n // standard primitive; the caller's `.catch()` swallows the AbortError.\n const init: RequestInit = {\n method: 'POST',\n headers,\n body,\n signal: AbortSignal.timeout(CANCEL_TIMEOUT_MS),\n };\n\n // adcp-client#1617 Phase 2: sign the cancel POST when the agent has a\n // signer configured. We bypass the `buildAgentSigningFetch` capability-\n // gate path because `tasks/cancel` is an A2A protocol method, not an\n // AdCP tool — the seller's `request_signing.supported_for` typically\n // lists AdCP tool names, not protocol-level methods. The right model\n // here: if the agent claims signing AT ALL, sign every mutating POST\n // we send to it on the cancel path. Sellers with uniform \"must be\n // signed\" policies accept this; sellers that only check signing on\n // specific AdCP tools simply ignore the extra signature.\n //\n // TODO(adcp#4318, adcp-client#1617): when the AdCP spec adds explicit\n // verifier coverage for A2A protocol methods (likely in 3.1 as a new\n // `protocol_methods_supported_for` / `protocol_methods_required_for`\n // field on `request_signing`), narrow this default by reading the\n // seller's advertised coverage from `getCapability()` and gating on\n // the `tasks/cancel` membership. The over-sign default stays as the\n // fallback for spec-silent sellers (3.0.x and earlier).\n if (agent.request_signing) {\n const upstream: FetchLike = (input, ini) =>\n fetchFn ? fetchFn(input as RequestInfo | URL, ini) : fetch(input as RequestInfo, ini);\n if (isInlineSigningConfig(agent.request_signing)) {\n const signed = createSigningFetch(upstream, toSignerKey(agent.request_signing));\n await signed(agentUrl, init);\n return;\n }\n if (isProviderSigningConfig(agent.request_signing)) {\n const signed = createSigningFetchAsync(upstream, agent.request_signing.provider);\n await signed(agentUrl, init);\n return;\n }\n }\n\n await (fetchFn ?? fetch)(agentUrl, init);\n}\n\nasync function getOrCreateA2AClient(\n agentUrl: string,\n authToken: string | undefined,\n customHeaders?: Record<string, string>,\n bypassCache = false\n): Promise<InstanceType<typeof A2AClient>> {\n const signingContext = signingContextStorage.getStore();\n const fetchFn = callContextStorage.getStore()?.fetchFn;\n const cacheKey = a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, customHeaders);\n // Scoped fetchers often carry request/tenant-specific egress policy. Keep\n // those calls one-shot so neither agent-card discovery nor a client created\n // under one policy can be reused by another caller, and so short-lived\n // closure identities do not grow the global cache without bound.\n if (bypassCache || fetchFn) {\n return createA2AClient(agentUrl, authToken);\n }\n const cached = a2aClientCache.get(cacheKey);\n if (cached) return cached;\n\n const pending = pendingA2AClients.get(cacheKey);\n if (pending) return pending;\n\n const promise = createA2AClient(agentUrl, authToken)\n .then(client => {\n a2aClientCache.set(cacheKey, client);\n return client;\n })\n .finally(() => {\n pendingA2AClients.delete(cacheKey);\n });\n\n pendingA2AClients.set(cacheKey, promise);\n return promise;\n}\n\nasync function createA2AClient(\n agentUrl: string,\n authToken: string | undefined\n): Promise<InstanceType<typeof A2AClient>> {\n const fetchImpl = buildFetchImpl(authToken);\n const cardUrls = buildCardUrls(agentUrl);\n\n const context = callContextStorage.getStore();\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Discovering agent card at ${cardUrls.join(', ')}`,\n timestamp: new Date().toISOString(),\n });\n\n let client: InstanceType<typeof A2AClient> | undefined;\n let lastError: Error = new Error(`A2A agent card not found at ${cardUrls.join(', ')}`);\n for (const cardUrl of cardUrls) {\n try {\n client = await A2AClient.fromCardUrl(cardUrl, { fetchImpl });\n break;\n } catch (err: unknown) {\n lastError = err as Error;\n if (context?.got401Ref.value) break;\n }\n }\n if (!client) throw lastError;\n\n return client;\n}\n\nfunction buildFetchImpl(authToken: string | undefined) {\n // The A2A client is cached per (url, authToken, signingCacheKey). We capture\n // the signing context at client-creation time so all subsequent calls that\n // share this cached client use the same signing identity — changing identity\n // requires a different cache entry, built on a separate call that enters ALS\n // with a different context.\n const signingContext = signingContextStorage.getStore();\n\n // Innermost wrapper: enforce response body size cap from the active\n // `responseSizeLimitStorage` slot. Pass-through when no slot is set.\n const networkFetch = wrapFetchWithTransportDiagnostics(\n wrapFetchWithSizeLimit((input, init) => {\n const scopedFetch = callContextStorage.getStore()?.fetchFn;\n return scopedFetch ? scopedFetch(input, init) : fetch(input as any, init);\n })\n );\n\n // Inner fetch handles auth/header injection and 401 detection. If the\n // agent has request-signing configured, we wrap it with the AdCP signing\n // fetch so the signature covers the exact bytes we're about to send (auth\n // headers included, since the signer re-reads the final header record).\n const baseFetch = async (url: string | URL | Request, options?: RequestInit): Promise<Response> => {\n const context = callContextStorage.getStore();\n\n const existingHeaders: Record<string, string> = {};\n if (options?.headers) {\n if (options.headers instanceof Headers) {\n options.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(options.headers)) {\n for (const [key, value] of options.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, options.headers);\n }\n }\n\n // Only inject trace context headers for actual tool requests, not discovery.\n // The agent card endpoint is external/untrusted — don't leak trace IDs to it.\n const urlString = typeof url === 'string' ? url : url.toString();\n const isDiscoveryRequest = isAgentCardPath(urlString);\n const traceHeaders = isDiscoveryRequest ? {} : injectTraceHeaders();\n const requestTimeoutMs = isDiscoveryRequest\n ? resolveRequestTimeoutMs(context?.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS)\n : resolveRequestTimeoutMs(context?.requestTimeoutMs);\n\n // Merge: existing < trace < custom < auth (auth always wins)\n const headers: Record<string, string> = {\n ...existingHeaders,\n ...traceHeaders,\n ...context?.customHeaders,\n ...(authToken && {\n Authorization: `Bearer ${authToken}`,\n 'x-adcp-auth': authToken,\n }),\n };\n\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Fetch to ${urlString}`,\n timestamp: new Date().toISOString(),\n hasAuth: !!authToken,\n headers: redactHeadersForDebug(headers),\n });\n\n const response = await withAbortSignal<Response>([context?.signal, options?.signal], requestTimeoutMs, signal =>\n networkFetch(url as any, { ...options, headers, signal })\n );\n\n if (response.status === 401 && context) {\n context.got401Ref.value = true;\n }\n\n return response;\n };\n\n if (!signingContext) return wrapFetchWithCapture(baseFetch);\n\n // The signing wrapper assembles headers into the signature base. We invoke\n // it first so the signer sees the caller-supplied headers; baseFetch then\n // overlays auth/trace headers afterwards — A2A's auth scheme (bearer) is\n // not among the MANDATORY_COMPONENTS and is injected by the counterparty's\n // transport layer, not signed.\n const signingFetch = buildAgentSigningFetch({\n upstream: (input, init) => baseFetch(input as any, init),\n signing: signingContext.signing,\n getCapability: signingContext.getCapability,\n });\n return wrapFetchWithCapture(signingFetch as typeof fetch);\n}\n\n/**\n * Terminal A2A task states per A2A 0.3.0 §3.4. Only these can carry the\n * AdCP-mandated artifact + DataPart envelope (per transport-errors §A2A\n * Binding); intermediate states (`working`, `submitted`, `input-required`,\n * `auth-required`) carry no completion artifact.\n */\nconst TERMINAL_A2A_STATES = new Set(['completed', 'failed', 'rejected', 'canceled']);\n\n/**\n * Detect whether a JSON-RPC response carries a spec-compliant terminal-state\n * Task with at least one artifact containing a structured DataPart payload.\n * Per AdCP transport-errors §A2A Binding, the artifact's DataPart is the\n * canonical envelope for both the success arm (`completed`) and the error\n * arms (`failed` / `rejected` / `canceled`). The criterion intentionally\n * matches the unwrapper's terminal-state extraction in\n * `unwrapA2AResponse` — keeping protocol layer and unwrapper in lockstep\n * across all terminal states, not just the error arms.\n *\n * Used to short-circuit the generic \"A2A agent returned error\" throw when\n * a non-conformant seller surfaces both a transport-level `result.error`\n * hint and the canonical artifact envelope side-by-side. The DataPart is\n * authoritative; the throw would otherwise swallow it.\n */\nfunction hasTerminalTaskWithDataArtifact(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false;\n const result = (response as { result?: unknown }).result;\n if (!result || typeof result !== 'object') return false;\n const r = result as { kind?: unknown; status?: unknown; artifacts?: unknown };\n if (r.kind !== 'task') return false;\n const status = r.status as { state?: unknown } | undefined;\n if (typeof status?.state !== 'string' || !TERMINAL_A2A_STATES.has(status.state)) return false;\n return getLatestA2ADataPartFromResponse(response) !== undefined;\n}\n\n/**\n * Protocol-level session identifiers that ride on the A2A Message envelope\n * (not in the skill parameters). `contextId` binds sends to a server-side\n * conversation; `taskId` resumes an existing non-terminal task.\n *\n * Callers (buyers) typically retain these across calls on a per-conversation\n * AgentClient; see AgentClient.getContextId() / getPendingTaskId().\n */\nexport interface A2ASessionIds {\n contextId?: string;\n taskId?: string;\n}\n\nexport async function callA2ATool(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n pushNotificationConfig?: PushNotificationConfig,\n customHeaders?: Record<string, string>,\n signingContext?: AgentSigningContext,\n session?: A2ASessionIds,\n signal?: AbortSignal,\n requestTimeoutMs?: number,\n fetchFn?: typeof fetch\n): Promise<unknown> {\n return withSpan(\n 'adcp.a2a.call_tool',\n {\n 'adcp.tool': toolName,\n 'http.url': agentUrl,\n },\n async () => {\n const context: A2ACallContext = {\n customHeaders,\n debugLogs,\n got401Ref: { value: false },\n signal,\n requestTimeoutMs,\n fetchFn,\n };\n return signingContextStorage.run(signingContext, () =>\n callContextStorage.run(context, () =>\n callA2AToolImpl(\n agentUrl,\n toolName,\n parameters,\n authToken,\n debugLogs,\n pushNotificationConfig,\n context,\n session\n )\n )\n );\n }\n );\n}\n\nasync function callA2AToolImpl(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken: string | undefined,\n debugLogs: DebugLogEntry[],\n pushNotificationConfig: PushNotificationConfig | undefined,\n context: A2ACallContext,\n session: A2ASessionIds | undefined\n): Promise<unknown> {\n try {\n const client = await getOrCreateA2AClient(\n agentUrl,\n authToken,\n context.customHeaders,\n !!context.signal || context.requestTimeoutMs !== undefined\n );\n\n const requestPayload: {\n message: {\n messageId: string;\n role: string;\n kind: string;\n parts: Array<{ kind: string; data: { skill: string; parameters: Record<string, unknown> } }>;\n contextId?: string;\n taskId?: string;\n };\n configuration?: { pushNotificationConfig: PushNotificationConfig };\n } = {\n message: {\n messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n role: 'user',\n kind: 'message',\n parts: [\n {\n kind: 'data',\n data: {\n skill: toolName,\n parameters: parameters,\n },\n },\n ],\n ...(session?.contextId && { contextId: session.contextId }),\n ...(session?.taskId && { taskId: session.taskId }),\n },\n };\n\n if (pushNotificationConfig) {\n requestPayload.configuration = {\n pushNotificationConfig: pushNotificationConfig,\n };\n }\n\n const payloadSize = JSON.stringify(requestPayload).length;\n const redactedParameters = redactIdempotencyKeyInArgs(parameters);\n const redactedPayload = {\n ...requestPayload,\n message: {\n ...requestPayload.message,\n parts: [\n {\n kind: 'data',\n data: { skill: toolName, parameters: redactedParameters },\n },\n ],\n },\n ...(requestPayload.configuration && {\n configuration: {\n pushNotificationConfig: redactPushNotificationConfigForDebug(\n requestPayload.configuration.pushNotificationConfig\n )!,\n },\n }),\n };\n debugLogs.push({\n type: 'info',\n message: `A2A: Calling skill ${toolName} with parameters: ${JSON.stringify(\n redactedParameters\n )}. Payload size: ${payloadSize} bytes`,\n timestamp: new Date().toISOString(),\n payloadSize,\n actualPayload: redactedPayload,\n });\n\n debugLogs.push({\n type: 'info',\n message: `A2A: Sending message via sendMessage()`,\n timestamp: new Date().toISOString(),\n skill: toolName,\n });\n\n const messageResponse = await client.sendMessage(requestPayload);\n\n debugLogs.push({\n type: messageResponse?.error ? 'error' : 'success',\n message: `A2A: Response received (${messageResponse?.error ? 'error' : 'success'})`,\n timestamp: new Date().toISOString(),\n response: messageResponse,\n skill: toolName,\n });\n\n if (messageResponse?.error || messageResponse?.result?.error) {\n // adcp-client#1575: when the seller emits a spec-compliant terminal-state\n // Task carrying an `adcp_error` DataPart (per AdCP transport-errors §A2A\n // Binding), the structured artifact is canonical — even if the seller\n // also surfaced a transport-level error string. Pass the response\n // through so the upstream unwrapper extracts `adcp_error.code` instead\n // of throwing a generic message that loses the AdCP error envelope.\n if (!hasTerminalTaskWithDataArtifact(messageResponse)) {\n const errorObj = messageResponse.error || messageResponse.result?.error;\n const errorMessage = errorObj.message || JSON.stringify(errorObj);\n throw new Error(`A2A agent returned error: ${errorMessage}`);\n }\n }\n\n return messageResponse;\n } catch (error: unknown) {\n if (is401Error(error, context.got401Ref.value)) {\n // Evict this cache entry — credential may have expired or been\n // revoked. Same disambiguator as the original `getOrCreateA2AClient`\n // call: when the credential rode on customHeaders.Authorization (Basic\n // case) rather than authToken, the cache key must reflect that or we\n // evict the wrong entry.\n const signingContext = signingContextStorage.getStore();\n a2aClientCache.delete(a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, context.customHeaders));\n\n debugLogs.push({\n type: 'error',\n message: `A2A: Authentication required for ${agentUrl}`,\n timestamp: new Date().toISOString(),\n });\n\n // Re-probe to surface the WWW-Authenticate scheme on the error envelope.\n // Basic-fronted agents (Apigee/Kong/AWS API GW with a BasicAuthentication\n // policy) would otherwise leave consumers chasing OAuth metadata that\n // doesn't exist. Matches the MCP discovery throw site in\n // `SingleAgentClient.discoverMCPEndpoint`.\n const challenge = await probeAuthChallenge(agentUrl, { fetchFn: context.fetchFn });\n const oauthMetadata = await discoverOAuthMetadata(agentUrl, { fetch: context.fetchFn });\n throw new AuthenticationRequiredError(agentUrl, oauthMetadata || undefined, undefined, challenge ?? undefined);\n }\n\n throw error;\n }\n}\n"],"mappings":"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","names":["import_client","A2AClientImpl"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/protocols/a2a.ts"],"sourcesContent":["// Official A2A client implementation - NO FALLBACKS\nimport { A2AClient as A2AClientImpl } from '@a2a-js/sdk/client';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHmac, randomUUID } from 'node:crypto';\nimport type { PushNotificationConfig } from '../types/tools.generated';\nimport type { DebugLogEntry } from '../types/adcp';\nimport { AuthenticationRequiredError, is401Error } from '../errors';\nimport { discoverOAuthMetadata } from '../auth/oauth/discovery';\nimport { probeAuthChallenge } from '../auth/oauth/authorization-required';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { isAgentCardPath, buildCardUrls } from '../utils/a2a-discovery';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport { toSignerKey, isInlineSigningConfig, isProviderSigningConfig } from '../signing/agent-fetch';\nimport { createSigningFetch, type FetchLike } from '../signing/fetch';\nimport { createSigningFetchAsync } from '../signing/fetch-async';\nimport type { AgentConfig } from '../types/adcp';\nimport { redactArgsForLog } from '../utils/redact-args';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\nimport { DEFAULT_REQUEST_TIMEOUT_MS, resolveRequestTimeoutMs, withAbortSignal } from './abort';\nimport { getLatestA2ADataPartFromResponse } from '../utils/a2a-artifacts';\n\n// The A2A SDK client is used untyped: request/response shapes are validated at\n// runtime against the AdCP wire contract, not against the SDK's exported\n// types. Preserves the prior behaviour of the CommonJS `require` form.\nconst A2AClient: any = A2AClientImpl;\n\nif (!A2AClient) {\n throw new Error('A2A SDK client is required. Please install @a2a-js/sdk');\n}\n\n/**\n * Per-call state flowed through AsyncLocalStorage so concurrent callers\n * that share a cached A2AClient don't clobber each other's debugLogs,\n * customHeaders, or 401 flag.\n */\ninterface A2ACallContext {\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n got401Ref: { value: boolean };\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n}\n\nconst callContextStorage = new AsyncLocalStorage<A2ACallContext>();\n\n/**\n * Cached A2AClient keyed by (agentUrl, authToken hash). Avoids re-fetching\n * /.well-known/agent.json on every tool call. The cached client's fetchImpl\n * reads per-call state from callContextStorage, so concurrent calls to the\n * same cache entry are safe.\n *\n * Process-global singleton — not suitable for multi-tenant servers that\n * want per-tenant isolation (use separate processes or explicit cache keys).\n */\nconst a2aClientCache = new Map<string, InstanceType<typeof A2AClient>>();\nconst pendingA2AClients = new Map<string, Promise<InstanceType<typeof A2AClient>>>();\n\n/**\n * Build the A2A connection-cache key. Mirrors the rationale in\n * `src/lib/protocols/mcp.ts:connectionCacheKey`: when the caller is using a\n * non-bearer scheme (RFC 7617 Basic from the CLI's `--auth-scheme basic`\n * shape, or any future caller-injected `Authorization` header), `authToken`\n * is undefined and the credential rides on the customHeaders bag. Hashing\n * only `authToken` would let two callers with different `user:pass`\n * credentials share a single cached A2AClient — single-CLI-process safe,\n * multi-tenant SDK consumer not safe.\n *\n * `customHeaders` also feed the key so tenant/routing headers cannot reuse a\n * card/client discovered for another caller. Scoped fetch calls bypass this\n * cache entirely (see `getOrCreateA2AClient`).\n */\nfunction a2aCacheKey(\n agentUrl: string,\n authToken?: string,\n signingCacheKey?: string,\n customHeaders?: Record<string, string>\n): string {\n // 64-bit Map-key disambiguator — NOT a password hash. The cached client\n // closes over the full credential, so a hypothetical hash collision still\n // sends the original credential on the wire, just possibly cache-miss\n // and reconnect. Routed via `cacheDisambiguator` (HMAC-SHA256 with empty\n // key) instead of bare `createHash` so CodeQL's\n // `js/insufficient-password-hash` heuristic doesn't misclassify the\n // dataflow — see the helper docstring for the full rationale.\n const fingerprint = authToken ?? extractA2AAuthHeader(customHeaders);\n const tokenSuffix = fingerprint ? `::${cacheDisambiguator(fingerprint)}` : '';\n const headersKey = headersCacheDisambiguator(customHeaders);\n const headersSuffix = headersKey ? `::headers:${headersKey}` : '';\n const signingSuffix = signingCacheKey ? `::${signingCacheKey}` : '';\n return `${agentUrl}${tokenSuffix}${headersSuffix}${signingSuffix}`;\n}\n\n/**\n * Produce a stable 64-bit Map-key disambiguator from credential material.\n * Mirrors the helper in `src/lib/protocols/mcp.ts` — the two protocol\n * modules intentionally don't share runtime imports, so each carries its\n * own copy. See the MCP-side docstring for the full rationale.\n */\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex').slice(0, 16);\n}\n\n/**\n * Case-insensitive lookup of `Authorization` on a header bag. Mirrors the\n * MCP-side helper; A2A keeps its own copy because the two protocol modules\n * intentionally don't share runtime imports.\n */\nfunction extractA2AAuthHeader(headers: Record<string, string> | undefined): string | undefined {\n if (!headers) return undefined;\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === 'authorization' && value) return value;\n }\n return undefined;\n}\n\nfunction headersCacheDisambiguator(headers?: Record<string, string>): string | undefined {\n const entries = Object.entries(headers ?? {})\n .filter(([key]) => {\n const lower = key.toLowerCase();\n return lower !== 'traceparent' && lower !== 'tracestate' && lower !== 'baggage';\n })\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([a], [b]) => a.localeCompare(b));\n return entries.length > 0 ? cacheDisambiguator(JSON.stringify(entries)) : undefined;\n}\n\nfunction redactHeadersForDebug(headers: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.keys(headers).map(key => [key, '***']));\n}\n\nfunction redactPushNotificationConfigForDebug(\n config: PushNotificationConfig | undefined\n): PushNotificationConfig | undefined {\n if (!config) return undefined;\n return {\n ...config,\n ...(config.token && { token: '***' }),\n ...(config.authentication && {\n authentication: {\n ...config.authentication,\n ...(config.authentication.credentials && { credentials: '***' }),\n },\n }),\n };\n}\n\n/**\n * Clear all cached A2A clients. Called by closeConnections('a2a').\n * A2A clients hold no persistent network resources (unlike MCP), so this\n * is just cache eviction.\n */\nexport function closeA2AConnections(): void {\n a2aClientCache.clear();\n pendingA2AClients.clear();\n}\n\n/**\n * Wall-clock cap on a fire-and-forget cancel. A2A sellers that accept the\n * TCP connect but never respond would otherwise pin the event loop past the\n * buyer's abort, which defeats the whole point of fire-and-forget.\n */\nconst CANCEL_TIMEOUT_MS = 5000;\n\n/**\n * Fire-and-forget A2A tasks/cancel for an in-flight task (A2A 0.3.0 §7.4).\n *\n * Sends a raw JSON-RPC 2.0 POST directly to the agent endpoint with the same\n * auth header shape as `callA2AToolImpl` (Bearer + x-adcp-auth). Does NOT\n * enter `callContextStorage` — debug-log capture and 401-cache-eviction are\n * intentionally skipped for best-effort cancellation.\n *\n * **Auth-code OAuth gap:** `authToken` is resolved by `getAuthToken(agent)`,\n * which returns `undefined` for authorization-code-flow sellers (those tokens\n * are managed by the OAuth provider path in `ProtocolClient.callTool`, not\n * accessible here). Cancel calls to those sellers go out unauthenticated and\n * will likely 401 non-fatally.\n *\n * **Phase 2 (adcp-client#1617 follow-up):** when `agent.request_signing` is\n * configured, the cancel POST is signed with the agent's signer key. The\n * `signingContextStorage` ALS scope around `callA2AToolImpl` does NOT extend\n * into `pollTaskCompletion` (sibling promise trees), so we can't replay the\n * captured ALS context — instead we rebuild a one-shot signer fetch from\n * `agent.request_signing` directly and use it for this single POST. Inline\n * keys go through `createSigningFetch` (sync); provider-backed configs use\n * `createSigningFetchAsync`. A `signed-requests` seller that requires\n * signing on `tasks/cancel` (or applies a uniform \"all mutating POSTs must\n * be signed\" policy) now accepts the cancel; one without signing config on\n * the agent gets the Phase 1 unsigned path.\n *\n * The caller is responsible for swallowing errors: cancel failure\n * (TaskNotCancelable, network error, auth rejection, network timeout) is\n * non-fatal because the buyer is already abandoning the task.\n *\n * @param agent The agent config (used for URL, auth token, signing).\n * @param taskId The server-assigned A2A Task.id to cancel.\n */\nexport async function cancelA2ATask(agent: AgentConfig, taskId: string, fetchFn?: typeof fetch): Promise<void> {\n // Defense-in-depth (ad-tech-protocol-expert review of #1640): the cancel\n // POST is JSON-RPC at the bare A2A endpoint. Calling this on an MCP agent\n // would POST `tasks/cancel` JSON-RPC at an MCP endpoint and 404. The\n // single call site (`pollTaskCompletion`) already gates on\n // `agent.protocol === 'a2a'`; this assertion catches future call sites\n // that forget the gate.\n if (agent.protocol !== 'a2a') {\n return;\n }\n const agentUrl = agent.agent_uri;\n const authToken = agent.auth_token;\n\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json',\n };\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n headers['x-adcp-auth'] = authToken;\n }\n // JSON-RPC 2.0 §4.1.3: `id: null` flags the request as a *notification*,\n // and the server MUST NOT respond. A2A 0.3.0 §7.4 defines `tasks/cancel`\n // as a request/response method (returns the canceled `Task` or\n // `TaskNotCancelableError`), so a strict A2A server can legitimately\n // reject `id: null` as a protocol violation. Use a real id and just drop\n // the response on the floor — fire-and-forget is the caller's discipline,\n // not a wire-protocol claim.\n const body = JSON.stringify({\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/cancel',\n params: { id: taskId },\n });\n // Bound the cancel: a hung fetch would orphan-pin the event loop past the\n // buyer's abort, defeating fire-and-forget. AbortSignal.timeout() is the\n // standard primitive; the caller's `.catch()` swallows the AbortError.\n const init: RequestInit = {\n method: 'POST',\n headers,\n body,\n signal: AbortSignal.timeout(CANCEL_TIMEOUT_MS),\n };\n\n // adcp-client#1617 Phase 2: sign the cancel POST when the agent has a\n // signer configured. We bypass the `buildAgentSigningFetch` capability-\n // gate path because `tasks/cancel` is an A2A protocol method, not an\n // AdCP tool — the seller's `request_signing.supported_for` typically\n // lists AdCP tool names, not protocol-level methods. The right model\n // here: if the agent claims signing AT ALL, sign every mutating POST\n // we send to it on the cancel path. Sellers with uniform \"must be\n // signed\" policies accept this; sellers that only check signing on\n // specific AdCP tools simply ignore the extra signature.\n //\n // TODO(adcp#4318, adcp-client#1617): when the AdCP spec adds explicit\n // verifier coverage for A2A protocol methods (likely in 3.1 as a new\n // `protocol_methods_supported_for` / `protocol_methods_required_for`\n // field on `request_signing`), narrow this default by reading the\n // seller's advertised coverage from `getCapability()` and gating on\n // the `tasks/cancel` membership. The over-sign default stays as the\n // fallback for spec-silent sellers (3.0.x and earlier).\n if (agent.request_signing) {\n const upstream: FetchLike = (input, ini) =>\n fetchFn ? fetchFn(input as RequestInfo | URL, ini) : fetch(input as RequestInfo, ini);\n if (isInlineSigningConfig(agent.request_signing)) {\n const signed = createSigningFetch(upstream, toSignerKey(agent.request_signing));\n await signed(agentUrl, init);\n return;\n }\n if (isProviderSigningConfig(agent.request_signing)) {\n const signed = createSigningFetchAsync(upstream, agent.request_signing.provider);\n await signed(agentUrl, init);\n return;\n }\n }\n\n await (fetchFn ?? fetch)(agentUrl, init);\n}\n\nasync function getOrCreateA2AClient(\n agentUrl: string,\n authToken: string | undefined,\n customHeaders?: Record<string, string>,\n bypassCache = false\n): Promise<InstanceType<typeof A2AClient>> {\n const signingContext = signingContextStorage.getStore();\n const fetchFn = callContextStorage.getStore()?.fetchFn;\n const cacheKey = a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, customHeaders);\n // Scoped fetchers often carry request/tenant-specific egress policy. Keep\n // those calls one-shot so neither agent-card discovery nor a client created\n // under one policy can be reused by another caller, and so short-lived\n // closure identities do not grow the global cache without bound.\n if (bypassCache || fetchFn) {\n return createA2AClient(agentUrl, authToken);\n }\n const cached = a2aClientCache.get(cacheKey);\n if (cached) return cached;\n\n const pending = pendingA2AClients.get(cacheKey);\n if (pending) return pending;\n\n const promise = createA2AClient(agentUrl, authToken)\n .then(client => {\n a2aClientCache.set(cacheKey, client);\n return client;\n })\n .finally(() => {\n pendingA2AClients.delete(cacheKey);\n });\n\n pendingA2AClients.set(cacheKey, promise);\n return promise;\n}\n\nasync function createA2AClient(\n agentUrl: string,\n authToken: string | undefined\n): Promise<InstanceType<typeof A2AClient>> {\n const fetchImpl = buildFetchImpl(authToken);\n const cardUrls = buildCardUrls(agentUrl);\n\n const context = callContextStorage.getStore();\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Discovering agent card at ${cardUrls.join(', ')}`,\n timestamp: new Date().toISOString(),\n });\n\n let client: InstanceType<typeof A2AClient> | undefined;\n let lastError: Error = new Error(`A2A agent card not found at ${cardUrls.join(', ')}`);\n for (const cardUrl of cardUrls) {\n try {\n client = await A2AClient.fromCardUrl(cardUrl, { fetchImpl });\n break;\n } catch (err: unknown) {\n lastError = err as Error;\n if (context?.got401Ref.value) break;\n }\n }\n if (!client) throw lastError;\n\n return client;\n}\n\nfunction buildFetchImpl(authToken: string | undefined) {\n // The A2A client is cached per (url, authToken, signingCacheKey). We capture\n // the signing context at client-creation time so all subsequent calls that\n // share this cached client use the same signing identity — changing identity\n // requires a different cache entry, built on a separate call that enters ALS\n // with a different context.\n const signingContext = signingContextStorage.getStore();\n\n // Innermost wrapper: enforce response body size cap from the active\n // `responseSizeLimitStorage` slot. Pass-through when no slot is set.\n const networkFetch = wrapFetchWithTransportDiagnostics(\n wrapFetchWithSizeLimit((input, init) => {\n const scopedFetch = callContextStorage.getStore()?.fetchFn;\n return scopedFetch ? scopedFetch(input, init) : fetch(input as any, init);\n })\n );\n\n // Inner fetch handles auth/header injection and 401 detection. If the\n // agent has request-signing configured, we wrap it with the AdCP signing\n // fetch so the signature covers the exact bytes we're about to send (auth\n // headers included, since the signer re-reads the final header record).\n const baseFetch = async (url: string | URL | Request, options?: RequestInit): Promise<Response> => {\n const context = callContextStorage.getStore();\n\n const existingHeaders: Record<string, string> = {};\n if (options?.headers) {\n if (options.headers instanceof Headers) {\n options.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(options.headers)) {\n for (const [key, value] of options.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, options.headers);\n }\n }\n\n // Only inject trace context headers for actual tool requests, not discovery.\n // The agent card endpoint is external/untrusted — don't leak trace IDs to it.\n const urlString = typeof url === 'string' ? url : url.toString();\n const isDiscoveryRequest = isAgentCardPath(urlString);\n const traceHeaders = isDiscoveryRequest ? {} : injectTraceHeaders();\n const requestTimeoutMs = isDiscoveryRequest\n ? resolveRequestTimeoutMs(context?.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS)\n : resolveRequestTimeoutMs(context?.requestTimeoutMs);\n\n // Merge: existing < trace < custom < auth (auth always wins)\n const headers: Record<string, string> = {\n ...existingHeaders,\n ...traceHeaders,\n ...context?.customHeaders,\n ...(authToken && {\n Authorization: `Bearer ${authToken}`,\n 'x-adcp-auth': authToken,\n }),\n };\n\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Fetch to ${urlString}`,\n timestamp: new Date().toISOString(),\n hasAuth: !!authToken,\n headers: redactHeadersForDebug(headers),\n });\n\n const response = await withAbortSignal<Response>([context?.signal, options?.signal], requestTimeoutMs, signal =>\n networkFetch(url as any, { ...options, headers, signal })\n );\n\n if (response.status === 401 && context) {\n context.got401Ref.value = true;\n }\n\n return response;\n };\n\n if (!signingContext) return wrapFetchWithCapture(baseFetch);\n\n // The signing wrapper assembles headers into the signature base. We invoke\n // it first so the signer sees the caller-supplied headers; baseFetch then\n // overlays auth/trace headers afterwards — A2A's auth scheme (bearer) is\n // not among the MANDATORY_COMPONENTS and is injected by the counterparty's\n // transport layer, not signed.\n const signingFetch = buildAgentSigningFetch({\n upstream: (input, init) => baseFetch(input as any, init),\n signing: signingContext.signing,\n getCapability: signingContext.getCapability,\n });\n return wrapFetchWithCapture(signingFetch as typeof fetch);\n}\n\n/**\n * Terminal A2A task states per A2A 0.3.0 §3.4. Only these can carry the\n * AdCP-mandated artifact + DataPart envelope (per transport-errors §A2A\n * Binding); intermediate states (`working`, `submitted`, `input-required`,\n * `auth-required`) carry no completion artifact.\n */\nconst TERMINAL_A2A_STATES = new Set(['completed', 'failed', 'rejected', 'canceled']);\n\n/**\n * Detect whether a JSON-RPC response carries a spec-compliant terminal-state\n * Task with at least one artifact containing a structured DataPart payload.\n * Per AdCP transport-errors §A2A Binding, the artifact's DataPart is the\n * canonical envelope for both the success arm (`completed`) and the error\n * arms (`failed` / `rejected` / `canceled`). The criterion intentionally\n * matches the unwrapper's terminal-state extraction in\n * `unwrapA2AResponse` — keeping protocol layer and unwrapper in lockstep\n * across all terminal states, not just the error arms.\n *\n * Used to short-circuit the generic \"A2A agent returned error\" throw when\n * a non-conformant seller surfaces both a transport-level `result.error`\n * hint and the canonical artifact envelope side-by-side. The DataPart is\n * authoritative; the throw would otherwise swallow it.\n */\nfunction hasTerminalTaskWithDataArtifact(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false;\n const result = (response as { result?: unknown }).result;\n if (!result || typeof result !== 'object') return false;\n const r = result as { kind?: unknown; status?: unknown; artifacts?: unknown };\n if (r.kind !== 'task') return false;\n const status = r.status as { state?: unknown } | undefined;\n if (typeof status?.state !== 'string' || !TERMINAL_A2A_STATES.has(status.state)) return false;\n return getLatestA2ADataPartFromResponse(response) !== undefined;\n}\n\n/**\n * Protocol-level session identifiers that ride on the A2A Message envelope\n * (not in the skill parameters). `contextId` binds sends to a server-side\n * conversation; `taskId` resumes an existing non-terminal task.\n *\n * Callers (buyers) typically retain these across calls on a per-conversation\n * AgentClient; see AgentClient.getContextId() / getPendingTaskId().\n */\nexport interface A2ASessionIds {\n contextId?: string;\n taskId?: string;\n}\n\nexport async function callA2ATool(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n pushNotificationConfig?: PushNotificationConfig,\n customHeaders?: Record<string, string>,\n signingContext?: AgentSigningContext,\n session?: A2ASessionIds,\n signal?: AbortSignal,\n requestTimeoutMs?: number,\n fetchFn?: typeof fetch\n): Promise<unknown> {\n return withSpan(\n 'adcp.a2a.call_tool',\n {\n 'adcp.tool': toolName,\n 'http.url': agentUrl,\n },\n async () => {\n const context: A2ACallContext = {\n customHeaders,\n debugLogs,\n got401Ref: { value: false },\n signal,\n requestTimeoutMs,\n fetchFn,\n };\n return signingContextStorage.run(signingContext, () =>\n callContextStorage.run(context, () =>\n callA2AToolImpl(\n agentUrl,\n toolName,\n parameters,\n authToken,\n debugLogs,\n pushNotificationConfig,\n context,\n session\n )\n )\n );\n }\n );\n}\n\nasync function callA2AToolImpl(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken: string | undefined,\n debugLogs: DebugLogEntry[],\n pushNotificationConfig: PushNotificationConfig | undefined,\n context: A2ACallContext,\n session: A2ASessionIds | undefined\n): Promise<unknown> {\n try {\n const client = await getOrCreateA2AClient(\n agentUrl,\n authToken,\n context.customHeaders,\n !!context.signal || context.requestTimeoutMs !== undefined\n );\n\n const requestPayload: {\n message: {\n messageId: string;\n role: string;\n kind: string;\n parts: Array<{ kind: string; data: { skill: string; parameters: Record<string, unknown> } }>;\n contextId?: string;\n taskId?: string;\n };\n configuration?: { pushNotificationConfig: PushNotificationConfig };\n } = {\n message: {\n messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n role: 'user',\n kind: 'message',\n parts: [\n {\n kind: 'data',\n data: {\n skill: toolName,\n parameters: parameters,\n },\n },\n ],\n ...(session?.contextId && { contextId: session.contextId }),\n ...(session?.taskId && { taskId: session.taskId }),\n },\n };\n\n if (pushNotificationConfig) {\n requestPayload.configuration = {\n pushNotificationConfig: pushNotificationConfig,\n };\n }\n\n const payloadSize = JSON.stringify(requestPayload).length;\n const redactedParameters = redactArgsForLog(parameters);\n const redactedPayload = {\n ...requestPayload,\n message: {\n ...requestPayload.message,\n parts: [\n {\n kind: 'data',\n data: { skill: toolName, parameters: redactedParameters },\n },\n ],\n },\n ...(requestPayload.configuration && {\n configuration: {\n pushNotificationConfig: redactPushNotificationConfigForDebug(\n requestPayload.configuration.pushNotificationConfig\n )!,\n },\n }),\n };\n debugLogs.push({\n type: 'info',\n message: `A2A: Calling skill ${toolName} with parameters: ${JSON.stringify(\n redactedParameters\n )}. Payload size: ${payloadSize} bytes`,\n timestamp: new Date().toISOString(),\n payloadSize,\n actualPayload: redactedPayload,\n });\n\n debugLogs.push({\n type: 'info',\n message: `A2A: Sending message via sendMessage()`,\n timestamp: new Date().toISOString(),\n skill: toolName,\n });\n\n const messageResponse = await client.sendMessage(requestPayload);\n\n debugLogs.push({\n type: messageResponse?.error ? 'error' : 'success',\n message: `A2A: Response received (${messageResponse?.error ? 'error' : 'success'})`,\n timestamp: new Date().toISOString(),\n response: messageResponse,\n skill: toolName,\n });\n\n if (messageResponse?.error || messageResponse?.result?.error) {\n // adcp-client#1575: when the seller emits a spec-compliant terminal-state\n // Task carrying an `adcp_error` DataPart (per AdCP transport-errors §A2A\n // Binding), the structured artifact is canonical — even if the seller\n // also surfaced a transport-level error string. Pass the response\n // through so the upstream unwrapper extracts `adcp_error.code` instead\n // of throwing a generic message that loses the AdCP error envelope.\n if (!hasTerminalTaskWithDataArtifact(messageResponse)) {\n const errorObj = messageResponse.error || messageResponse.result?.error;\n const errorMessage = errorObj.message || JSON.stringify(errorObj);\n throw new Error(`A2A agent returned error: ${errorMessage}`);\n }\n }\n\n return messageResponse;\n } catch (error: unknown) {\n if (is401Error(error, context.got401Ref.value)) {\n // Evict this cache entry — credential may have expired or been\n // revoked. Same disambiguator as the original `getOrCreateA2AClient`\n // call: when the credential rode on customHeaders.Authorization (Basic\n // case) rather than authToken, the cache key must reflect that or we\n // evict the wrong entry.\n const signingContext = signingContextStorage.getStore();\n a2aClientCache.delete(a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, context.customHeaders));\n\n debugLogs.push({\n type: 'error',\n message: `A2A: Authentication required for ${agentUrl}`,\n timestamp: new Date().toISOString(),\n });\n\n // Re-probe to surface the WWW-Authenticate scheme on the error envelope.\n // Basic-fronted agents (Apigee/Kong/AWS API GW with a BasicAuthentication\n // policy) would otherwise leave consumers chasing OAuth metadata that\n // doesn't exist. Matches the MCP discovery throw site in\n // `SingleAgentClient.discoverMCPEndpoint`.\n const challenge = await probeAuthChallenge(agentUrl, { fetchFn: context.fetchFn });\n const oauthMetadata = await discoverOAuthMetadata(agentUrl, { fetch: context.fetchFn });\n throw new AuthenticationRequiredError(agentUrl, oauthMetadata || undefined, undefined, challenge ?? undefined);\n }\n\n throw error;\n }\n}\n"],"mappings":"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","names":["import_client","A2AClientImpl"]}
|
|
@@ -15,7 +15,7 @@ import { buildAgentSigningFetch, signingContextStorage } from "../signing/client
|
|
|
15
15
|
import { toSignerKey, isInlineSigningConfig, isProviderSigningConfig } from "../signing/agent-fetch.mjs";
|
|
16
16
|
import { createSigningFetch } from "../signing/fetch.mjs";
|
|
17
17
|
import { createSigningFetchAsync } from "../signing/fetch-async.mjs";
|
|
18
|
-
import {
|
|
18
|
+
import { redactArgsForLog } from "../utils/redact-args.mjs";
|
|
19
19
|
import { wrapFetchWithCapture } from "./rawResponseCapture.mjs";
|
|
20
20
|
import { wrapFetchWithSizeLimit } from "./responseSizeLimit.mjs";
|
|
21
21
|
import { wrapFetchWithTransportDiagnostics } from "./transportDiagnostics.mjs";
|
|
@@ -298,7 +298,7 @@ async function callA2AToolImpl(agentUrl, toolName, parameters, authToken, debugL
|
|
|
298
298
|
};
|
|
299
299
|
}
|
|
300
300
|
const payloadSize = JSON.stringify(requestPayload).length;
|
|
301
|
-
const redactedParameters =
|
|
301
|
+
const redactedParameters = redactArgsForLog(parameters);
|
|
302
302
|
const redactedPayload = {
|
|
303
303
|
...requestPayload,
|
|
304
304
|
message: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/protocols/a2a.ts"],"sourcesContent":["import { fileURLToPath as __adcpFileURLToPath } from 'node:url';\nimport { dirname as __adcpDirname } from 'node:path';\nimport { createRequire as __adcpCreateRequire } from 'node:module';\nconst __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));\nconst require = __adcpCreateRequire(import.meta.url);\n// Official A2A client implementation - NO FALLBACKS\nimport { A2AClient as A2AClientImpl } from '@a2a-js/sdk/client';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHmac, randomUUID } from 'node:crypto';\nimport type { PushNotificationConfig } from '../types/tools.generated';\nimport type { DebugLogEntry } from '../types/adcp';\nimport { AuthenticationRequiredError, is401Error } from '../errors';\nimport { discoverOAuthMetadata } from '../auth/oauth/discovery';\nimport { probeAuthChallenge } from '../auth/oauth/authorization-required';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { isAgentCardPath, buildCardUrls } from '../utils/a2a-discovery';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport { toSignerKey, isInlineSigningConfig, isProviderSigningConfig } from '../signing/agent-fetch';\nimport { createSigningFetch, type FetchLike } from '../signing/fetch';\nimport { createSigningFetchAsync } from '../signing/fetch-async';\nimport type { AgentConfig } from '../types/adcp';\nimport { redactIdempotencyKeyInArgs } from '../utils/idempotency';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\nimport { DEFAULT_REQUEST_TIMEOUT_MS, resolveRequestTimeoutMs, withAbortSignal } from './abort';\nimport { getLatestA2ADataPartFromResponse } from '../utils/a2a-artifacts';\n\n// The A2A SDK client is used untyped: request/response shapes are validated at\n// runtime against the AdCP wire contract, not against the SDK's exported\n// types. Preserves the prior behaviour of the CommonJS `require` form.\nconst A2AClient: any = A2AClientImpl;\n\nif (!A2AClient) {\n throw new Error('A2A SDK client is required. Please install @a2a-js/sdk');\n}\n\n/**\n * Per-call state flowed through AsyncLocalStorage so concurrent callers\n * that share a cached A2AClient don't clobber each other's debugLogs,\n * customHeaders, or 401 flag.\n */\ninterface A2ACallContext {\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n got401Ref: { value: boolean };\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n}\n\nconst callContextStorage = new AsyncLocalStorage<A2ACallContext>();\n\n/**\n * Cached A2AClient keyed by (agentUrl, authToken hash). Avoids re-fetching\n * /.well-known/agent.json on every tool call. The cached client's fetchImpl\n * reads per-call state from callContextStorage, so concurrent calls to the\n * same cache entry are safe.\n *\n * Process-global singleton — not suitable for multi-tenant servers that\n * want per-tenant isolation (use separate processes or explicit cache keys).\n */\nconst a2aClientCache = new Map<string, InstanceType<typeof A2AClient>>();\nconst pendingA2AClients = new Map<string, Promise<InstanceType<typeof A2AClient>>>();\n\n/**\n * Build the A2A connection-cache key. Mirrors the rationale in\n * `src/lib/protocols/mcp.ts:connectionCacheKey`: when the caller is using a\n * non-bearer scheme (RFC 7617 Basic from the CLI's `--auth-scheme basic`\n * shape, or any future caller-injected `Authorization` header), `authToken`\n * is undefined and the credential rides on the customHeaders bag. Hashing\n * only `authToken` would let two callers with different `user:pass`\n * credentials share a single cached A2AClient — single-CLI-process safe,\n * multi-tenant SDK consumer not safe.\n *\n * `customHeaders` also feed the key so tenant/routing headers cannot reuse a\n * card/client discovered for another caller. Scoped fetch calls bypass this\n * cache entirely (see `getOrCreateA2AClient`).\n */\nfunction a2aCacheKey(\n agentUrl: string,\n authToken?: string,\n signingCacheKey?: string,\n customHeaders?: Record<string, string>\n): string {\n // 64-bit Map-key disambiguator — NOT a password hash. The cached client\n // closes over the full credential, so a hypothetical hash collision still\n // sends the original credential on the wire, just possibly cache-miss\n // and reconnect. Routed via `cacheDisambiguator` (HMAC-SHA256 with empty\n // key) instead of bare `createHash` so CodeQL's\n // `js/insufficient-password-hash` heuristic doesn't misclassify the\n // dataflow — see the helper docstring for the full rationale.\n const fingerprint = authToken ?? extractA2AAuthHeader(customHeaders);\n const tokenSuffix = fingerprint ? `::${cacheDisambiguator(fingerprint)}` : '';\n const headersKey = headersCacheDisambiguator(customHeaders);\n const headersSuffix = headersKey ? `::headers:${headersKey}` : '';\n const signingSuffix = signingCacheKey ? `::${signingCacheKey}` : '';\n return `${agentUrl}${tokenSuffix}${headersSuffix}${signingSuffix}`;\n}\n\n/**\n * Produce a stable 64-bit Map-key disambiguator from credential material.\n * Mirrors the helper in `src/lib/protocols/mcp.ts` — the two protocol\n * modules intentionally don't share runtime imports, so each carries its\n * own copy. See the MCP-side docstring for the full rationale.\n */\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex').slice(0, 16);\n}\n\n/**\n * Case-insensitive lookup of `Authorization` on a header bag. Mirrors the\n * MCP-side helper; A2A keeps its own copy because the two protocol modules\n * intentionally don't share runtime imports.\n */\nfunction extractA2AAuthHeader(headers: Record<string, string> | undefined): string | undefined {\n if (!headers) return undefined;\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === 'authorization' && value) return value;\n }\n return undefined;\n}\n\nfunction headersCacheDisambiguator(headers?: Record<string, string>): string | undefined {\n const entries = Object.entries(headers ?? {})\n .filter(([key]) => {\n const lower = key.toLowerCase();\n return lower !== 'traceparent' && lower !== 'tracestate' && lower !== 'baggage';\n })\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([a], [b]) => a.localeCompare(b));\n return entries.length > 0 ? cacheDisambiguator(JSON.stringify(entries)) : undefined;\n}\n\nfunction redactHeadersForDebug(headers: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.keys(headers).map(key => [key, '***']));\n}\n\nfunction redactPushNotificationConfigForDebug(\n config: PushNotificationConfig | undefined\n): PushNotificationConfig | undefined {\n if (!config) return undefined;\n return {\n ...config,\n ...(config.token && { token: '***' }),\n ...(config.authentication && {\n authentication: {\n ...config.authentication,\n ...(config.authentication.credentials && { credentials: '***' }),\n },\n }),\n };\n}\n\n/**\n * Clear all cached A2A clients. Called by closeConnections('a2a').\n * A2A clients hold no persistent network resources (unlike MCP), so this\n * is just cache eviction.\n */\nexport function closeA2AConnections(): void {\n a2aClientCache.clear();\n pendingA2AClients.clear();\n}\n\n/**\n * Wall-clock cap on a fire-and-forget cancel. A2A sellers that accept the\n * TCP connect but never respond would otherwise pin the event loop past the\n * buyer's abort, which defeats the whole point of fire-and-forget.\n */\nconst CANCEL_TIMEOUT_MS = 5000;\n\n/**\n * Fire-and-forget A2A tasks/cancel for an in-flight task (A2A 0.3.0 §7.4).\n *\n * Sends a raw JSON-RPC 2.0 POST directly to the agent endpoint with the same\n * auth header shape as `callA2AToolImpl` (Bearer + x-adcp-auth). Does NOT\n * enter `callContextStorage` — debug-log capture and 401-cache-eviction are\n * intentionally skipped for best-effort cancellation.\n *\n * **Auth-code OAuth gap:** `authToken` is resolved by `getAuthToken(agent)`,\n * which returns `undefined` for authorization-code-flow sellers (those tokens\n * are managed by the OAuth provider path in `ProtocolClient.callTool`, not\n * accessible here). Cancel calls to those sellers go out unauthenticated and\n * will likely 401 non-fatally.\n *\n * **Phase 2 (adcp-client#1617 follow-up):** when `agent.request_signing` is\n * configured, the cancel POST is signed with the agent's signer key. The\n * `signingContextStorage` ALS scope around `callA2AToolImpl` does NOT extend\n * into `pollTaskCompletion` (sibling promise trees), so we can't replay the\n * captured ALS context — instead we rebuild a one-shot signer fetch from\n * `agent.request_signing` directly and use it for this single POST. Inline\n * keys go through `createSigningFetch` (sync); provider-backed configs use\n * `createSigningFetchAsync`. A `signed-requests` seller that requires\n * signing on `tasks/cancel` (or applies a uniform \"all mutating POSTs must\n * be signed\" policy) now accepts the cancel; one without signing config on\n * the agent gets the Phase 1 unsigned path.\n *\n * The caller is responsible for swallowing errors: cancel failure\n * (TaskNotCancelable, network error, auth rejection, network timeout) is\n * non-fatal because the buyer is already abandoning the task.\n *\n * @param agent The agent config (used for URL, auth token, signing).\n * @param taskId The server-assigned A2A Task.id to cancel.\n */\nexport async function cancelA2ATask(agent: AgentConfig, taskId: string, fetchFn?: typeof fetch): Promise<void> {\n // Defense-in-depth (ad-tech-protocol-expert review of #1640): the cancel\n // POST is JSON-RPC at the bare A2A endpoint. Calling this on an MCP agent\n // would POST `tasks/cancel` JSON-RPC at an MCP endpoint and 404. The\n // single call site (`pollTaskCompletion`) already gates on\n // `agent.protocol === 'a2a'`; this assertion catches future call sites\n // that forget the gate.\n if (agent.protocol !== 'a2a') {\n return;\n }\n const agentUrl = agent.agent_uri;\n const authToken = agent.auth_token;\n\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json',\n };\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n headers['x-adcp-auth'] = authToken;\n }\n // JSON-RPC 2.0 §4.1.3: `id: null` flags the request as a *notification*,\n // and the server MUST NOT respond. A2A 0.3.0 §7.4 defines `tasks/cancel`\n // as a request/response method (returns the canceled `Task` or\n // `TaskNotCancelableError`), so a strict A2A server can legitimately\n // reject `id: null` as a protocol violation. Use a real id and just drop\n // the response on the floor — fire-and-forget is the caller's discipline,\n // not a wire-protocol claim.\n const body = JSON.stringify({\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/cancel',\n params: { id: taskId },\n });\n // Bound the cancel: a hung fetch would orphan-pin the event loop past the\n // buyer's abort, defeating fire-and-forget. AbortSignal.timeout() is the\n // standard primitive; the caller's `.catch()` swallows the AbortError.\n const init: RequestInit = {\n method: 'POST',\n headers,\n body,\n signal: AbortSignal.timeout(CANCEL_TIMEOUT_MS),\n };\n\n // adcp-client#1617 Phase 2: sign the cancel POST when the agent has a\n // signer configured. We bypass the `buildAgentSigningFetch` capability-\n // gate path because `tasks/cancel` is an A2A protocol method, not an\n // AdCP tool — the seller's `request_signing.supported_for` typically\n // lists AdCP tool names, not protocol-level methods. The right model\n // here: if the agent claims signing AT ALL, sign every mutating POST\n // we send to it on the cancel path. Sellers with uniform \"must be\n // signed\" policies accept this; sellers that only check signing on\n // specific AdCP tools simply ignore the extra signature.\n //\n // TODO(adcp#4318, adcp-client#1617): when the AdCP spec adds explicit\n // verifier coverage for A2A protocol methods (likely in 3.1 as a new\n // `protocol_methods_supported_for` / `protocol_methods_required_for`\n // field on `request_signing`), narrow this default by reading the\n // seller's advertised coverage from `getCapability()` and gating on\n // the `tasks/cancel` membership. The over-sign default stays as the\n // fallback for spec-silent sellers (3.0.x and earlier).\n if (agent.request_signing) {\n const upstream: FetchLike = (input, ini) =>\n fetchFn ? fetchFn(input as RequestInfo | URL, ini) : fetch(input as RequestInfo, ini);\n if (isInlineSigningConfig(agent.request_signing)) {\n const signed = createSigningFetch(upstream, toSignerKey(agent.request_signing));\n await signed(agentUrl, init);\n return;\n }\n if (isProviderSigningConfig(agent.request_signing)) {\n const signed = createSigningFetchAsync(upstream, agent.request_signing.provider);\n await signed(agentUrl, init);\n return;\n }\n }\n\n await (fetchFn ?? fetch)(agentUrl, init);\n}\n\nasync function getOrCreateA2AClient(\n agentUrl: string,\n authToken: string | undefined,\n customHeaders?: Record<string, string>,\n bypassCache = false\n): Promise<InstanceType<typeof A2AClient>> {\n const signingContext = signingContextStorage.getStore();\n const fetchFn = callContextStorage.getStore()?.fetchFn;\n const cacheKey = a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, customHeaders);\n // Scoped fetchers often carry request/tenant-specific egress policy. Keep\n // those calls one-shot so neither agent-card discovery nor a client created\n // under one policy can be reused by another caller, and so short-lived\n // closure identities do not grow the global cache without bound.\n if (bypassCache || fetchFn) {\n return createA2AClient(agentUrl, authToken);\n }\n const cached = a2aClientCache.get(cacheKey);\n if (cached) return cached;\n\n const pending = pendingA2AClients.get(cacheKey);\n if (pending) return pending;\n\n const promise = createA2AClient(agentUrl, authToken)\n .then(client => {\n a2aClientCache.set(cacheKey, client);\n return client;\n })\n .finally(() => {\n pendingA2AClients.delete(cacheKey);\n });\n\n pendingA2AClients.set(cacheKey, promise);\n return promise;\n}\n\nasync function createA2AClient(\n agentUrl: string,\n authToken: string | undefined\n): Promise<InstanceType<typeof A2AClient>> {\n const fetchImpl = buildFetchImpl(authToken);\n const cardUrls = buildCardUrls(agentUrl);\n\n const context = callContextStorage.getStore();\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Discovering agent card at ${cardUrls.join(', ')}`,\n timestamp: new Date().toISOString(),\n });\n\n let client: InstanceType<typeof A2AClient> | undefined;\n let lastError: Error = new Error(`A2A agent card not found at ${cardUrls.join(', ')}`);\n for (const cardUrl of cardUrls) {\n try {\n client = await A2AClient.fromCardUrl(cardUrl, { fetchImpl });\n break;\n } catch (err: unknown) {\n lastError = err as Error;\n if (context?.got401Ref.value) break;\n }\n }\n if (!client) throw lastError;\n\n return client;\n}\n\nfunction buildFetchImpl(authToken: string | undefined) {\n // The A2A client is cached per (url, authToken, signingCacheKey). We capture\n // the signing context at client-creation time so all subsequent calls that\n // share this cached client use the same signing identity — changing identity\n // requires a different cache entry, built on a separate call that enters ALS\n // with a different context.\n const signingContext = signingContextStorage.getStore();\n\n // Innermost wrapper: enforce response body size cap from the active\n // `responseSizeLimitStorage` slot. Pass-through when no slot is set.\n const networkFetch = wrapFetchWithTransportDiagnostics(\n wrapFetchWithSizeLimit((input, init) => {\n const scopedFetch = callContextStorage.getStore()?.fetchFn;\n return scopedFetch ? scopedFetch(input, init) : fetch(input as any, init);\n })\n );\n\n // Inner fetch handles auth/header injection and 401 detection. If the\n // agent has request-signing configured, we wrap it with the AdCP signing\n // fetch so the signature covers the exact bytes we're about to send (auth\n // headers included, since the signer re-reads the final header record).\n const baseFetch = async (url: string | URL | Request, options?: RequestInit): Promise<Response> => {\n const context = callContextStorage.getStore();\n\n const existingHeaders: Record<string, string> = {};\n if (options?.headers) {\n if (options.headers instanceof Headers) {\n options.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(options.headers)) {\n for (const [key, value] of options.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, options.headers);\n }\n }\n\n // Only inject trace context headers for actual tool requests, not discovery.\n // The agent card endpoint is external/untrusted — don't leak trace IDs to it.\n const urlString = typeof url === 'string' ? url : url.toString();\n const isDiscoveryRequest = isAgentCardPath(urlString);\n const traceHeaders = isDiscoveryRequest ? {} : injectTraceHeaders();\n const requestTimeoutMs = isDiscoveryRequest\n ? resolveRequestTimeoutMs(context?.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS)\n : resolveRequestTimeoutMs(context?.requestTimeoutMs);\n\n // Merge: existing < trace < custom < auth (auth always wins)\n const headers: Record<string, string> = {\n ...existingHeaders,\n ...traceHeaders,\n ...context?.customHeaders,\n ...(authToken && {\n Authorization: `Bearer ${authToken}`,\n 'x-adcp-auth': authToken,\n }),\n };\n\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Fetch to ${urlString}`,\n timestamp: new Date().toISOString(),\n hasAuth: !!authToken,\n headers: redactHeadersForDebug(headers),\n });\n\n const response = await withAbortSignal<Response>([context?.signal, options?.signal], requestTimeoutMs, signal =>\n networkFetch(url as any, { ...options, headers, signal })\n );\n\n if (response.status === 401 && context) {\n context.got401Ref.value = true;\n }\n\n return response;\n };\n\n if (!signingContext) return wrapFetchWithCapture(baseFetch);\n\n // The signing wrapper assembles headers into the signature base. We invoke\n // it first so the signer sees the caller-supplied headers; baseFetch then\n // overlays auth/trace headers afterwards — A2A's auth scheme (bearer) is\n // not among the MANDATORY_COMPONENTS and is injected by the counterparty's\n // transport layer, not signed.\n const signingFetch = buildAgentSigningFetch({\n upstream: (input, init) => baseFetch(input as any, init),\n signing: signingContext.signing,\n getCapability: signingContext.getCapability,\n });\n return wrapFetchWithCapture(signingFetch as typeof fetch);\n}\n\n/**\n * Terminal A2A task states per A2A 0.3.0 §3.4. Only these can carry the\n * AdCP-mandated artifact + DataPart envelope (per transport-errors §A2A\n * Binding); intermediate states (`working`, `submitted`, `input-required`,\n * `auth-required`) carry no completion artifact.\n */\nconst TERMINAL_A2A_STATES = new Set(['completed', 'failed', 'rejected', 'canceled']);\n\n/**\n * Detect whether a JSON-RPC response carries a spec-compliant terminal-state\n * Task with at least one artifact containing a structured DataPart payload.\n * Per AdCP transport-errors §A2A Binding, the artifact's DataPart is the\n * canonical envelope for both the success arm (`completed`) and the error\n * arms (`failed` / `rejected` / `canceled`). The criterion intentionally\n * matches the unwrapper's terminal-state extraction in\n * `unwrapA2AResponse` — keeping protocol layer and unwrapper in lockstep\n * across all terminal states, not just the error arms.\n *\n * Used to short-circuit the generic \"A2A agent returned error\" throw when\n * a non-conformant seller surfaces both a transport-level `result.error`\n * hint and the canonical artifact envelope side-by-side. The DataPart is\n * authoritative; the throw would otherwise swallow it.\n */\nfunction hasTerminalTaskWithDataArtifact(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false;\n const result = (response as { result?: unknown }).result;\n if (!result || typeof result !== 'object') return false;\n const r = result as { kind?: unknown; status?: unknown; artifacts?: unknown };\n if (r.kind !== 'task') return false;\n const status = r.status as { state?: unknown } | undefined;\n if (typeof status?.state !== 'string' || !TERMINAL_A2A_STATES.has(status.state)) return false;\n return getLatestA2ADataPartFromResponse(response) !== undefined;\n}\n\n/**\n * Protocol-level session identifiers that ride on the A2A Message envelope\n * (not in the skill parameters). `contextId` binds sends to a server-side\n * conversation; `taskId` resumes an existing non-terminal task.\n *\n * Callers (buyers) typically retain these across calls on a per-conversation\n * AgentClient; see AgentClient.getContextId() / getPendingTaskId().\n */\nexport interface A2ASessionIds {\n contextId?: string;\n taskId?: string;\n}\n\nexport async function callA2ATool(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n pushNotificationConfig?: PushNotificationConfig,\n customHeaders?: Record<string, string>,\n signingContext?: AgentSigningContext,\n session?: A2ASessionIds,\n signal?: AbortSignal,\n requestTimeoutMs?: number,\n fetchFn?: typeof fetch\n): Promise<unknown> {\n return withSpan(\n 'adcp.a2a.call_tool',\n {\n 'adcp.tool': toolName,\n 'http.url': agentUrl,\n },\n async () => {\n const context: A2ACallContext = {\n customHeaders,\n debugLogs,\n got401Ref: { value: false },\n signal,\n requestTimeoutMs,\n fetchFn,\n };\n return signingContextStorage.run(signingContext, () =>\n callContextStorage.run(context, () =>\n callA2AToolImpl(\n agentUrl,\n toolName,\n parameters,\n authToken,\n debugLogs,\n pushNotificationConfig,\n context,\n session\n )\n )\n );\n }\n );\n}\n\nasync function callA2AToolImpl(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken: string | undefined,\n debugLogs: DebugLogEntry[],\n pushNotificationConfig: PushNotificationConfig | undefined,\n context: A2ACallContext,\n session: A2ASessionIds | undefined\n): Promise<unknown> {\n try {\n const client = await getOrCreateA2AClient(\n agentUrl,\n authToken,\n context.customHeaders,\n !!context.signal || context.requestTimeoutMs !== undefined\n );\n\n const requestPayload: {\n message: {\n messageId: string;\n role: string;\n kind: string;\n parts: Array<{ kind: string; data: { skill: string; parameters: Record<string, unknown> } }>;\n contextId?: string;\n taskId?: string;\n };\n configuration?: { pushNotificationConfig: PushNotificationConfig };\n } = {\n message: {\n messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n role: 'user',\n kind: 'message',\n parts: [\n {\n kind: 'data',\n data: {\n skill: toolName,\n parameters: parameters,\n },\n },\n ],\n ...(session?.contextId && { contextId: session.contextId }),\n ...(session?.taskId && { taskId: session.taskId }),\n },\n };\n\n if (pushNotificationConfig) {\n requestPayload.configuration = {\n pushNotificationConfig: pushNotificationConfig,\n };\n }\n\n const payloadSize = JSON.stringify(requestPayload).length;\n const redactedParameters = redactIdempotencyKeyInArgs(parameters);\n const redactedPayload = {\n ...requestPayload,\n message: {\n ...requestPayload.message,\n parts: [\n {\n kind: 'data',\n data: { skill: toolName, parameters: redactedParameters },\n },\n ],\n },\n ...(requestPayload.configuration && {\n configuration: {\n pushNotificationConfig: redactPushNotificationConfigForDebug(\n requestPayload.configuration.pushNotificationConfig\n )!,\n },\n }),\n };\n debugLogs.push({\n type: 'info',\n message: `A2A: Calling skill ${toolName} with parameters: ${JSON.stringify(\n redactedParameters\n )}. Payload size: ${payloadSize} bytes`,\n timestamp: new Date().toISOString(),\n payloadSize,\n actualPayload: redactedPayload,\n });\n\n debugLogs.push({\n type: 'info',\n message: `A2A: Sending message via sendMessage()`,\n timestamp: new Date().toISOString(),\n skill: toolName,\n });\n\n const messageResponse = await client.sendMessage(requestPayload);\n\n debugLogs.push({\n type: messageResponse?.error ? 'error' : 'success',\n message: `A2A: Response received (${messageResponse?.error ? 'error' : 'success'})`,\n timestamp: new Date().toISOString(),\n response: messageResponse,\n skill: toolName,\n });\n\n if (messageResponse?.error || messageResponse?.result?.error) {\n // adcp-client#1575: when the seller emits a spec-compliant terminal-state\n // Task carrying an `adcp_error` DataPart (per AdCP transport-errors §A2A\n // Binding), the structured artifact is canonical — even if the seller\n // also surfaced a transport-level error string. Pass the response\n // through so the upstream unwrapper extracts `adcp_error.code` instead\n // of throwing a generic message that loses the AdCP error envelope.\n if (!hasTerminalTaskWithDataArtifact(messageResponse)) {\n const errorObj = messageResponse.error || messageResponse.result?.error;\n const errorMessage = errorObj.message || JSON.stringify(errorObj);\n throw new Error(`A2A agent returned error: ${errorMessage}`);\n }\n }\n\n return messageResponse;\n } catch (error: unknown) {\n if (is401Error(error, context.got401Ref.value)) {\n // Evict this cache entry — credential may have expired or been\n // revoked. Same disambiguator as the original `getOrCreateA2AClient`\n // call: when the credential rode on customHeaders.Authorization (Basic\n // case) rather than authToken, the cache key must reflect that or we\n // evict the wrong entry.\n const signingContext = signingContextStorage.getStore();\n a2aClientCache.delete(a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, context.customHeaders));\n\n debugLogs.push({\n type: 'error',\n message: `A2A: Authentication required for ${agentUrl}`,\n timestamp: new Date().toISOString(),\n });\n\n // Re-probe to surface the WWW-Authenticate scheme on the error envelope.\n // Basic-fronted agents (Apigee/Kong/AWS API GW with a BasicAuthentication\n // policy) would otherwise leave consumers chasing OAuth metadata that\n // doesn't exist. Matches the MCP discovery throw site in\n // `SingleAgentClient.discoverMCPEndpoint`.\n const challenge = await probeAuthChallenge(agentUrl, { fetchFn: context.fetchFn });\n const oauthMetadata = await discoverOAuthMetadata(agentUrl, { fetch: context.fetchFn });\n throw new AuthenticationRequiredError(agentUrl, oauthMetadata || undefined, undefined, challenge ?? undefined);\n }\n\n throw error;\n }\n}\n"],"mappings":"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","names":["require"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/protocols/a2a.ts"],"sourcesContent":["import { fileURLToPath as __adcpFileURLToPath } from 'node:url';\nimport { dirname as __adcpDirname } from 'node:path';\nimport { createRequire as __adcpCreateRequire } from 'node:module';\nconst __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));\nconst require = __adcpCreateRequire(import.meta.url);\n// Official A2A client implementation - NO FALLBACKS\nimport { A2AClient as A2AClientImpl } from '@a2a-js/sdk/client';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { createHmac, randomUUID } from 'node:crypto';\nimport type { PushNotificationConfig } from '../types/tools.generated';\nimport type { DebugLogEntry } from '../types/adcp';\nimport { AuthenticationRequiredError, is401Error } from '../errors';\nimport { discoverOAuthMetadata } from '../auth/oauth/discovery';\nimport { probeAuthChallenge } from '../auth/oauth/authorization-required';\nimport { withSpan, injectTraceHeaders } from '../observability/tracing';\nimport { isAgentCardPath, buildCardUrls } from '../utils/a2a-discovery';\nimport { buildAgentSigningFetch, signingContextStorage, type AgentSigningContext } from '../signing/client';\nimport { toSignerKey, isInlineSigningConfig, isProviderSigningConfig } from '../signing/agent-fetch';\nimport { createSigningFetch, type FetchLike } from '../signing/fetch';\nimport { createSigningFetchAsync } from '../signing/fetch-async';\nimport type { AgentConfig } from '../types/adcp';\nimport { redactArgsForLog } from '../utils/redact-args';\nimport { wrapFetchWithCapture } from './rawResponseCapture';\nimport { wrapFetchWithSizeLimit } from './responseSizeLimit';\nimport { wrapFetchWithTransportDiagnostics } from './transportDiagnostics';\nimport { DEFAULT_REQUEST_TIMEOUT_MS, resolveRequestTimeoutMs, withAbortSignal } from './abort';\nimport { getLatestA2ADataPartFromResponse } from '../utils/a2a-artifacts';\n\n// The A2A SDK client is used untyped: request/response shapes are validated at\n// runtime against the AdCP wire contract, not against the SDK's exported\n// types. Preserves the prior behaviour of the CommonJS `require` form.\nconst A2AClient: any = A2AClientImpl;\n\nif (!A2AClient) {\n throw new Error('A2A SDK client is required. Please install @a2a-js/sdk');\n}\n\n/**\n * Per-call state flowed through AsyncLocalStorage so concurrent callers\n * that share a cached A2AClient don't clobber each other's debugLogs,\n * customHeaders, or 401 flag.\n */\ninterface A2ACallContext {\n customHeaders?: Record<string, string>;\n debugLogs: DebugLogEntry[];\n got401Ref: { value: boolean };\n signal?: AbortSignal;\n requestTimeoutMs?: number;\n fetchFn?: typeof fetch;\n}\n\nconst callContextStorage = new AsyncLocalStorage<A2ACallContext>();\n\n/**\n * Cached A2AClient keyed by (agentUrl, authToken hash). Avoids re-fetching\n * /.well-known/agent.json on every tool call. The cached client's fetchImpl\n * reads per-call state from callContextStorage, so concurrent calls to the\n * same cache entry are safe.\n *\n * Process-global singleton — not suitable for multi-tenant servers that\n * want per-tenant isolation (use separate processes or explicit cache keys).\n */\nconst a2aClientCache = new Map<string, InstanceType<typeof A2AClient>>();\nconst pendingA2AClients = new Map<string, Promise<InstanceType<typeof A2AClient>>>();\n\n/**\n * Build the A2A connection-cache key. Mirrors the rationale in\n * `src/lib/protocols/mcp.ts:connectionCacheKey`: when the caller is using a\n * non-bearer scheme (RFC 7617 Basic from the CLI's `--auth-scheme basic`\n * shape, or any future caller-injected `Authorization` header), `authToken`\n * is undefined and the credential rides on the customHeaders bag. Hashing\n * only `authToken` would let two callers with different `user:pass`\n * credentials share a single cached A2AClient — single-CLI-process safe,\n * multi-tenant SDK consumer not safe.\n *\n * `customHeaders` also feed the key so tenant/routing headers cannot reuse a\n * card/client discovered for another caller. Scoped fetch calls bypass this\n * cache entirely (see `getOrCreateA2AClient`).\n */\nfunction a2aCacheKey(\n agentUrl: string,\n authToken?: string,\n signingCacheKey?: string,\n customHeaders?: Record<string, string>\n): string {\n // 64-bit Map-key disambiguator — NOT a password hash. The cached client\n // closes over the full credential, so a hypothetical hash collision still\n // sends the original credential on the wire, just possibly cache-miss\n // and reconnect. Routed via `cacheDisambiguator` (HMAC-SHA256 with empty\n // key) instead of bare `createHash` so CodeQL's\n // `js/insufficient-password-hash` heuristic doesn't misclassify the\n // dataflow — see the helper docstring for the full rationale.\n const fingerprint = authToken ?? extractA2AAuthHeader(customHeaders);\n const tokenSuffix = fingerprint ? `::${cacheDisambiguator(fingerprint)}` : '';\n const headersKey = headersCacheDisambiguator(customHeaders);\n const headersSuffix = headersKey ? `::headers:${headersKey}` : '';\n const signingSuffix = signingCacheKey ? `::${signingCacheKey}` : '';\n return `${agentUrl}${tokenSuffix}${headersSuffix}${signingSuffix}`;\n}\n\n/**\n * Produce a stable 64-bit Map-key disambiguator from credential material.\n * Mirrors the helper in `src/lib/protocols/mcp.ts` — the two protocol\n * modules intentionally don't share runtime imports, so each carries its\n * own copy. See the MCP-side docstring for the full rationale.\n */\nfunction cacheDisambiguator(value: string): string {\n return createHmac('sha256', '').update(value).digest('hex').slice(0, 16);\n}\n\n/**\n * Case-insensitive lookup of `Authorization` on a header bag. Mirrors the\n * MCP-side helper; A2A keeps its own copy because the two protocol modules\n * intentionally don't share runtime imports.\n */\nfunction extractA2AAuthHeader(headers: Record<string, string> | undefined): string | undefined {\n if (!headers) return undefined;\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === 'authorization' && value) return value;\n }\n return undefined;\n}\n\nfunction headersCacheDisambiguator(headers?: Record<string, string>): string | undefined {\n const entries = Object.entries(headers ?? {})\n .filter(([key]) => {\n const lower = key.toLowerCase();\n return lower !== 'traceparent' && lower !== 'tracestate' && lower !== 'baggage';\n })\n .map(([key, value]) => [key.toLowerCase(), value] as const)\n .sort(([a], [b]) => a.localeCompare(b));\n return entries.length > 0 ? cacheDisambiguator(JSON.stringify(entries)) : undefined;\n}\n\nfunction redactHeadersForDebug(headers: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.keys(headers).map(key => [key, '***']));\n}\n\nfunction redactPushNotificationConfigForDebug(\n config: PushNotificationConfig | undefined\n): PushNotificationConfig | undefined {\n if (!config) return undefined;\n return {\n ...config,\n ...(config.token && { token: '***' }),\n ...(config.authentication && {\n authentication: {\n ...config.authentication,\n ...(config.authentication.credentials && { credentials: '***' }),\n },\n }),\n };\n}\n\n/**\n * Clear all cached A2A clients. Called by closeConnections('a2a').\n * A2A clients hold no persistent network resources (unlike MCP), so this\n * is just cache eviction.\n */\nexport function closeA2AConnections(): void {\n a2aClientCache.clear();\n pendingA2AClients.clear();\n}\n\n/**\n * Wall-clock cap on a fire-and-forget cancel. A2A sellers that accept the\n * TCP connect but never respond would otherwise pin the event loop past the\n * buyer's abort, which defeats the whole point of fire-and-forget.\n */\nconst CANCEL_TIMEOUT_MS = 5000;\n\n/**\n * Fire-and-forget A2A tasks/cancel for an in-flight task (A2A 0.3.0 §7.4).\n *\n * Sends a raw JSON-RPC 2.0 POST directly to the agent endpoint with the same\n * auth header shape as `callA2AToolImpl` (Bearer + x-adcp-auth). Does NOT\n * enter `callContextStorage` — debug-log capture and 401-cache-eviction are\n * intentionally skipped for best-effort cancellation.\n *\n * **Auth-code OAuth gap:** `authToken` is resolved by `getAuthToken(agent)`,\n * which returns `undefined` for authorization-code-flow sellers (those tokens\n * are managed by the OAuth provider path in `ProtocolClient.callTool`, not\n * accessible here). Cancel calls to those sellers go out unauthenticated and\n * will likely 401 non-fatally.\n *\n * **Phase 2 (adcp-client#1617 follow-up):** when `agent.request_signing` is\n * configured, the cancel POST is signed with the agent's signer key. The\n * `signingContextStorage` ALS scope around `callA2AToolImpl` does NOT extend\n * into `pollTaskCompletion` (sibling promise trees), so we can't replay the\n * captured ALS context — instead we rebuild a one-shot signer fetch from\n * `agent.request_signing` directly and use it for this single POST. Inline\n * keys go through `createSigningFetch` (sync); provider-backed configs use\n * `createSigningFetchAsync`. A `signed-requests` seller that requires\n * signing on `tasks/cancel` (or applies a uniform \"all mutating POSTs must\n * be signed\" policy) now accepts the cancel; one without signing config on\n * the agent gets the Phase 1 unsigned path.\n *\n * The caller is responsible for swallowing errors: cancel failure\n * (TaskNotCancelable, network error, auth rejection, network timeout) is\n * non-fatal because the buyer is already abandoning the task.\n *\n * @param agent The agent config (used for URL, auth token, signing).\n * @param taskId The server-assigned A2A Task.id to cancel.\n */\nexport async function cancelA2ATask(agent: AgentConfig, taskId: string, fetchFn?: typeof fetch): Promise<void> {\n // Defense-in-depth (ad-tech-protocol-expert review of #1640): the cancel\n // POST is JSON-RPC at the bare A2A endpoint. Calling this on an MCP agent\n // would POST `tasks/cancel` JSON-RPC at an MCP endpoint and 404. The\n // single call site (`pollTaskCompletion`) already gates on\n // `agent.protocol === 'a2a'`; this assertion catches future call sites\n // that forget the gate.\n if (agent.protocol !== 'a2a') {\n return;\n }\n const agentUrl = agent.agent_uri;\n const authToken = agent.auth_token;\n\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json',\n };\n if (authToken) {\n headers['Authorization'] = `Bearer ${authToken}`;\n headers['x-adcp-auth'] = authToken;\n }\n // JSON-RPC 2.0 §4.1.3: `id: null` flags the request as a *notification*,\n // and the server MUST NOT respond. A2A 0.3.0 §7.4 defines `tasks/cancel`\n // as a request/response method (returns the canceled `Task` or\n // `TaskNotCancelableError`), so a strict A2A server can legitimately\n // reject `id: null` as a protocol violation. Use a real id and just drop\n // the response on the floor — fire-and-forget is the caller's discipline,\n // not a wire-protocol claim.\n const body = JSON.stringify({\n jsonrpc: '2.0',\n id: randomUUID(),\n method: 'tasks/cancel',\n params: { id: taskId },\n });\n // Bound the cancel: a hung fetch would orphan-pin the event loop past the\n // buyer's abort, defeating fire-and-forget. AbortSignal.timeout() is the\n // standard primitive; the caller's `.catch()` swallows the AbortError.\n const init: RequestInit = {\n method: 'POST',\n headers,\n body,\n signal: AbortSignal.timeout(CANCEL_TIMEOUT_MS),\n };\n\n // adcp-client#1617 Phase 2: sign the cancel POST when the agent has a\n // signer configured. We bypass the `buildAgentSigningFetch` capability-\n // gate path because `tasks/cancel` is an A2A protocol method, not an\n // AdCP tool — the seller's `request_signing.supported_for` typically\n // lists AdCP tool names, not protocol-level methods. The right model\n // here: if the agent claims signing AT ALL, sign every mutating POST\n // we send to it on the cancel path. Sellers with uniform \"must be\n // signed\" policies accept this; sellers that only check signing on\n // specific AdCP tools simply ignore the extra signature.\n //\n // TODO(adcp#4318, adcp-client#1617): when the AdCP spec adds explicit\n // verifier coverage for A2A protocol methods (likely in 3.1 as a new\n // `protocol_methods_supported_for` / `protocol_methods_required_for`\n // field on `request_signing`), narrow this default by reading the\n // seller's advertised coverage from `getCapability()` and gating on\n // the `tasks/cancel` membership. The over-sign default stays as the\n // fallback for spec-silent sellers (3.0.x and earlier).\n if (agent.request_signing) {\n const upstream: FetchLike = (input, ini) =>\n fetchFn ? fetchFn(input as RequestInfo | URL, ini) : fetch(input as RequestInfo, ini);\n if (isInlineSigningConfig(agent.request_signing)) {\n const signed = createSigningFetch(upstream, toSignerKey(agent.request_signing));\n await signed(agentUrl, init);\n return;\n }\n if (isProviderSigningConfig(agent.request_signing)) {\n const signed = createSigningFetchAsync(upstream, agent.request_signing.provider);\n await signed(agentUrl, init);\n return;\n }\n }\n\n await (fetchFn ?? fetch)(agentUrl, init);\n}\n\nasync function getOrCreateA2AClient(\n agentUrl: string,\n authToken: string | undefined,\n customHeaders?: Record<string, string>,\n bypassCache = false\n): Promise<InstanceType<typeof A2AClient>> {\n const signingContext = signingContextStorage.getStore();\n const fetchFn = callContextStorage.getStore()?.fetchFn;\n const cacheKey = a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, customHeaders);\n // Scoped fetchers often carry request/tenant-specific egress policy. Keep\n // those calls one-shot so neither agent-card discovery nor a client created\n // under one policy can be reused by another caller, and so short-lived\n // closure identities do not grow the global cache without bound.\n if (bypassCache || fetchFn) {\n return createA2AClient(agentUrl, authToken);\n }\n const cached = a2aClientCache.get(cacheKey);\n if (cached) return cached;\n\n const pending = pendingA2AClients.get(cacheKey);\n if (pending) return pending;\n\n const promise = createA2AClient(agentUrl, authToken)\n .then(client => {\n a2aClientCache.set(cacheKey, client);\n return client;\n })\n .finally(() => {\n pendingA2AClients.delete(cacheKey);\n });\n\n pendingA2AClients.set(cacheKey, promise);\n return promise;\n}\n\nasync function createA2AClient(\n agentUrl: string,\n authToken: string | undefined\n): Promise<InstanceType<typeof A2AClient>> {\n const fetchImpl = buildFetchImpl(authToken);\n const cardUrls = buildCardUrls(agentUrl);\n\n const context = callContextStorage.getStore();\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Discovering agent card at ${cardUrls.join(', ')}`,\n timestamp: new Date().toISOString(),\n });\n\n let client: InstanceType<typeof A2AClient> | undefined;\n let lastError: Error = new Error(`A2A agent card not found at ${cardUrls.join(', ')}`);\n for (const cardUrl of cardUrls) {\n try {\n client = await A2AClient.fromCardUrl(cardUrl, { fetchImpl });\n break;\n } catch (err: unknown) {\n lastError = err as Error;\n if (context?.got401Ref.value) break;\n }\n }\n if (!client) throw lastError;\n\n return client;\n}\n\nfunction buildFetchImpl(authToken: string | undefined) {\n // The A2A client is cached per (url, authToken, signingCacheKey). We capture\n // the signing context at client-creation time so all subsequent calls that\n // share this cached client use the same signing identity — changing identity\n // requires a different cache entry, built on a separate call that enters ALS\n // with a different context.\n const signingContext = signingContextStorage.getStore();\n\n // Innermost wrapper: enforce response body size cap from the active\n // `responseSizeLimitStorage` slot. Pass-through when no slot is set.\n const networkFetch = wrapFetchWithTransportDiagnostics(\n wrapFetchWithSizeLimit((input, init) => {\n const scopedFetch = callContextStorage.getStore()?.fetchFn;\n return scopedFetch ? scopedFetch(input, init) : fetch(input as any, init);\n })\n );\n\n // Inner fetch handles auth/header injection and 401 detection. If the\n // agent has request-signing configured, we wrap it with the AdCP signing\n // fetch so the signature covers the exact bytes we're about to send (auth\n // headers included, since the signer re-reads the final header record).\n const baseFetch = async (url: string | URL | Request, options?: RequestInit): Promise<Response> => {\n const context = callContextStorage.getStore();\n\n const existingHeaders: Record<string, string> = {};\n if (options?.headers) {\n if (options.headers instanceof Headers) {\n options.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n } else if (Array.isArray(options.headers)) {\n for (const [key, value] of options.headers) {\n existingHeaders[key] = value;\n }\n } else {\n Object.assign(existingHeaders, options.headers);\n }\n }\n\n // Only inject trace context headers for actual tool requests, not discovery.\n // The agent card endpoint is external/untrusted — don't leak trace IDs to it.\n const urlString = typeof url === 'string' ? url : url.toString();\n const isDiscoveryRequest = isAgentCardPath(urlString);\n const traceHeaders = isDiscoveryRequest ? {} : injectTraceHeaders();\n const requestTimeoutMs = isDiscoveryRequest\n ? resolveRequestTimeoutMs(context?.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS)\n : resolveRequestTimeoutMs(context?.requestTimeoutMs);\n\n // Merge: existing < trace < custom < auth (auth always wins)\n const headers: Record<string, string> = {\n ...existingHeaders,\n ...traceHeaders,\n ...context?.customHeaders,\n ...(authToken && {\n Authorization: `Bearer ${authToken}`,\n 'x-adcp-auth': authToken,\n }),\n };\n\n context?.debugLogs.push({\n type: 'info',\n message: `A2A: Fetch to ${urlString}`,\n timestamp: new Date().toISOString(),\n hasAuth: !!authToken,\n headers: redactHeadersForDebug(headers),\n });\n\n const response = await withAbortSignal<Response>([context?.signal, options?.signal], requestTimeoutMs, signal =>\n networkFetch(url as any, { ...options, headers, signal })\n );\n\n if (response.status === 401 && context) {\n context.got401Ref.value = true;\n }\n\n return response;\n };\n\n if (!signingContext) return wrapFetchWithCapture(baseFetch);\n\n // The signing wrapper assembles headers into the signature base. We invoke\n // it first so the signer sees the caller-supplied headers; baseFetch then\n // overlays auth/trace headers afterwards — A2A's auth scheme (bearer) is\n // not among the MANDATORY_COMPONENTS and is injected by the counterparty's\n // transport layer, not signed.\n const signingFetch = buildAgentSigningFetch({\n upstream: (input, init) => baseFetch(input as any, init),\n signing: signingContext.signing,\n getCapability: signingContext.getCapability,\n });\n return wrapFetchWithCapture(signingFetch as typeof fetch);\n}\n\n/**\n * Terminal A2A task states per A2A 0.3.0 §3.4. Only these can carry the\n * AdCP-mandated artifact + DataPart envelope (per transport-errors §A2A\n * Binding); intermediate states (`working`, `submitted`, `input-required`,\n * `auth-required`) carry no completion artifact.\n */\nconst TERMINAL_A2A_STATES = new Set(['completed', 'failed', 'rejected', 'canceled']);\n\n/**\n * Detect whether a JSON-RPC response carries a spec-compliant terminal-state\n * Task with at least one artifact containing a structured DataPart payload.\n * Per AdCP transport-errors §A2A Binding, the artifact's DataPart is the\n * canonical envelope for both the success arm (`completed`) and the error\n * arms (`failed` / `rejected` / `canceled`). The criterion intentionally\n * matches the unwrapper's terminal-state extraction in\n * `unwrapA2AResponse` — keeping protocol layer and unwrapper in lockstep\n * across all terminal states, not just the error arms.\n *\n * Used to short-circuit the generic \"A2A agent returned error\" throw when\n * a non-conformant seller surfaces both a transport-level `result.error`\n * hint and the canonical artifact envelope side-by-side. The DataPart is\n * authoritative; the throw would otherwise swallow it.\n */\nfunction hasTerminalTaskWithDataArtifact(response: unknown): boolean {\n if (!response || typeof response !== 'object') return false;\n const result = (response as { result?: unknown }).result;\n if (!result || typeof result !== 'object') return false;\n const r = result as { kind?: unknown; status?: unknown; artifacts?: unknown };\n if (r.kind !== 'task') return false;\n const status = r.status as { state?: unknown } | undefined;\n if (typeof status?.state !== 'string' || !TERMINAL_A2A_STATES.has(status.state)) return false;\n return getLatestA2ADataPartFromResponse(response) !== undefined;\n}\n\n/**\n * Protocol-level session identifiers that ride on the A2A Message envelope\n * (not in the skill parameters). `contextId` binds sends to a server-side\n * conversation; `taskId` resumes an existing non-terminal task.\n *\n * Callers (buyers) typically retain these across calls on a per-conversation\n * AgentClient; see AgentClient.getContextId() / getPendingTaskId().\n */\nexport interface A2ASessionIds {\n contextId?: string;\n taskId?: string;\n}\n\nexport async function callA2ATool(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken?: string,\n debugLogs: DebugLogEntry[] = [],\n pushNotificationConfig?: PushNotificationConfig,\n customHeaders?: Record<string, string>,\n signingContext?: AgentSigningContext,\n session?: A2ASessionIds,\n signal?: AbortSignal,\n requestTimeoutMs?: number,\n fetchFn?: typeof fetch\n): Promise<unknown> {\n return withSpan(\n 'adcp.a2a.call_tool',\n {\n 'adcp.tool': toolName,\n 'http.url': agentUrl,\n },\n async () => {\n const context: A2ACallContext = {\n customHeaders,\n debugLogs,\n got401Ref: { value: false },\n signal,\n requestTimeoutMs,\n fetchFn,\n };\n return signingContextStorage.run(signingContext, () =>\n callContextStorage.run(context, () =>\n callA2AToolImpl(\n agentUrl,\n toolName,\n parameters,\n authToken,\n debugLogs,\n pushNotificationConfig,\n context,\n session\n )\n )\n );\n }\n );\n}\n\nasync function callA2AToolImpl(\n agentUrl: string,\n toolName: string,\n parameters: Record<string, unknown>,\n authToken: string | undefined,\n debugLogs: DebugLogEntry[],\n pushNotificationConfig: PushNotificationConfig | undefined,\n context: A2ACallContext,\n session: A2ASessionIds | undefined\n): Promise<unknown> {\n try {\n const client = await getOrCreateA2AClient(\n agentUrl,\n authToken,\n context.customHeaders,\n !!context.signal || context.requestTimeoutMs !== undefined\n );\n\n const requestPayload: {\n message: {\n messageId: string;\n role: string;\n kind: string;\n parts: Array<{ kind: string; data: { skill: string; parameters: Record<string, unknown> } }>;\n contextId?: string;\n taskId?: string;\n };\n configuration?: { pushNotificationConfig: PushNotificationConfig };\n } = {\n message: {\n messageId: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n role: 'user',\n kind: 'message',\n parts: [\n {\n kind: 'data',\n data: {\n skill: toolName,\n parameters: parameters,\n },\n },\n ],\n ...(session?.contextId && { contextId: session.contextId }),\n ...(session?.taskId && { taskId: session.taskId }),\n },\n };\n\n if (pushNotificationConfig) {\n requestPayload.configuration = {\n pushNotificationConfig: pushNotificationConfig,\n };\n }\n\n const payloadSize = JSON.stringify(requestPayload).length;\n const redactedParameters = redactArgsForLog(parameters);\n const redactedPayload = {\n ...requestPayload,\n message: {\n ...requestPayload.message,\n parts: [\n {\n kind: 'data',\n data: { skill: toolName, parameters: redactedParameters },\n },\n ],\n },\n ...(requestPayload.configuration && {\n configuration: {\n pushNotificationConfig: redactPushNotificationConfigForDebug(\n requestPayload.configuration.pushNotificationConfig\n )!,\n },\n }),\n };\n debugLogs.push({\n type: 'info',\n message: `A2A: Calling skill ${toolName} with parameters: ${JSON.stringify(\n redactedParameters\n )}. Payload size: ${payloadSize} bytes`,\n timestamp: new Date().toISOString(),\n payloadSize,\n actualPayload: redactedPayload,\n });\n\n debugLogs.push({\n type: 'info',\n message: `A2A: Sending message via sendMessage()`,\n timestamp: new Date().toISOString(),\n skill: toolName,\n });\n\n const messageResponse = await client.sendMessage(requestPayload);\n\n debugLogs.push({\n type: messageResponse?.error ? 'error' : 'success',\n message: `A2A: Response received (${messageResponse?.error ? 'error' : 'success'})`,\n timestamp: new Date().toISOString(),\n response: messageResponse,\n skill: toolName,\n });\n\n if (messageResponse?.error || messageResponse?.result?.error) {\n // adcp-client#1575: when the seller emits a spec-compliant terminal-state\n // Task carrying an `adcp_error` DataPart (per AdCP transport-errors §A2A\n // Binding), the structured artifact is canonical — even if the seller\n // also surfaced a transport-level error string. Pass the response\n // through so the upstream unwrapper extracts `adcp_error.code` instead\n // of throwing a generic message that loses the AdCP error envelope.\n if (!hasTerminalTaskWithDataArtifact(messageResponse)) {\n const errorObj = messageResponse.error || messageResponse.result?.error;\n const errorMessage = errorObj.message || JSON.stringify(errorObj);\n throw new Error(`A2A agent returned error: ${errorMessage}`);\n }\n }\n\n return messageResponse;\n } catch (error: unknown) {\n if (is401Error(error, context.got401Ref.value)) {\n // Evict this cache entry — credential may have expired or been\n // revoked. Same disambiguator as the original `getOrCreateA2AClient`\n // call: when the credential rode on customHeaders.Authorization (Basic\n // case) rather than authToken, the cache key must reflect that or we\n // evict the wrong entry.\n const signingContext = signingContextStorage.getStore();\n a2aClientCache.delete(a2aCacheKey(agentUrl, authToken, signingContext?.cacheKey, context.customHeaders));\n\n debugLogs.push({\n type: 'error',\n message: `A2A: Authentication required for ${agentUrl}`,\n timestamp: new Date().toISOString(),\n });\n\n // Re-probe to surface the WWW-Authenticate scheme on the error envelope.\n // Basic-fronted agents (Apigee/Kong/AWS API GW with a BasicAuthentication\n // policy) would otherwise leave consumers chasing OAuth metadata that\n // doesn't exist. Matches the MCP discovery throw site in\n // `SingleAgentClient.discoverMCPEndpoint`.\n const challenge = await probeAuthChallenge(agentUrl, { fetchFn: context.fetchFn });\n const oauthMetadata = await discoverOAuthMetadata(agentUrl, { fetch: context.fetchFn });\n throw new AuthenticationRequiredError(agentUrl, oauthMetadata || undefined, undefined, challenge ?? undefined);\n }\n\n throw error;\n }\n}\n"],"mappings":"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","names":["require"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/protocols/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,OAAO,CAAC;AAKf;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,GAAE,KAAK,GAAG,KAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrF;AACD,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAmB3D,OAAO,EAEL,KAAK,wBAAwB,IAAI,0BAA0B,EAC5D,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,wBAAwB,EACxB,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAEpH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAyBjE;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAWzE;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/protocols/index.ts"],"names":[],"mappings":"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"}
|