Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions adr/0024-entry-trust-manifest-publisher-domain-alignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# ADR-0024: Define Publisher-Domain Alignment for Entry Trust Manifests

## Status

Proposed

## Date

2026-09-02

## Context

The Trust Manifest required the domain in its `identity` to align with the
publisher domain in the containing Catalog Entry's `identifier` without
defining how to obtain or compare those domains. Non-`urn:air` identifiers do
not necessarily communicate a publisher domain, so implementations could not
apply the requirement interoperably.

Alignment can check consistency between the `{publisher}` domain in the
Catalog Entry's `identifier` and the domain in the Entry Trust Manifest's
`identity`. A Trust Manifest signature covers its `identity`, but does not by
itself authenticate the containing Catalog Entry's `identifier`. Alignment
cannot prove domain control, publisher or signer authorization, or
authenticity; those guarantees require verification and an independent trust
policy.

## Decision

Entry Trust Manifests are supported only on Catalog Entries whose `identifier`
is publisher-authorized and uses the standard `urn:air` syntax defined in
Catalog Entry. Non-`urn:air` identifiers remain valid for Catalog Entries that
do not include an Entry Trust Manifest.

Catalog operators may reproduce an Entry Trust Manifest together with an
identifier assigned by the publisher or its authorized delegate.

AI Catalog defines how to obtain the domain used for publisher-domain
comparison from three identity URI forms:

- the resolution domain of a `did:web` identity, excluding any port;
- the host of an HTTPS identity, excluding any port; and
- the trust domain of a SPIFFE identity when it is an IDNA2008 domain name.

The applicable URN, URI, `did:web`, SPIFFE, and IDNA standards govern syntax
and validity; AI Catalog does not redefine their syntax. AI Catalog compares
complete IDNA2008 domain names serialized in ASCII form exactly after ASCII
case normalization. Ports, paths, queries, and fragments remain part of an
identity and may affect its interpretation or resolution, but they are ignored
when comparing its domain with the publisher domain.

When no comparison domain can be obtained or the domains are not aligned,
consumers disregard the Entry Trust Manifest's claims and apply their policy
for an entry without a usable Trust Manifest. The optional `identityType`
member is informational: consumers obtain the domain from the `identity` URI
itself, not from this hint.

Supporting another identity URI form would require defining how to obtain its
domain for comparison.

## Consequences

