Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ __pycache__/
dist/
*.egg-info/
.coverage

# Local virtual environments
.venv/
venv/
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

### Changed

- **BREAKING: the suite now conforms to TRACE v0.2.** `TR-ENV` requires the profile `tag:agentrust-io.com,2026:trace-v0.2` and fails a record carrying the v0.1 identifier. The v0.1 URI named `agentrust.io`, a domain this project never controlled, which RFC 4151 does not permit for a tag URI; see agentrust-io/trace-spec#107. Nothing else about the record format changed, so a producer migrates by updating the profile string and bumping `agentrust-trace` to 0.5.0.

This is a deliberate cutover rather than dual acceptance: a conformance suite that passed both identifiers would certify records minted under a domain we do not own. A v0.1 record is checked with the 0.3.x releases of this suite, which stay published.

- Registry, verifier, and documentation hosts moved from `agentrust.io` to `agentrust-io.com`.

## v0.3.0 — 2026-07-21

- `azure-cvm-sev-snp` platform accepted (`runtime.platform`): Azure confidential VMs run SEV-SNP behind a Hyper-V paravisor (vTPM-rooted). Added to the bundled schema enum and the TR-RTE valid-platform set so Azure TRACE records pass conformance. Matches `agentrust-trace>=0.4`.
Expand Down
4 changes: 2 additions & 2 deletions docs/error-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ All TRACE test failures emit a structured error code of the form `TR-<MODULE>-<N

| Code | Description | How to fix |
|------|-------------|------------|
| TR-ENV-001 | Missing or invalid `eat_profile` URI | Set `eat_profile` to `"tag:agentrust.io,2026:trace-v0.1"` |
| TR-ENV-001 | Missing or invalid `eat_profile` URI | Set `eat_profile` to `"tag:agentrust-io.com,2026:trace-v0.2"` |
| TR-ENV-002 | `iat` is missing, not an integer, or out of range | Set `iat` to a Unix timestamp integer (e.g. `int(time.time())`) |
| TR-ENV-003 | `subject` does not match SPIFFE URI or DID pattern | Use `spiffe://<trust-domain>/<path>` or a `did:` URI |
| TR-ENV-004 | One or more required fields are absent | Add the missing field(s); check the [Schema Reference](https://trace.agentrust-io.com/schema) for the full required set |
Expand Down Expand Up @@ -47,7 +47,7 @@ All TRACE test failures emit a structured error code of the form `TR-<MODULE>-<N
| Code | Description | How to fix |
|------|-------------|------------|
| TR-ANC-001 | `transparency` field missing or empty | Submit the record to a SCITT transparency log and set `transparency` to the returned receipt URI |
| TR-ANC-002 | `transparency` URI does not use `https://` scheme | Only `https://` URIs are accepted; update the URI or use the agentrust registry at `https://registry.agentrust.io` |
| TR-ANC-002 | `transparency` URI does not use `https://` scheme | Only `https://` URIs are accepted; update the URI or use the agentrust registry at `https://registry.agentrust-io.com` |

## TR-SCA — Provenance

Expand Down
14 changes: 7 additions & 7 deletions docs/levels.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Level 0 records are signed with a software key. The `runtime.platform` must be `

```json
{
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1750000000,
"subject": "spiffe://trust.example.org/agent/my-agent",
"model": {
Expand All @@ -41,7 +41,7 @@ Level 0 records are signed with a software key. The `runtime.platform` must be `
"status": "none",
"verifier": "https://verifier.example.org"
},
"transparency": "https://registry.agentrust.io/claim/placeholder",
"transparency": "https://registry.agentrust-io.com/claim/placeholder",
"cnf": {
"jwk": {
"kty": "OKP",
Expand Down Expand Up @@ -73,7 +73,7 @@ Level 1 adds hardware attestation. `runtime.platform` must be one of: `tpm2`, `s

```json
{
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1750000000,
"subject": "spiffe://trust.example.org/agent/my-agent",
"model": {
Expand All @@ -96,9 +96,9 @@ Level 1 adds hardware attestation. `runtime.platform` must be one of: `tpm2`, `s
},
"appraisal": {
"status": "affirming",
"verifier": "https://verifier.agentrust.io"
"verifier": "https://verifier.agentrust-io.com"
},
"transparency": "https://registry.agentrust.io/claim/placeholder",
"transparency": "https://registry.agentrust-io.com/claim/placeholder",
"cnf": {
"jwk": {
"kty": "OKP",
Expand Down Expand Up @@ -133,9 +133,9 @@ Level 2 adds tool transcript and transparency anchor requirements. The `transpar
"hash": "sha256:c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4",
"call_count": 4
},
"transparency": "https://registry.agentrust.io/claim/01J3XKWP4NQZ8R5HT6YD7VMBCE",
"transparency": "https://registry.agentrust-io.com/claim/01J3XKWP4NQZ8R5HT6YD7VMBCE",
"anchor": {
"log_id": "https://registry.agentrust.io",
"log_id": "https://registry.agentrust-io.com",
"leaf_hash": "sha256:f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5"
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/tr-env.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Tests the top-level EAT envelope structure of a TRACE Trust Record.

| Test ID | Description | Positive Case | Negative Case |
|---------|-------------|---------------|---------------|
| TR-ENV-001 | `eat_profile` present and correct URI | `tag:agentrust.io,2026:trace-v0.1` | missing or wrong |
| TR-ENV-001 | `eat_profile` present and correct URI | `tag:agentrust-io.com,2026:trace-v0.2` | missing or wrong |
| TR-ENV-002 | `iat` is a valid Unix timestamp | integer, reasonable range | string, future date |
| TR-ENV-003 | `subject` matches SPIFFE URI or DID | `spiffe://trust.example/agent/x` or `did:key:z6Mk...` | bare string |
| TR-ENV-004 | Required fields present | all of: eat_profile, iat, subject, model, runtime, policy, data_class, build_provenance, appraisal | missing any |
4 changes: 2 additions & 2 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ from agentrust_trace import generate_key, sign_record
key = generate_key()

record = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": int(time.time()),
"subject": "spiffe://trust.example.org/agent/sample",
"model": {
Expand All @@ -49,7 +49,7 @@ record = {
"status": "none",
"verifier": "https://verifier.example.org",
},
"transparency": "https://registry.agentrust.io/claim/placeholder",
"transparency": "https://registry.agentrust-io.com/claim/placeholder",
}

signed = sign_record(record, key)
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/writing-conformance-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def build_signed_cmcp_record(platform: str = "tpm2") -> dict:
record = {
"cmcp_version": "1.0",
"trace": {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": int(time.time()) - 30,
"subject": "spiffe://cmcp.gateway/session/my-test",
"runtime": {
Expand Down Expand Up @@ -228,7 +228,7 @@ Common codes you will encounter:

| Code | Field | Fix |
|------|-------|-----|
| TR-ENV-001 | `eat_profile` | Must be `tag:agentrust.io,2026:trace-v0.1` |
| TR-ENV-001 | `eat_profile` | Must be `tag:agentrust-io.com,2026:trace-v0.2` |
| TR-ENV-002 | `iat` | Must be a Unix timestamp in the last 24 hours |
| TR-SIG-001 | `signature` | Signature missing or does not verify |
| TR-SIG-002 | `cnf.jwk` | Key must be OKP/Ed25519 |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description = "TRACE conformance test suite"
readme = "README.md"
license = { text = "Apache-2.0" }
authors = [
{ name = "agentrust.io" },
{ name = "agentrust-io.com" },
]
keywords = ["trace", "conformance", "attestation", "ai-agents", "provenance"]
classifiers = [
Expand Down
6 changes: 3 additions & 3 deletions schemas/trace-claim.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://agentrust.io/schema/trace-v0.1.json",
"$id": "https://agentrust-io.com/schema/trace-v0.1.json",
"title": "TRACE Trust Record",
"description": "A TRACE v0.1 Trust Record — hardware-attested governance evidence for an AI agent execution.",
"description": "A TRACE v0.2 Trust Record — hardware-attested governance evidence for an AI agent execution.",
"type": "object",
"required": [
"eat_profile", "iat", "subject", "model", "runtime", "policy",
"data_class", "build_provenance", "appraisal", "transparency", "cnf"
],
"properties": {
"eat_profile": {"type": "string", "const": "tag:agentrust.io,2026:trace-v0.1"},
"eat_profile": {"type": "string", "const": "tag:agentrust-io.com,2026:trace-v0.2"},
"iat": {"type": "integer", "minimum": 1700000000},
"subject": {"type": "string", "pattern": "^(spiffe://|did:)"},
"model": {
Expand Down
2 changes: 1 addition & 1 deletion src/trace_tests/modules/tr_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from trace_tests.result import Finding, Status

_PROFILE = "tag:agentrust.io,2026:trace-v0.1"
_PROFILE = "tag:agentrust-io.com,2026:trace-v0.2"
_SUBJECT_RE = re.compile(r'^(spiffe://[^/]+/.+|did:[a-z0-9]+:.+)$')
_IAT_MIN = 1_700_000_000

Expand Down
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _build_signed_cmcp_record(*, platform: str = "tpm2", nonce: str | None = Non
iat = int(time.time()) - 30 # fresh but not future-dated

trace: dict = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": iat,
"subject": "spiffe://cmcp.gateway/session/conformance-test",
"runtime": {
Expand Down Expand Up @@ -135,7 +135,7 @@ def _build_software_only_record() -> dict:
record: dict = {
"cmcp_version": "1.0",
"trace": {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": iat,
"subject": "spiffe://cmcp.gateway/session/level2-test",
"runtime": {
Expand Down
2 changes: 1 addition & 1 deletion tests/test_level0.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_schema_valid(self, schema, valid_level0):
jsonschema.validate(valid_level0, schema)

def test_eat_profile_sentinel(self, valid_level0):
assert valid_level0["eat_profile"] == "tag:agentrust.io,2026:trace-v0.1"
assert valid_level0["eat_profile"] == "tag:agentrust-io.com,2026:trace-v0.2"

def test_iat_is_positive_integer(self, valid_level0):
assert isinstance(valid_level0["iat"], int)
Expand Down
6 changes: 3 additions & 3 deletions tests/test_level1.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ def test_eat_protected_header_content_type(self, signed_eat_fixture):

In the cMCP profile the eat_profile field inside trace serves the role
of the COSE protected header content-type: it binds the record to the
TRACE v0.1 specification and prevents cross-profile replay.
TRACE v0.2 specification and prevents cross-profile replay.
"""
trace = signed_eat_fixture["trace"]
assert trace.get("eat_profile") == "tag:agentrust.io,2026:trace-v0.1", (
"trace.eat_profile must be 'tag:agentrust.io,2026:trace-v0.1'"
assert trace.get("eat_profile") == "tag:agentrust-io.com,2026:trace-v0.2", (
"trace.eat_profile must be 'tag:agentrust-io.com,2026:trace-v0.2'"
)

def test_signature_verifies_against_cnf_key(self, signed_eat_fixture):
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

VALID_CMCP = {
"cmcp_version": "1.0",
"trace": {"eat_profile": "tag:agentrust.io,2026:trace-v0.1"},
"trace": {"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2"},
"gateway": {"session_id": "s1"},
"signature": "sig",
}

VALID_TRACE = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "spiffe://example.org/agent/test",
}
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_tr_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from trace_tests.result import Status

_VALID = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": int(time.time()) - 600, # fresh: 10 minutes old
"subject": "spiffe://example.org/agent/test",
"cnf": {"jwk": {"kty": "OKP", "crv": "Ed25519", "x": "dGVzdA"}},
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_tr_sig.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _make_signed_record() -> dict:
record = {
"cmcp_version": "1.0",
"trace": {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "spiffe://cmcp.gateway/session/unit-test",
"runtime": {
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_plain_trace_embedded_ed25519_signature_passes():
x = _b64url(pub.public_bytes_raw())

trace: dict = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "did:mesh:spiffe://example.org/agent/test",
"runtime": {"platform": "software-only", "measurement": "sha256:" + "a" * 64},
Expand All @@ -135,7 +135,7 @@ def test_plain_trace_tampered_embedded_signature_fails():
x = _b64url(pub.public_bytes_raw())

trace: dict = {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "did:mesh:spiffe://example.org/agent/test",
"runtime": {"platform": "software-only", "measurement": "sha256:" + "a" * 64},
Expand Down
2 changes: 1 addition & 1 deletion tests/vectors/invalid_missing_runtime.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "spiffe://example.org/agent/test/001",
"model": {"provider": "anthropic", "model_id": "claude-sonnet-4-5"},
Expand Down
2 changes: 1 addition & 1 deletion tests/vectors/valid_cmcp_runtime.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"cmcp_version": "1.0",
"trace": {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "spiffe://cmcp.gateway/session/test-session-001",
"runtime": {
Expand Down
2 changes: 1 addition & 1 deletion tests/vectors/valid_level0.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000000,
"subject": "spiffe://example.org/agent/credit-risk/01926b4c-1234-7abc-9def-000000000001",
"model": {
Expand Down
2 changes: 1 addition & 1 deletion tests/vectors/valid_level0_with_transcript.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"eat_profile": "tag:agentrust-io.com,2026:trace-v0.2",
"iat": 1748000001,
"subject": "spiffe://example.org/agent/payments/01926b4c-1234-7abc-9def-000000000002",
"model": {
Expand Down