@adcp/sdk 7.10.2 → 7.11.1
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/compliance/cache/3.1.0-rc.2/domains/brand/index.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/distributed_brand_resolution.yaml +415 -0
- package/compliance/cache/3.1.0-rc.2/domains/brand/scenarios/single_side_trust_extension.yaml +454 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/index.yaml +339 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/billing_out_of_band.yaml +153 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/canonical_supported_formats.yaml +212 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
- package/compliance/cache/3.1.0-rc.2/domains/creative/scenarios/native_in_feed.yaml +543 -0
- package/compliance/cache/3.1.0-rc.2/domains/governance/index.yaml +682 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/index.yaml +789 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/audience_buy_flow.yaml +380 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/available_actions.yaml +565 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/canonical_formats.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/create_media_buy_async.yaml +234 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/creative_reception.yaml +247 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/delivery_reporting.yaml +357 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment.yaml +633 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/event_dedup_flow.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_approved.yaml +214 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_conditions.yaml +199 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/invalid_transitions.yaml +289 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_accountability.yaml +244 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow.yaml +428 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/product_signal_targeting.yaml +373 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_enforcement.yaml +517 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/reach_buy_flow.yaml +823 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
- package/compliance/cache/3.1.0-rc.2/domains/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.1.0-rc.2/domains/signals/index.yaml +266 -0
- package/compliance/cache/3.1.0-rc.2/domains/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.1.0-rc.2/index.json +356 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/index.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/distributed_brand_resolution.yaml +415 -0
- package/compliance/cache/3.1.0-rc.2/protocols/brand/scenarios/single_side_trust_extension.yaml +454 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/index.yaml +339 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/billing_out_of_band.yaml +153 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/canonical_supported_formats.yaml +212 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/creative_lifecycle_webhooks.yaml +389 -0
- package/compliance/cache/3.1.0-rc.2/protocols/creative/scenarios/native_in_feed.yaml +543 -0
- package/compliance/cache/3.1.0-rc.2/protocols/governance/index.yaml +682 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/index.yaml +789 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/audience_buy_flow.yaml +380 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/available_actions.yaml +565 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/billing_finality_delivery.yaml +354 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/canonical_formats.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/clicks_buy_flow.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/completed_views_buy_flow.yaml +344 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/create_media_buy_async.yaml +234 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_fate_after_cancellation.yaml +419 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/creative_reception.yaml +247 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/delivery_reporting.yaml +357 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment.yaml +633 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/dependency_impairment_cardinality.yaml +800 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/event_dedup_flow.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/frequency_cap_enforcement.yaml +309 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_approved.yaml +214 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_conditions.yaml +199 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied.yaml +204 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/governance_denied_recovery.yaml +252 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/invalid_transitions.yaml +289 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_no_match.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/inventory_list_targeting.yaml +276 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_accountability.yaml +244 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/measurement_terms_rejected.yaml +203 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/package_correlation_legacy_fallback.yaml +113 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/pending_creatives_to_start.yaml +292 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/per_creative_conversion_attribution.yaml +500 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow.yaml +428 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/performance_buy_flow_roas.yaml +470 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/product_signal_targeting.yaml +373 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize.yaml +399 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_finalize_asap_timing.yaml +264 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/proposal_not_found_errors.yaml +257 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_audit_observation.yaml +333 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_enforcement.yaml +517 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/provenance_truth_of_claim.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/reach_buy_flow.yaml +823 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_finalize_exclusivity.yaml +360 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/refine_products.yaml +148 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_accountability.yaml +293 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_catalog_precondition.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/scenarios/vendor_metric_optimization_flow.yaml +576 -0
- package/compliance/cache/3.1.0-rc.2/protocols/media-buy/state-machine.yaml +442 -0
- package/compliance/cache/3.1.0-rc.2/protocols/signals/index.yaml +266 -0
- package/compliance/cache/3.1.0-rc.2/protocols/sponsored-intelligence/index.yaml +256 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/audience-sync/index.yaml +313 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/index.yaml +350 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/brand-rights/scenarios/governance_denied.yaml +226 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/collection-lists/index.yaml +359 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/content-standards/index.yaml +572 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-ad-server/index.yaml +409 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/generative-seller.yaml +807 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-generative/index.yaml +758 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/creative-template/index.yaml +510 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/index.yaml +143 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-aware-seller/scenarios/governance_multi_agent_rejected.yaml +117 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-delivery-monitor/index.yaml +441 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/denied.yaml +221 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/governance-spend-authority/index.yaml +330 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/property-lists/index.yaml +482 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-broadcast-tv/index.yaml +738 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-catalog-driven/index.yaml +840 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-guaranteed/index.yaml +601 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-non-guaranteed/index.yaml +546 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-proposal-mode/index.yaml +586 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sales-social/index.yaml +919 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/index.yaml +424 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-marketplace/scenarios/governance_denied.yaml +210 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/signal-owned/index.yaml +317 -0
- package/compliance/cache/3.1.0-rc.2/specialisms/sponsored-intelligence/index.yaml +59 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor-live.yaml +78 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/acme-outdoor.yaml +223 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/billing-gate-runner.yaml +115 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/bistro-oranje.yaml +126 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/distributed-brand-runner.yaml +281 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/nova-motors.yaml +262 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/osei-natural.yaml +126 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/parallel-dispatch-runner.yaml +196 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/rate-limit-trip-runner.yaml +172 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/signed-requests-runner.yaml +155 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/single-side-trust-runner.yaml +294 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/substitution-observer-runner.yaml +688 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/summit-foods.yaml +125 -0
- package/compliance/cache/3.1.0-rc.2/test-kits/webhook-receiver-runner.yaml +265 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/001-minimal-plan.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/002-full-plan.json +217 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/003-bookkeeping-stripped.json +60 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004a-human-review-omitted.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/004b-human-review-explicit-null.json +49 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005a-policy-categories-order-1.json +53 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/005b-policy-categories-order-2.json +57 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006a-ext-trace-v1.json +49 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/006b-ext-trace-v2.json +53 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/007-unicode-objectives.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/plan-hash/008-numeric-canonicalization.json +65 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/README.md +220 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/canonicalization.json +241 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/keys.json +60 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/001-no-signature-header.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/002-wrong-tag.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/003-expired-signature.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/004-window-too-long.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/005-alg-not-allowed.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/006-missing-covered-component.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/007-missing-content-digest.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/008-unknown-keyid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/009-key-ops-missing-verify.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/010-content-digest-mismatch.json +33 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/011-malformed-header.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/013-expires-le-created.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/014-missing-nonce-param.json +27 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/015-signature-invalid.json +28 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/016-replayed-nonce.json +35 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/017-key-revoked.json +38 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/018-digest-covered-when-forbidden.json +28 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/019-signature-without-signature-input.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/020-rate-abuse.json +34 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/021-duplicate-signature-input-label.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/022-multi-valued-content-type.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/023-multi-valued-content-digest.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/024-unquoted-string-param.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/025-jwk-alg-crv-mismatch.json +43 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/026-non-ascii-host.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/027-webhook-registration-authentication-unsigned.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/negative/028-unsigned-protocol-method-required.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/001-basic-post.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/002-post-with-content-digest.json +31 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/003-es256-post.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/004-multiple-signature-labels.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/005-default-port-stripped.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/006-dot-segment-path.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/007-query-byte-preserved.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/008-percent-encoded-path.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/009-percent-encoded-unreserved-decoded.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/010-percent-encoded-slash-preserved.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/011-ipv6-authority.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/request-signing/positive/012-ipv6-authority-default-port-stripped.json +30 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/README.md +211 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/keys.json +61 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/001-wrong-tag.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/002-expired-signature.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/003-window-too-long.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/004-alg-not-allowed.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/005-missing-authority-component.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/006-missing-content-digest.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/007-unknown-keyid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/008-wrong-adcp-use.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/009-content-digest-mismatch.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/010-malformed-signature-input.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/011-signature-without-input.json +25 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/012-missing-expires-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/013-expires-le-created.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/014-missing-nonce-param.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/015-signature-invalid.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/016-replayed-nonce.json +37 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/017-key-revoked.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/018-rate-abuse.json +33 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/019-revocation-stale.json +32 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/020-key-ops-missing-verify.json +41 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/negative/021-base64-alphabet-mixing.json +26 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/001-basic-post.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/002-es256-post.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/003-multiple-signature-labels.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/004-default-port-stripped.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/005-percent-encoded-path.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/006-query-byte-preserved.json +24 -0
- package/compliance/cache/3.1.0-rc.2/test-vectors/webhook-signing/positive/007-body-without-idempotency-key.json +25 -0
- package/compliance/cache/3.1.0-rc.2/universal/billing-gate-dispatch.yaml +450 -0
- package/compliance/cache/3.1.0-rc.2/universal/canonical-format-validate-input.yaml +640 -0
- package/compliance/cache/3.1.0-rc.2/universal/capability-discovery.yaml +125 -0
- package/compliance/cache/3.1.0-rc.2/universal/collection-lists-pagination-integrity.yaml +306 -0
- package/compliance/cache/3.1.0-rc.2/universal/comply-controller-mode-gate.yaml +141 -0
- package/compliance/cache/3.1.0-rc.2/universal/content-standards-pagination-integrity.yaml +326 -0
- package/compliance/cache/3.1.0-rc.2/universal/deterministic-testing.yaml +1430 -0
- package/compliance/cache/3.1.0-rc.2/universal/error-compliance-signals.yaml +377 -0
- package/compliance/cache/3.1.0-rc.2/universal/error-compliance.yaml +528 -0
- package/compliance/cache/3.1.0-rc.2/universal/fictional-entities.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/universal/get-media-buys-pagination-integrity.yaml +160 -0
- package/compliance/cache/3.1.0-rc.2/universal/get-signals-pagination-integrity.yaml +210 -0
- package/compliance/cache/3.1.0-rc.2/universal/idempotency.yaml +861 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-event-scope.yaml +119 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-lifecycle.yaml +337 -0
- package/compliance/cache/3.1.0-rc.2/universal/notification-config-rejections.yaml +107 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-creative-formats.yaml +265 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity-list-accounts.yaml +245 -0
- package/compliance/cache/3.1.0-rc.2/universal/pagination-integrity.yaml +263 -0
- package/compliance/cache/3.1.0-rc.2/universal/property-lists-pagination-integrity.yaml +307 -0
- package/compliance/cache/3.1.0-rc.2/universal/read-tool-idempotency.yaml +405 -0
- package/compliance/cache/3.1.0-rc.2/universal/runner-output-contract.yaml +1285 -0
- package/compliance/cache/3.1.0-rc.2/universal/schema-validation-signals.yaml +181 -0
- package/compliance/cache/3.1.0-rc.2/universal/schema-validation.yaml +548 -0
- package/compliance/cache/3.1.0-rc.2/universal/security.yaml +539 -0
- package/compliance/cache/3.1.0-rc.2/universal/signed-requests.yaml +217 -0
- package/compliance/cache/3.1.0-rc.2/universal/stale-response-advisory.yaml +295 -0
- package/compliance/cache/3.1.0-rc.2/universal/storyboard-schema.yaml +2194 -0
- package/compliance/cache/3.1.0-rc.2/universal/v3-envelope-integrity.yaml +117 -0
- package/compliance/cache/3.1.0-rc.2/universal/version-negotiation.yaml +130 -0
- package/compliance/cache/3.1.0-rc.2/universal/webhook-emission.yaml +411 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-bulk-webhooks.yaml +82 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-product-webhooks.yaml +83 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-products.yaml +151 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signal-webhooks.yaml +83 -0
- package/compliance/cache/3.1.0-rc.2/universal/wholesale-feed-signals.yaml +149 -0
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +9 -5
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/testing/storyboard/default-invariants.js +30 -1
- package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +84 -21
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +21 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/testing/types.d.ts +9 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.d.ts +6707 -12040
- package/dist/lib/types/schemas.generated.d.ts.map +1 -1
- package/dist/lib/types/schemas.generated.js +1 -1
- package/dist/lib/types/schemas.generated.js.map +1 -1
- package/dist/lib/utils/signal-id-builders.d.ts +19 -0
- package/dist/lib/utils/signal-id-builders.d.ts.map +1 -1
- package/dist/lib/utils/signal-id-builders.js +30 -0
- package/dist/lib/utils/signal-id-builders.js.map +1 -1
- package/dist/lib/utils/tool-request-schemas.d.ts.map +1 -1
- package/dist/lib/utils/tool-request-schemas.js +3 -0
- package/dist/lib/utils/tool-request-schemas.js.map +1 -1
- package/dist/lib/v2/projection/constants.d.ts +28 -0
- package/dist/lib/v2/projection/constants.d.ts.map +1 -0
- package/dist/lib/v2/projection/constants.js +31 -0
- package/dist/lib/v2/projection/constants.js.map +1 -0
- package/dist/lib/v2/projection/registry.d.ts.map +1 -1
- package/dist/lib/v2/projection/registry.js +9 -4
- package/dist/lib/v2/projection/registry.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/package.json +1 -1
- package/skills/SHAPE-GOTCHAS.md +5 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
id: security_baseline
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
title: "Authentication baseline"
|
|
4
|
+
category: security
|
|
5
|
+
summary: "Every AdCP agent MUST require authentication on protected operations. At least one of static credentials or OAuth MUST be implemented and correctly advertised."
|
|
6
|
+
track: security
|
|
7
|
+
required_tools: [] # protocol-level, not tool-level
|
|
8
|
+
|
|
9
|
+
narrative: |
|
|
10
|
+
Every AdCP agent handles data belonging to publishers or buyers that other parties
|
|
11
|
+
should not see or modify. Without authentication on protected operations, a seller
|
|
12
|
+
agent would leak media buys, creative libraries, or account-level reports to anyone
|
|
13
|
+
who knew the URL. Without correct authentication metadata, buyers cannot obtain
|
|
14
|
+
tokens with the right audience and every authenticated request fails with 401 — an
|
|
15
|
+
agent-side misconfiguration that looks identical to "my client is broken".
|
|
16
|
+
|
|
17
|
+
AdCP uses a tiered model: discovery operations (`get_adcp_capabilities`,
|
|
18
|
+
`list_creative_formats`, `get_products` without pricing) are public; operations
|
|
19
|
+
that return tenant-scoped data or modify state (`list_creatives`, `create_media_buy`,
|
|
20
|
+
`get_media_buy_delivery`, `sync_creatives`, etc.) require credentials. See
|
|
21
|
+
[/docs/building/by-layer/L2/authentication](/docs/building/by-layer/L2/authentication).
|
|
22
|
+
|
|
23
|
+
AdCP accepts three credential mechanisms: static API keys (Authorization:
|
|
24
|
+
Bearer <key>), HTTP Basic credentials sent in the Authorization header, or OAuth
|
|
25
|
+
2.0 + RFC 8707 resource indicators. An agent MUST implement at least one. It
|
|
26
|
+
MAY implement more than one. This storyboard verifies that (a) a protected
|
|
27
|
+
operation is rejected when called without credentials, (b) deliberately invalid
|
|
28
|
+
credentials are also rejected (an agent that 200s on an unauth call and 200s on
|
|
29
|
+
a bad-credential call is ignoring credentials entirely), and (c) at least one
|
|
30
|
+
auth mechanism is present and correctly advertised.
|
|
31
|
+
|
|
32
|
+
Pass semantics are encoded in the step flow: the unauth probe and
|
|
33
|
+
invalid-credential probe (when a test-kit key or Basic credential is present)
|
|
34
|
+
are always required, and at least one of the API key phase, Basic phase, or
|
|
35
|
+
OAuth discovery phase must contribute `auth_mechanism_verified`. Agents that
|
|
36
|
+
fail any required phase, or advertise no working auth mechanism, are
|
|
37
|
+
non-conformant.
|
|
38
|
+
|
|
39
|
+
**Static-credential agents (no OAuth).** An agent with no OAuth issuer -
|
|
40
|
+
sandbox, staging, or any production deployment that chose Bearer or Basic auth
|
|
41
|
+
- does NOT need to advertise RFC 9728 protected-resource metadata. Declare
|
|
42
|
+
`auth.api_key` or `auth.basic` in the test-kit and do not serve
|
|
43
|
+
`/.well-known/oauth-protected-resource/...`. The matching static-credential
|
|
44
|
+
phase contributes `auth_mechanism_verified` and `oauth_discovery` is allowed
|
|
45
|
+
to fail silently as an optional phase - no fake issuer URL or stub RFC 8414
|
|
46
|
+
metadata document is required. Agents that DO advertise `authorization_servers`
|
|
47
|
+
in their PRM MUST stand up the RFC 8414 auth-server metadata document to match;
|
|
48
|
+
advertising an issuer without serving its metadata is the failure mode this
|
|
49
|
+
storyboard was written to catch.
|
|
50
|
+
|
|
51
|
+
For local debugging before re-running compliance, use `adcp diagnose-auth <alias>`
|
|
52
|
+
(see adcp-client#563) to trace the full OAuth handshake and surface ranked
|
|
53
|
+
hypotheses about what's wrong.
|
|
54
|
+
|
|
55
|
+
agent:
|
|
56
|
+
interaction_model: "*" # applies to every agent regardless of specialism
|
|
57
|
+
examples:
|
|
58
|
+
- "Any AdCP agent (seller, signals, creative, retail media, SI, governance)"
|
|
59
|
+
|
|
60
|
+
caller:
|
|
61
|
+
role: buyer_agent
|
|
62
|
+
example: "Compliance test harness"
|
|
63
|
+
|
|
64
|
+
prerequisites:
|
|
65
|
+
description: |
|
|
66
|
+
The test kit declares the agent's **protected probe task** at `auth.probe_task`
|
|
67
|
+
— an auth-required, read-only task the agent supports (`list_creatives`,
|
|
68
|
+
`get_media_buy_delivery`, `get_signals`, etc.). The runner defaults to
|
|
69
|
+
`list_creatives` if unspecified. This is the task used for both the unauth and
|
|
70
|
+
invalid-credential probes, since public tasks like `get_adcp_capabilities`
|
|
71
|
+
return 200 without credentials by design.
|
|
72
|
+
|
|
73
|
+
The test kit MAY also provide an API key at `auth.api_key` or HTTP Basic
|
|
74
|
+
credentials at `auth.basic`. If both are absent, the static-credential phases
|
|
75
|
+
are skipped and the OAuth discovery phase MUST succeed instead. OAuth discovery
|
|
76
|
+
probes the well-known endpoint directly and does not require any test-kit
|
|
77
|
+
input.
|
|
78
|
+
|
|
79
|
+
Agent URLs MUST use `https://` in production compliance runs. The runner rejects
|
|
80
|
+
`http://` agent URLs outright unless invoked with `--allow-http` for local dev.
|
|
81
|
+
test_kit: "test-kits/acme-outdoor.yaml"
|
|
82
|
+
|
|
83
|
+
phases:
|
|
84
|
+
- id: unauth_rejection
|
|
85
|
+
title: "Unauthenticated requests on protected operations are rejected"
|
|
86
|
+
narrative: |
|
|
87
|
+
The baseline conformance bar. A compliant agent MUST NOT serve protected
|
|
88
|
+
operations without credentials. 401 is the semantically correct response
|
|
89
|
+
(no/invalid credentials, retry with auth); 403 is accepted for pragmatic
|
|
90
|
+
reasons (many production gateways conflate them behind path-based ACLs)
|
|
91
|
+
but is suboptimal — 403 means "authenticated but forbidden" and should not
|
|
92
|
+
apply to an anonymous caller. Anything else (200, 500, network hang) is
|
|
93
|
+
non-conformant.
|
|
94
|
+
|
|
95
|
+
On 401, the response MUST include a `WWW-Authenticate` header so clients
|
|
96
|
+
know how to authenticate. Correct examples:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
WWW-Authenticate: Bearer realm="https://agent.example.com/mcp", as_uri="https://auth.example.com"
|
|
100
|
+
WWW-Authenticate: Basic realm="https://agent.example.com/mcp"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
steps:
|
|
104
|
+
- id: probe_unauth
|
|
105
|
+
title: "Call the protected probe task with no credentials"
|
|
106
|
+
narrative: |
|
|
107
|
+
Send the test kit's declared protected task (`auth.probe_task`, default
|
|
108
|
+
`list_creatives`) with no Authorization header and no API key. The runner
|
|
109
|
+
forces credentials to be stripped via `auth: none` even when the transport
|
|
110
|
+
has a valid token configured. Expect 401 or 403.
|
|
111
|
+
|
|
112
|
+
If this probe returns 200 the agent is ignoring credentials on protected
|
|
113
|
+
operations — the most serious conformance failure this storyboard catches.
|
|
114
|
+
task: "$test_kit.auth.probe_task"
|
|
115
|
+
task_default: list_creatives
|
|
116
|
+
doc_ref: "/protocol/authentication"
|
|
117
|
+
comply_scenario: security_unauth_rejection
|
|
118
|
+
stateful: false
|
|
119
|
+
auth: none
|
|
120
|
+
expect_error: true
|
|
121
|
+
negative_path: schema_invalid
|
|
122
|
+
expected: |
|
|
123
|
+
The agent rejects the request with:
|
|
124
|
+
- http_status: 401 (preferred) or 403
|
|
125
|
+
- On 401, a `WWW-Authenticate` header naming the supported scheme
|
|
126
|
+
- Example: `WWW-Authenticate: Bearer realm="<agent-url>", as_uri="<auth-server>"`
|
|
127
|
+
- Example: `WWW-Authenticate: Basic realm="<agent-url>"`
|
|
128
|
+
|
|
129
|
+
sample_request:
|
|
130
|
+
context:
|
|
131
|
+
correlation_id: "security_baseline--probe_unauth"
|
|
132
|
+
|
|
133
|
+
validations:
|
|
134
|
+
- check: http_status_in
|
|
135
|
+
allowed_values: [401, 403]
|
|
136
|
+
description: "Agent returned 200 or 5xx on an unauthenticated protected call — it MUST reject with 401 (and send WWW-Authenticate) or 403"
|
|
137
|
+
- check: on_401_require_header
|
|
138
|
+
value: "www-authenticate"
|
|
139
|
+
description: "401 responses MUST include a WWW-Authenticate header naming the supported scheme (e.g. `Bearer realm=\"<agent-url>\", as_uri=\"<auth-server>\"` or `Basic realm=\"<agent-url>\"`)"
|
|
140
|
+
|
|
141
|
+
- id: api_key_path
|
|
142
|
+
title: "API key mechanism"
|
|
143
|
+
narrative: |
|
|
144
|
+
**This phase OR `basic_path` OR `oauth_discovery` MUST pass — see `mechanism_required`.**
|
|
145
|
+
|
|
146
|
+
If the test kit provides an API key, the agent MUST accept it on the protected
|
|
147
|
+
probe task AND MUST reject a deliberately invalid key. Both checks together
|
|
148
|
+
prove the key is actually enforced — a 200 response with a valid key means
|
|
149
|
+
nothing if the agent returns 200 with an obviously bad key too. If no key is
|
|
150
|
+
provided the phase is skipped and OAuth discovery must succeed instead.
|
|
151
|
+
|
|
152
|
+
optional: true
|
|
153
|
+
skip_if: "!test_kit.auth.api_key"
|
|
154
|
+
branch_set:
|
|
155
|
+
id: auth_mechanism_verified
|
|
156
|
+
semantics: any_of
|
|
157
|
+
|
|
158
|
+
steps:
|
|
159
|
+
- id: probe_api_key
|
|
160
|
+
title: "Call the protected probe task with the provided API key"
|
|
161
|
+
narrative: |
|
|
162
|
+
Authenticate with the API key supplied by the test kit (as a Bearer token
|
|
163
|
+
in the Authorization header) and expect a normal 200 response on the
|
|
164
|
+
declared protected task. This confirms the static-credential path works
|
|
165
|
+
end to end.
|
|
166
|
+
task: "$test_kit.auth.probe_task"
|
|
167
|
+
task_default: list_creatives
|
|
168
|
+
doc_ref: "/protocol/authentication"
|
|
169
|
+
comply_scenario: security_api_key
|
|
170
|
+
stateful: false
|
|
171
|
+
auth:
|
|
172
|
+
type: api_key
|
|
173
|
+
from_test_kit: true
|
|
174
|
+
expected: |
|
|
175
|
+
The agent accepts the API key and returns a well-formed response with
|
|
176
|
+
http_status 200.
|
|
177
|
+
|
|
178
|
+
sample_request:
|
|
179
|
+
context:
|
|
180
|
+
correlation_id: "security_baseline--probe_api_key"
|
|
181
|
+
|
|
182
|
+
validations:
|
|
183
|
+
- check: http_status
|
|
184
|
+
value: 200
|
|
185
|
+
description: "Agent accepts the provided API key on the protected probe task"
|
|
186
|
+
- check: field_present
|
|
187
|
+
path: "context"
|
|
188
|
+
description: "Response echoes back the context object"
|
|
189
|
+
- check: field_value
|
|
190
|
+
path: "context.correlation_id"
|
|
191
|
+
value: "security_baseline--probe_api_key"
|
|
192
|
+
description: "Context correlation_id returned unchanged"
|
|
193
|
+
|
|
194
|
+
- id: probe_invalid_api_key
|
|
195
|
+
title: "Reject a deliberately invalid API key"
|
|
196
|
+
narrative: |
|
|
197
|
+
Send the same protected task with a Bearer token the runner generates
|
|
198
|
+
per-run from 32 random bytes (prefix `invalid-` for log readability,
|
|
199
|
+
e.g. `invalid-8e4a2c1f...`). A conformant agent rejects this with
|
|
200
|
+
401/403. An agent that returns 200 here is ignoring credentials entirely
|
|
201
|
+
and falsely appeared to pass `probe_api_key` — only the pair of (200 with
|
|
202
|
+
valid key, 401/403 with random-invalid key) proves the key is actually
|
|
203
|
+
checked. The token is randomized per run so no allowlist can collide
|
|
204
|
+
with it by accident.
|
|
205
|
+
|
|
206
|
+
Contributes `auth_mechanism_verified` only when *both* this step and
|
|
207
|
+
`probe_api_key` succeed.
|
|
208
|
+
task: "$test_kit.auth.probe_task"
|
|
209
|
+
task_default: list_creatives
|
|
210
|
+
doc_ref: "/protocol/authentication"
|
|
211
|
+
comply_scenario: security_invalid_key_rejection
|
|
212
|
+
stateful: false
|
|
213
|
+
auth:
|
|
214
|
+
type: api_key
|
|
215
|
+
value_strategy: random_invalid
|
|
216
|
+
contributes: true
|
|
217
|
+
contributes_if: "prior_step.probe_api_key.passed"
|
|
218
|
+
expect_error: true
|
|
219
|
+
negative_path: schema_invalid
|
|
220
|
+
expected: |
|
|
221
|
+
The agent rejects the random-invalid key with:
|
|
222
|
+
- http_status: 400 (if the agent enforces a key format the random token
|
|
223
|
+
doesn't match), 401 (preferred), or 403
|
|
224
|
+
- On 401, a `WWW-Authenticate: Bearer ... error="invalid_token"` header
|
|
225
|
+
|
|
226
|
+
sample_request:
|
|
227
|
+
context:
|
|
228
|
+
correlation_id: "security_baseline--probe_invalid_api_key"
|
|
229
|
+
|
|
230
|
+
validations:
|
|
231
|
+
- check: http_status_in
|
|
232
|
+
allowed_values: [400, 401, 403]
|
|
233
|
+
description: "Agent returned 200 on a known-bad API key — credentials are not being validated. MUST reject with 400 (key-format validation failure per RFC 6750 §3.1), 401 (preferred), or 403"
|
|
234
|
+
- check: on_401_require_header
|
|
235
|
+
value: "www-authenticate"
|
|
236
|
+
description: "401 responses on invalid credentials MUST include WWW-Authenticate with `error=\"invalid_token\"` per RFC 6750 §3"
|
|
237
|
+
|
|
238
|
+
- id: basic_path
|
|
239
|
+
title: "HTTP Basic auth mechanism"
|
|
240
|
+
narrative: |
|
|
241
|
+
**This phase OR `api_key_path` OR `oauth_discovery` MUST pass — see
|
|
242
|
+
`mechanism_required`.**
|
|
243
|
+
|
|
244
|
+
If the test kit provides Basic credentials, the agent MUST accept them on
|
|
245
|
+
the protected probe task AND MUST reject deliberately invalid Basic
|
|
246
|
+
credentials. Both checks together prove the Basic credential is actually
|
|
247
|
+
enforced. Basic is a static shared-secret mechanism like a Bearer API key;
|
|
248
|
+
it is acceptable for conformance when sent in the Authorization header over
|
|
249
|
+
HTTPS and validated on every protected request. If no Basic credential is
|
|
250
|
+
provided the phase is skipped and another auth mechanism must succeed
|
|
251
|
+
instead.
|
|
252
|
+
|
|
253
|
+
optional: true
|
|
254
|
+
skip_if: "!test_kit.auth.basic"
|
|
255
|
+
branch_set:
|
|
256
|
+
id: auth_mechanism_verified
|
|
257
|
+
semantics: any_of
|
|
258
|
+
|
|
259
|
+
steps:
|
|
260
|
+
- id: probe_basic
|
|
261
|
+
title: "Call the protected probe task with the provided Basic credential"
|
|
262
|
+
narrative: |
|
|
263
|
+
Authenticate with the Basic credential supplied by the test kit (as an
|
|
264
|
+
`Authorization: Basic ...` header) and expect a normal 200 response on
|
|
265
|
+
the declared protected task. This confirms the Basic credential path
|
|
266
|
+
works end to end.
|
|
267
|
+
task: "$test_kit.auth.probe_task"
|
|
268
|
+
task_default: list_creatives
|
|
269
|
+
doc_ref: "/protocol/authentication"
|
|
270
|
+
comply_scenario: security_basic
|
|
271
|
+
stateful: false
|
|
272
|
+
auth:
|
|
273
|
+
type: basic
|
|
274
|
+
from_test_kit: "auth.basic"
|
|
275
|
+
expected: |
|
|
276
|
+
The agent accepts the Basic credential and returns a well-formed response
|
|
277
|
+
with http_status 200.
|
|
278
|
+
|
|
279
|
+
sample_request:
|
|
280
|
+
context:
|
|
281
|
+
correlation_id: "security_baseline--probe_basic"
|
|
282
|
+
|
|
283
|
+
validations:
|
|
284
|
+
- check: http_status
|
|
285
|
+
value: 200
|
|
286
|
+
description: "Agent accepts the provided Basic credential on the protected probe task"
|
|
287
|
+
- check: field_present
|
|
288
|
+
path: "context"
|
|
289
|
+
description: "Response echoes back the context object"
|
|
290
|
+
- check: field_value
|
|
291
|
+
path: "context.correlation_id"
|
|
292
|
+
value: "security_baseline--probe_basic"
|
|
293
|
+
description: "Context correlation_id returned unchanged"
|
|
294
|
+
|
|
295
|
+
- id: probe_invalid_basic
|
|
296
|
+
title: "Reject deliberately invalid Basic credentials"
|
|
297
|
+
narrative: |
|
|
298
|
+
Send the same protected task with Basic credentials the runner generates
|
|
299
|
+
per-run from random bytes. A conformant agent rejects this with 401/403.
|
|
300
|
+
An agent that returns 200 here is ignoring credentials entirely and
|
|
301
|
+
falsely appeared to pass `probe_basic` - only the pair of (200 with
|
|
302
|
+
valid Basic, 401/403 with random-invalid Basic) proves the credential is
|
|
303
|
+
actually checked. The credential is randomized per run so no allowlist
|
|
304
|
+
can collide with it by accident.
|
|
305
|
+
|
|
306
|
+
Contributes `auth_mechanism_verified` only when *both* this step and
|
|
307
|
+
`probe_basic` succeed.
|
|
308
|
+
task: "$test_kit.auth.probe_task"
|
|
309
|
+
task_default: list_creatives
|
|
310
|
+
doc_ref: "/protocol/authentication"
|
|
311
|
+
comply_scenario: security_invalid_basic_rejection
|
|
312
|
+
stateful: false
|
|
313
|
+
auth:
|
|
314
|
+
type: basic
|
|
315
|
+
value_strategy: random_invalid
|
|
316
|
+
contributes: true
|
|
317
|
+
contributes_if: "prior_step.probe_basic.passed"
|
|
318
|
+
expect_error: true
|
|
319
|
+
negative_path: schema_invalid
|
|
320
|
+
expected: |
|
|
321
|
+
The agent rejects the random-invalid Basic credential with:
|
|
322
|
+
- http_status: 400 (credential format validation failure), 401
|
|
323
|
+
(preferred), or 403
|
|
324
|
+
- On 401, a `WWW-Authenticate: Basic ...` header
|
|
325
|
+
|
|
326
|
+
sample_request:
|
|
327
|
+
context:
|
|
328
|
+
correlation_id: "security_baseline--probe_invalid_basic"
|
|
329
|
+
|
|
330
|
+
validations:
|
|
331
|
+
- check: http_status_in
|
|
332
|
+
allowed_values: [400, 401, 403]
|
|
333
|
+
description: "Agent returned 200 on known-bad Basic credentials — credentials are not being validated. MUST reject with 400 (credential-format validation failure), 401 (preferred), or 403"
|
|
334
|
+
- check: on_401_require_header
|
|
335
|
+
value: "www-authenticate"
|
|
336
|
+
description: "401 responses on invalid Basic credentials MUST include WWW-Authenticate (for example, `Basic realm=\"<agent-url>\"`)"
|
|
337
|
+
|
|
338
|
+
- id: oauth_discovery
|
|
339
|
+
title: "OAuth discovery and audience binding"
|
|
340
|
+
narrative: |
|
|
341
|
+
**This phase OR `api_key_path` OR `basic_path` MUST pass — see
|
|
342
|
+
`mechanism_required`.**
|
|
343
|
+
|
|
344
|
+
**Skip for static-credential-only agents.** If your agent has no OAuth
|
|
345
|
+
issuer, declare `auth.api_key` or `auth.basic` in the test-kit and do not
|
|
346
|
+
serve PRM. This phase will fail its probes (404 on the well-known path),
|
|
347
|
+
but failures inside an `optional: true` phase do not fail the storyboard —
|
|
348
|
+
the static credential path carries `auth_mechanism_verified` on its own.
|
|
349
|
+
Do NOT serve
|
|
350
|
+
PRM pointing at a fake issuer to "pass" this phase; that triggers the
|
|
351
|
+
advertised-but-unserved failure mode below.
|
|
352
|
+
|
|
353
|
+
OAuth-enabled agents advertise their auth server at the well-known path defined
|
|
354
|
+
by RFC 9728 §3. For an agent at `https://agent.example.com/mcp`, metadata lives
|
|
355
|
+
at `https://agent.example.com/.well-known/oauth-protected-resource/mcp` — the
|
|
356
|
+
agent's resource path is appended after the well-known segment. The metadata
|
|
357
|
+
MUST include a `resource` URL that matches the full URL being called (including
|
|
358
|
+
path) so clients issue RFC 8707 `resource` parameters that result in tokens
|
|
359
|
+
bound to the correct audience.
|
|
360
|
+
|
|
361
|
+
The canonical failure this phase catches: an agent advertising the auth
|
|
362
|
+
server's origin as its own `resource`, causing issued tokens to have the
|
|
363
|
+
wrong audience and every request to 401 for reasons the buyer cannot
|
|
364
|
+
diagnose from the error message alone (see adcp-client#563). Fix the metadata
|
|
365
|
+
document, not the OAuth config.
|
|
366
|
+
|
|
367
|
+
Contribution to `auth_mechanism_verified` is gated on the pair of
|
|
368
|
+
`probe_protected_resource` (advertises OAuth correctly) AND
|
|
369
|
+
`probe_invalid_oauth_token` (actually validates inbound tokens), symmetric
|
|
370
|
+
with the API key path. Metadata alone is not sufficient — an agent that
|
|
371
|
+
advertises OAuth but accepts any Bearer is broken in the same way an
|
|
372
|
+
agent that ignores API keys is broken.
|
|
373
|
+
|
|
374
|
+
optional: true
|
|
375
|
+
branch_set:
|
|
376
|
+
id: auth_mechanism_verified
|
|
377
|
+
semantics: any_of
|
|
378
|
+
|
|
379
|
+
steps:
|
|
380
|
+
- id: probe_protected_resource
|
|
381
|
+
title: "GET /.well-known/oauth-protected-resource/<path>"
|
|
382
|
+
narrative: |
|
|
383
|
+
Fetch the protected-resource metadata document for the agent's URL per
|
|
384
|
+
RFC 9728. Verify it returns 200, contains `resource` and
|
|
385
|
+
`authorization_servers`, and — the critical check — that the `resource`
|
|
386
|
+
value equals the agent URL under test. A mismatched `resource` silently
|
|
387
|
+
breaks every OAuth client.
|
|
388
|
+
task: protected_resource_metadata
|
|
389
|
+
doc_ref: "/protocol/authentication"
|
|
390
|
+
comply_scenario: security_oauth_discovery
|
|
391
|
+
stateful: false
|
|
392
|
+
expected: |
|
|
393
|
+
A 200 response with a JSON document. Example for an agent at
|
|
394
|
+
`https://agent.example.com/mcp`:
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"resource": "https://agent.example.com/mcp",
|
|
399
|
+
"authorization_servers": ["https://auth.example.com"],
|
|
400
|
+
"bearer_methods_supported": ["header"]
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Required fields:
|
|
405
|
+
- `resource`: MUST equal the agent URL being called (including path)
|
|
406
|
+
- `authorization_servers`: MUST be a non-empty array of issuer URLs
|
|
407
|
+
|
|
408
|
+
sample_response:
|
|
409
|
+
resource: "https://agent.example.com/mcp"
|
|
410
|
+
authorization_servers:
|
|
411
|
+
- "https://auth.example.com"
|
|
412
|
+
bearer_methods_supported:
|
|
413
|
+
- "header"
|
|
414
|
+
|
|
415
|
+
validations:
|
|
416
|
+
- check: http_status
|
|
417
|
+
value: 200
|
|
418
|
+
description: "Protected-resource metadata is served at the well-known path per RFC 9728 §3"
|
|
419
|
+
- check: field_present
|
|
420
|
+
path: "resource"
|
|
421
|
+
description: "Metadata declares the protected resource URL"
|
|
422
|
+
- check: field_present
|
|
423
|
+
path: "authorization_servers"
|
|
424
|
+
description: "Metadata declares at least one authorization server issuer URL"
|
|
425
|
+
- check: resource_equals_agent_url
|
|
426
|
+
description: "The `resource` field in your metadata MUST equal the full URL clients call (including path). A common mistake: advertising the auth server's origin as `resource`. Fix the metadata document, not the OAuth config. Runner normalizes: scheme+host lowercased, default ports (443/80) elided; path is case-sensitive."
|
|
427
|
+
|
|
428
|
+
- id: probe_auth_server_metadata
|
|
429
|
+
title: "Verify authorization_servers[0] resolves (RFC 8414)"
|
|
430
|
+
narrative: |
|
|
431
|
+
Fetch the OAuth authorization-server metadata for the first issuer listed,
|
|
432
|
+
per RFC 8414 §3. The path is `<issuer>/.well-known/oauth-authorization-server`
|
|
433
|
+
— NOT `/.well-known/openid-configuration` (that's OIDC Discovery, a
|
|
434
|
+
different spec). Confirm the document is reachable and exposes the minimum
|
|
435
|
+
fields clients need to request a token (`issuer` and `token_endpoint`).
|
|
436
|
+
|
|
437
|
+
The runner applies SSRF guardrails on this outbound fetch: HTTPS only,
|
|
438
|
+
no RFC 1918 / loopback / link-local hosts, bounded response size and
|
|
439
|
+
time. If you are testing locally against a localhost auth server, run
|
|
440
|
+
the compliance runner with `--allow-http` to relax these guards for dev.
|
|
441
|
+
task: oauth_auth_server_metadata
|
|
442
|
+
doc_ref: "/protocol/authentication"
|
|
443
|
+
comply_scenario: security_oauth_discovery
|
|
444
|
+
stateful: false
|
|
445
|
+
expected: |
|
|
446
|
+
A 200 response from `<issuer>/.well-known/oauth-authorization-server` per
|
|
447
|
+
RFC 8414 §3 with at least `issuer`, `token_endpoint`, and one of
|
|
448
|
+
`grant_types_supported` or `response_types_supported` present.
|
|
449
|
+
|
|
450
|
+
validations:
|
|
451
|
+
- check: http_status
|
|
452
|
+
value: 200
|
|
453
|
+
description: "Authorization server metadata is reachable at <issuer>/.well-known/oauth-authorization-server (RFC 8414 §3) — not /.well-known/openid-configuration"
|
|
454
|
+
- check: field_present
|
|
455
|
+
path: "issuer"
|
|
456
|
+
description: "Authorization server declares its issuer"
|
|
457
|
+
- check: field_present
|
|
458
|
+
path: "token_endpoint"
|
|
459
|
+
description: "Authorization server exposes a token endpoint"
|
|
460
|
+
|
|
461
|
+
- id: probe_invalid_oauth_token
|
|
462
|
+
title: "Reject a bogus Bearer token on the protected task"
|
|
463
|
+
narrative: |
|
|
464
|
+
Metadata correctness proves the agent *advertises* OAuth correctly. It
|
|
465
|
+
does NOT prove the agent actually validates inbound tokens. An agent
|
|
466
|
+
that accepts any Bearer token on protected operations is broken in
|
|
467
|
+
exactly the same way an agent that ignores API keys is broken — this
|
|
468
|
+
step closes that loophole symmetrically.
|
|
469
|
+
|
|
470
|
+
The runner sends a JWT-shaped token generated per run: the header and
|
|
471
|
+
payload are well-formed base64url-encoded JSON objects
|
|
472
|
+
(`{"alg":"RS256","typ":"JWT"}` / `{"sub":"invalid","aud":"<agent-url>"}`)
|
|
473
|
+
so the agent's JWT parser succeeds, and the signature segment is
|
|
474
|
+
random base64url bytes so signature verification fails. Well-implemented
|
|
475
|
+
validators will return 401 `invalid_token` per RFC 6750 §3.1. Strict
|
|
476
|
+
validators that reject at parse time may return 400 `invalid_request`
|
|
477
|
+
per RFC 6750 §3.1 — both outcomes are conformant (the agent rejected
|
|
478
|
+
the bogus token). Minimal validators that don't parse at all should
|
|
479
|
+
still return 401 because the Bearer string doesn't match any issued
|
|
480
|
+
token. The token is randomized per run so no allowlist can collide
|
|
481
|
+
with it.
|
|
482
|
+
task: "$test_kit.auth.probe_task"
|
|
483
|
+
task_default: list_creatives
|
|
484
|
+
doc_ref: "/protocol/authentication"
|
|
485
|
+
comply_scenario: security_oauth_token_rejection
|
|
486
|
+
stateful: false
|
|
487
|
+
auth:
|
|
488
|
+
type: oauth_bearer
|
|
489
|
+
value_strategy: random_invalid_jwt
|
|
490
|
+
contributes: true
|
|
491
|
+
contributes_if: "prior_step.probe_protected_resource.passed"
|
|
492
|
+
expect_error: true
|
|
493
|
+
negative_path: schema_invalid
|
|
494
|
+
expected: |
|
|
495
|
+
The agent rejects the bogus Bearer with:
|
|
496
|
+
- http_status: 400 (syntactic parse-time rejection), 401 (preferred —
|
|
497
|
+
signature/audience/expiry failure), or 403
|
|
498
|
+
- On 401, a `WWW-Authenticate: Bearer ... error="invalid_token"` header
|
|
499
|
+
|
|
500
|
+
sample_request:
|
|
501
|
+
context:
|
|
502
|
+
correlation_id: "security_baseline--probe_invalid_oauth_token"
|
|
503
|
+
|
|
504
|
+
validations:
|
|
505
|
+
- check: http_status_in
|
|
506
|
+
allowed_values: [400, 401, 403]
|
|
507
|
+
description: "Agent returned 200 on a bogus Bearer token — OAuth validation is not running on protected operations. MUST reject with 400 (parse-time rejection per RFC 6750 §3.1), 401 (preferred — signature/audience failure), or 403"
|
|
508
|
+
- check: on_401_require_header
|
|
509
|
+
value: "www-authenticate"
|
|
510
|
+
description: "401 responses on invalid tokens MUST include WWW-Authenticate with `error=\"invalid_token\"` per RFC 6750 §3"
|
|
511
|
+
|
|
512
|
+
- id: mechanism_required
|
|
513
|
+
title: "At least one mechanism must be verified"
|
|
514
|
+
narrative: |
|
|
515
|
+
Logical check — not a network call. The storyboard runner fails this phase
|
|
516
|
+
if none of `api_key_path`, `basic_path`, or `oauth_discovery` contributed
|
|
517
|
+
`auth_mechanism_verified`. An agent that rejects unauthenticated requests
|
|
518
|
+
but advertises no working auth mechanism cannot actually be called by a
|
|
519
|
+
compliant buyer, so it does not pass the baseline.
|
|
520
|
+
|
|
521
|
+
steps:
|
|
522
|
+
- id: assert_mechanism
|
|
523
|
+
title: "Require auth_mechanism_verified from at least one path"
|
|
524
|
+
narrative: |
|
|
525
|
+
Synthetic assertion over accumulated flags from prior phases. Passes
|
|
526
|
+
if any prior optional phase contributed `auth_mechanism_verified`.
|
|
527
|
+
task: assert_contribution
|
|
528
|
+
comply_scenario: security_mechanism_required
|
|
529
|
+
stateful: false
|
|
530
|
+
expected: |
|
|
531
|
+
At least one of the API key path (both valid-key and invalid-key steps
|
|
532
|
+
must succeed), Basic path (both valid-credential and invalid-credential
|
|
533
|
+
steps must succeed), or OAuth path (correct metadata AND token
|
|
534
|
+
validation both must succeed) contributed `auth_mechanism_verified`.
|
|
535
|
+
|
|
536
|
+
validations:
|
|
537
|
+
- check: any_of
|
|
538
|
+
allowed_values: ["auth_mechanism_verified"]
|
|
539
|
+
description: "No auth mechanism was verified. Three things to check: (1) your test kit declares `auth.probe_task` pointing at a read-only authenticated task your agent supports (defaults to `list_creatives`); (2) you provide `auth.api_key` or `auth.basic` in your test kit AND the agent accepts it and rejects random-invalid credentials; OR (3) you serve protected-resource metadata at /.well-known/oauth-protected-resource/<path> with `resource` equal to your agent URL."
|