a2a

package
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package a2a fetches and verifies Agent2Agent (A2A) AgentCards for the remote-agent allowlist (ADR-0024): bounded, SSRF-safe https fetches, the card digest Halos pins into policy and releases, and the card's JWS signatures (A2A specification v1.0, section 8.4: RFC 7515 JWS over the RFC 8785 canonical card without its signatures field).

Index

Constants

View Source
const (
	MaxCardBytes   = 256 << 10
	DefaultTimeout = 10 * time.Second
)

Limits of a card or JWKS fetch.

Variables

View Source
var (
	ErrDigestMismatch = errors.New("a2a: AgentCard digest does not match the pinned digest")
	ErrSignature      = errors.New("a2a: AgentCard signature verification failed")
	ErrBlockedAddress = errors.New("a2a: destination address is not public")
)

Errors callers branch on.

Functions

func Canonicalize

func Canonicalize(b []byte) ([]byte, error)

Canonicalize returns the RFC 8785 JSON Canonicalization Scheme form of the single JSON value in b: object members sorted by UTF-16 code units, no insignificant whitespace, ECMAScript number and string serialization.

func Digest

func Digest(raw []byte) (string, error)

Digest is the pin Halos stores for a card: "sha256:<hex>" over its RFC 8785 canonical form, signatures included, so whitespace and member order do not matter but any change of content does.

func VerifySignatures

func VerifySignatures(raw []byte, keys []Key) error

VerifySignatures checks that at least one of the card's signatures verifies with one of keys. The payload is the RFC 8785 form of the card without its signatures member; a card signed after dropping empty (default-valued) members, as section 8.4.1 asks, verifies too. A jku header is never followed: keys come from policy only.

Types

type AgentCardSignature

type AgentCardSignature struct {
	Protected string         `json:"protected"`
	Signature string         `json:"signature"`
	Header    map[string]any `json:"header,omitempty"`
}

AgentCardSignature is one JWS over the card (A2A section 4.4.7).

type Card

type Card struct {
	Name                string               `json:"name"`
	Description         string               `json:"description"`
	Version             string               `json:"version"`
	SupportedInterfaces []Interface          `json:"supportedInterfaces"`
	URL                 string               `json:"url"` // pre-1.0 cards
	SecuritySchemes     map[string]any       `json:"securitySchemes"`
	Skills              []Skill              `json:"skills"`
	Signatures          []AgentCardSignature `json:"signatures"`
}

Card is the part of an AgentCard Halos reads. Unknown fields are kept in the raw bytes (the digest and signatures cover the whole card).

func ParseCard

func ParseCard(raw []byte) (Card, error)

ParseCard decodes a card. It must be one JSON object without duplicate keys. Fields are read by exact key from the same decoded value the digest covers: json.Unmarshal matches keys ignoring case, so a card holding both "skills" and "SKILLS" could show Halos one skill list and an A2A client another.

func (Card) SkillIDs

func (c Card) SkillIDs() []string

SkillIDs lists the card's skill ids.

type Expect

type Expect struct {
	Digest    string // sha256:<hex>; "" = not checked
	PublicKey string // PEM
	JWKSURL   string
}

Expect is what policy pins for a card.

type Fetcher

type Fetcher struct {
	Timeout time.Duration // 0 = DefaultTimeout
	// AllowPrivate permits loopback, private, link-local and other
	// non-public destinations (an agent on the internal network).
	AllowPrivate bool
	// RootCAs overrides the system roots (tests, private PKI).
	RootCAs *x509.CertPool
}

Fetcher fetches cards and key sets: https only, a size and time limit, at most three redirects and only to the same host, and (unless AllowPrivate) only to public addresses, checked on the address actually dialed so DNS rebinding cannot reach an internal service.

func (Fetcher) Get

func (f Fetcher) Get(ctx context.Context, rawURL string) ([]byte, error)

Get fetches rawURL (https only) within the limits and returns the body.

func (Fetcher) Verify

func (f Fetcher) Verify(ctx context.Context, cardURL string, exp Expect) (Result, error)

Verify fetches cardURL and checks it against exp: the JWS signature when a key or JWKS is pinned (an unsigned card then fails), and the digest when one is pinned. The Result is returned with the error, for reporting.

type Interface

type Interface struct {
	URL             string `json:"url"`
	ProtocolBinding string `json:"protocolBinding"`
	ProtocolVersion string `json:"protocolVersion"`
}

Interface is one AgentInterface (transport binding and URL).

type Key

type Key struct {
	ID  string // JWK kid; "" for a pinned PEM key (matches any kid)
	Pub crypto.PublicKey
}

Key is a public key that may have signed a card.

func ParseJWKS

func ParseJWKS(b []byte) ([]Key, error)

ParseJWKS reads the keys of an RFC 7517 JWK Set: OKP Ed25519, EC P-256 and P-384, RSA (>= 2048 bits). Keys of other types are skipped.

type Result

type Result struct {
	Card   Card   `json:"card"`
	Digest string `json:"digest"`
	// Signed: the card carries signatures; Verified: one verified with the
	// pinned key or JWKS (false when none is configured).
	Signed   bool `json:"signed"`
	Verified bool `json:"verified"`
}

Result is a fetched and verified card.

type Skill

type Skill struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

Skill is one AgentSkill.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL