1use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "lowercase")]
9pub enum CadiType {
10 Source,
11 Intermediate,
12 Blob,
13 Container,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ChunkMeta {
19 pub name: String,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub description: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub version: Option<String>,
24 #[serde(default)]
25 pub tags: Vec<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub created_at: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub updated_at: Option<String>,
30}
31
32#[derive(Debug, Clone, Default, Serialize, Deserialize)]
34pub struct ChunkProvides {
35 #[serde(default)]
36 pub concepts: Vec<String>,
37 #[serde(default)]
38 pub interfaces: Vec<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub abi: Option<String>,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ChunkLicensing {
46 pub license: String,
47 #[serde(default)]
48 pub restrictions: Vec<String>,
49}
50
51#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53pub struct ChunkLineage {
54 #[serde(default)]
55 pub parents: Vec<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub build_receipt: Option<String>,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct Chunk {
63 pub chunk_id: String,
64 pub cadi_type: CadiType,
65 pub meta: ChunkMeta,
66 #[serde(default)]
67 pub provides: ChunkProvides,
68 pub licensing: ChunkLicensing,
69 #[serde(default)]
70 pub lineage: ChunkLineage,
71 #[serde(default)]
72 pub signatures: Vec<String>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct SourceFile {
78 pub path: String,
79 pub hash: String,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub size: Option<usize>,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct Entrypoint {
87 pub symbol: String,
88 pub path: String,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct Dependency {
94 pub id: String,
95 #[serde(default)]
96 pub optional: bool,
97 #[serde(default)]
98 pub features: Vec<String>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct SourceData {
104 pub language: String,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub version: Option<String>,
107 #[serde(skip_serializing_if = "Option::is_none")]
108 pub dialect: Option<String>,
109 pub files: Vec<SourceFile>,
110 #[serde(default)]
111 pub entrypoints: Vec<Entrypoint>,
112 #[serde(default)]
113 pub runtime_dependencies: Vec<Dependency>,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct SourceCadi {
119 #[serde(flatten)]
120 pub chunk: Chunk,
121 pub source: SourceData,
122 #[serde(default)]
123 pub compiled_forms: Vec<CompiledForm>,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct CompiledForm {
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub ir_cadi: Option<String>,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub blob_cadi: Option<String>,
133 #[serde(default)]
134 pub architectures: Vec<String>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub derived_at: Option<String>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub compiler: Option<String>,
139 #[serde(skip_serializing_if = "Option::is_none")]
140 pub deterministic: Option<bool>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct IrModule {
146 pub hash: String,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub size: Option<usize>,
149 #[serde(default)]
150 pub exports: Vec<ModuleExport>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ModuleExport {
156 pub name: String,
157 pub kind: String,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub signature: Option<String>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct IntermediateData {
165 pub format: String,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 pub version: Option<String>,
168 pub module: IrModule,
169 #[serde(default)]
170 pub imports: Vec<ModuleImport>,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct ModuleImport {
176 pub module: String,
177 pub name: String,
178 pub kind: String,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub signature: Option<String>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct IrCadi {
186 #[serde(flatten)]
187 pub chunk: Chunk,
188 pub intermediate: IntermediateData,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub source_link: Option<SourceLink>,
191 #[serde(default)]
192 pub compiled_forms: Vec<CompiledForm>,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct SourceLink {
198 #[serde(skip_serializing_if = "Option::is_none")]
199 pub source_cadi: Option<String>,
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub verification: Option<String>,
202}
203
204#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct BlobEntry {
207 pub architecture: String,
208 pub format: String,
209 pub hash: String,
210 pub size: usize,
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub linking: Option<LinkingInfo>,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub security: Option<SecurityInfo>,
215 #[serde(skip_serializing_if = "Option::is_none")]
216 pub build_info: Option<BuildInfo>,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct LinkingInfo {
222 #[serde(rename = "type")]
223 pub linking_type: String,
224 #[serde(default)]
225 pub dependencies: Vec<String>,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct SecurityInfo {
231 #[serde(default)]
232 pub pie: bool,
233 #[serde(default)]
234 pub nx: bool,
235 #[serde(default)]
236 pub stack_canary: bool,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub relro: Option<String>,
239}
240
241#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct BuildInfo {
244 #[serde(skip_serializing_if = "Option::is_none")]
245 pub compiler: Option<String>,
246 #[serde(default)]
247 pub flags: Vec<String>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 pub source_hash: Option<String>,
250 #[serde(skip_serializing_if = "Option::is_none")]
251 pub reproducible: Option<bool>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct BlobCadi {
257 #[serde(flatten)]
258 pub chunk: Chunk,
259 pub blobs: Vec<BlobEntry>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct ContainerData {
265 pub format: String,
266 pub image_ref: String,
267 #[serde(default)]
268 pub layers: Vec<ContainerLayer>,
269 #[serde(default)]
270 pub entrypoint: Vec<String>,
271 #[serde(default)]
272 pub cmd: Vec<String>,
273 #[serde(default)]
274 pub environment: Vec<EnvVar>,
275 #[serde(default)]
276 pub exposed_ports: Vec<String>,
277 #[serde(default)]
278 pub labels: HashMap<String, String>,
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub architecture: Option<String>,
281 #[serde(default = "default_os")]
282 pub os: String,
283}
284
285fn default_os() -> String {
286 "linux".to_string()
287}
288
289#[derive(Debug, Clone, Serialize, Deserialize)]
291pub struct ContainerLayer {
292 pub hash: String,
293 pub size: usize,
294 #[serde(skip_serializing_if = "Option::is_none")]
295 pub description: Option<String>,
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub cadi_chunk: Option<String>,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
302pub struct EnvVar {
303 pub name: String,
304 pub value: String,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct ContainerCadi {
310 #[serde(flatten)]
311 pub chunk: Chunk,
312 pub container: ContainerData,
313 #[serde(default)]
314 pub deployment_target: Vec<String>,
315}
316
317impl Chunk {
318 pub fn new(chunk_id: String, cadi_type: CadiType, name: String) -> Self {
320 Self {
321 chunk_id,
322 cadi_type,
323 meta: ChunkMeta {
324 name,
325 description: None,
326 version: None,
327 tags: Vec::new(),
328 created_at: Some(chrono::Utc::now().to_rfc3339()),
329 updated_at: None,
330 },
331 provides: ChunkProvides::default(),
332 licensing: ChunkLicensing {
333 license: "MIT".to_string(),
334 restrictions: Vec::new(),
335 },
336 lineage: ChunkLineage::default(),
337 signatures: Vec::new(),
338 }
339 }
340}