Skip to main content

ploit_malper/db/
schema.rs

1use crate::config::db_schema_file;
2use crate::error::Result;
3
4/// Canonical PBSL schema shipped with PloitMalper. Written to the config
5/// directory so `pbctl` can be pointed at it.
6pub const SCHEMA_PBSL: &str = include_str!("../../schema/schema.pbsl");
7
8/// Collection names and their field definitions used by the direct
9/// PocketBase REST path.
10pub const REQUIRED_COLLECTIONS: [&str; 6] = [
11    "Assets",
12    "Services",
13    "Findings",
14    "Observations",
15    "ScanRuns",
16    "ExploitExecutions",
17];
18
19pub struct FieldDef {
20    pub name: &'static str,
21    pub kind: &'static str,
22    pub required: bool,
23    pub unique: bool,
24}
25
26pub fn field_defs(collection: &str) -> &'static [FieldDef] {
27    match collection {
28        "Assets" => &[
29            FieldDef {
30                name: "stable_id",
31                kind: "text",
32                required: true,
33                unique: true,
34            },
35            FieldDef {
36                name: "asset_type",
37                kind: "select",
38                required: false,
39                unique: false,
40            },
41            FieldDef {
42                name: "name",
43                kind: "text",
44                required: true,
45                unique: false,
46            },
47            FieldDef {
48                name: "ip",
49                kind: "text",
50                required: false,
51                unique: false,
52            },
53            FieldDef {
54                name: "fqdn",
55                kind: "text",
56                required: false,
57                unique: false,
58            },
59            FieldDef {
60                name: "reverse_dns",
61                kind: "text",
62                required: false,
63                unique: false,
64            },
65            FieldDef {
66                name: "first_seen",
67                kind: "text",
68                required: false,
69                unique: false,
70            },
71            FieldDef {
72                name: "last_seen",
73                kind: "text",
74                required: false,
75                unique: false,
76            },
77            FieldDef {
78                name: "status",
79                kind: "text",
80                required: false,
81                unique: false,
82            },
83            FieldDef {
84                name: "metadata",
85                kind: "json",
86                required: false,
87                unique: false,
88            },
89        ],
90        "Services" => &[
91            FieldDef {
92                name: "stable_id",
93                kind: "text",
94                required: true,
95                unique: true,
96            },
97            FieldDef {
98                name: "asset_id",
99                kind: "text",
100                required: true,
101                unique: false,
102            },
103            FieldDef {
104                name: "port",
105                kind: "number",
106                required: false,
107                unique: false,
108            },
109            FieldDef {
110                name: "protocol",
111                kind: "text",
112                required: false,
113                unique: false,
114            },
115            FieldDef {
116                name: "service_name",
117                kind: "text",
118                required: false,
119                unique: false,
120            },
121            FieldDef {
122                name: "product",
123                kind: "text",
124                required: false,
125                unique: false,
126            },
127            FieldDef {
128                name: "version",
129                kind: "text",
130                required: false,
131                unique: false,
132            },
133            FieldDef {
134                name: "version_str",
135                kind: "text",
136                required: false,
137                unique: false,
138            },
139            FieldDef {
140                name: "banner",
141                kind: "text",
142                required: false,
143                unique: false,
144            },
145            FieldDef {
146                name: "technologies",
147                kind: "json",
148                required: false,
149                unique: false,
150            },
151            FieldDef {
152                name: "cpes",
153                kind: "json",
154                required: false,
155                unique: false,
156            },
157            FieldDef {
158                name: "first_seen",
159                kind: "text",
160                required: false,
161                unique: false,
162            },
163            FieldDef {
164                name: "last_seen",
165                kind: "text",
166                required: false,
167                unique: false,
168            },
169            FieldDef {
170                name: "status",
171                kind: "text",
172                required: false,
173                unique: false,
174            },
175            FieldDef {
176                name: "metadata",
177                kind: "json",
178                required: false,
179                unique: false,
180            },
181        ],
182        "Findings" => &[
183            FieldDef {
184                name: "stable_id",
185                kind: "text",
186                required: true,
187                unique: true,
188            },
189            FieldDef {
190                name: "asset_id",
191                kind: "text",
192                required: true,
193                unique: false,
194            },
195            FieldDef {
196                name: "service_id",
197                kind: "text",
198                required: false,
199                unique: false,
200            },
201            FieldDef {
202                name: "title",
203                kind: "text",
204                required: true,
205                unique: false,
206            },
207            FieldDef {
208                name: "severity",
209                kind: "text",
210                required: false,
211                unique: false,
212            },
213            FieldDef {
214                name: "tool",
215                kind: "text",
216                required: false,
217                unique: false,
218            },
219            FieldDef {
220                name: "target_url",
221                kind: "text",
222                required: false,
223                unique: false,
224            },
225            FieldDef {
226                name: "detail",
227                kind: "text",
228                required: false,
229                unique: false,
230            },
231            FieldDef {
232                name: "detail_path",
233                kind: "text",
234                required: false,
235                unique: false,
236            },
237            FieldDef {
238                name: "reference",
239                kind: "text",
240                required: false,
241                unique: false,
242            },
243            FieldDef {
244                name: "cves",
245                kind: "json",
246                required: false,
247                unique: false,
248            },
249            FieldDef {
250                name: "endpoints",
251                kind: "json",
252                required: false,
253                unique: false,
254            },
255            FieldDef {
256                name: "technologies",
257                kind: "json",
258                required: false,
259                unique: false,
260            },
261            FieldDef {
262                name: "first_seen",
263                kind: "text",
264                required: false,
265                unique: false,
266            },
267            FieldDef {
268                name: "last_seen",
269                kind: "text",
270                required: false,
271                unique: false,
272            },
273            FieldDef {
274                name: "status",
275                kind: "text",
276                required: false,
277                unique: false,
278            },
279            FieldDef {
280                name: "exploitability",
281                kind: "text",
282                required: false,
283                unique: false,
284            },
285            FieldDef {
286                name: "metadata",
287                kind: "json",
288                required: false,
289                unique: false,
290            },
291        ],
292        "Observations" => &[
293            FieldDef {
294                name: "stable_id",
295                kind: "text",
296                required: true,
297                unique: true,
298            },
299            FieldDef {
300                name: "run_id",
301                kind: "text",
302                required: true,
303                unique: false,
304            },
305            FieldDef {
306                name: "subject_type",
307                kind: "text",
308                required: true,
309                unique: false,
310            },
311            FieldDef {
312                name: "subject_id",
313                kind: "text",
314                required: true,
315                unique: false,
316            },
317            FieldDef {
318                name: "kind",
319                kind: "text",
320                required: true,
321                unique: false,
322            },
323            FieldDef {
324                name: "before",
325                kind: "json",
326                required: false,
327                unique: false,
328            },
329            FieldDef {
330                name: "after",
331                kind: "json",
332                required: false,
333                unique: false,
334            },
335            FieldDef {
336                name: "detail",
337                kind: "text",
338                required: false,
339                unique: false,
340            },
341            FieldDef {
342                name: "observed_at",
343                kind: "text",
344                required: false,
345                unique: false,
346            },
347        ],
348        "ScanRuns" => &[
349            FieldDef {
350                name: "stable_id",
351                kind: "text",
352                required: true,
353                unique: true,
354            },
355            FieldDef {
356                name: "target",
357                kind: "text",
358                required: true,
359                unique: false,
360            },
361            FieldDef {
362                name: "folder",
363                kind: "text",
364                required: false,
365                unique: false,
366            },
367            FieldDef {
368                name: "started_at",
369                kind: "text",
370                required: false,
371                unique: false,
372            },
373            FieldDef {
374                name: "finished_at",
375                kind: "text",
376                required: false,
377                unique: false,
378            },
379            FieldDef {
380                name: "tools",
381                kind: "json",
382                required: false,
383                unique: false,
384            },
385            FieldDef {
386                name: "artifacts",
387                kind: "json",
388                required: false,
389                unique: false,
390            },
391            FieldDef {
392                name: "content_hash",
393                kind: "text",
394                required: false,
395                unique: false,
396            },
397            FieldDef {
398                name: "imported_at",
399                kind: "text",
400                required: false,
401                unique: false,
402            },
403            FieldDef {
404                name: "stats",
405                kind: "json",
406                required: false,
407                unique: false,
408            },
409        ],
410        "ExploitExecutions" => &[
411            FieldDef {
412                name: "execution_id",
413                kind: "text",
414                required: true,
415                unique: true,
416            },
417            FieldDef {
418                name: "run_id",
419                kind: "text",
420                required: true,
421                unique: false,
422            },
423            FieldDef {
424                name: "asset_id",
425                kind: "text",
426                required: true,
427                unique: false,
428            },
429            FieldDef {
430                name: "vulnerability_id",
431                kind: "text",
432                required: true,
433                unique: false,
434            },
435            FieldDef {
436                name: "module_type",
437                kind: "text",
438                required: false,
439                unique: false,
440            },
441            FieldDef {
442                name: "module",
443                kind: "text",
444                required: true,
445                unique: false,
446            },
447            FieldDef {
448                name: "host",
449                kind: "text",
450                required: false,
451                unique: false,
452            },
453            FieldDef {
454                name: "payload",
455                kind: "text",
456                required: false,
457                unique: false,
458            },
459            FieldDef {
460                name: "status",
461                kind: "text",
462                required: false,
463                unique: false,
464            },
465            FieldDef {
466                name: "start_time",
467                kind: "text",
468                required: false,
469                unique: false,
470            },
471            FieldDef {
472                name: "finish_time",
473                kind: "text",
474                required: false,
475                unique: false,
476            },
477            FieldDef {
478                name: "job_id",
479                kind: "text",
480                required: false,
481                unique: false,
482            },
483            FieldDef {
484                name: "session_id",
485                kind: "text",
486                required: false,
487                unique: false,
488            },
489            FieldDef {
490                name: "error",
491                kind: "text",
492                required: false,
493                unique: false,
494            },
495            FieldDef {
496                name: "loot",
497                kind: "json",
498                required: false,
499                unique: false,
500            },
501            FieldDef {
502                name: "options",
503                kind: "json",
504                required: false,
505                unique: false,
506            },
507            FieldDef {
508                name: "selected",
509                kind: "bool",
510                required: false,
511                unique: false,
512            },
513            FieldDef {
514                name: "created_at",
515                kind: "text",
516                required: false,
517                unique: false,
518            },
519        ],
520        _ => &[],
521    }
522}
523
524/// Write the canonical PBSL schema into the config directory and return its
525/// path. This file documents the intended schema; the actual schema is
526/// created directly via the PocketBase REST API (no pbctl required).
527pub fn write_schema_file() -> Result<std::path::PathBuf> {
528    let path = db_schema_file();
529    if let Some(parent) = path.parent() {
530        std::fs::create_dir_all(parent)?;
531    }
532    std::fs::write(&path, SCHEMA_PBSL)?;
533    Ok(path)
534}