@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.js CHANGED
@@ -139,286 +139,55 @@ var import_ajv_formats = __toESM(require("ajv-formats"));
139
139
 
140
140
  // ../../../schema/cyvest.schema.json
141
141
  var cyvest_schema_default = {
142
- $schema: "https://json-schema.org/draft/2020-12/schema",
143
- $id: "https://cyvest.io/schema/investigation.json",
144
- title: "Cyvest Investigation",
145
- type: "object",
146
- additionalProperties: false,
147
- required: [
148
- "score",
149
- "level",
150
- "whitelisted",
151
- "whitelists",
152
- "observables",
153
- "checks",
154
- "checks_by_level",
155
- "threat_intels",
156
- "enrichments",
157
- "containers",
158
- "stats",
159
- "stats_checks",
160
- "data_extraction"
161
- ],
162
- properties: {
163
- score: {
164
- type: "number"
165
- },
166
- level: {
167
- $ref: "#/$defs/level"
168
- },
169
- whitelisted: {
170
- type: "boolean"
171
- },
172
- whitelists: {
173
- type: "array",
174
- items: {
175
- $ref: "#/$defs/whitelist"
176
- },
177
- default: []
178
- },
179
- observables: {
180
- type: "object",
181
- additionalProperties: {
182
- $ref: "#/$defs/observable"
183
- },
184
- default: {}
185
- },
186
- checks: {
187
- type: "object",
188
- additionalProperties: {
189
- type: "array",
190
- items: {
191
- $ref: "#/$defs/check"
192
- },
193
- default: []
194
- },
195
- default: {}
196
- },
197
- checks_by_level: {
198
- type: "object",
199
- additionalProperties: {
200
- type: "array",
201
- items: {
202
- type: "string"
203
- },
204
- default: []
205
- },
206
- default: {}
207
- },
208
- threat_intels: {
209
- type: "object",
210
- additionalProperties: {
211
- $ref: "#/$defs/threat_intel"
212
- },
213
- default: {}
214
- },
215
- enrichments: {
216
- type: "object",
217
- additionalProperties: {
218
- $ref: "#/$defs/enrichment"
219
- },
220
- default: {}
221
- },
222
- containers: {
223
- type: "object",
224
- additionalProperties: {
225
- $ref: "#/$defs/container"
226
- },
227
- default: {}
228
- },
229
- stats: {
230
- $ref: "#/$defs/statistics"
231
- },
232
- stats_checks: {
233
- $ref: "#/$defs/stats_checks"
234
- },
235
- data_extraction: {
236
- $ref: "#/$defs/data_extraction"
237
- }
238
- },
239
142
  $defs: {
240
- level: {
241
- type: "string",
242
- enum: [
243
- "NONE",
244
- "TRUSTED",
245
- "INFO",
246
- "SAFE",
247
- "NOTABLE",
248
- "SUSPICIOUS",
249
- "MALICIOUS"
250
- ],
251
- description: "Security level classification from NONE (lowest) to MALICIOUS (highest)."
252
- },
253
- relationship_direction: {
254
- type: "string",
255
- enum: [
256
- "outbound",
257
- "inbound",
258
- "bidirectional"
259
- ],
260
- description: "Direction of a relationship between observables."
261
- },
262
- score_policy: {
263
- type: "string",
264
- enum: [
265
- "auto",
266
- "manual"
267
- ],
268
- description: "Score computation policy: 'auto' calculates from level, 'manual' uses explicit score."
269
- },
270
- score_mode: {
271
- type: "string",
272
- enum: [
273
- "max",
274
- "sum"
275
- ],
276
- description: "Score aggregation mode: 'max' takes highest score, 'sum' adds all scores."
277
- },
278
- whitelist: {
279
- type: "object",
280
- required: [
281
- "identifier",
282
- "name"
283
- ],
143
+ Check: {
144
+ 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.",
284
145
  properties: {
285
- identifier: {
286
- type: "string"
287
- },
288
- name: {
289
- type: "string"
290
- },
291
- justification: {
292
- type: [
293
- "string",
294
- "null"
295
- ]
296
- }
297
- },
298
- additionalProperties: false
299
- },
300
- relationship: {
301
- type: "object",
302
- required: [
303
- "target_key",
304
- "relationship_type",
305
- "direction"
306
- ],
307
- properties: {
308
- target_key: {
146
+ check_id: {
147
+ title: "Check Id",
309
148
  type: "string"
310
149
  },
311
- relationship_type: {
312
- type: "string",
313
- description: "Relationship label; defaults to related-to.",
314
- examples: [
315
- "related-to"
316
- ]
317
- },
318
- direction: {
319
- $ref: "#/$defs/relationship_direction"
320
- }
321
- },
322
- additionalProperties: false
323
- },
324
- observable: {
325
- type: "object",
326
- required: [
327
- "key",
328
- "type",
329
- "value",
330
- "internal",
331
- "whitelisted",
332
- "comment",
333
- "extra",
334
- "score",
335
- "level",
336
- "relationships",
337
- "threat_intels",
338
- "generated_by_checks"
339
- ],
340
- properties: {
341
- key: {
150
+ scope: {
151
+ title: "Scope",
342
152
  type: "string"
343
153
  },
344
- type: {
345
- type: "string",
346
- description: "Observable type (e.g., ipv4-addr, url). Custom values are allowed.",
347
- examples: [
348
- "ipv4-addr",
349
- "ipv6-addr",
350
- "domain-name",
351
- "url",
352
- "network-traffic",
353
- "mac-addr",
354
- "file",
355
- "directory",
356
- "email-addr",
357
- "email-message",
358
- "email-mime-part",
359
- "user-account",
360
- "process",
361
- "software",
362
- "windows-registry-key",
363
- "artifact",
364
- "autonomous-system",
365
- "mutex",
366
- "x509-certificate"
367
- ]
368
- },
369
- value: {
154
+ description: {
155
+ title: "Description",
370
156
  type: "string"
371
157
  },
372
- internal: {
373
- type: "boolean"
374
- },
375
- whitelisted: {
376
- type: "boolean"
377
- },
378
158
  comment: {
159
+ title: "Comment",
379
160
  type: "string"
380
161
  },
381
162
  extra: {
382
- type: [
383
- "object",
384
- "null"
385
- ],
386
- default: {}
163
+ additionalProperties: true,
164
+ title: "Extra",
165
+ type: "object"
387
166
  },
388
167
  score: {
168
+ title: "Score",
389
169
  type: "number"
390
170
  },
391
171
  level: {
392
- $ref: "#/$defs/level"
393
- },
394
- relationships: {
395
- type: "array",
396
- items: {
397
- $ref: "#/$defs/relationship"
398
- },
399
- default: []
172
+ $ref: "#/$defs/Level"
400
173
  },
401
- threat_intels: {
402
- type: "array",
174
+ observables: {
403
175
  items: {
404
176
  type: "string"
405
177
  },
406
- default: []
178
+ title: "Observables",
179
+ type: "array"
407
180
  },
408
- generated_by_checks: {
409
- type: "array",
410
- items: {
411
- type: "string"
412
- },
413
- default: []
181
+ score_policy: {
182
+ $ref: "#/$defs/CheckScorePolicy",
183
+ default: "auto"
184
+ },
185
+ key: {
186
+ title: "Key",
187
+ type: "string"
414
188
  }
415
189
  },
416
- additionalProperties: false
417
- },
418
- check: {
419
- type: "object",
420
190
  required: [
421
- "key",
422
191
  "check_id",
423
192
  "scope",
424
193
  "description",
@@ -426,342 +195,603 @@ var cyvest_schema_default = {
426
195
  "extra",
427
196
  "score",
428
197
  "level",
429
- "score_policy",
430
- "observables"
198
+ "observables",
199
+ "key"
200
+ ],
201
+ title: "Check",
202
+ type: "object"
203
+ },
204
+ CheckScorePolicy: {
205
+ description: "Controls how a check reacts to linked observables.",
206
+ enum: [
207
+ "auto",
208
+ "manual"
431
209
  ],
210
+ title: "CheckScorePolicy",
211
+ type: "string"
212
+ },
213
+ Container: {
214
+ additionalProperties: false,
215
+ description: "Groups checks and sub-containers for hierarchical organization.\n\nContainers allow structuring the investigation into logical sections\nwith aggregated scores and levels.",
432
216
  properties: {
433
- key: {
217
+ path: {
218
+ title: "Path",
434
219
  type: "string"
435
220
  },
436
- check_id: {
221
+ description: {
222
+ default: "",
223
+ title: "Description",
437
224
  type: "string"
438
225
  },
439
- scope: {
440
- type: "string"
226
+ checks: {
227
+ items: {
228
+ type: "string"
229
+ },
230
+ title: "Checks",
231
+ type: "array"
441
232
  },
442
- description: {
443
- type: "string"
233
+ sub_containers: {
234
+ additionalProperties: {
235
+ $ref: "#/$defs/Container"
236
+ },
237
+ title: "Sub Containers",
238
+ type: "object"
444
239
  },
445
- comment: {
240
+ key: {
241
+ title: "Key",
446
242
  type: "string"
447
243
  },
448
- extra: {
449
- type: [
450
- "object",
451
- "null"
452
- ],
453
- default: {}
454
- },
455
- score: {
244
+ aggregated_score: {
245
+ readOnly: true,
246
+ title: "Aggregated Score",
456
247
  type: "number"
457
248
  },
458
- level: {
459
- $ref: "#/$defs/level"
460
- },
461
- score_policy: {
462
- $ref: "#/$defs/score_policy"
463
- },
464
- observables: {
465
- type: "array",
466
- items: {
467
- type: "string"
468
- },
469
- default: []
249
+ aggregated_level: {
250
+ $ref: "#/$defs/Level",
251
+ description: "Calculate the aggregated level from the aggregated score.\n\nReturns:\n Level based on aggregated score",
252
+ readOnly: true
470
253
  }
471
254
  },
472
- additionalProperties: false
473
- },
474
- threat_intel: {
475
- type: "object",
476
255
  required: [
256
+ "path",
257
+ "checks",
258
+ "sub_containers",
477
259
  "key",
478
- "source",
479
- "observable_key",
480
- "comment",
481
- "extra",
482
- "score",
483
- "level",
484
- "taxonomies"
260
+ "aggregated_score",
261
+ "aggregated_level"
485
262
  ],
263
+ title: "Container",
264
+ type: "object"
265
+ },
266
+ DataExtractionSchema: {
267
+ additionalProperties: false,
268
+ description: "Schema for data extraction metadata.",
486
269
  properties: {
487
- key: {
488
- type: "string"
270
+ root_type: {
271
+ anyOf: [
272
+ {
273
+ type: "string"
274
+ },
275
+ {
276
+ type: "null"
277
+ }
278
+ ],
279
+ default: null,
280
+ description: "Root observable type used during data extraction.",
281
+ title: "Root Type"
489
282
  },
490
- source: {
283
+ score_mode: {
284
+ $ref: "#/$defs/ScoreMode",
285
+ description: "Score aggregation mode: 'max' takes highest score, 'sum' adds all scores."
286
+ }
287
+ },
288
+ required: [
289
+ "score_mode"
290
+ ],
291
+ title: "DataExtractionSchema",
292
+ type: "object"
293
+ },
294
+ Enrichment: {
295
+ 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.",
296
+ properties: {
297
+ name: {
298
+ title: "Name",
491
299
  type: "string"
492
300
  },
493
- observable_key: {
494
- type: "string"
301
+ data: {
302
+ title: "Data"
495
303
  },
496
- comment: {
304
+ context: {
305
+ title: "Context",
497
306
  type: "string"
498
307
  },
499
- extra: {
500
- type: [
501
- "object",
502
- "null"
503
- ],
504
- default: {}
505
- },
506
- score: {
507
- type: "number"
508
- },
509
- level: {
510
- $ref: "#/$defs/level"
511
- },
512
- taxonomies: {
513
- type: "array",
514
- items: {
515
- type: "object"
516
- },
517
- default: []
308
+ key: {
309
+ title: "Key",
310
+ type: "string"
518
311
  }
519
312
  },
520
- additionalProperties: false
521
- },
522
- enrichment: {
523
- type: "object",
524
313
  required: [
525
- "key",
526
314
  "name",
527
315
  "data",
528
- "context"
316
+ "context",
317
+ "key"
529
318
  ],
319
+ title: "Enrichment",
320
+ type: "object"
321
+ },
322
+ InvestigationWhitelist: {
323
+ description: "Represents a whitelist entry on an investigation.",
530
324
  properties: {
531
- key: {
325
+ identifier: {
326
+ minLength: 1,
327
+ title: "Identifier",
532
328
  type: "string"
533
329
  },
534
330
  name: {
331
+ minLength: 1,
332
+ title: "Name",
535
333
  type: "string"
536
334
  },
537
- data: {
538
- type: "object"
539
- },
540
- context: {
541
- type: "string"
335
+ justification: {
336
+ anyOf: [
337
+ {
338
+ type: "string"
339
+ },
340
+ {
341
+ type: "null"
342
+ }
343
+ ],
344
+ default: null,
345
+ title: "Justification"
542
346
  }
543
347
  },
544
- additionalProperties: false
545
- },
546
- container: {
547
- type: "object",
548
348
  required: [
549
- "key",
550
- "path",
551
- "description",
552
- "checks",
553
- "sub_containers",
554
- "aggregated_score",
555
- "aggregated_level"
349
+ "identifier",
350
+ "name"
351
+ ],
352
+ title: "InvestigationWhitelist",
353
+ type: "object"
354
+ },
355
+ Level: {
356
+ description: "Security level classification for checks, observables, and threat intelligence.\n\nLevels are ordered from lowest (NONE) to highest (MALICIOUS) severity.",
357
+ enum: [
358
+ "NONE",
359
+ "TRUSTED",
360
+ "INFO",
361
+ "SAFE",
362
+ "NOTABLE",
363
+ "SUSPICIOUS",
364
+ "MALICIOUS"
556
365
  ],
366
+ title: "Level",
367
+ type: "string"
368
+ },
369
+ Observable: {
370
+ description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence, checks, and other observables\nthrough relationships.",
557
371
  properties: {
558
- key: {
372
+ type: {
373
+ title: "Type",
559
374
  type: "string"
560
375
  },
561
- path: {
376
+ value: {
377
+ title: "Value",
562
378
  type: "string"
563
379
  },
564
- description: {
380
+ internal: {
381
+ title: "Internal",
382
+ type: "boolean"
383
+ },
384
+ whitelisted: {
385
+ title: "Whitelisted",
386
+ type: "boolean"
387
+ },
388
+ comment: {
389
+ title: "Comment",
565
390
  type: "string"
566
391
  },
567
- checks: {
568
- type: "array",
392
+ extra: {
393
+ additionalProperties: true,
394
+ title: "Extra",
395
+ type: "object"
396
+ },
397
+ score: {
398
+ title: "Score",
399
+ type: "number"
400
+ },
401
+ level: {
402
+ $ref: "#/$defs/Level"
403
+ },
404
+ threat_intels: {
569
405
  items: {
570
406
  type: "string"
571
407
  },
572
- default: []
408
+ title: "Threat Intels",
409
+ type: "array"
573
410
  },
574
- sub_containers: {
575
- type: "object",
576
- additionalProperties: {
577
- $ref: "#/$defs/container"
411
+ relationships: {
412
+ items: {
413
+ $ref: "#/$defs/Relationship"
578
414
  },
579
- default: {}
415
+ title: "Relationships",
416
+ type: "array"
580
417
  },
581
- aggregated_score: {
582
- type: "number"
418
+ key: {
419
+ title: "Key",
420
+ type: "string"
583
421
  },
584
- aggregated_level: {
585
- $ref: "#/$defs/level"
422
+ generated_by_checks: {
423
+ description: "Checks that generated this observable.",
424
+ items: {
425
+ type: "string"
426
+ },
427
+ readOnly: true,
428
+ title: "Generated By Checks",
429
+ type: "array"
586
430
  }
587
431
  },
588
- additionalProperties: false
432
+ required: [
433
+ "type",
434
+ "value",
435
+ "internal",
436
+ "whitelisted",
437
+ "comment",
438
+ "extra",
439
+ "score",
440
+ "level",
441
+ "threat_intels",
442
+ "relationships",
443
+ "key",
444
+ "generated_by_checks"
445
+ ],
446
+ title: "Observable",
447
+ type: "object"
589
448
  },
590
- statistics: {
591
- type: "object",
449
+ Relationship: {
450
+ description: "Represents a relationship between observables.",
451
+ properties: {
452
+ target_key: {
453
+ title: "Target Key",
454
+ type: "string"
455
+ },
456
+ relationship_type: {
457
+ title: "Relationship Type",
458
+ type: "string"
459
+ },
460
+ direction: {
461
+ $ref: "#/$defs/RelationshipDirection"
462
+ }
463
+ },
592
464
  required: [
593
- "total_observables",
594
- "internal_observables",
595
- "external_observables",
596
- "whitelisted_observables",
597
- "observables_by_type",
598
- "observables_by_level",
599
- "observables_by_type_and_level",
600
- "total_checks",
601
- "applied_checks",
602
- "checks_by_scope",
603
- "checks_by_level",
604
- "total_threat_intel",
605
- "threat_intel_by_source",
606
- "threat_intel_by_level",
607
- "total_containers"
465
+ "target_key",
466
+ "relationship_type",
467
+ "direction"
468
+ ],
469
+ title: "Relationship",
470
+ type: "object"
471
+ },
472
+ RelationshipDirection: {
473
+ description: "Direction of a relationship between observables.",
474
+ enum: [
475
+ "outbound",
476
+ "inbound",
477
+ "bidirectional"
608
478
  ],
479
+ title: "RelationshipDirection",
480
+ type: "string"
481
+ },
482
+ ScoreMode: {
483
+ description: "Score calculation mode for observables.",
484
+ enum: [
485
+ "max",
486
+ "sum"
487
+ ],
488
+ title: "ScoreMode",
489
+ type: "string"
490
+ },
491
+ StatisticsSchema: {
492
+ additionalProperties: false,
493
+ description: "Schema for investigation statistics.\n\nMirrors the output of `InvestigationStats.get_summary()`.",
609
494
  properties: {
610
495
  total_observables: {
611
- type: "integer",
612
- minimum: 0
496
+ minimum: 0,
497
+ title: "Total Observables",
498
+ type: "integer"
613
499
  },
614
500
  internal_observables: {
615
- type: "integer",
616
- minimum: 0
501
+ minimum: 0,
502
+ title: "Internal Observables",
503
+ type: "integer"
617
504
  },
618
505
  external_observables: {
619
- type: "integer",
620
- minimum: 0
506
+ minimum: 0,
507
+ title: "External Observables",
508
+ type: "integer"
621
509
  },
622
510
  whitelisted_observables: {
623
- type: "integer",
624
- minimum: 0
511
+ minimum: 0,
512
+ title: "Whitelisted Observables",
513
+ type: "integer"
625
514
  },
626
515
  observables_by_type: {
627
- type: "object",
628
516
  additionalProperties: {
629
- type: "integer",
630
- minimum: 0
517
+ minimum: 0,
518
+ type: "integer"
631
519
  },
632
- default: {}
520
+ title: "Observables By Type",
521
+ type: "object"
633
522
  },
634
523
  observables_by_level: {
635
- type: "object",
636
524
  additionalProperties: {
637
- type: "integer",
638
- minimum: 0
525
+ minimum: 0,
526
+ type: "integer"
639
527
  },
640
- default: {}
528
+ title: "Observables By Level",
529
+ type: "object"
641
530
  },
642
531
  observables_by_type_and_level: {
643
- type: "object",
644
532
  additionalProperties: {
645
- type: "object",
646
533
  additionalProperties: {
647
- type: "integer",
648
- minimum: 0
534
+ minimum: 0,
535
+ type: "integer"
649
536
  },
650
- default: {}
537
+ type: "object"
651
538
  },
652
- default: {}
539
+ title: "Observables By Type And Level",
540
+ type: "object"
653
541
  },
654
542
  total_checks: {
655
- type: "integer",
656
- minimum: 0
543
+ minimum: 0,
544
+ title: "Total Checks",
545
+ type: "integer"
657
546
  },
658
547
  applied_checks: {
659
- type: "integer",
660
- minimum: 0
548
+ minimum: 0,
549
+ title: "Applied Checks",
550
+ type: "integer"
661
551
  },
662
552
  checks_by_scope: {
663
- type: "object",
664
553
  additionalProperties: {
665
- type: "integer",
666
- minimum: 0
554
+ minimum: 0,
555
+ type: "integer"
667
556
  },
668
- default: {}
557
+ title: "Checks By Scope",
558
+ type: "object"
669
559
  },
670
560
  checks_by_level: {
671
- type: "object",
672
561
  additionalProperties: {
673
- type: "integer",
674
- minimum: 0
562
+ minimum: 0,
563
+ type: "integer"
675
564
  },
676
- default: {}
565
+ title: "Checks By Level",
566
+ type: "object"
677
567
  },
678
568
  total_threat_intel: {
679
- type: "integer",
680
- minimum: 0
569
+ minimum: 0,
570
+ title: "Total Threat Intel",
571
+ type: "integer"
681
572
  },
682
573
  threat_intel_by_source: {
683
- type: "object",
684
574
  additionalProperties: {
685
- type: "integer",
686
- minimum: 0
575
+ minimum: 0,
576
+ type: "integer"
687
577
  },
688
- default: {}
578
+ title: "Threat Intel By Source",
579
+ type: "object"
689
580
  },
690
581
  threat_intel_by_level: {
691
- type: "object",
692
582
  additionalProperties: {
693
- type: "integer",
694
- minimum: 0
583
+ minimum: 0,
584
+ type: "integer"
695
585
  },
696
- default: {}
586
+ title: "Threat Intel By Level",
587
+ type: "object"
697
588
  },
698
589
  total_containers: {
699
- type: "integer",
700
- minimum: 0
590
+ minimum: 0,
591
+ title: "Total Containers",
592
+ type: "integer"
701
593
  }
702
594
  },
703
- additionalProperties: false
704
- },
705
- stats_checks: {
706
- type: "object",
707
595
  required: [
708
- "checks",
709
- "applied"
596
+ "total_observables",
597
+ "internal_observables",
598
+ "external_observables",
599
+ "whitelisted_observables",
600
+ "total_checks",
601
+ "applied_checks",
602
+ "total_threat_intel",
603
+ "total_containers"
710
604
  ],
605
+ title: "StatisticsSchema",
606
+ type: "object"
607
+ },
608
+ StatsChecksSchema: {
609
+ additionalProperties: false,
610
+ description: "Schema for check statistics summary.",
711
611
  properties: {
712
612
  checks: {
713
- type: "integer",
714
- minimum: 0
613
+ minimum: 0,
614
+ title: "Checks",
615
+ type: "integer"
715
616
  },
716
617
  applied: {
717
- type: "integer",
718
- minimum: 0
618
+ minimum: 0,
619
+ title: "Applied",
620
+ type: "integer"
719
621
  }
720
622
  },
721
- additionalProperties: false
722
- },
723
- data_extraction: {
724
- type: "object",
725
623
  required: [
726
- "root_type",
727
- "score_mode"
624
+ "checks",
625
+ "applied"
728
626
  ],
627
+ title: "StatsChecksSchema",
628
+ type: "object"
629
+ },
630
+ ThreatIntel: {
631
+ description: "Represents threat intelligence from an external source.\n\nThreat intelligence provides verdicts about observables from sources\nlike VirusTotal, URLScan.io, etc.",
729
632
  properties: {
730
- root_type: {
731
- type: [
732
- "string",
733
- "null"
734
- ],
735
- description: "Root observable type used during data extraction.",
736
- examples: [
737
- "ipv4-addr",
738
- "ipv6-addr",
739
- "domain-name",
740
- "url",
741
- "network-traffic",
742
- "mac-addr",
743
- "file",
744
- "directory",
745
- "email-addr",
746
- "email-message",
747
- "email-mime-part",
748
- "user-account",
749
- "process",
750
- "software",
751
- "windows-registry-key",
752
- "artifact",
753
- "autonomous-system",
754
- "mutex",
755
- "x509-certificate"
756
- ]
633
+ source: {
634
+ title: "Source",
635
+ type: "string"
757
636
  },
758
- score_mode: {
759
- $ref: "#/$defs/score_mode"
637
+ observable_key: {
638
+ title: "Observable Key",
639
+ type: "string"
640
+ },
641
+ comment: {
642
+ title: "Comment",
643
+ type: "string"
644
+ },
645
+ extra: {
646
+ additionalProperties: true,
647
+ title: "Extra",
648
+ type: "object"
649
+ },
650
+ score: {
651
+ title: "Score",
652
+ type: "number"
653
+ },
654
+ level: {
655
+ $ref: "#/$defs/Level"
656
+ },
657
+ taxonomies: {
658
+ items: {
659
+ additionalProperties: true,
660
+ type: "object"
661
+ },
662
+ title: "Taxonomies",
663
+ type: "array"
664
+ },
665
+ key: {
666
+ title: "Key",
667
+ type: "string"
760
668
  }
761
669
  },
762
- additionalProperties: false
670
+ required: [
671
+ "source",
672
+ "observable_key",
673
+ "comment",
674
+ "extra",
675
+ "score",
676
+ "level",
677
+ "taxonomies",
678
+ "key"
679
+ ],
680
+ title: "ThreatIntel",
681
+ type: "object"
763
682
  }
764
- }
683
+ },
684
+ $id: "https://cyvest.io/schema/investigation.json",
685
+ $schema: "https://json-schema.org/draft/2020-12/schema",
686
+ additionalProperties: false,
687
+ 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.",
688
+ properties: {
689
+ score: {
690
+ description: "Global investigation score.",
691
+ title: "Score",
692
+ type: "number"
693
+ },
694
+ level: {
695
+ $ref: "#/$defs/Level",
696
+ description: "Security level classification from NONE (lowest) to MALICIOUS (highest)."
697
+ },
698
+ whitelisted: {
699
+ description: "Whether the investigation is whitelisted.",
700
+ title: "Whitelisted",
701
+ type: "boolean"
702
+ },
703
+ whitelists: {
704
+ description: "List of whitelist entries applied to this investigation.",
705
+ items: {
706
+ $ref: "#/$defs/InvestigationWhitelist"
707
+ },
708
+ title: "Whitelists",
709
+ type: "array"
710
+ },
711
+ observables: {
712
+ additionalProperties: {
713
+ $ref: "#/$defs/Observable"
714
+ },
715
+ description: "Observables keyed by their unique key.",
716
+ title: "Observables",
717
+ type: "object"
718
+ },
719
+ checks: {
720
+ additionalProperties: {
721
+ items: {
722
+ $ref: "#/$defs/Check"
723
+ },
724
+ type: "array"
725
+ },
726
+ description: "Checks organized by scope.",
727
+ title: "Checks",
728
+ type: "object"
729
+ },
730
+ checks_by_level: {
731
+ additionalProperties: {
732
+ items: {
733
+ type: "string"
734
+ },
735
+ type: "array"
736
+ },
737
+ description: "Check keys organized by level name.",
738
+ title: "Checks By Level",
739
+ type: "object"
740
+ },
741
+ threat_intels: {
742
+ additionalProperties: {
743
+ $ref: "#/$defs/ThreatIntel"
744
+ },
745
+ description: "Threat intelligence entries keyed by their unique key.",
746
+ title: "Threat Intels",
747
+ type: "object"
748
+ },
749
+ enrichments: {
750
+ additionalProperties: {
751
+ $ref: "#/$defs/Enrichment"
752
+ },
753
+ description: "Enrichment entries keyed by their unique key.",
754
+ title: "Enrichments",
755
+ type: "object"
756
+ },
757
+ containers: {
758
+ additionalProperties: {
759
+ $ref: "#/$defs/Container"
760
+ },
761
+ description: "Containers keyed by their unique key.",
762
+ title: "Containers",
763
+ type: "object"
764
+ },
765
+ stats: {
766
+ $ref: "#/$defs/StatisticsSchema",
767
+ description: "Investigation statistics summary."
768
+ },
769
+ stats_checks: {
770
+ $ref: "#/$defs/StatsChecksSchema",
771
+ description: "Check statistics summary."
772
+ },
773
+ data_extraction: {
774
+ $ref: "#/$defs/DataExtractionSchema",
775
+ description: "Data extraction metadata."
776
+ }
777
+ },
778
+ required: [
779
+ "score",
780
+ "level",
781
+ "whitelisted",
782
+ "whitelists",
783
+ "observables",
784
+ "checks",
785
+ "checks_by_level",
786
+ "threat_intels",
787
+ "enrichments",
788
+ "containers",
789
+ "stats",
790
+ "stats_checks",
791
+ "data_extraction"
792
+ ],
793
+ title: "Cyvest Investigation",
794
+ type: "object"
765
795
  };
766
796
 
767
797
  // src/helpers.ts
@@ -989,9 +1019,15 @@ function hasLevel(obj) {
989
1019
  }
990
1020
  function getEntityLevel(entity) {
991
1021
  if ("aggregated_level" in entity) {
992
- return entity.aggregated_level;
1022
+ const aggregatedLevel = entity.aggregated_level;
1023
+ if (typeof aggregatedLevel === "string" && isValidLevel(aggregatedLevel)) {
1024
+ return aggregatedLevel;
1025
+ }
1026
+ }
1027
+ if ("level" in entity && isValidLevel(entity.level)) {
1028
+ return entity.level;
993
1029
  }
994
- return entity.level;
1030
+ throw new Error("Entity does not have a valid level.");
995
1031
  }
996
1032
 
997
1033
  // src/getters.ts