Skip to main content

rustev_contract/
source.rs

1//! Context source descriptors, `rustev.source/1` (spec 032, 3.3.1): what the
2//! host says a source can attest, per definition input and path. Bound at
3//! compile time like a backend descriptor; Rustev stores nothing and
4//! verifies no source.
5
6use serde::{Deserialize, Serialize};
7
8use crate::definition::ProvenanceClass;
9use crate::grade::Grade;
10use crate::ids::SourceId;
11use crate::limits::DESCRIPTOR_V1;
12use crate::schema;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
15#[serde(deny_unknown_fields)]
16pub struct SourceDescriptor {
17    pub schema: String,
18    /// 1 to 64 bytes of `[a-z0-9_-]`; compared with a snapshot entry's
19    /// `source`.
20    pub name: String,
21    /// `MAJOR.MINOR.PATCH`.
22    pub version: String,
23    /// Later #76 specs add optional members beside this one (spec 032,
24    /// 3.1.2).
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub facts: Option<Vec<Fact>>,
27    /// Acquisition operations (spec 036, 3.2), omitted when absent.
28    #[serde(
29        default,
30        skip_serializing_if = "Option::is_none",
31        deserialize_with = "crate::acquisition::operations"
32    )]
33    #[schemars(with = "Vec<crate::acquisition::Operation>", length(min = 1, max = 64))]
34    pub operations: Option<Vec<crate::acquisition::Operation>>,
35}
36
37crate::document::document!(SourceDescriptor, schema::SOURCE, DESCRIPTOR_V1, SourceId);
38
39/// What a source attests for one definition input.
40#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
41#[serde(deny_unknown_fields)]
42pub struct Fact {
43    /// A definition input name.
44    pub name: String,
45    pub provenance: ProvenanceClass,
46    /// Non-empty; declares `""` exactly once and no path twice.
47    pub grades: Vec<FactGrade>,
48}
49
50/// The highest grade a path can have from this source.
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
52#[serde(deny_unknown_fields)]
53pub struct FactGrade {
54    /// `""` (the whole value) or segments joined by `/`: a record field
55    /// name, or `*` for every list item or map value.
56    pub path: String,
57    pub max_grade: Grade,
58    pub reliability: Reliability,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
62#[serde(rename_all = "snake_case", deny_unknown_fields)]
63pub enum Reliability {
64    Reliable,
65    /// The path's ceiling is at most `hint`, whatever its `max_grade`.
66    KnownUnreliable {
67        /// 1 to 256 bytes.
68        note: String,
69    },
70}
71
72impl FactGrade {
73    /// This declaration's own limit: `max_grade`, or `hint` (the lowest
74    /// grade) when the source marks the path unreliable (spec 032, 3.3.1).
75    pub fn limit(&self) -> Grade {
76        match self.reliability {
77            Reliability::Reliable => self.max_grade,
78            Reliability::KnownUnreliable { .. } => Grade::Hint,
79        }
80    }
81}
82
83/// A valid source name: 1 to 64 bytes of `[a-z0-9_-]`.
84pub fn valid_source_name(s: &str) -> bool {
85    !s.is_empty()
86        && s.len() <= 64
87        && s.bytes()
88            .all(|b| b.is_ascii_lowercase() || b.is_ascii_digit() || b == b'_' || b == b'-')
89}