- Alignment means consistency, not authentication or authorization.
- Non-`urn:air` identifiers remain valid for Catalog Entries that do not
include an Entry Trust Manifest.
- Ports, paths, queries, and fragments remain part of an identity even though
they do not participate in publisher-domain comparison.
2 changes: 1 addition & 1 deletion docs/examples/multi-protocol-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ An agent that supports both MCP and A2A protocols can be represented as a single
]
},
"trustManifest": {
"identity": "urn:air:acme-corp.com:agent:finance",
"identity": "did:web:acme-corp.com:agent:finance",
"attestations": [
{
"type": "SOC2-Type2",
Expand Down
19 changes: 13 additions & 6 deletions docs/guides/adding-trust.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Trust builds on the three conformance levels:
"type": "application/a2a-agent-card+json",
"url": "...",
"trustManifest": {
"identity": "urn:air:acme-corp.com:a2a:finance",
"identity": "did:web:acme-corp.com:a2a:finance",
"attestations": [...]
}
}
Expand All @@ -68,13 +68,20 @@ Trust builds on the three conformance levels:
A Trust Manifest is an object on a Catalog Entry (or Host Info object) with one required field:

`identity`
: A globally unique URI that identifies this artifact. **Its trust domain must align with the publisher domain in the containing entry's `identifier`.** This binding ties trust claims to the authorized publisher.
: A globally unique URI that identifies this artifact.

For a Trust Manifest on a Catalog Entry:

- The containing Catalog Entry's `identifier` must be a publisher-authorized `urn:air` identifier.
- The publisher domain in the Catalog Entry's `identifier` must exactly match the domain obtained from the Trust Manifest's `identity`, ignoring ASCII case. AI Catalog defines how to obtain that domain from `did:web`, HTTPS, and SPIFFE identities.

This alignment is a consistency check; it does not prove publisher authorization or control of the domain. See the [full specification](../specification.md) for the normative rules.

All other fields are optional:

| Field | Description |
|---|---|
| `identityType` | Type hint for the identity URI: `"did"`, `"spiffe"`, `"dns"` |
| `identityType` | Optional hint describing the identity URI, such as `did` or `spiffe`; consumers use `identity` itself—not this hint—to determine the domain for publisher-domain alignment |
| `trustSchema` | Describes the trust framework applied |
| `attestations` | Array of compliance and identity attestation objects |
| `provenance` | Array of provenance links (source code, OCI digests) |
Expand All @@ -92,7 +99,7 @@ The simplest trust step is asserting publisher identity. Use an attestation of t

```json
"trustManifest": {
"identity": "urn:air:acme-corp.com:a2a:finance",
"identity": "did:web:acme-corp.com:a2a:finance",
"attestations": [
{
"type": "publisher-identity",
Expand Down Expand Up @@ -165,7 +172,7 @@ The `signature` field holds a detached JWS (RFC 7515):

```json
"trustManifest": {
"identity": "urn:air:acme-corp.com:a2a:finance",
"identity": "did:web:acme-corp.com:a2a:finance",
"attestations": [...],
"signature": "eyJhbGciOiJFUzI1NiJ9..detached-jws-signature"
}
Expand Down Expand Up @@ -207,7 +214,7 @@ A Trust Manifest with identity, compliance attestation, provenance, and signatur
"displayName": "Acme Financial Corp"
},
"trustManifest": {
"identity": "urn:air:acme-corp.com:a2a:finance",
"identity": "did:web:acme-corp.com:a2a:finance",
"trustSchema": {
"identifier": "urn:trust:acme-enterprise-v1",
"version": "1.0",
Expand Down
2 changes: 1 addition & 1 deletion docs/mappings/mcp-servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ server's Server Card and whose `type` is the known type
"displayName": "Acme Financial Corp"
},
"trustManifest": {
"identity": "urn:air:acme-corp.com:mcp:finance-server",
"identity": "did:web:acme-corp.com:mcp:finance-server",
"attestations": [
{
"type": "publisher-identity",
Expand Down
84 changes: 71 additions & 13 deletions specification/ai-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,9 @@ The following members are OPTIONAL:
`trustManifest`
: A Trust Manifest object as defined in [Trust Manifest](#trust-manifest)
providing verifiable identity and trust metadata for this artifact.
See [Trust Manifest](#trust-manifest) for details.
A Trust Manifest carried here is an *Entry Trust Manifest*. See
[Entry Trust Manifest Publisher-Domain Alignment](#entry-trust-manifest-publisher-domain-alignment)
for its requirements.

### Resolving an Artifact's Display Name

Expand Down Expand Up @@ -513,19 +515,75 @@ A Trust Manifest MUST contain:
DID, SPIFFE ID, or URL; these are illustrative and the set of
identity schemes is open.

When a Trust Manifest appears within a Catalog Entry, the `identity`
field's trust domain MUST align with the publisher domain in the
containing entry's `identifier` field. This binding ensures
trust claims are associated with the authorized publisher namespace even
when `identity` and `identifier` use different URI schemes.
Consumers MUST reject a Trust Manifest whose `identity` domain does not
align with the publisher domain in the containing entry's `identifier`.
The `identity` is carried here so domain binding is part of the signed
payload, rather than inferred only from unsigned entry context.

When a Trust Manifest appears on a Host Info object, `identity`
SHOULD match the host's `identifier` field when present.

### Entry Trust Manifest Publisher-Domain Alignment

This subsection applies only to a Trust Manifest on a Catalog Entry. A Catalog
Entry that includes a Trust Manifest MUST use a publisher-authorized `urn:air`
identifier with the standard syntax defined in [Catalog Entry](#catalog-entry).
The identifier MUST have been assigned by the artifact publisher or its
authorized delegate using the publisher's domain in its `{publisher}`
component. Non-`urn:air` identifiers remain valid for Catalog Entries that do
not include an Entry Trust Manifest.

An independent catalog operator MAY reproduce an Entry Trust Manifest together
with its publisher-assigned identifier.

The publisher domain is the `{publisher}` component of the Catalog Entry's
`urn:air` identifier. Consumers obtain the identity domain from a valid Trust
Manifest `identity` URI [[RFC3986]] as follows:

- **`did:web`:** the domain used by the method's resolution rules
[[DIDWEB]], excluding any port;
- **HTTPS:** the URI host, excluding any port [[RFC9110]]; or
- **SPIFFE:** the trust domain of a valid SPIFFE ID [[SPIFFEID]], when that
trust domain is an IDNA2008 domain name [[RFC5890]] [[RFC5891]].

URI, DID, SPIFFE, and domain syntax validity are defined by their respective
standards, including [[RFC8141]]. A valid port remains part of the identity but
is not part of the domain used for publisher-domain comparison. Paths, queries,
and fragments likewise do not participate in the comparison. The `identity`
URI itself determines which rule above applies. The optional `identityType`
member is only a descriptive hint and MUST NOT be used to select a
domain-extraction rule.

The publisher domain and identity domain MUST be valid IDNA2008 domain names in
ASCII form, with internationalized labels encoded as A-labels (the ASCII form
beginning with `xn--`) and without a trailing root dot. Consumers MUST compare
them for exact equality after converting ASCII letters to lowercase; suffix
matching and organizational-ownership heuristics MUST NOT be used.

| Entry identifier | Trust Manifest `identity` | Alignment |
|---|---|---|
| `urn:air:example.com:agent:billing` | `did:web:example.com:agent:billing` | aligned |
| `urn:air:example.com:agent:billing` | `https://EXAMPLE.com:8443/keys/billing` | aligned |
| `urn:air:example.com:agent:billing` | `spiffe://example.com/billing` | aligned |
| `urn:air:example.com:agent:billing` | `did:web:service.example.com:billing` | not aligned |

A consumer MUST disregard all claims in an Entry Trust Manifest if any of the
following conditions applies:

- The Catalog Entry's `identifier` does not use the standard `urn:air` syntax.
- The Catalog Entry's `identifier`, the Trust Manifest's `identity`, or either
domain is invalid under the applicable standards or the requirements above.
- This subsection does not define how to obtain a domain from the Trust
Manifest's `identity` URI.
- The publisher domain and identity domain are not aligned.

The consumer MUST then apply the same policy it would apply to a Catalog Entry
without a usable Trust Manifest.

Alignment establishes consistency between the publisher domain in the Catalog
Entry's `identifier` and the domain in the Trust Manifest's `identity`. It does
not establish control of that domain, publisher or signer authorization,
signature validity, artifact integrity, publisher authenticity, or
trustworthiness. Those properties require the corresponding verification and
trust-anchoring procedures. A Trust Manifest signature covers its `identity`,
but does not by itself authenticate the containing Catalog Entry's
`identifier`.

When multiple entries share the same `identifier` (with different `version`
values), each entry MAY carry its own Trust Manifest. There is no
requirement that all versions carry identical trust metadata — trust
Expand Down Expand Up @@ -1822,7 +1880,7 @@ artifact types including a nested catalog packaging related artifacts:
"type": "application/parquet",
"url": "https://data.acme-corp.com/market-2026q1.parquet",
"trustManifest": {
"identity": "urn:air:acme.com:data:market-2026q1",
"identity": "did:web:acme.com:data:market-2026q1",
"provenance": [
{
"relation": "publishedFrom",
Expand All @@ -1835,7 +1893,7 @@ artifact types including a nested catalog packaging related artifacts:
]
},
"trustManifest": {
"identity": "urn:air:acme.com:plugin:finance-suite",
"identity": "did:web:acme.com:plugin:finance-suite",
"signature": "eyJhbGciOiJFUzI1NiJ9..detached"
},
"updatedAt": "2026-03-20T14:00:00Z"
Expand Down
12 changes: 12 additions & 0 deletions specification/respec-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@
"href": "https://www.rfc-editor.org/rfc/rfc8288",
"status": "RFC",
"publisher": "IETF"
},
"DIDWEB": {
"title": "did:web Method Specification",
"href": "https://github.com/w3c-ccg/did-method-web/blob/ea423c114e6f2537498ee6f94e8d794c64f60c18/index.html",
"status": "Draft Community Group Report",
"publisher": "W3C Credentials Community Group"
},
"SPIFFEID": {
"title": "SPIFFE ID Standard",
"href": "https://github.com/spiffe/spiffe/blob/dc4e9d9b4eff8aa181a54cd330ff9f877186060e/standards/SPIFFE-ID.md",
"status": "Standard",
"publisher": "SPIFFE"
}
}
}