1use crate::config::db_schema_file;
2use crate::error::Result;
3
4pub const SCHEMA_PBSL: &str = include_str!("../../schema/schema.pbsl");
7
8pub const REQUIRED_COLLECTIONS: [&str; 5] =
11 ["Assets", "Services", "Findings", "Observations", "ScanRuns"];
12
13pub struct FieldDef {
14 pub name: &'static str,
15 pub kind: &'static str,
16 pub required: bool,
17 pub unique: bool,
18}
19
20pub fn field_defs(collection: &str) -> &'static [FieldDef] {
21 match collection {
22 "Assets" => &[
23 FieldDef {
24 name: "stable_id",
25 kind: "text",
26 required: true,
27 unique: true,
28 },
29 FieldDef {
30 name: "asset_type",
31 kind: "select",
32 required: false,
33 unique: false,
34 },
35 FieldDef {
36 name: "name",
37 kind: "text",
38 required: true,
39 unique: false,
40 },
41 FieldDef {
42 name: "ip",
43 kind: "text",
44 required: false,
45 unique: false,
46 },
47 FieldDef {
48 name: "fqdn",
49 kind: "text",
50 required: false,
51 unique: false,
52 },
53 FieldDef {
54 name: "reverse_dns",
55 kind: "text",
56 required: false,
57 unique: false,
58 },
59 FieldDef {
60 name: "first_seen",
61 kind: "text",
62 required: false,
63 unique: false,
64 },
65 FieldDef {
66 name: "last_seen",
67 kind: "text",
68 required: false,
69 unique: false,
70 },
71 FieldDef {
72 name: "status",
73 kind: "text",
74 required: false,
75 unique: false,
76 },
77 FieldDef {
78 name: "metadata",
79 kind: "json",
80 required: false,
81 unique: false,
82 },
83 ],
84 "Services" => &[
85 FieldDef {
86 name: "stable_id",
87 kind: "text",
88 required: true,
89 unique: true,
90 },
91 FieldDef {
92 name: "asset_id",
93 kind: "text",
94 required: true,
95 unique: false,
96 },
97 FieldDef {
98 name: "port",
99 kind: "number",
100 required: false,
101 unique: false,
102 },
103 FieldDef {
104 name: "protocol",
105 kind: "text",
106 required: false,
107 unique: false,
108 },
109 FieldDef {
110 name: "service_name",
111 kind: "text",
112 required: false,
113 unique: false,
114 },
115 FieldDef {
116 name: "product",
117 kind: "text",
118 required: false,
119 unique: false,
120 },
121 FieldDef {
122 name: "version",
123 kind: "text",
124 required: false,
125 unique: false,
126 },
127 FieldDef {
128 name: "version_str",
129 kind: "text",
130 required: false,
131 unique: false,
132 },
133 FieldDef {
134 name: "banner",
135 kind: "text",
136 required: false,
137 unique: false,
138 },
139 FieldDef {
140 name: "technologies",
141 kind: "json",
142 required: false,
143 unique: false,
144 },
145 FieldDef {
146 name: "cpes",
147 kind: "json",
148 required: false,
149 unique: false,
150 },
151 FieldDef {
152 name: "first_seen",
153 kind: "text",
154 required: false,
155 unique: false,
156 },
157 FieldDef {
158 name: "last_seen",
159 kind: "text",
160 required: false,
161 unique: false,
162 },
163 FieldDef {
164 name: "status",
165 kind: "text",
166 required: false,
167 unique: false,
168 },
169 FieldDef {
170 name: "metadata",
171 kind: "json",
172 required: false,
173 unique: false,
174 },
175 ],
176 "Findings" => &[
177 FieldDef {
178 name: "stable_id",
179 kind: "text",
180 required: true,
181 unique: true,
182 },
183 FieldDef {
184 name: "asset_id",
185 kind: "text",
186 required: true,
187 unique: false,
188 },
189 FieldDef {
190 name: "service_id",
191 kind: "text",
192 required: false,
193 unique: false,
194 },
195 FieldDef {
196 name: "title",
197 kind: "text",
198 required: true,
199 unique: false,
200 },
201 FieldDef {
202 name: "severity",
203 kind: "text",
204 required: false,
205 unique: false,
206 },
207 FieldDef {
208 name: "tool",
209 kind: "text",
210 required: false,
211 unique: false,
212 },
213 FieldDef {
214 name: "target_url",
215 kind: "text",
216 required: false,
217 unique: false,
218 },
219 FieldDef {
220 name: "detail",
221 kind: "text",
222 required: false,
223 unique: false,
224 },
225 FieldDef {
226 name: "detail_path",
227 kind: "text",
228 required: false,
229 unique: false,
230 },
231 FieldDef {
232 name: "reference",
233 kind: "text",
234 required: false,
235 unique: false,
236 },
237 FieldDef {
238 name: "cves",
239 kind: "json",
240 required: false,
241 unique: false,
242 },
243 FieldDef {
244 name: "endpoints",
245 kind: "json",
246 required: false,
247 unique: false,
248 },
249 FieldDef {
250 name: "technologies",
251 kind: "json",
252 required: false,
253 unique: false,
254 },
255 FieldDef {
256 name: "first_seen",
257 kind: "text",
258 required: false,
259 unique: false,
260 },
261 FieldDef {
262 name: "last_seen",
263 kind: "text",
264 required: false,
265 unique: false,
266 },
267 FieldDef {
268 name: "status",
269 kind: "text",
270 required: false,
271 unique: false,
272 },
273 FieldDef {
274 name: "exploitability",
275 kind: "text",
276 required: false,
277 unique: false,
278 },
279 FieldDef {
280 name: "metadata",
281 kind: "json",
282 required: false,
283 unique: false,
284 },
285 ],
286 "Observations" => &[
287 FieldDef {
288 name: "stable_id",
289 kind: "text",
290 required: true,
291 unique: true,
292 },
293 FieldDef {
294 name: "run_id",
295 kind: "text",
296 required: true,
297 unique: false,
298 },
299 FieldDef {
300 name: "subject_type",
301 kind: "text",
302 required: true,
303 unique: false,
304 },
305 FieldDef {
306 name: "subject_id",
307 kind: "text",
308 required: true,
309 unique: false,
310 },
311 FieldDef {
312 name: "kind",
313 kind: "text",
314 required: true,
315 unique: false,
316 },
317 FieldDef {
318 name: "before",
319 kind: "json",
320 required: false,
321 unique: false,
322 },
323 FieldDef {
324 name: "after",
325 kind: "json",
326 required: false,
327 unique: false,
328 },
329 FieldDef {
330 name: "detail",
331 kind: "text",
332 required: false,
333 unique: false,
334 },
335 FieldDef {
336 name: "observed_at",
337 kind: "text",
338 required: false,
339 unique: false,
340 },
341 ],
342 "ScanRuns" => &[
343 FieldDef {
344 name: "stable_id",
345 kind: "text",
346 required: true,
347 unique: true,
348 },
349 FieldDef {
350 name: "target",
351 kind: "text",
352 required: true,
353 unique: false,
354 },
355 FieldDef {
356 name: "folder",
357 kind: "text",
358 required: false,
359 unique: false,
360 },
361 FieldDef {
362 name: "started_at",
363 kind: "text",
364 required: false,
365 unique: false,
366 },
367 FieldDef {
368 name: "finished_at",
369 kind: "text",
370 required: false,
371 unique: false,
372 },
373 FieldDef {
374 name: "tools",
375 kind: "json",
376 required: false,
377 unique: false,
378 },
379 FieldDef {
380 name: "artifacts",
381 kind: "json",
382 required: false,
383 unique: false,
384 },
385 FieldDef {
386 name: "content_hash",
387 kind: "text",
388 required: false,
389 unique: false,
390 },
391 FieldDef {
392 name: "imported_at",
393 kind: "text",
394 required: false,
395 unique: false,
396 },
397 FieldDef {
398 name: "stats",
399 kind: "json",
400 required: false,
401 unique: false,
402 },
403 ],
404 _ => &[],
405 }
406}
407
408pub fn write_schema_file() -> Result<std::path::PathBuf> {
412 let path = db_schema_file();
413 if let Some(parent) = path.parent() {
414 std::fs::create_dir_all(parent)?;
415 }
416 std::fs::write(&path, SCHEMA_PBSL)?;
417 Ok(path)
418}