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; 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
408/// Write the canonical PBSL schema into the config directory and return its
409/// path. This file documents the intended schema; the actual schema is
410/// created directly via the PocketBase REST API (no pbctl required).
411pub 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}