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
15 changes: 14 additions & 1 deletion src/agentrust_trace/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,20 @@ class TrustRecord(BaseModel):
delegation: Delegation | None = None
build_provenance: BuildProvenance
appraisal: Appraisal
transparency: Annotated[str, Field(min_length=1)]
transparency: Annotated[str, Field(min_length=1)] | None = None
"""SCITT receipt URI resolving to the inclusion proof on the transparency log.

Optional in the model, and required by conformance at **Level 2**, where
`TR-ANC` runs (`agentrust-trace-tests`). A Level 0 or Level 1 record is not
anchored, so it has no receipt to name, and the model must be able to
represent that. Enforcing a non-empty value here regardless of level made the
model stricter than both the conformance suite and `schema/trace-claim.json`,
which sets no minimum length.

Use `None` for an unanchored record rather than an empty string: `""` is not a
URI, and a field that looks populated but resolves to nothing is worse than an
absent one.
"""
cnf: ConfirmationKey
signature: Annotated[str, Field(pattern=r"^[A-Za-z0-9_-]+$")] | None = None
"""Optional embedded signature (base64url, no padding) by the cnf key over the
Expand Down
25 changes: 25 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,28 @@ def test_delegation_extra_field_rejected() -> None:
}
with pytest.raises(ValidationError):
TrustRecord.model_validate(data)


def test_transparency_optional_for_unanchored_records() -> None:
"""A Level 0/1 record has no receipt to name, so its absence must be representable.

Conformance requires `transparency` at Level 2, where TR-ANC runs. Requiring a
non-empty value in the model regardless of level made it stricter than both the
conformance suite and schema/trace-claim.json, and left an unanchored record
unrepresentable.
"""
data = _load("intel-tdx.json")
data.pop("transparency", None)
assert TrustRecord.model_validate(data).transparency is None

data = _load("intel-tdx.json")
data["transparency"] = None
assert TrustRecord.model_validate(data).transparency is None


def test_transparency_rejects_empty_string() -> None:
"""`None` means unanchored; `""` is a URI-shaped lie and stays rejected."""
data = _load("intel-tdx.json")
data["transparency"] = ""
with pytest.raises(ValidationError):
TrustRecord.model_validate(data)