//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `process-attestation`. Version: `0.1`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///Deterministic identification of the object whose production is in question.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Deterministic identification of the object whose production is in question.",
/// "type": "object",
/// "required": [
/// "algorithm",
/// "digest"
/// ],
/// "properties": {
/// "algorithm": {
/// "description": "Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.",
/// "type": "string",
/// "enum": [
/// "sha-256",
/// "sha-384",
/// "sha-512",
/// "blake3"
/// ]
/// },
/// "byteLength": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "digest": {
/// "description": "base64url, unpadded.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43,128}$"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Artifact {
///Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.
pub algorithm: ArtifactAlgorithm,
#[serde(
rename = "byteLength",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub byte_length: ::std::option::Option<u64>,
///base64url, unpadded.
pub digest: ArtifactDigest,
}
impl Artifact {
pub fn builder() -> builder::Artifact {
Default::default()
}
}
///Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.",
/// "type": "string",
/// "enum": [
/// "sha-256",
/// "sha-384",
/// "sha-512",
/// "blake3"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum ArtifactAlgorithm {
#[serde(rename = "sha-256")]
Sha256,
#[serde(rename = "sha-384")]
Sha384,
#[serde(rename = "sha-512")]
Sha512,
#[serde(rename = "blake3")]
Blake3,
}
impl ::std::fmt::Display for ArtifactAlgorithm {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Sha256 => f.write_str("sha-256"),
Self::Sha384 => f.write_str("sha-384"),
Self::Sha512 => f.write_str("sha-512"),
Self::Blake3 => f.write_str("blake3"),
}
}
}
impl ::std::str::FromStr for ArtifactAlgorithm {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"sha-256" => Ok(Self::Sha256),
"sha-384" => Ok(Self::Sha384),
"sha-512" => Ok(Self::Sha512),
"blake3" => Ok(Self::Blake3),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for ArtifactAlgorithm {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ArtifactAlgorithm {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ArtifactAlgorithm {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///base64url, unpadded.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "base64url, unpadded.",
/// "type": "string",
/// "pattern": "^[A-Za-z0-9_-]{43,128}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ArtifactDigest(::std::string::String);
impl ::std::ops::Deref for ArtifactDigest {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ArtifactDigest> for ::std::string::String {
fn from(value: ArtifactDigest) -> Self {
value.0
}
}
impl ::std::str::FromStr for ArtifactDigest {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[A-Za-z0-9_-]{43,128}$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9_-]{43,128}$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ArtifactDigest {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ArtifactDigest {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ArtifactDigest {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ArtifactDigest {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Opaque at the task layer. The task standardizes the interaction, not the receipt.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Opaque at the task layer. The task standardizes the interaction, not the receipt.",
/// "type": "object",
/// "required": [
/// "determination",
/// "primitive"
/// ],
/// "properties": {
/// "confidence": {
/// "description": "The primitive's confidence in `determination`, as an integer percentage. An integer rather than a fraction because no other specification in this registry puts a floating-point value on the wire: a float's textual form is not stable across JSON implementations, which makes byte-exact re-serialization a language-dependent property.",
/// "type": "integer",
/// "maximum": 100.0,
/// "minimum": 0.0
/// },
/// "determination": {
/// "description": "Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
/// },
/// "primitive": {
/// "description": "Specification the receipt is verified under. Names which vocabulary `determination` belongs to.",
/// "type": "string",
/// "format": "uri",
/// "maxLength": 2048
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Assessment {
///The primitive's confidence in `determination`, as an integer percentage. An integer rather than a fraction because no other specification in this registry puts a floating-point value on the wire: a float's textual form is not stable across JSON implementations, which makes byte-exact re-serialization a language-dependent property.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub confidence: ::std::option::Option<i64>,
///Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.
pub determination: AssessmentDetermination,
///Specification the receipt is verified under. Names which vocabulary `determination` belongs to.
pub primitive: ::std::string::String,
}
impl Assessment {
pub fn builder() -> builder::Assessment {
Default::default()
}
}
///Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct AssessmentDetermination(::std::string::String);
impl ::std::ops::Deref for AssessmentDetermination {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<AssessmentDetermination> for ::std::string::String {
fn from(value: AssessmentDetermination) -> Self {
value.0
}
}
impl ::std::str::FromStr for AssessmentDetermination {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for AssessmentDetermination {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for AssessmentDetermination {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for AssessmentDetermination {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for AssessmentDetermination {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Only the categories the request asked for.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Only the categories the request asked for.",
/// "type": "object",
/// "properties": {
/// "anchors": {
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "kind"
/// ],
/// "properties": {
/// "anchoredAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "kind": {
/// "type": "string",
/// "enum": [
/// "rfc3161",
/// "opentimestamps",
/// "roughtime"
/// ]
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "document": {
/// "type": "object",
/// "properties": {
/// "mediaType": {
/// "type": "string",
/// "maxLength": 255
/// }
/// },
/// "additionalProperties": false
/// },
/// "integrity": {
/// "type": "object",
/// "properties": {
/// "chainValid": {
/// "type": "boolean"
/// },
/// "keyCustody": {
/// "type": "string",
/// "enum": [
/// "software",
/// "tpm",
/// "secureEnclave"
/// ]
/// },
/// "signatureValid": {
/// "type": "boolean"
/// }
/// },
/// "additionalProperties": false
/// },
/// "timeline": {
/// "type": "object",
/// "properties": {
/// "checkpointCount": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "endedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "startedAt": {
/// "type": "string",
/// "format": "date-time"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Disclosed {
#[serde(default, skip_serializing_if = "::std::vec::Vec::is_empty")]
pub anchors: ::std::vec::Vec<DisclosedAnchorsItem>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub document: ::std::option::Option<DisclosedDocument>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub integrity: ::std::option::Option<DisclosedIntegrity>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub timeline: ::std::option::Option<DisclosedTimeline>,
}
impl ::std::default::Default for Disclosed {
fn default() -> Self {
Self {
anchors: Default::default(),
document: Default::default(),
integrity: Default::default(),
timeline: Default::default(),
}
}
}
impl Disclosed {
pub fn builder() -> builder::Disclosed {
Default::default()
}
}
///`DisclosedAnchorsItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "kind"
/// ],
/// "properties": {
/// "anchoredAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "kind": {
/// "type": "string",
/// "enum": [
/// "rfc3161",
/// "opentimestamps",
/// "roughtime"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DisclosedAnchorsItem {
#[serde(
rename = "anchoredAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub anchored_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
pub kind: DisclosedAnchorsItemKind,
}
impl DisclosedAnchorsItem {
pub fn builder() -> builder::DisclosedAnchorsItem {
Default::default()
}
}
///`DisclosedAnchorsItemKind`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "rfc3161",
/// "opentimestamps",
/// "roughtime"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DisclosedAnchorsItemKind {
#[serde(rename = "rfc3161")]
Rfc3161,
#[serde(rename = "opentimestamps")]
Opentimestamps,
#[serde(rename = "roughtime")]
Roughtime,
}
impl ::std::fmt::Display for DisclosedAnchorsItemKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Rfc3161 => f.write_str("rfc3161"),
Self::Opentimestamps => f.write_str("opentimestamps"),
Self::Roughtime => f.write_str("roughtime"),
}
}
}
impl ::std::str::FromStr for DisclosedAnchorsItemKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"rfc3161" => Ok(Self::Rfc3161),
"opentimestamps" => Ok(Self::Opentimestamps),
"roughtime" => Ok(Self::Roughtime),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DisclosedAnchorsItemKind {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DisclosedAnchorsItemKind {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DisclosedAnchorsItemKind {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`DisclosedDocument`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "mediaType": {
/// "type": "string",
/// "maxLength": 255
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DisclosedDocument {
#[serde(
rename = "mediaType",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub media_type: ::std::option::Option<DisclosedDocumentMediaType>,
}
impl ::std::default::Default for DisclosedDocument {
fn default() -> Self {
Self {
media_type: Default::default(),
}
}
}
impl DisclosedDocument {
pub fn builder() -> builder::DisclosedDocument {
Default::default()
}
}
///`DisclosedDocumentMediaType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 255
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DisclosedDocumentMediaType(::std::string::String);
impl ::std::ops::Deref for DisclosedDocumentMediaType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DisclosedDocumentMediaType> for ::std::string::String {
fn from(value: DisclosedDocumentMediaType) -> Self {
value.0
}
}
impl ::std::str::FromStr for DisclosedDocumentMediaType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 255usize {
return Err("longer than 255 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DisclosedDocumentMediaType {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DisclosedDocumentMediaType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DisclosedDocumentMediaType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for DisclosedDocumentMediaType {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`DisclosedIntegrity`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "chainValid": {
/// "type": "boolean"
/// },
/// "keyCustody": {
/// "type": "string",
/// "enum": [
/// "software",
/// "tpm",
/// "secureEnclave"
/// ]
/// },
/// "signatureValid": {
/// "type": "boolean"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DisclosedIntegrity {
#[serde(
rename = "chainValid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub chain_valid: ::std::option::Option<bool>,
#[serde(
rename = "keyCustody",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub key_custody: ::std::option::Option<DisclosedIntegrityKeyCustody>,
#[serde(
rename = "signatureValid",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub signature_valid: ::std::option::Option<bool>,
}
impl ::std::default::Default for DisclosedIntegrity {
fn default() -> Self {
Self {
chain_valid: Default::default(),
key_custody: Default::default(),
signature_valid: Default::default(),
}
}
}
impl DisclosedIntegrity {
pub fn builder() -> builder::DisclosedIntegrity {
Default::default()
}
}
///`DisclosedIntegrityKeyCustody`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "software",
/// "tpm",
/// "secureEnclave"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DisclosedIntegrityKeyCustody {
#[serde(rename = "software")]
Software,
#[serde(rename = "tpm")]
Tpm,
#[serde(rename = "secureEnclave")]
SecureEnclave,
}
impl ::std::fmt::Display for DisclosedIntegrityKeyCustody {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Software => f.write_str("software"),
Self::Tpm => f.write_str("tpm"),
Self::SecureEnclave => f.write_str("secureEnclave"),
}
}
}
impl ::std::str::FromStr for DisclosedIntegrityKeyCustody {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"software" => Ok(Self::Software),
"tpm" => Ok(Self::Tpm),
"secureEnclave" => Ok(Self::SecureEnclave),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DisclosedIntegrityKeyCustody {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DisclosedIntegrityKeyCustody {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DisclosedIntegrityKeyCustody {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`DisclosedTimeline`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "properties": {
/// "checkpointCount": {
/// "type": "integer",
/// "minimum": 0.0
/// },
/// "endedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "startedAt": {
/// "type": "string",
/// "format": "date-time"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DisclosedTimeline {
#[serde(
rename = "checkpointCount",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub checkpoint_count: ::std::option::Option<u64>,
#[serde(
rename = "endedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ended_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(
rename = "startedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub started_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
}
impl ::std::default::Default for DisclosedTimeline {
fn default() -> Self {
Self {
checkpoint_count: Default::default(),
ended_at: Default::default(),
started_at: Default::default(),
}
}
}
impl DisclosedTimeline {
pub fn builder() -> builder::DisclosedTimeline {
Default::default()
}
}
///Derived aggregates only. An enum rather than a pattern so a primitive cannot widen its own disclosure surface by inventing a name. The determination itself is not a category: it is always in `assessment` when the result is `attested`. Raw behavioral samples and fingerprints are out of scope for 0.1.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Derived aggregates only. An enum rather than a pattern so a primitive cannot widen its own disclosure surface by inventing a name. The determination itself is not a category: it is always in `assessment` when the result is `attested`. Raw behavioral samples and fingerprints are out of scope for 0.1.",
/// "type": "string",
/// "enum": [
/// "document",
/// "timeline",
/// "integrity",
/// "anchors"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DisclosureCategory {
#[serde(rename = "document")]
Document,
#[serde(rename = "timeline")]
Timeline,
#[serde(rename = "integrity")]
Integrity,
#[serde(rename = "anchors")]
Anchors,
}
impl ::std::fmt::Display for DisclosureCategory {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Document => f.write_str("document"),
Self::Timeline => f.write_str("timeline"),
Self::Integrity => f.write_str("integrity"),
Self::Anchors => f.write_str("anchors"),
}
}
}
impl ::std::str::FromStr for DisclosureCategory {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"document" => Ok(Self::Document),
"timeline" => Ok(Self::Timeline),
"integrity" => Ok(Self::Integrity),
"anchors" => Ok(Self::Anchors),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DisclosureCategory {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for DisclosureCategory {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for DisclosureCategory {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///What a Verifier asks of a Holder: identify an artifact by digest, supply a freshness challenge, and name the disclosure categories wanted. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/process-attestation/0.1",
/// "title": "Payload",
/// "description": "What a Verifier asks of a Holder: identify an artifact by digest, supply a freshness challenge, and name the disclosure categories wanted. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.",
/// "type": "object",
/// "required": [
/// "artifact",
/// "challenge"
/// ],
/// "properties": {
/// "artifact": {
/// "$ref": "#/definitions/Artifact"
/// },
/// "challenge": {
/// "description": "Verifier-supplied freshness nonce, echoed verbatim in the response. The floor is 16 characters because anti-replay is the only integrity property the request has.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 16
/// },
/// "disclosure": {
/// "description": "Categories the Verifier requests. A Holder MAY return fewer; it MUST NOT return more.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/DisclosureCategory"
/// },
/// "uniqueItems": true
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
pub artifact: Artifact,
///Verifier-supplied freshness nonce, echoed verbatim in the response. The floor is 16 characters because anti-replay is the only integrity property the request has.
pub challenge: PayloadChallenge,
///Categories the Verifier requests. A Holder MAY return fewer; it MUST NOT return more.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub disclosure: ::std::option::Option<Vec<DisclosureCategory>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///Verifier-supplied freshness nonce, echoed verbatim in the response. The floor is 16 characters because anti-replay is the only integrity property the request has.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Verifier-supplied freshness nonce, echoed verbatim in the response. The floor is 16 characters because anti-replay is the only integrity property the request has.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadChallenge(::std::string::String);
impl ::std::ops::Deref for PayloadChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadChallenge> for ::std::string::String {
fn from(value: PayloadChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadChallenge {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadChallenge {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Tagged union. Inline exists for Verifiers that cannot dereference a URI at verification time.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Tagged union. Inline exists for Verifiers that cannot dereference a URI at verification time.",
/// "oneOf": [
/// {
/// "type": "object",
/// "required": [
/// "type",
/// "uri"
/// ],
/// "properties": {
/// "mediaType": {
/// "type": "string",
/// "maxLength": 255
/// },
/// "type": {
/// "const": "uri"
/// },
/// "uri": {
/// "type": "string",
/// "format": "uri",
/// "maxLength": 2048
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "type": "object",
/// "required": [
/// "data",
/// "mediaType",
/// "type"
/// ],
/// "properties": {
/// "data": {
/// "description": "base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.",
/// "type": "string",
/// "maxLength": 262144,
/// "pattern": "^[A-Za-z0-9_-]+$"
/// },
/// "mediaType": {
/// "type": "string",
/// "maxLength": 255
/// },
/// "type": {
/// "const": "inline"
/// }
/// },
/// "additionalProperties": false
/// }
/// ]
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(tag = "type", deny_unknown_fields)]
#[non_exhaustive]
pub enum ReceiptReference {
#[serde(rename = "uri")]
Uri {
#[serde(
rename = "mediaType",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
media_type: ::std::option::Option<ReceiptReferenceMediaType>,
uri: ::std::string::String,
},
#[serde(rename = "inline")]
Inline {
///base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.
data: ReceiptReferenceData,
#[serde(rename = "mediaType")]
media_type: ReceiptReferenceMediaType,
},
}
///base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.",
/// "type": "string",
/// "maxLength": 262144,
/// "pattern": "^[A-Za-z0-9_-]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ReceiptReferenceData(::std::string::String);
impl ::std::ops::Deref for ReceiptReferenceData {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ReceiptReferenceData> for ::std::string::String {
fn from(value: ReceiptReferenceData) -> Self {
value.0
}
}
impl ::std::str::FromStr for ReceiptReferenceData {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 262144usize {
return Err("longer than 262144 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[A-Za-z0-9_-]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[A-Za-z0-9_-]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ReceiptReferenceData {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ReceiptReferenceData {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ReceiptReferenceData {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ReceiptReferenceData {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`ReceiptReferenceMediaType`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "maxLength": 255
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ReceiptReferenceMediaType(::std::string::String);
impl ::std::ops::Deref for ReceiptReferenceMediaType {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ReceiptReferenceMediaType> for ::std::string::String {
fn from(value: ReceiptReferenceMediaType) -> Self {
value.0
}
}
impl ::std::str::FromStr for ReceiptReferenceMediaType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 255usize {
return Err("longer than 255 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ReceiptReferenceMediaType {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ReceiptReferenceMediaType {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ReceiptReferenceMediaType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ReceiptReferenceMediaType {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The Holder's answer. Failures use trust-task-error, not this shape. Both results share one response type so the envelope carries no observable distinction between them. `result` is the discriminator and stays inside the payload, so one envelope type covers both branches.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "The Holder's answer. Failures use trust-task-error, not this shape. Both results share one response type so the envelope carries no observable distinction between them. `result` is the discriminator and stays inside the payload, so one envelope type covers both branches.",
/// "oneOf": [
/// {
/// "title": "Attested",
/// "type": "object",
/// "required": [
/// "artifact",
/// "assessment",
/// "challenge",
/// "receiptReference",
/// "result"
/// ],
/// "properties": {
/// "artifact": {
/// "$ref": "#/definitions/Artifact"
/// },
/// "assessment": {
/// "$ref": "#/definitions/Assessment"
/// },
/// "challenge": {
/// "description": "The request's challenge, echoed verbatim.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 16
/// },
/// "disclosed": {
/// "$ref": "#/definitions/Disclosed"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "receiptReference": {
/// "$ref": "#/definitions/ReceiptReference"
/// },
/// "result": {
/// "const": "attested"
/// }
/// },
/// "additionalProperties": false
/// },
/// {
/// "title": "Unavailable",
/// "type": "object",
/// "required": [
/// "artifact",
/// "challenge",
/// "result"
/// ],
/// "properties": {
/// "artifact": {
/// "$ref": "#/definitions/Artifact"
/// },
/// "challenge": {
/// "description": "The request's challenge, echoed verbatim.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 16
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "result": {
/// "const": "unavailable"
/// }
/// },
/// "additionalProperties": false
/// }
/// ],
/// "$anchor": "response",
/// "unevaluatedProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(tag = "result", deny_unknown_fields)]
#[non_exhaustive]
pub enum Response {
///Attested
#[serde(rename = "attested")]
Attested {
artifact: Artifact,
assessment: Assessment,
///The request's challenge, echoed verbatim.
challenge: ResponseChallenge,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
disclosed: ::std::option::Option<Disclosed>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
ext: ::std::option::Option<Ext>,
#[serde(rename = "receiptReference")]
receipt_reference: ReceiptReference,
},
///Unavailable
#[serde(rename = "unavailable")]
Unavailable {
artifact: Artifact,
///The request's challenge, echoed verbatim.
challenge: ResponseChallenge,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
ext: ::std::option::Option<Ext>,
},
}
///The request's challenge, echoed verbatim.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The request's challenge, echoed verbatim.",
/// "type": "string",
/// "maxLength": 256,
/// "minLength": 16
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseChallenge(::std::string::String);
impl ::std::ops::Deref for ResponseChallenge {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseChallenge> for ::std::string::String {
fn from(value: ResponseChallenge) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseChallenge {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
if value.chars().count() < 16usize {
return Err("shorter than 16 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ResponseChallenge {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ResponseChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ResponseChallenge {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ResponseChallenge {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct Artifact {
algorithm: ::std::result::Result<super::ArtifactAlgorithm, ::std::string::String>,
byte_length: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
digest: ::std::result::Result<super::ArtifactDigest, ::std::string::String>,
}
impl ::std::default::Default for Artifact {
fn default() -> Self {
Self {
algorithm: Err("no value supplied for algorithm".to_string()),
byte_length: Ok(Default::default()),
digest: Err("no value supplied for digest".to_string()),
}
}
}
impl Artifact {
pub fn algorithm<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ArtifactAlgorithm>,
T::Error: ::std::fmt::Display,
{
self.algorithm = value
.try_into()
.map_err(|e| format!("error converting supplied value for algorithm: {e}"));
self
}
pub fn byte_length<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.byte_length = value
.try_into()
.map_err(|e| format!("error converting supplied value for byte_length: {e}"));
self
}
pub fn digest<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ArtifactDigest>,
T::Error: ::std::fmt::Display,
{
self.digest = value
.try_into()
.map_err(|e| format!("error converting supplied value for digest: {e}"));
self
}
}
impl ::std::convert::TryFrom<Artifact> for super::Artifact {
type Error = super::error::ConversionError;
fn try_from(value: Artifact) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
algorithm: value.algorithm?,
byte_length: value.byte_length?,
digest: value.digest?,
})
}
}
impl ::std::convert::From<super::Artifact> for Artifact {
fn from(value: super::Artifact) -> Self {
Self {
algorithm: Ok(value.algorithm),
byte_length: Ok(value.byte_length),
digest: Ok(value.digest),
}
}
}
#[derive(Clone, Debug)]
pub struct Assessment {
confidence: ::std::result::Result<::std::option::Option<i64>, ::std::string::String>,
determination: ::std::result::Result<super::AssessmentDetermination, ::std::string::String>,
primitive: ::std::result::Result<::std::string::String, ::std::string::String>,
}
impl ::std::default::Default for Assessment {
fn default() -> Self {
Self {
confidence: Ok(Default::default()),
determination: Err("no value supplied for determination".to_string()),
primitive: Err("no value supplied for primitive".to_string()),
}
}
}
impl Assessment {
pub fn confidence<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<i64>>,
T::Error: ::std::fmt::Display,
{
self.confidence = value
.try_into()
.map_err(|e| format!("error converting supplied value for confidence: {e}"));
self
}
pub fn determination<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::AssessmentDetermination>,
T::Error: ::std::fmt::Display,
{
self.determination = value
.try_into()
.map_err(|e| format!("error converting supplied value for determination: {e}"));
self
}
pub fn primitive<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.primitive = value
.try_into()
.map_err(|e| format!("error converting supplied value for primitive: {e}"));
self
}
}
impl ::std::convert::TryFrom<Assessment> for super::Assessment {
type Error = super::error::ConversionError;
fn try_from(
value: Assessment,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
confidence: value.confidence?,
determination: value.determination?,
primitive: value.primitive?,
})
}
}
impl ::std::convert::From<super::Assessment> for Assessment {
fn from(value: super::Assessment) -> Self {
Self {
confidence: Ok(value.confidence),
determination: Ok(value.determination),
primitive: Ok(value.primitive),
}
}
}
#[derive(Clone, Debug)]
pub struct Disclosed {
anchors: ::std::result::Result<
::std::vec::Vec<super::DisclosedAnchorsItem>,
::std::string::String,
>,
document: ::std::result::Result<
::std::option::Option<super::DisclosedDocument>,
::std::string::String,
>,
integrity: ::std::result::Result<
::std::option::Option<super::DisclosedIntegrity>,
::std::string::String,
>,
timeline: ::std::result::Result<
::std::option::Option<super::DisclosedTimeline>,
::std::string::String,
>,
}
impl ::std::default::Default for Disclosed {
fn default() -> Self {
Self {
anchors: Ok(Default::default()),
document: Ok(Default::default()),
integrity: Ok(Default::default()),
timeline: Ok(Default::default()),
}
}
}
impl Disclosed {
pub fn anchors<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::DisclosedAnchorsItem>>,
T::Error: ::std::fmt::Display,
{
self.anchors = value
.try_into()
.map_err(|e| format!("error converting supplied value for anchors: {e}"));
self
}
pub fn document<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DisclosedDocument>>,
T::Error: ::std::fmt::Display,
{
self.document = value
.try_into()
.map_err(|e| format!("error converting supplied value for document: {e}"));
self
}
pub fn integrity<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DisclosedIntegrity>>,
T::Error: ::std::fmt::Display,
{
self.integrity = value
.try_into()
.map_err(|e| format!("error converting supplied value for integrity: {e}"));
self
}
pub fn timeline<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DisclosedTimeline>>,
T::Error: ::std::fmt::Display,
{
self.timeline = value
.try_into()
.map_err(|e| format!("error converting supplied value for timeline: {e}"));
self
}
}
impl ::std::convert::TryFrom<Disclosed> for super::Disclosed {
type Error = super::error::ConversionError;
fn try_from(
value: Disclosed,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
anchors: value.anchors?,
document: value.document?,
integrity: value.integrity?,
timeline: value.timeline?,
})
}
}
impl ::std::convert::From<super::Disclosed> for Disclosed {
fn from(value: super::Disclosed) -> Self {
Self {
anchors: Ok(value.anchors),
document: Ok(value.document),
integrity: Ok(value.integrity),
timeline: Ok(value.timeline),
}
}
}
#[derive(Clone, Debug)]
pub struct DisclosedAnchorsItem {
anchored_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
kind: ::std::result::Result<super::DisclosedAnchorsItemKind, ::std::string::String>,
}
impl ::std::default::Default for DisclosedAnchorsItem {
fn default() -> Self {
Self {
anchored_at: Ok(Default::default()),
kind: Err("no value supplied for kind".to_string()),
}
}
}
impl DisclosedAnchorsItem {
pub fn anchored_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.anchored_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for anchored_at: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DisclosedAnchorsItemKind>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
}
impl ::std::convert::TryFrom<DisclosedAnchorsItem> for super::DisclosedAnchorsItem {
type Error = super::error::ConversionError;
fn try_from(
value: DisclosedAnchorsItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
anchored_at: value.anchored_at?,
kind: value.kind?,
})
}
}
impl ::std::convert::From<super::DisclosedAnchorsItem> for DisclosedAnchorsItem {
fn from(value: super::DisclosedAnchorsItem) -> Self {
Self {
anchored_at: Ok(value.anchored_at),
kind: Ok(value.kind),
}
}
}
#[derive(Clone, Debug)]
pub struct DisclosedDocument {
media_type: ::std::result::Result<
::std::option::Option<super::DisclosedDocumentMediaType>,
::std::string::String,
>,
}
impl ::std::default::Default for DisclosedDocument {
fn default() -> Self {
Self {
media_type: Ok(Default::default()),
}
}
}
impl DisclosedDocument {
pub fn media_type<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DisclosedDocumentMediaType>>,
T::Error: ::std::fmt::Display,
{
self.media_type = value
.try_into()
.map_err(|e| format!("error converting supplied value for media_type: {e}"));
self
}
}
impl ::std::convert::TryFrom<DisclosedDocument> for super::DisclosedDocument {
type Error = super::error::ConversionError;
fn try_from(
value: DisclosedDocument,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
media_type: value.media_type?,
})
}
}
impl ::std::convert::From<super::DisclosedDocument> for DisclosedDocument {
fn from(value: super::DisclosedDocument) -> Self {
Self {
media_type: Ok(value.media_type),
}
}
}
#[derive(Clone, Debug)]
pub struct DisclosedIntegrity {
chain_valid: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
key_custody: ::std::result::Result<
::std::option::Option<super::DisclosedIntegrityKeyCustody>,
::std::string::String,
>,
signature_valid: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
}
impl ::std::default::Default for DisclosedIntegrity {
fn default() -> Self {
Self {
chain_valid: Ok(Default::default()),
key_custody: Ok(Default::default()),
signature_valid: Ok(Default::default()),
}
}
}
impl DisclosedIntegrity {
pub fn chain_valid<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.chain_valid = value
.try_into()
.map_err(|e| format!("error converting supplied value for chain_valid: {e}"));
self
}
pub fn key_custody<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DisclosedIntegrityKeyCustody>>,
T::Error: ::std::fmt::Display,
{
self.key_custody = value
.try_into()
.map_err(|e| format!("error converting supplied value for key_custody: {e}"));
self
}
pub fn signature_valid<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.signature_valid = value
.try_into()
.map_err(|e| format!("error converting supplied value for signature_valid: {e}"));
self
}
}
impl ::std::convert::TryFrom<DisclosedIntegrity> for super::DisclosedIntegrity {
type Error = super::error::ConversionError;
fn try_from(
value: DisclosedIntegrity,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
chain_valid: value.chain_valid?,
key_custody: value.key_custody?,
signature_valid: value.signature_valid?,
})
}
}
impl ::std::convert::From<super::DisclosedIntegrity> for DisclosedIntegrity {
fn from(value: super::DisclosedIntegrity) -> Self {
Self {
chain_valid: Ok(value.chain_valid),
key_custody: Ok(value.key_custody),
signature_valid: Ok(value.signature_valid),
}
}
}
#[derive(Clone, Debug)]
pub struct DisclosedTimeline {
checkpoint_count: ::std::result::Result<::std::option::Option<u64>, ::std::string::String>,
ended_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
started_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
}
impl ::std::default::Default for DisclosedTimeline {
fn default() -> Self {
Self {
checkpoint_count: Ok(Default::default()),
ended_at: Ok(Default::default()),
started_at: Ok(Default::default()),
}
}
}
impl DisclosedTimeline {
pub fn checkpoint_count<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<u64>>,
T::Error: ::std::fmt::Display,
{
self.checkpoint_count = value
.try_into()
.map_err(|e| format!("error converting supplied value for checkpoint_count: {e}"));
self
}
pub fn ended_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.ended_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for ended_at: {e}"));
self
}
pub fn started_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.started_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for started_at: {e}"));
self
}
}
impl ::std::convert::TryFrom<DisclosedTimeline> for super::DisclosedTimeline {
type Error = super::error::ConversionError;
fn try_from(
value: DisclosedTimeline,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
checkpoint_count: value.checkpoint_count?,
ended_at: value.ended_at?,
started_at: value.started_at?,
})
}
}
impl ::std::convert::From<super::DisclosedTimeline> for DisclosedTimeline {
fn from(value: super::DisclosedTimeline) -> Self {
Self {
checkpoint_count: Ok(value.checkpoint_count),
ended_at: Ok(value.ended_at),
started_at: Ok(value.started_at),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
artifact: ::std::result::Result<super::Artifact, ::std::string::String>,
challenge: ::std::result::Result<super::PayloadChallenge, ::std::string::String>,
disclosure: ::std::result::Result<
::std::option::Option<Vec<super::DisclosureCategory>>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
artifact: Err("no value supplied for artifact".to_string()),
challenge: Err("no value supplied for challenge".to_string()),
disclosure: Ok(Default::default()),
ext: Ok(Default::default()),
}
}
}
impl Payload {
pub fn artifact<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Artifact>,
T::Error: ::std::fmt::Display,
{
self.artifact = value
.try_into()
.map_err(|e| format!("error converting supplied value for artifact: {e}"));
self
}
pub fn challenge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadChallenge>,
T::Error: ::std::fmt::Display,
{
self.challenge = value
.try_into()
.map_err(|e| format!("error converting supplied value for challenge: {e}"));
self
}
pub fn disclosure<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::DisclosureCategory>>>,
T::Error: ::std::fmt::Display,
{
self.disclosure = value
.try_into()
.map_err(|e| format!("error converting supplied value for disclosure: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
artifact: value.artifact?,
challenge: value.challenge?,
disclosure: value.disclosure?,
ext: value.ext?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
artifact: Ok(value.artifact),
challenge: Ok(value.challenge),
disclosure: Ok(value.disclosure),
ext: Ok(value.ext),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/process-attestation/0.1";
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Artifact\": {\n \"additionalProperties\": false,\n \"description\": \"Deterministic identification of the object whose production is in question.\",\n \"properties\": {\n \"algorithm\": {\n \"description\": \"Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.\",\n \"enum\": [\n \"sha-256\",\n \"sha-384\",\n \"sha-512\",\n \"blake3\"\n ],\n \"type\": \"string\"\n },\n \"byteLength\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"digest\": {\n \"description\": \"base64url, unpadded.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43,128}$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"digest\",\n \"algorithm\"\n ],\n \"type\": \"object\"\n },\n \"Assessment\": {\n \"additionalProperties\": false,\n \"description\": \"Opaque at the task layer. The task standardizes the interaction, not the receipt.\",\n \"properties\": {\n \"confidence\": {\n \"description\": \"The primitive's confidence in `determination`, as an integer percentage. An integer rather than a fraction because no other specification in this registry puts a floating-point value on the wire: a float's textual form is not stable across JSON implementations, which makes byte-exact re-serialization a language-dependent property.\",\n \"maximum\": 100,\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"determination\": {\n \"description\": \"Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"primitive\": {\n \"description\": \"Specification the receipt is verified under. Names which vocabulary `determination` belongs to.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"primitive\",\n \"determination\"\n ],\n \"type\": \"object\"\n },\n \"Disclosed\": {\n \"additionalProperties\": false,\n \"description\": \"Only the categories the request asked for.\",\n \"properties\": {\n \"anchors\": {\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"anchoredAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"enum\": [\n \"rfc3161\",\n \"opentimestamps\",\n \"roughtime\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\"\n ],\n \"type\": \"object\"\n },\n \"type\": \"array\"\n },\n \"document\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n }\n },\n \"type\": \"object\"\n },\n \"integrity\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"chainValid\": {\n \"type\": \"boolean\"\n },\n \"keyCustody\": {\n \"enum\": [\n \"software\",\n \"tpm\",\n \"secureEnclave\"\n ],\n \"type\": \"string\"\n },\n \"signatureValid\": {\n \"type\": \"boolean\"\n }\n },\n \"type\": \"object\"\n },\n \"timeline\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"checkpointCount\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"endedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"startedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n }\n },\n \"type\": \"object\"\n }\n },\n \"type\": \"object\"\n },\n \"DisclosureCategory\": {\n \"description\": \"Derived aggregates only. An enum rather than a pattern so a primitive cannot widen its own disclosure surface by inventing a name. The determination itself is not a category: it is always in `assessment` when the result is `attested`. Raw behavioral samples and fingerprints are out of scope for 0.1.\",\n \"enum\": [\n \"document\",\n \"timeline\",\n \"integrity\",\n \"anchors\"\n ],\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ReceiptReference\": {\n \"description\": \"Tagged union. Inline exists for Verifiers that cannot dereference a URI at verification time.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"uri\"\n },\n \"uri\": {\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"uri\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"data\": {\n \"description\": \"base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.\",\n \"maxLength\": 262144,\n \"pattern\": \"^[A-Za-z0-9_-]+$\",\n \"type\": \"string\"\n },\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"inline\"\n }\n },\n \"required\": [\n \"type\",\n \"mediaType\",\n \"data\"\n ],\n \"type\": \"object\"\n }\n ]\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"description\": \"The Holder's answer. Failures use trust-task-error, not this shape. Both results share one response type so the envelope carries no observable distinction between them. `result` is the discriminator and stays inside the payload, so one envelope type covers both branches.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"artifact\": {\n \"$ref\": \"#/$defs/Artifact\"\n },\n \"assessment\": {\n \"$ref\": \"#/$defs/Assessment\"\n },\n \"challenge\": {\n \"description\": \"The request's challenge, echoed verbatim.\",\n \"maxLength\": 256,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"disclosed\": {\n \"$ref\": \"#/$defs/Disclosed\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"receiptReference\": {\n \"$ref\": \"#/$defs/ReceiptReference\"\n },\n \"result\": {\n \"const\": \"attested\"\n }\n },\n \"required\": [\n \"result\",\n \"challenge\",\n \"artifact\",\n \"assessment\",\n \"receiptReference\"\n ],\n \"title\": \"Attested\",\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"artifact\": {\n \"$ref\": \"#/$defs/Artifact\"\n },\n \"challenge\": {\n \"description\": \"The request's challenge, echoed verbatim.\",\n \"maxLength\": 256,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"result\": {\n \"const\": \"unavailable\"\n }\n },\n \"required\": [\n \"result\",\n \"challenge\",\n \"artifact\"\n ],\n \"title\": \"Unavailable\",\n \"type\": \"object\"\n }\n ],\n \"title\": \"Process Attestation — response payload\",\n \"unevaluatedProperties\": false\n }\n },\n \"$id\": \"https://trusttasks.org/spec/process-attestation/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"What a Verifier asks of a Holder: identify an artifact by digest, supply a freshness challenge, and name the disclosure categories wanted. The outer document members (id, type, issuer, recipient, issuedAt, expiresAt, proof) are owned by the framework — SPEC §6.3.\",\n \"properties\": {\n \"artifact\": {\n \"$ref\": \"#/$defs/Artifact\"\n },\n \"challenge\": {\n \"description\": \"Verifier-supplied freshness nonce, echoed verbatim in the response. The floor is 16 characters because anti-replay is the only integrity property the request has.\",\n \"maxLength\": 256,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"disclosure\": {\n \"description\": \"Categories the Verifier requests. A Holder MAY return fewer; it MUST NOT return more.\",\n \"items\": {\n \"$ref\": \"#/$defs/DisclosureCategory\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n }\n },\n \"required\": [\n \"artifact\",\n \"challenge\"\n ],\n \"title\": \"Process Attestation — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/process-attestation/0.1#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Artifact\": {\n \"additionalProperties\": false,\n \"description\": \"Deterministic identification of the object whose production is in question.\",\n \"properties\": {\n \"algorithm\": {\n \"description\": \"Carried verbatim from the IANA Named Information Hash Algorithm registry, not re-cased — SPEC §4.10 externally-owned values.\",\n \"enum\": [\n \"sha-256\",\n \"sha-384\",\n \"sha-512\",\n \"blake3\"\n ],\n \"type\": \"string\"\n },\n \"byteLength\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"digest\": {\n \"description\": \"base64url, unpadded.\",\n \"pattern\": \"^[A-Za-z0-9_-]{43,128}$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"digest\",\n \"algorithm\"\n ],\n \"type\": \"object\"\n },\n \"Assessment\": {\n \"additionalProperties\": false,\n \"description\": \"Opaque at the task layer. The task standardizes the interaction, not the receipt.\",\n \"properties\": {\n \"confidence\": {\n \"description\": \"The primitive's confidence in `determination`, as an integer percentage. An integer rather than a fraction because no other specification in this registry puts a floating-point value on the wire: a float's textual form is not stable across JSON implementations, which makes byte-exact re-serialization a language-dependent property.\",\n \"maximum\": 100,\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"determination\": {\n \"description\": \"Primitive-defined. Deliberately not normalized across primitives: a determination means only what the primitive that produced it defines it to mean.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"type\": \"string\"\n },\n \"primitive\": {\n \"description\": \"Specification the receipt is verified under. Names which vocabulary `determination` belongs to.\",\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"primitive\",\n \"determination\"\n ],\n \"type\": \"object\"\n },\n \"Disclosed\": {\n \"additionalProperties\": false,\n \"description\": \"Only the categories the request asked for.\",\n \"properties\": {\n \"anchors\": {\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"anchoredAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"kind\": {\n \"enum\": [\n \"rfc3161\",\n \"opentimestamps\",\n \"roughtime\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\"\n ],\n \"type\": \"object\"\n },\n \"type\": \"array\"\n },\n \"document\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n }\n },\n \"type\": \"object\"\n },\n \"integrity\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"chainValid\": {\n \"type\": \"boolean\"\n },\n \"keyCustody\": {\n \"enum\": [\n \"software\",\n \"tpm\",\n \"secureEnclave\"\n ],\n \"type\": \"string\"\n },\n \"signatureValid\": {\n \"type\": \"boolean\"\n }\n },\n \"type\": \"object\"\n },\n \"timeline\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"checkpointCount\": {\n \"minimum\": 0,\n \"type\": \"integer\"\n },\n \"endedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"startedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n }\n },\n \"type\": \"object\"\n }\n },\n \"type\": \"object\"\n },\n \"DisclosureCategory\": {\n \"description\": \"Derived aggregates only. An enum rather than a pattern so a primitive cannot widen its own disclosure surface by inventing a name. The determination itself is not a category: it is always in `assessment` when the result is `attested`. Raw behavioral samples and fingerprints are out of scope for 0.1.\",\n \"enum\": [\n \"document\",\n \"timeline\",\n \"integrity\",\n \"anchors\"\n ],\n \"type\": \"string\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"ReceiptReference\": {\n \"description\": \"Tagged union. Inline exists for Verifiers that cannot dereference a URI at verification time.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"uri\"\n },\n \"uri\": {\n \"format\": \"uri\",\n \"maxLength\": 2048,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"uri\"\n ],\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"data\": {\n \"description\": \"base64url, unpadded. Bounded at 256 KiB of encoded text (~192 KiB of receipt): inline exists for the offline case, not as the general transport. A receipt larger than the bound MUST use the `uri` form.\",\n \"maxLength\": 262144,\n \"pattern\": \"^[A-Za-z0-9_-]+$\",\n \"type\": \"string\"\n },\n \"mediaType\": {\n \"maxLength\": 255,\n \"type\": \"string\"\n },\n \"type\": {\n \"const\": \"inline\"\n }\n },\n \"required\": [\n \"type\",\n \"mediaType\",\n \"data\"\n ],\n \"type\": \"object\"\n }\n ]\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"description\": \"The Holder's answer. Failures use trust-task-error, not this shape. Both results share one response type so the envelope carries no observable distinction between them. `result` is the discriminator and stays inside the payload, so one envelope type covers both branches.\",\n \"oneOf\": [\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"artifact\": {\n \"$ref\": \"#/$defs/Artifact\"\n },\n \"assessment\": {\n \"$ref\": \"#/$defs/Assessment\"\n },\n \"challenge\": {\n \"description\": \"The request's challenge, echoed verbatim.\",\n \"maxLength\": 256,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"disclosed\": {\n \"$ref\": \"#/$defs/Disclosed\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"receiptReference\": {\n \"$ref\": \"#/$defs/ReceiptReference\"\n },\n \"result\": {\n \"const\": \"attested\"\n }\n },\n \"required\": [\n \"result\",\n \"challenge\",\n \"artifact\",\n \"assessment\",\n \"receiptReference\"\n ],\n \"title\": \"Attested\",\n \"type\": \"object\"\n },\n {\n \"additionalProperties\": false,\n \"properties\": {\n \"artifact\": {\n \"$ref\": \"#/$defs/Artifact\"\n },\n \"challenge\": {\n \"description\": \"The request's challenge, echoed verbatim.\",\n \"maxLength\": 256,\n \"minLength\": 16,\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"result\": {\n \"const\": \"unavailable\"\n }\n },\n \"required\": [\n \"result\",\n \"challenge\",\n \"artifact\"\n ],\n \"title\": \"Unavailable\",\n \"type\": \"object\"\n }\n ],\n \"title\": \"Process Attestation — response payload\",\n \"unevaluatedProperties\": false\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
#[cfg(test)]
mod conformance {
//! Round-trip tests harvested from the spec's `spec.md`,
//! plus a `rejects_invalid_examples` test for any fixtures
//! in `payload.invalid-examples.json` (validate feature).
#[test]
fn request_example_1() {
const JSON: &str = "{\n \"id\": \"9f1c3a72-5e4b-4c8a-9d21-7b6e0f3a1c58\",\n \"type\": \"https://trusttasks.org/spec/process-attestation/0.1#request\",\n \"issuer\": \"did:web:verifier.example\",\n \"recipient\": \"did:web:author.example\",\n \"issuedAt\": \"2026-09-09T14:02:11Z\",\n \"threadId\": \"1c9d4e60-8a2f-4b13-bd77-2e5a6c0918af\",\n \"payload\": {\n \"artifact\": {\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\",\n \"algorithm\": \"sha-256\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"disclosure\": [\"document\", \"timeline\"]\n }\n}\n";
let doc: crate::TrustTask<super::Payload> =
serde_json::from_str(JSON).expect("deserialize request example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "request example failed round-trip");
}
#[test]
fn response_example_1() {
const JSON: &str = "{\n \"id\": \"4b8e1f05-6c3d-42a9-8e71-0d5f2a7c91b3\",\n \"type\": \"https://trusttasks.org/spec/process-attestation/0.1#response\",\n \"issuer\": \"did:web:author.example\",\n \"recipient\": \"did:web:verifier.example\",\n \"issuedAt\": \"2026-09-09T14:02:14Z\",\n \"threadId\": \"1c9d4e60-8a2f-4b13-bd77-2e5a6c0918af\",\n \"payload\": {\n \"result\": \"attested\",\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"artifact\": {\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\",\n \"algorithm\": \"sha-256\"\n },\n \"assessment\": {\n \"primitive\": \"https://lf-decentralized-trust-labs.github.io/proof-of-effort/\",\n \"determination\": \"V1_VerifiedHuman\",\n \"confidence\": 94\n },\n \"receiptReference\": {\n \"type\": \"uri\",\n \"uri\": \"https://evidence.author.example/r/4b8e1f05.cpoe\",\n \"mediaType\": \"application/cpoe+cose\"\n },\n \"disclosed\": {\n \"document\": {\n \"mediaType\": \"text/markdown\"\n },\n \"timeline\": {\n \"startedAt\": \"2026-09-08T09:14:02Z\",\n \"endedAt\": \"2026-09-08T11:47:35Z\",\n \"checkpointCount\": 41\n }\n }\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"created\": \"2026-09-09T14:02:14Z\",\n \"verificationMethod\": \"did:web:author.example#key-1\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z4oey6cnBVUCyx9YKvQZ8mR2vN4pT7sYwD1jB6xK0aC3eI9Mh\"\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
#[test]
fn response_example_2() {
const JSON: &str = "{\n \"id\": \"7d2a9c41-3f8b-4e05-a6d9-1b4c8e07f52a\",\n \"type\": \"https://trusttasks.org/spec/process-attestation/0.1#response\",\n \"issuer\": \"did:web:author.example\",\n \"recipient\": \"did:web:verifier.example\",\n \"issuedAt\": \"2026-09-09T14:02:14Z\",\n \"threadId\": \"1c9d4e60-8a2f-4b13-bd77-2e5a6c0918af\",\n \"payload\": {\n \"result\": \"unavailable\",\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"artifact\": {\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\",\n \"algorithm\": \"sha-256\"\n }\n },\n \"proof\": {\n \"type\": \"DataIntegrityProof\",\n \"cryptosuite\": \"eddsa-jcs-2022\",\n \"created\": \"2026-09-09T14:02:14Z\",\n \"verificationMethod\": \"did:web:author.example#key-1\",\n \"proofPurpose\": \"assertionMethod\",\n \"proofValue\": \"z3xKp7mQzR2vLbN9hJ4cWfA6dY0sE5uT8gO1iZBVUCyx9\"\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
/// Each fixture in `payload.invalid-examples.json` MUST be
/// rejected by at least one of: serde deserialization, or
/// JSON-Schema validation under the `validate` feature. The
/// fixture file documents the producer-side bug class that
/// each payload exemplifies; this generated test pins it.
#[cfg(feature = "validate")]
#[test]
fn rejects_invalid_examples() {
use crate::validate::ValidatedPayload;
let fixtures: &[(&str, &str)] = &[
(
"Bare/unnamespaced ext key. SPEC §4.5.1 requires every immediate child of ext to be reverse-DNS namespaced.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"ext\": {\n \"bare-key\": {\n \"anything\": \"here\"\n }\n }\n}",
),
(
"Unknown top-level payload member. additionalProperties: false catches `frobnicate`.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"frobnicate\": true\n}",
),
(
"Challenge below the 16-character floor. A short nonce is guessable, and anti-replay is the only integrity property the request has.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"tooshort\"\n}",
),
(
"Digest carries base64 padding and '+'. The Artifact pattern is base64url unpadded, so a producer emitting standard base64 is rejected rather than silently compared against a differently-encoded digest.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8+Rk2vN4pT7sYwD1jB6xK0aC3eI9M=\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\"\n}",
),
(
"Unregistered disclosure category. An enum rather than a pattern, so a primitive cannot widen its own disclosure surface by inventing a name.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"disclosure\": [\n \"summary\",\n \"keystroke-samples\"\n ]\n}",
),
(
"Duplicate disclosure entries; uniqueItems. Repeats are a producer bug and would otherwise reach the Holder as a request to disclose twice.",
"{\n \"artifact\": {\n \"algorithm\": \"sha-256\",\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\",\n \"disclosure\": [\n \"document\",\n \"document\"\n ]\n}",
),
(
"Missing algorithm. A bare digest cannot be compared without knowing which function produced it.",
"{\n \"artifact\": {\n \"digest\": \"hcHFbGVGLXVQqZ8mRk2vN4pT7sYwD1jB6xK0aC3eI9M\"\n },\n \"challenge\": \"9tKpX2mQzR7vLbN4hJ8cWfA6dY0sE5uT3gO1iZ\"\n}",
),
];
for (i, (note, raw)) in fixtures.iter().enumerate() {
let value: serde_json::Value = match serde_json::from_str(raw) {
Ok(v) => v,
Err(_) => continue,
};
let serde_ok = serde_json::from_value::<super::Payload>(value.clone()).is_ok();
let schema_ok = super::Payload::validate_value(&value).is_ok();
assert!(
!(serde_ok && schema_ok),
"invalid-example #{} ({:?}) was accepted by both serde and JSON Schema; \
the fixture's stated failure class is no longer caught:\n{}",
i + 1,
note,
raw
);
}
}
}