@cyvest/cyvest-js 2.0.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,286 +4,55 @@ import addFormats from "ajv-formats";
4
4
 
5
5
  // ../../../schema/cyvest.schema.json
6
6
  var cyvest_schema_default = {
7
- $schema: "https://json-schema.org/draft/2020-12/schema",
8
- $id: "https://cyvest.io/schema/investigation.json",
9
- title: "Cyvest Investigation",
10
- type: "object",
11
- additionalProperties: false,
12
- required: [
13
- "score",
14
- "level",
15
- "whitelisted",
16
- "whitelists",
17
- "observables",
18
- "checks",
19
- "checks_by_level",
20
- "threat_intels",
21
- "enrichments",
22
- "containers",
23
- "stats",
24
- "stats_checks",
25
- "data_extraction"
26
- ],
27
- properties: {
28
- score: {
29
- type: "number"
30
- },
31
- level: {
32
- $ref: "#/$defs/level"
33
- },
34
- whitelisted: {
35
- type: "boolean"
36
- },
37
- whitelists: {
38
- type: "array",
39
- items: {
40
- $ref: "#/$defs/whitelist"
41
- },
42
- default: []
43
- },
44
- observables: {
45
- type: "object",
46
- additionalProperties: {
47
- $ref: "#/$defs/observable"
48
- },
49
- default: {}
50
- },
51
- checks: {
52
- type: "object",
53
- additionalProperties: {
54
- type: "array",
55
- items: {
56
- $ref: "#/$defs/check"
57
- },
58
- default: []
59
- },
60
- default: {}
61
- },
62
- checks_by_level: {
63
- type: "object",
64
- additionalProperties: {
65
- type: "array",
66
- items: {
67
- type: "string"
68
- },
69
- default: []
70
- },
71
- default: {}
72
- },
73
- threat_intels: {
74
- type: "object",
75
- additionalProperties: {
76
- $ref: "#/$defs/threat_intel"
77
- },
78
- default: {}
79
- },
80
- enrichments: {
81
- type: "object",
82
- additionalProperties: {
83
- $ref: "#/$defs/enrichment"
84
- },
85
- default: {}
86
- },
87
- containers: {
88
- type: "object",
89
- additionalProperties: {
90
- $ref: "#/$defs/container"
91
- },
92
- default: {}
93
- },
94
- stats: {
95
- $ref: "#/$defs/statistics"
96
- },
97
- stats_checks: {
98
- $ref: "#/$defs/stats_checks"
99
- },
100
- data_extraction: {
101
- $ref: "#/$defs/data_extraction"
102
- }
103
- },
104
7
  $defs: {
105
- level: {
106
- type: "string",
107
- enum: [
108
- "NONE",
109
- "TRUSTED",
110
- "INFO",
111
- "SAFE",
112
- "NOTABLE",
113
- "SUSPICIOUS",
114
- "MALICIOUS"
115
- ],
116
- description: "Security level classification from NONE (lowest) to MALICIOUS (highest)."
117
- },
118
- relationship_direction: {
119
- type: "string",
120
- enum: [
121
- "outbound",
122
- "inbound",
123
- "bidirectional"
124
- ],
125
- description: "Direction of a relationship between observables."
126
- },
127
- score_policy: {
128
- type: "string",
129
- enum: [
130
- "auto",
131
- "manual"
132
- ],
133
- description: "Score computation policy: 'auto' calculates from level, 'manual' uses explicit score."
134
- },
135
- score_mode: {
136
- type: "string",
137
- enum: [
138
- "max",
139
- "sum"
140
- ],
141
- description: "Score aggregation mode: 'max' takes highest score, 'sum' adds all scores."
142
- },
143
- whitelist: {
144
- type: "object",
145
- required: [
146
- "identifier",
147
- "name"
148
- ],
8
+ Check: {
9
+ description: "Represents a verification step in the investigation.\n\nA check validates a specific aspect of the data under investigation\nand contributes to the overall investigation score.",
149
10
  properties: {
150
- identifier: {
151
- type: "string"
152
- },
153
- name: {
154
- type: "string"
155
- },
156
- justification: {
157
- type: [
158
- "string",
159
- "null"
160
- ]
161
- }
162
- },
163
- additionalProperties: false
164
- },
165
- relationship: {
166
- type: "object",
167
- required: [
168
- "target_key",
169
- "relationship_type",
170
- "direction"
171
- ],
172
- properties: {
173
- target_key: {
11
+ check_id: {
12
+ title: "Check Id",
174
13
  type: "string"
175
14
  },
176
- relationship_type: {
177
- type: "string",
178
- description: "Relationship label; defaults to related-to.",
179
- examples: [
180
- "related-to"
181
- ]
182
- },
183
- direction: {
184
- $ref: "#/$defs/relationship_direction"
185
- }
186
- },
187
- additionalProperties: false
188
- },
189
- observable: {
190
- type: "object",
191
- required: [
192
- "key",
193
- "type",
194
- "value",
195
- "internal",
196
- "whitelisted",
197
- "comment",
198
- "extra",
199
- "score",
200
- "level",
201
- "relationships",
202
- "threat_intels",
203
- "generated_by_checks"
204
- ],
205
- properties: {
206
- key: {
15
+ scope: {
16
+ title: "Scope",
207
17
  type: "string"
208
18
  },
209
- type: {
210
- type: "string",
211
- description: "Observable type (e.g., ipv4-addr, url). Custom values are allowed.",
212
- examples: [
213
- "ipv4-addr",
214
- "ipv6-addr",
215
- "domain-name",
216
- "url",
217
- "network-traffic",
218
- "mac-addr",
219
- "file",
220
- "directory",
221
- "email-addr",
222
- "email-message",
223
- "email-mime-part",
224
- "user-account",
225
- "process",
226
- "software",
227
- "windows-registry-key",
228
- "artifact",
229
- "autonomous-system",
230
- "mutex",
231
- "x509-certificate"
232
- ]
233
- },
234
- value: {
19
+ description: {
20
+ title: "Description",
235
21
  type: "string"
236
22
  },
237
- internal: {
238
- type: "boolean"
239
- },
240
- whitelisted: {
241
- type: "boolean"
242
- },
243
23
  comment: {
24
+ title: "Comment",
244
25
  type: "string"
245
26
  },
246
27
  extra: {
247
- type: [
248
- "object",
249
- "null"
250
- ],
251
- default: {}
28
+ additionalProperties: true,
29
+ title: "Extra",
30
+ type: "object"
252
31
  },
253
32
  score: {
33
+ title: "Score",
254
34
  type: "number"
255
35
  },
256
36
  level: {
257
- $ref: "#/$defs/level"
258
- },
259
- relationships: {
260
- type: "array",
261
- items: {
262
- $ref: "#/$defs/relationship"
263
- },
264
- default: []
37
+ $ref: "#/$defs/Level"
265
38
  },
266
- threat_intels: {
267
- type: "array",
39
+ observables: {
268
40
  items: {
269
41
  type: "string"
270
42
  },
271
- default: []
43
+ title: "Observables",
44
+ type: "array"
272
45
  },
273
- generated_by_checks: {
274
- type: "array",
275
- items: {
276
- type: "string"
277
- },
278
- default: []
46
+ score_policy: {
47
+ $ref: "#/$defs/CheckScorePolicy",
48
+ default: "auto"
49
+ },
50
+ key: {
51
+ title: "Key",
52
+ type: "string"
279
53
  }
280
54
  },
281
- additionalProperties: false
282
- },
283
- check: {
284
- type: "object",
285
55
  required: [
286
- "key",
287
56
  "check_id",
288
57
  "scope",
289
58
  "description",
@@ -291,342 +60,603 @@ var cyvest_schema_default = {
291
60
  "extra",
292
61
  "score",
293
62
  "level",
294
- "score_policy",
295
- "observables"
63
+ "observables",
64
+ "key"
65
+ ],
66
+ title: "Check",
67
+ type: "object"
68
+ },
69
+ CheckScorePolicy: {
70
+ description: "Controls how a check reacts to linked observables.",
71
+ enum: [
72
+ "auto",
73
+ "manual"
296
74
  ],
75
+ title: "CheckScorePolicy",
76
+ type: "string"
77
+ },
78
+ Container: {
79
+ additionalProperties: false,
80
+ description: "Groups checks and sub-containers for hierarchical organization.\n\nContainers allow structuring the investigation into logical sections\nwith aggregated scores and levels.",
297
81
  properties: {
298
- key: {
82
+ path: {
83
+ title: "Path",
299
84
  type: "string"
300
85
  },
301
- check_id: {
86
+ description: {
87
+ default: "",
88
+ title: "Description",
302
89
  type: "string"
303
90
  },
304
- scope: {
305
- type: "string"
91
+ checks: {
92
+ items: {
93
+ type: "string"
94
+ },
95
+ title: "Checks",
96
+ type: "array"
306
97
  },
307
- description: {
308
- type: "string"
98
+ sub_containers: {
99
+ additionalProperties: {
100
+ $ref: "#/$defs/Container"
101
+ },
102
+ title: "Sub Containers",
103
+ type: "object"
309
104
  },
310
- comment: {
105
+ key: {
106
+ title: "Key",
311
107
  type: "string"
312
108
  },
313
- extra: {
314
- type: [
315
- "object",
316
- "null"
317
- ],
318
- default: {}
319
- },
320
- score: {
109
+ aggregated_score: {
110
+ readOnly: true,
111
+ title: "Aggregated Score",
321
112
  type: "number"
322
113
  },
323
- level: {
324
- $ref: "#/$defs/level"
325
- },
326
- score_policy: {
327
- $ref: "#/$defs/score_policy"
328
- },
329
- observables: {
330
- type: "array",
331
- items: {
332
- type: "string"
333
- },
334
- default: []
114
+ aggregated_level: {
115
+ $ref: "#/$defs/Level",
116
+ description: "Calculate the aggregated level from the aggregated score.\n\nReturns:\n Level based on aggregated score",
117
+ readOnly: true
335
118
  }
336
119
  },
337
- additionalProperties: false
338
- },
339
- threat_intel: {
340
- type: "object",
341
120
  required: [
121
+ "path",
122
+ "checks",
123
+ "sub_containers",
342
124
  "key",
343
- "source",
344
- "observable_key",
345
- "comment",
346
- "extra",
347
- "score",
348
- "level",
349
- "taxonomies"
125
+ "aggregated_score",
126
+ "aggregated_level"
350
127
  ],
128
+ title: "Container",
129
+ type: "object"
130
+ },
131
+ DataExtractionSchema: {
132
+ additionalProperties: false,
133
+ description: "Schema for data extraction metadata.",
351
134
  properties: {
352
- key: {
353
- type: "string"
135
+ root_type: {
136
+ anyOf: [
137
+ {
138
+ type: "string"
139
+ },
140
+ {
141
+ type: "null"
142
+ }
143
+ ],
144
+ default: null,
145
+ description: "Root observable type used during data extraction.",
146
+ title: "Root Type"
354
147
  },
355
- source: {
148
+ score_mode: {
149
+ $ref: "#/$defs/ScoreMode",
150
+ description: "Score aggregation mode: 'max' takes highest score, 'sum' adds all scores."
151
+ }
152
+ },
153
+ required: [
154
+ "score_mode"
155
+ ],
156
+ title: "DataExtractionSchema",
157
+ type: "object"
158
+ },
159
+ Enrichment: {
160
+ description: "Represents structured data enrichment for the investigation.\n\nEnrichments store arbitrary structured data that provides additional\ncontext but doesn't directly contribute to scoring.",
161
+ properties: {
162
+ name: {
163
+ title: "Name",
356
164
  type: "string"
357
165
  },
358
- observable_key: {
359
- type: "string"
166
+ data: {
167
+ title: "Data"
360
168
  },
361
- comment: {
169
+ context: {
170
+ title: "Context",
362
171
  type: "string"
363
172
  },
364
- extra: {
365
- type: [
366
- "object",
367
- "null"
368
- ],
369
- default: {}
370
- },
371
- score: {
372
- type: "number"
373
- },
374
- level: {
375
- $ref: "#/$defs/level"
376
- },
377
- taxonomies: {
378
- type: "array",
379
- items: {
380
- type: "object"
381
- },
382
- default: []
173
+ key: {
174
+ title: "Key",
175
+ type: "string"
383
176
  }
384
177
  },
385
- additionalProperties: false
386
- },
387
- enrichment: {
388
- type: "object",
389
178
  required: [
390
- "key",
391
179
  "name",
392
180
  "data",
393
- "context"
181
+ "context",
182
+ "key"
394
183
  ],
184
+ title: "Enrichment",
185
+ type: "object"
186
+ },
187
+ InvestigationWhitelist: {
188
+ description: "Represents a whitelist entry on an investigation.",
395
189
  properties: {
396
- key: {
190
+ identifier: {
191
+ minLength: 1,
192
+ title: "Identifier",
397
193
  type: "string"
398
194
  },
399
195
  name: {
196
+ minLength: 1,
197
+ title: "Name",
400
198
  type: "string"
401
199
  },
402
- data: {
403
- type: "object"
404
- },
405
- context: {
406
- type: "string"
200
+ justification: {
201
+ anyOf: [
202
+ {
203
+ type: "string"
204
+ },
205
+ {
206
+ type: "null"
207
+ }
208
+ ],
209
+ default: null,
210
+ title: "Justification"
407
211
  }
408
212
  },
409
- additionalProperties: false
410
- },
411
- container: {
412
- type: "object",
413
213
  required: [
414
- "key",
415
- "path",
416
- "description",
417
- "checks",
418
- "sub_containers",
419
- "aggregated_score",
420
- "aggregated_level"
214
+ "identifier",
215
+ "name"
216
+ ],
217
+ title: "InvestigationWhitelist",
218
+ type: "object"
219
+ },
220
+ Level: {
221
+ description: "Security level classification for checks, observables, and threat intelligence.\n\nLevels are ordered from lowest (NONE) to highest (MALICIOUS) severity.",
222
+ enum: [
223
+ "NONE",
224
+ "TRUSTED",
225
+ "INFO",
226
+ "SAFE",
227
+ "NOTABLE",
228
+ "SUSPICIOUS",
229
+ "MALICIOUS"
421
230
  ],
231
+ title: "Level",
232
+ type: "string"
233
+ },
234
+ Observable: {
235
+ description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence, checks, and other observables\nthrough relationships.",
422
236
  properties: {
423
- key: {
237
+ type: {
238
+ title: "Type",
424
239
  type: "string"
425
240
  },
426
- path: {
241
+ value: {
242
+ title: "Value",
427
243
  type: "string"
428
244
  },
429
- description: {
245
+ internal: {
246
+ title: "Internal",
247
+ type: "boolean"
248
+ },
249
+ whitelisted: {
250
+ title: "Whitelisted",
251
+ type: "boolean"
252
+ },
253
+ comment: {
254
+ title: "Comment",
430
255
  type: "string"
431
256
  },
432
- checks: {
433
- type: "array",
257
+ extra: {
258
+ additionalProperties: true,
259
+ title: "Extra",
260
+ type: "object"
261
+ },
262
+ score: {
263
+ title: "Score",
264
+ type: "number"
265
+ },
266
+ level: {
267
+ $ref: "#/$defs/Level"
268
+ },
269
+ threat_intels: {
434
270
  items: {
435
271
  type: "string"
436
272
  },
437
- default: []
273
+ title: "Threat Intels",
274
+ type: "array"
438
275
  },
439
- sub_containers: {
440
- type: "object",
441
- additionalProperties: {
442
- $ref: "#/$defs/container"
276
+ relationships: {
277
+ items: {
278
+ $ref: "#/$defs/Relationship"
443
279
  },
444
- default: {}
280
+ title: "Relationships",
281
+ type: "array"
445
282
  },
446
- aggregated_score: {
447
- type: "number"
283
+ key: {
284
+ title: "Key",
285
+ type: "string"
448
286
  },
449
- aggregated_level: {
450
- $ref: "#/$defs/level"
287
+ generated_by_checks: {
288
+ description: "Checks that generated this observable.",
289
+ items: {
290
+ type: "string"
291
+ },
292
+ readOnly: true,
293
+ title: "Generated By Checks",
294
+ type: "array"
451
295
  }
452
296
  },
453
- additionalProperties: false
297
+ required: [
298
+ "type",
299
+ "value",
300
+ "internal",
301
+ "whitelisted",
302
+ "comment",
303
+ "extra",
304
+ "score",
305
+ "level",
306
+ "threat_intels",
307
+ "relationships",
308
+ "key",
309
+ "generated_by_checks"
310
+ ],
311
+ title: "Observable",
312
+ type: "object"
454
313
  },
455
- statistics: {
456
- type: "object",
314
+ Relationship: {
315
+ description: "Represents a relationship between observables.",
316
+ properties: {
317
+ target_key: {
318
+ title: "Target Key",
319
+ type: "string"
320
+ },
321
+ relationship_type: {
322
+ title: "Relationship Type",
323
+ type: "string"
324
+ },
325
+ direction: {
326
+ $ref: "#/$defs/RelationshipDirection"
327
+ }
328
+ },
457
329
  required: [
458
- "total_observables",
459
- "internal_observables",
460
- "external_observables",
461
- "whitelisted_observables",
462
- "observables_by_type",
463
- "observables_by_level",
464
- "observables_by_type_and_level",
465
- "total_checks",
466
- "applied_checks",
467
- "checks_by_scope",
468
- "checks_by_level",
469
- "total_threat_intel",
470
- "threat_intel_by_source",
471
- "threat_intel_by_level",
472
- "total_containers"
330
+ "target_key",
331
+ "relationship_type",
332
+ "direction"
333
+ ],
334
+ title: "Relationship",
335
+ type: "object"
336
+ },
337
+ RelationshipDirection: {
338
+ description: "Direction of a relationship between observables.",
339
+ enum: [
340
+ "outbound",
341
+ "inbound",
342
+ "bidirectional"
473
343
  ],
344
+ title: "RelationshipDirection",
345
+ type: "string"
346
+ },
347
+ ScoreMode: {
348
+ description: "Score calculation mode for observables.",
349
+ enum: [
350
+ "max",
351
+ "sum"
352
+ ],
353
+ title: "ScoreMode",
354
+ type: "string"
355
+ },
356
+ StatisticsSchema: {
357
+ additionalProperties: false,
358
+ description: "Schema for investigation statistics.\n\nMirrors the output of `InvestigationStats.get_summary()`.",
474
359
  properties: {
475
360
  total_observables: {
476
- type: "integer",
477
- minimum: 0
361
+ minimum: 0,
362
+ title: "Total Observables",
363
+ type: "integer"
478
364
  },
479
365
  internal_observables: {
480
- type: "integer",
481
- minimum: 0
366
+ minimum: 0,
367
+ title: "Internal Observables",
368
+ type: "integer"
482
369
  },
483
370
  external_observables: {
484
- type: "integer",
485
- minimum: 0
371
+ minimum: 0,
372
+ title: "External Observables",
373
+ type: "integer"
486
374
  },
487
375
  whitelisted_observables: {
488
- type: "integer",
489
- minimum: 0
376
+ minimum: 0,
377
+ title: "Whitelisted Observables",
378
+ type: "integer"
490
379
  },
491
380
  observables_by_type: {
492
- type: "object",
493
381
  additionalProperties: {
494
- type: "integer",
495
- minimum: 0
382
+ minimum: 0,
383
+ type: "integer"
496
384
  },
497
- default: {}
385
+ title: "Observables By Type",
386
+ type: "object"
498
387
  },
499
388
  observables_by_level: {
500
- type: "object",
501
389
  additionalProperties: {
502
- type: "integer",
503
- minimum: 0
390
+ minimum: 0,
391
+ type: "integer"
504
392
  },
505
- default: {}
393
+ title: "Observables By Level",
394
+ type: "object"
506
395
  },
507
396
  observables_by_type_and_level: {
508
- type: "object",
509
397
  additionalProperties: {
510
- type: "object",
511
398
  additionalProperties: {
512
- type: "integer",
513
- minimum: 0
399
+ minimum: 0,
400
+ type: "integer"
514
401
  },
515
- default: {}
402
+ type: "object"
516
403
  },
517
- default: {}
404
+ title: "Observables By Type And Level",
405
+ type: "object"
518
406
  },
519
407
  total_checks: {
520
- type: "integer",
521
- minimum: 0
408
+ minimum: 0,
409
+ title: "Total Checks",
410
+ type: "integer"
522
411
  },
523
412
  applied_checks: {
524
- type: "integer",
525
- minimum: 0
413
+ minimum: 0,
414
+ title: "Applied Checks",
415
+ type: "integer"
526
416
  },
527
417
  checks_by_scope: {
528
- type: "object",
529
418
  additionalProperties: {
530
- type: "integer",
531
- minimum: 0
419
+ minimum: 0,
420
+ type: "integer"
532
421
  },
533
- default: {}
422
+ title: "Checks By Scope",
423
+ type: "object"
534
424
  },
535
425
  checks_by_level: {
536
- type: "object",
537
426
  additionalProperties: {
538
- type: "integer",
539
- minimum: 0
427
+ minimum: 0,
428
+ type: "integer"
540
429
  },
541
- default: {}
430
+ title: "Checks By Level",
431
+ type: "object"
542
432
  },
543
433
  total_threat_intel: {
544
- type: "integer",
545
- minimum: 0
434
+ minimum: 0,
435
+ title: "Total Threat Intel",
436
+ type: "integer"
546
437
  },
547
438
  threat_intel_by_source: {
548
- type: "object",
549
439
  additionalProperties: {
550
- type: "integer",
551
- minimum: 0
440
+ minimum: 0,
441
+ type: "integer"
552
442
  },
553
- default: {}
443
+ title: "Threat Intel By Source",
444
+ type: "object"
554
445
  },
555
446
  threat_intel_by_level: {
556
- type: "object",
557
447
  additionalProperties: {
558
- type: "integer",
559
- minimum: 0
448
+ minimum: 0,
449
+ type: "integer"
560
450
  },
561
- default: {}
451
+ title: "Threat Intel By Level",
452
+ type: "object"
562
453
  },
563
454
  total_containers: {
564
- type: "integer",
565
- minimum: 0
455
+ minimum: 0,
456
+ title: "Total Containers",
457
+ type: "integer"
566
458
  }
567
459
  },
568
- additionalProperties: false
569
- },
570
- stats_checks: {
571
- type: "object",
572
460
  required: [
573
- "checks",
574
- "applied"
461
+ "total_observables",
462
+ "internal_observables",
463
+ "external_observables",
464
+ "whitelisted_observables",
465
+ "total_checks",
466
+ "applied_checks",
467
+ "total_threat_intel",
468
+ "total_containers"
575
469
  ],
470
+ title: "StatisticsSchema",
471
+ type: "object"
472
+ },
473
+ StatsChecksSchema: {
474
+ additionalProperties: false,
475
+ description: "Schema for check statistics summary.",
576
476
  properties: {
577
477
  checks: {
578
- type: "integer",
579
- minimum: 0
478
+ minimum: 0,
479
+ title: "Checks",
480
+ type: "integer"
580
481
  },
581
482
  applied: {
582
- type: "integer",
583
- minimum: 0
483
+ minimum: 0,
484
+ title: "Applied",
485
+ type: "integer"
584
486
  }
585
487
  },
586
- additionalProperties: false
587
- },
588
- data_extraction: {
589
- type: "object",
590
488
  required: [
591
- "root_type",
592
- "score_mode"
489
+ "checks",
490
+ "applied"
593
491
  ],
492
+ title: "StatsChecksSchema",
493
+ type: "object"
494
+ },
495
+ ThreatIntel: {
496
+ description: "Represents threat intelligence from an external source.\n\nThreat intelligence provides verdicts about observables from sources\nlike VirusTotal, URLScan.io, etc.",
594
497
  properties: {
595
- root_type: {
596
- type: [
597
- "string",
598
- "null"
599
- ],
600
- description: "Root observable type used during data extraction.",
601
- examples: [
602
- "ipv4-addr",
603
- "ipv6-addr",
604
- "domain-name",
605
- "url",
606
- "network-traffic",
607
- "mac-addr",
608
- "file",
609
- "directory",
610
- "email-addr",
611
- "email-message",
612
- "email-mime-part",
613
- "user-account",
614
- "process",
615
- "software",
616
- "windows-registry-key",
617
- "artifact",
618
- "autonomous-system",
619
- "mutex",
620
- "x509-certificate"
621
- ]
498
+ source: {
499
+ title: "Source",
500
+ type: "string"
622
501
  },
623
- score_mode: {
624
- $ref: "#/$defs/score_mode"
502
+ observable_key: {
503
+ title: "Observable Key",
504
+ type: "string"
505
+ },
506
+ comment: {
507
+ title: "Comment",
508
+ type: "string"
509
+ },
510
+ extra: {
511
+ additionalProperties: true,
512
+ title: "Extra",
513
+ type: "object"
514
+ },
515
+ score: {
516
+ title: "Score",
517
+ type: "number"
518
+ },
519
+ level: {
520
+ $ref: "#/$defs/Level"
521
+ },
522
+ taxonomies: {
523
+ items: {
524
+ additionalProperties: true,
525
+ type: "object"
526
+ },
527
+ title: "Taxonomies",
528
+ type: "array"
529
+ },
530
+ key: {
531
+ title: "Key",
532
+ type: "string"
625
533
  }
626
534
  },
627
- additionalProperties: false
535
+ required: [
536
+ "source",
537
+ "observable_key",
538
+ "comment",
539
+ "extra",
540
+ "score",
541
+ "level",
542
+ "taxonomies",
543
+ "key"
544
+ ],
545
+ title: "ThreatIntel",
546
+ type: "object"
628
547
  }
629
- }
548
+ },
549
+ $id: "https://cyvest.io/schema/investigation.json",
550
+ $schema: "https://json-schema.org/draft/2020-12/schema",
551
+ additionalProperties: false,
552
+ description: "Schema for a complete serialized investigation.\n\nThis model describes the output of `serialize_investigation()` from\n`cyvest.io_serialization`. It is the top-level schema for exported investigations.\n\nEntity types reference the runtime models directly. When generating schemas with\n`mode='serialization'`, Pydantic respects field_serializer decorators and produces\nschemas matching the actual model_dump() output.",
553
+ properties: {
554
+ score: {
555
+ description: "Global investigation score.",
556
+ title: "Score",
557
+ type: "number"
558
+ },
559
+ level: {
560
+ $ref: "#/$defs/Level",
561
+ description: "Security level classification from NONE (lowest) to MALICIOUS (highest)."
562
+ },
563
+ whitelisted: {
564
+ description: "Whether the investigation is whitelisted.",
565
+ title: "Whitelisted",
566
+ type: "boolean"
567
+ },
568
+ whitelists: {
569
+ description: "List of whitelist entries applied to this investigation.",
570
+ items: {
571
+ $ref: "#/$defs/InvestigationWhitelist"
572
+ },
573
+ title: "Whitelists",
574
+ type: "array"
575
+ },
576
+ observables: {
577
+ additionalProperties: {
578
+ $ref: "#/$defs/Observable"
579
+ },
580
+ description: "Observables keyed by their unique key.",
581
+ title: "Observables",
582
+ type: "object"
583
+ },
584
+ checks: {
585
+ additionalProperties: {
586
+ items: {
587
+ $ref: "#/$defs/Check"
588
+ },
589
+ type: "array"
590
+ },
591
+ description: "Checks organized by scope.",
592
+ title: "Checks",
593
+ type: "object"
594
+ },
595
+ checks_by_level: {
596
+ additionalProperties: {
597
+ items: {
598
+ type: "string"
599
+ },
600
+ type: "array"
601
+ },
602
+ description: "Check keys organized by level name.",
603
+ title: "Checks By Level",
604
+ type: "object"
605
+ },
606
+ threat_intels: {
607
+ additionalProperties: {
608
+ $ref: "#/$defs/ThreatIntel"
609
+ },
610
+ description: "Threat intelligence entries keyed by their unique key.",
611
+ title: "Threat Intels",
612
+ type: "object"
613
+ },
614
+ enrichments: {
615
+ additionalProperties: {
616
+ $ref: "#/$defs/Enrichment"
617
+ },
618
+ description: "Enrichment entries keyed by their unique key.",
619
+ title: "Enrichments",
620
+ type: "object"
621
+ },
622
+ containers: {
623
+ additionalProperties: {
624
+ $ref: "#/$defs/Container"
625
+ },
626
+ description: "Containers keyed by their unique key.",
627
+ title: "Containers",
628
+ type: "object"
629
+ },
630
+ stats: {
631
+ $ref: "#/$defs/StatisticsSchema",
632
+ description: "Investigation statistics summary."
633
+ },
634
+ stats_checks: {
635
+ $ref: "#/$defs/StatsChecksSchema",
636
+ description: "Check statistics summary."
637
+ },
638
+ data_extraction: {
639
+ $ref: "#/$defs/DataExtractionSchema",
640
+ description: "Data extraction metadata."
641
+ }
642
+ },
643
+ required: [
644
+ "score",
645
+ "level",
646
+ "whitelisted",
647
+ "whitelists",
648
+ "observables",
649
+ "checks",
650
+ "checks_by_level",
651
+ "threat_intels",
652
+ "enrichments",
653
+ "containers",
654
+ "stats",
655
+ "stats_checks",
656
+ "data_extraction"
657
+ ],
658
+ title: "Cyvest Investigation",
659
+ type: "object"
630
660
  };
631
661
 
632
662
  // src/helpers.ts
@@ -854,9 +884,15 @@ function hasLevel(obj) {
854
884
  }
855
885
  function getEntityLevel(entity) {
856
886
  if ("aggregated_level" in entity) {
857
- return entity.aggregated_level;
887
+ const aggregatedLevel = entity.aggregated_level;
888
+ if (typeof aggregatedLevel === "string" && isValidLevel(aggregatedLevel)) {
889
+ return aggregatedLevel;
890
+ }
891
+ }
892
+ if ("level" in entity && isValidLevel(entity.level)) {
893
+ return entity.level;
858
894
  }
859
- return entity.level;
895
+ throw new Error("Entity does not have a valid level.");
860
896
  }
861
897
 
862
898
  // src/getters.ts