1use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct Statement {
19 #[serde(rename = "_type")]
21 pub type_: String,
22 pub subject: Vec<Subject>,
24 pub predicate_type: String,
26 pub predicate: serde_json::Value,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct Subject {
36 pub name: String,
38 pub digest: Digest,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47pub struct Digest {
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub sha256: Option<String>,
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub sha512: Option<String>,
54}
55
56impl Statement {
57 pub fn matches_sha256(&self, hash_hex: &str) -> bool {
59 self.subject.iter().any(|subject| {
60 subject
61 .digest
62 .sha256
63 .as_ref()
64 .is_some_and(|h| h == hash_hex)
65 })
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_statement_deserialization() {
75 let json = r#"{
76 "_type": "https://in-toto.io/Statement/v1",
77 "subject": [
78 {
79 "name": "example.txt",
80 "digest": {
81 "sha256": "abc123"
82 }
83 }
84 ],
85 "predicateType": "https://slsa.dev/provenance/v1",
86 "predicate": {}
87 }"#;
88
89 let statement: Statement = serde_json::from_str(json).unwrap();
90 assert_eq!(statement.type_, "https://in-toto.io/Statement/v1");
91 assert_eq!(statement.subject.len(), 1);
92 assert_eq!(statement.subject[0].name, "example.txt");
93 assert_eq!(
94 statement.subject[0].digest.sha256,
95 Some("abc123".to_string())
96 );
97 }
98
99 #[test]
100 fn test_matches_sha256() {
101 let statement = Statement {
102 type_: "https://in-toto.io/Statement/v1".to_string(),
103 subject: vec![
104 Subject {
105 name: "file1.txt".to_string(),
106 digest: Digest {
107 sha256: Some("hash1".to_string()),
108 sha512: None,
109 },
110 },
111 Subject {
112 name: "file2.txt".to_string(),
113 digest: Digest {
114 sha256: Some("hash2".to_string()),
115 sha512: None,
116 },
117 },
118 ],
119 predicate_type: "https://slsa.dev/provenance/v1".to_string(),
120 predicate: serde_json::json!({}),
121 };
122
123 assert!(statement.matches_sha256("hash1"));
124 assert!(statement.matches_sha256("hash2"));
125 assert!(!statement.matches_sha256("hash3"));
126 }
127}