1use camino::Utf8PathBuf;
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ReceiptEnvelope {
15 pub schema: String,
17
18 pub tool: ToolInfo,
19
20 #[serde(default)]
21 pub run: RunInfo,
22
23 #[serde(default)]
24 pub verdict: Verdict,
25
26 #[serde(default)]
27 pub findings: Vec<Finding>,
28
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub capabilities: Option<ReceiptCapabilities>,
32
33 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub data: Option<serde_json::Value>,
36}
37
38#[derive(Debug, Clone, Default, Serialize, Deserialize)]
40pub struct ReceiptCapabilities {
41 #[serde(default, skip_serializing_if = "Vec::is_empty")]
43 pub check_ids: Vec<String>,
44
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub scopes: Vec<String>,
48
49 #[serde(default)]
51 pub partial: bool,
52
53 #[serde(default, skip_serializing_if = "Option::is_none")]
55 pub reason: Option<String>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ToolInfo {
60 pub name: String,
61
62 #[serde(default, skip_serializing_if = "Option::is_none")]
63 pub version: Option<String>,
64
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub repo: Option<String>,
67
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub commit: Option<String>,
70}
71
72#[derive(Debug, Clone, Default, Serialize, Deserialize)]
73pub struct RunInfo {
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub started_at: Option<DateTime<Utc>>,
76
77 #[serde(default, skip_serializing_if = "Option::is_none")]
78 pub ended_at: Option<DateTime<Utc>>,
79
80 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub git_head_sha: Option<String>,
84}
85
86#[derive(Debug, Clone, Default, Serialize, Deserialize)]
87pub struct Verdict {
88 #[serde(default)]
89 pub status: VerdictStatus,
90
91 #[serde(default)]
92 pub counts: Counts,
93
94 #[serde(default, skip_serializing_if = "Vec::is_empty")]
95 pub reasons: Vec<String>,
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
99#[serde(rename_all = "snake_case")]
100pub enum VerdictStatus {
101 Pass,
102 Warn,
103 Fail,
104 #[default]
105 Unknown,
106}
107
108#[derive(Debug, Clone, Default, Serialize, Deserialize)]
109pub struct Counts {
110 #[serde(default)]
111 pub findings: u64,
112
113 #[serde(default)]
114 pub errors: u64,
115
116 #[serde(default)]
117 pub warnings: u64,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct Finding {
122 #[serde(default)]
123 pub severity: Severity,
124
125 #[serde(default, skip_serializing_if = "Option::is_none")]
126 pub check_id: Option<String>,
127
128 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub code: Option<String>,
130
131 #[serde(default, skip_serializing_if = "Option::is_none")]
132 pub message: Option<String>,
133
134 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub location: Option<Location>,
136
137 #[serde(default, skip_serializing_if = "Option::is_none")]
139 pub fingerprint: Option<String>,
140
141 #[serde(default, skip_serializing_if = "Option::is_none")]
143 pub data: Option<serde_json::Value>,
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
147#[serde(rename_all = "snake_case")]
148pub enum Severity {
149 #[default]
150 Info,
151 Warn,
152 Error,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct Location {
157 pub path: Utf8PathBuf,
158
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub line: Option<u64>,
161
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub column: Option<u64>,
164}