@cyvest/cyvest-js 5.4.0 → 6.0.0

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
@@ -96,69 +96,6 @@ var cyvest_schema_default = {
96
96
  title: "AuditEvent",
97
97
  type: "object"
98
98
  },
99
- Check: {
100
- 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.",
101
- properties: {
102
- check_name: {
103
- title: "Check Name",
104
- type: "string"
105
- },
106
- description: {
107
- title: "Description",
108
- type: "string"
109
- },
110
- comment: {
111
- title: "Comment",
112
- type: "string"
113
- },
114
- extra: {
115
- additionalProperties: true,
116
- title: "Extra",
117
- type: "object"
118
- },
119
- score: {
120
- title: "Score",
121
- type: "number"
122
- },
123
- level: {
124
- $ref: "#/$defs/Level"
125
- },
126
- origin_investigation_id: {
127
- title: "Origin Investigation Id",
128
- type: "string"
129
- },
130
- observable_links: {
131
- items: {
132
- $ref: "#/$defs/ObservableLink"
133
- },
134
- title: "Observable Links",
135
- type: "array"
136
- },
137
- key: {
138
- title: "Key",
139
- type: "string"
140
- },
141
- score_display: {
142
- readOnly: true,
143
- title: "Score Display",
144
- type: "string"
145
- }
146
- },
147
- required: [
148
- "check_name",
149
- "description",
150
- "comment",
151
- "extra",
152
- "score",
153
- "level",
154
- "origin_investigation_id",
155
- "observable_links",
156
- "key",
157
- "score_display"
158
- ],
159
- title: "Check",
160
- type: "object"
161
- },
162
99
  DataExtractionSchema: {
163
100
  additionalProperties: false,
164
101
  description: "Schema for data extraction metadata.",
@@ -219,6 +156,182 @@ var cyvest_schema_default = {
219
156
  title: "Enrichment",
220
157
  type: "object"
221
158
  },
159
+ Evidence: {
160
+ description: "Structured material supporting one or more findings.",
161
+ properties: {
162
+ type: {
163
+ title: "Type",
164
+ type: "string"
165
+ },
166
+ title: {
167
+ title: "Title",
168
+ type: "string"
169
+ },
170
+ description: {
171
+ title: "Description",
172
+ type: "string"
173
+ },
174
+ source: {
175
+ title: "Source",
176
+ type: "string"
177
+ },
178
+ external_id: {
179
+ anyOf: [
180
+ {
181
+ type: "string"
182
+ },
183
+ {
184
+ type: "null"
185
+ }
186
+ ],
187
+ title: "External Id"
188
+ },
189
+ content: {
190
+ anyOf: [
191
+ {},
192
+ {
193
+ type: "null"
194
+ }
195
+ ],
196
+ title: "Content"
197
+ },
198
+ uri: {
199
+ anyOf: [
200
+ {
201
+ type: "string"
202
+ },
203
+ {
204
+ type: "null"
205
+ }
206
+ ],
207
+ title: "Uri"
208
+ },
209
+ captured_at: {
210
+ format: "date-time",
211
+ title: "Captured At",
212
+ type: "string"
213
+ },
214
+ extra: {
215
+ additionalProperties: true,
216
+ title: "Extra",
217
+ type: "object"
218
+ },
219
+ key: {
220
+ title: "Key",
221
+ type: "string"
222
+ },
223
+ finding_links: {
224
+ description: "Findings that currently link to this evidence (navigation-only).",
225
+ items: {
226
+ type: "string"
227
+ },
228
+ readOnly: true,
229
+ title: "Finding Links",
230
+ type: "array"
231
+ }
232
+ },
233
+ required: [
234
+ "type",
235
+ "title",
236
+ "description",
237
+ "source",
238
+ "external_id",
239
+ "content",
240
+ "uri",
241
+ "captured_at",
242
+ "extra",
243
+ "key",
244
+ "finding_links"
245
+ ],
246
+ title: "Evidence",
247
+ type: "object"
248
+ },
249
+ EvidenceLink: {
250
+ additionalProperties: false,
251
+ description: "Edge metadata for a Finding\u2194Evidence association.",
252
+ properties: {
253
+ evidence_key: {
254
+ title: "Evidence Key",
255
+ type: "string"
256
+ }
257
+ },
258
+ required: [
259
+ "evidence_key"
260
+ ],
261
+ title: "EvidenceLink",
262
+ type: "object"
263
+ },
264
+ Finding: {
265
+ description: "Represents a verification step in the investigation.\n\nA finding validates a specific aspect of the data under investigation\nand contributes to the overall investigation score.",
266
+ properties: {
267
+ finding_name: {
268
+ title: "Finding Name",
269
+ type: "string"
270
+ },
271
+ description: {
272
+ title: "Description",
273
+ type: "string"
274
+ },
275
+ comment: {
276
+ title: "Comment",
277
+ type: "string"
278
+ },
279
+ extra: {
280
+ additionalProperties: true,
281
+ title: "Extra",
282
+ type: "object"
283
+ },
284
+ score: {
285
+ title: "Score",
286
+ type: "number"
287
+ },
288
+ level: {
289
+ $ref: "#/$defs/Level"
290
+ },
291
+ origin_investigation_id: {
292
+ title: "Origin Investigation Id",
293
+ type: "string"
294
+ },
295
+ observable_links: {
296
+ items: {
297
+ $ref: "#/$defs/ObservableLink"
298
+ },
299
+ title: "Observable Links",
300
+ type: "array"
301
+ },
302
+ evidence_links: {
303
+ items: {
304
+ $ref: "#/$defs/EvidenceLink"
305
+ },
306
+ title: "Evidence Links",
307
+ type: "array"
308
+ },
309
+ key: {
310
+ title: "Key",
311
+ type: "string"
312
+ },
313
+ score_display: {
314
+ readOnly: true,
315
+ title: "Score Display",
316
+ type: "string"
317
+ }
318
+ },
319
+ required: [
320
+ "finding_name",
321
+ "description",
322
+ "comment",
323
+ "extra",
324
+ "score",
325
+ "level",
326
+ "origin_investigation_id",
327
+ "observable_links",
328
+ "evidence_links",
329
+ "key",
330
+ "score_display"
331
+ ],
332
+ title: "Finding",
333
+ type: "object"
334
+ },
222
335
  InvestigationWhitelist: {
223
336
  description: "Represents a whitelist entry on an investigation.",
224
337
  properties: {
@@ -253,7 +366,7 @@ var cyvest_schema_default = {
253
366
  type: "object"
254
367
  },
255
368
  Level: {
256
- description: "Security level classification for checks, observables, and threat intelligence.\n\nLevels are ordered from lowest (NONE) to highest (MALICIOUS) severity.",
369
+ description: "Security level classification for findings, observables, and threat intelligence.\n\nLevels are ordered from lowest (NONE) to highest (MALICIOUS) severity.",
257
370
  enum: [
258
371
  "NONE",
259
372
  "TRUSTED",
@@ -267,12 +380,35 @@ var cyvest_schema_default = {
267
380
  type: "string"
268
381
  },
269
382
  Observable: {
270
- description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence, checks, and other observables\nthrough relationships.",
383
+ description: "Represents a cyber observable (IP, URL, domain, hash, etc.).\n\nObservables can be linked to threat intelligence, findings, and other observables\nthrough relationships.",
271
384
  properties: {
272
385
  type: {
273
386
  title: "Type",
274
387
  type: "string"
275
388
  },
389
+ subtype: {
390
+ anyOf: [
391
+ {
392
+ type: "string"
393
+ },
394
+ {
395
+ type: "null"
396
+ }
397
+ ],
398
+ title: "Subtype"
399
+ },
400
+ namespace: {
401
+ anyOf: [
402
+ {
403
+ type: "string"
404
+ },
405
+ {
406
+ type: "null"
407
+ }
408
+ ],
409
+ default: null,
410
+ title: "Namespace"
411
+ },
276
412
  value: {
277
413
  title: "Value",
278
414
  type: "string"
@@ -319,13 +455,13 @@ var cyvest_schema_default = {
319
455
  title: "Key",
320
456
  type: "string"
321
457
  },
322
- check_links: {
323
- description: "Checks that currently link to this observable (navigation-only).",
458
+ finding_links: {
459
+ description: "Findings that currently link to this observable (navigation-only).",
324
460
  items: {
325
461
  type: "string"
326
462
  },
327
463
  readOnly: true,
328
- title: "Check Links",
464
+ title: "Finding Links",
329
465
  type: "array"
330
466
  },
331
467
  score_display: {
@@ -346,7 +482,7 @@ var cyvest_schema_default = {
346
482
  "threat_intels",
347
483
  "relationships",
348
484
  "key",
349
- "check_links",
485
+ "finding_links",
350
486
  "score_display"
351
487
  ],
352
488
  title: "Observable",
@@ -354,7 +490,7 @@ var cyvest_schema_default = {
354
490
  },
355
491
  ObservableLink: {
356
492
  additionalProperties: false,
357
- description: "Edge metadata for a Check\u2194Observable association.",
493
+ description: "Edge metadata for a Finding\u2194Observable association.",
358
494
  properties: {
359
495
  observable_key: {
360
496
  title: "Observable Key",
@@ -372,7 +508,7 @@ var cyvest_schema_default = {
372
508
  type: "object"
373
509
  },
374
510
  PropagationMode: {
375
- description: "Controls how a Check\u2194Observable link propagates across merged investigations.",
511
+ description: "Controls how a Finding\u2194Observable link propagates across merged investigations.",
376
512
  enum: [
377
513
  "LOCAL_ONLY",
378
514
  "GLOBAL"
@@ -473,24 +609,45 @@ var cyvest_schema_default = {
473
609
  title: "Observables By Type And Level",
474
610
  type: "object"
475
611
  },
476
- total_checks: {
612
+ total_findings: {
477
613
  minimum: 0,
478
- title: "Total Checks",
614
+ title: "Total Findings",
479
615
  type: "integer"
480
616
  },
481
- applied_checks: {
617
+ applied_findings: {
482
618
  minimum: 0,
483
- title: "Applied Checks",
619
+ title: "Applied Findings",
484
620
  type: "integer"
485
621
  },
486
- checks_by_level: {
622
+ findings_by_level: {
487
623
  additionalProperties: {
488
624
  items: {
489
625
  type: "string"
490
626
  },
491
627
  type: "array"
492
628
  },
493
- title: "Checks By Level",
629
+ title: "Findings By Level",
630
+ type: "object"
631
+ },
632
+ total_evidences: {
633
+ minimum: 0,
634
+ title: "Total Evidences",
635
+ type: "integer"
636
+ },
637
+ evidences_by_type: {
638
+ additionalProperties: {
639
+ minimum: 0,
640
+ type: "integer"
641
+ },
642
+ title: "Evidences By Type",
643
+ type: "object"
644
+ },
645
+ evidences_by_source: {
646
+ additionalProperties: {
647
+ minimum: 0,
648
+ type: "integer"
649
+ },
650
+ title: "Evidences By Source",
494
651
  type: "object"
495
652
  },
496
653
  total_threat_intel: {
@@ -525,8 +682,9 @@ var cyvest_schema_default = {
525
682
  "internal_observables",
526
683
  "external_observables",
527
684
  "whitelisted_observables",
528
- "total_checks",
529
- "applied_checks",
685
+ "total_findings",
686
+ "applied_findings",
687
+ "total_evidences",
530
688
  "total_threat_intel",
531
689
  "total_tags"
532
690
  ],
@@ -535,7 +693,7 @@ var cyvest_schema_default = {
535
693
  },
536
694
  Tag: {
537
695
  additionalProperties: false,
538
- description: 'Groups checks for categorical organization.\n\nTags allow structuring the investigation into logical sections\nwith aggregated scores and levels. Hierarchy is automatic based on\nthe ":" delimiter in tag names (e.g., "header:auth:dkim").',
696
+ description: 'Groups findings for categorical organization.\n\nTags allow structuring the investigation into logical sections\nwith aggregated scores and levels. Hierarchy is automatic based on\nthe ":" delimiter in tag names (e.g., "header:auth:dkim").',
539
697
  properties: {
540
698
  name: {
541
699
  title: "Name",
@@ -546,11 +704,11 @@ var cyvest_schema_default = {
546
704
  title: "Description",
547
705
  type: "string"
548
706
  },
549
- checks: {
707
+ findings: {
550
708
  items: {
551
709
  type: "string"
552
710
  },
553
- title: "Checks",
711
+ title: "Findings",
554
712
  type: "array"
555
713
  },
556
714
  key: {
@@ -558,20 +716,20 @@ var cyvest_schema_default = {
558
716
  type: "string"
559
717
  },
560
718
  direct_score: {
561
- description: "Calculate the score from direct checks only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_score() or TagProxy.get_aggregated_score().\n\nReturns:\n Total score from direct checks",
719
+ description: "Calculate the score from direct findings only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_score() or TagProxy.get_aggregated_score().\n\nReturns:\n Total score from direct findings",
562
720
  readOnly: true,
563
721
  title: "Direct Score",
564
722
  type: "number"
565
723
  },
566
724
  direct_level: {
567
725
  $ref: "#/$defs/Level",
568
- description: "Calculate the level from direct checks only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_level() or TagProxy.get_aggregated_level().\n\nReturns:\n Level based on direct score",
726
+ description: "Calculate the level from direct findings only (no hierarchy).\n\nFor hierarchical aggregation (including descendant tags), use\nInvestigation.get_tag_aggregated_level() or TagProxy.get_aggregated_level().\n\nReturns:\n Level based on direct score",
569
727
  readOnly: true
570
728
  }
571
729
  },
572
730
  required: [
573
731
  "name",
574
- "checks",
732
+ "findings",
575
733
  "key",
576
734
  "direct_score",
577
735
  "direct_level"
@@ -667,6 +825,12 @@ var cyvest_schema_default = {
667
825
  additionalProperties: false,
668
826
  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.",
669
827
  properties: {
828
+ schema_version: {
829
+ const: "6.0.0",
830
+ default: "6.0.0",
831
+ title: "Schema Version",
832
+ type: "string"
833
+ },
670
834
  investigation_id: {
671
835
  description: "Stable investigation identity (ULID).",
672
836
  title: "Investigation Id",
@@ -730,12 +894,20 @@ var cyvest_schema_default = {
730
894
  title: "Observables",
731
895
  type: "object"
732
896
  },
733
- checks: {
897
+ findings: {
898
+ additionalProperties: {
899
+ $ref: "#/$defs/Finding"
900
+ },
901
+ description: "Findings keyed by their unique key.",
902
+ title: "Findings",
903
+ type: "object"
904
+ },
905
+ evidences: {
734
906
  additionalProperties: {
735
- $ref: "#/$defs/Check"
907
+ $ref: "#/$defs/Evidence"
736
908
  },
737
- description: "Checks keyed by their unique key.",
738
- title: "Checks",
909
+ description: "Evidence objects keyed by their unique key.",
910
+ title: "Evidences",
739
911
  type: "object"
740
912
  },
741
913
  threat_intels: {
@@ -784,7 +956,8 @@ var cyvest_schema_default = {
784
956
  "whitelisted",
785
957
  "whitelists",
786
958
  "observables",
787
- "checks",
959
+ "findings",
960
+ "evidences",
788
961
  "threat_intels",
789
962
  "enrichments",
790
963
  "tags",
@@ -823,6 +996,108 @@ function isCyvest(json) {
823
996
  function normalizeValue(value) {
824
997
  return value.trim().toLowerCase();
825
998
  }
999
+ function normalizeObservableValue(obsType, value, subtype) {
1000
+ const normalizedType = normalizeValue(obsType);
1001
+ const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
1002
+ const stripped = value.trim();
1003
+ if (normalizedType === "command_line") return stripped;
1004
+ if (normalizedType === "email" || normalizedType === "host") {
1005
+ return stripped.toLowerCase();
1006
+ }
1007
+ if (normalizedType === "user" && (normalizedSubtype === "email" || normalizedSubtype === "upn")) {
1008
+ return stripped.toLowerCase();
1009
+ }
1010
+ if (normalizedSubtype === "uid" || normalizedSubtype === "pid") {
1011
+ if (!/^[+-]?\d+$/.test(stripped)) {
1012
+ throw new Error(`${normalizedSubtype} observable values must be base-10 integers`);
1013
+ }
1014
+ return BigInt(stripped).toString(10);
1015
+ }
1016
+ return stripped;
1017
+ }
1018
+ function sha256(content) {
1019
+ const bytes = new TextEncoder().encode(content);
1020
+ const words = [];
1021
+ const bitLength = bytes.length * 8;
1022
+ for (const byte of bytes) {
1023
+ words.push(byte);
1024
+ }
1025
+ words.push(128);
1026
+ while (words.length % 64 !== 56) words.push(0);
1027
+ for (let i = 7; i >= 0; i--) {
1028
+ words.push(Math.floor(bitLength / 2 ** (i * 8)) & 255);
1029
+ }
1030
+ const h = [
1031
+ 1779033703,
1032
+ 3144134277,
1033
+ 1013904242,
1034
+ 2773480762,
1035
+ 1359893119,
1036
+ 2600822924,
1037
+ 528734635,
1038
+ 1541459225
1039
+ ];
1040
+ const k = Array.from({ length: 64 }, (_, index) => {
1041
+ let primeCount = 0;
1042
+ let candidate = 2;
1043
+ while (true) {
1044
+ let prime = true;
1045
+ for (let divisor = 2; divisor * divisor <= candidate; divisor++) {
1046
+ if (candidate % divisor === 0) {
1047
+ prime = false;
1048
+ break;
1049
+ }
1050
+ }
1051
+ if (prime && primeCount++ === index) {
1052
+ return Math.floor(Math.cbrt(candidate) % 1 * 2 ** 32) >>> 0;
1053
+ }
1054
+ candidate++;
1055
+ }
1056
+ });
1057
+ const rotateRight = (value, amount) => value >>> amount | value << 32 - amount;
1058
+ for (let offset = 0; offset < words.length; offset += 64) {
1059
+ const schedule = new Array(64);
1060
+ for (let i = 0; i < 16; i++) {
1061
+ const base = offset + i * 4;
1062
+ schedule[i] = (words[base] << 24 | words[base + 1] << 16 | words[base + 2] << 8 | words[base + 3]) >>> 0;
1063
+ }
1064
+ for (let i = 16; i < 64; i++) {
1065
+ const s0 = rotateRight(schedule[i - 15], 7) ^ rotateRight(schedule[i - 15], 18) ^ schedule[i - 15] >>> 3;
1066
+ const s1 = rotateRight(schedule[i - 2], 17) ^ rotateRight(schedule[i - 2], 19) ^ schedule[i - 2] >>> 10;
1067
+ schedule[i] = schedule[i - 16] + s0 + schedule[i - 7] + s1 >>> 0;
1068
+ }
1069
+ let [a, b, c, d, e, f, g, hh] = h;
1070
+ for (let i = 0; i < 64; i++) {
1071
+ const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
1072
+ const choice = e & f ^ ~e & g;
1073
+ const temp1 = hh + s1 + choice + k[i] + schedule[i] >>> 0;
1074
+ const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
1075
+ const majority = a & b ^ a & c ^ b & c;
1076
+ const temp2 = s0 + majority >>> 0;
1077
+ hh = g;
1078
+ g = f;
1079
+ f = e;
1080
+ e = d + temp1 >>> 0;
1081
+ d = c;
1082
+ c = b;
1083
+ b = a;
1084
+ a = temp1 + temp2 >>> 0;
1085
+ }
1086
+ [a, b, c, d, e, f, g, hh].forEach((value, index) => {
1087
+ h[index] = h[index] + value >>> 0;
1088
+ });
1089
+ }
1090
+ return h.map((value) => value.toString(16).padStart(8, "0")).join("");
1091
+ }
1092
+ function encodeKeyPart(value, keepSlash = false) {
1093
+ let encoded = encodeURIComponent(value).replace(
1094
+ /[!'()*]/g,
1095
+ (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
1096
+ );
1097
+ encoded = encoded.replace(/%40/gi, "@");
1098
+ if (keepSlash) encoded = encoded.replace(/%2F/gi, "/").replace(/%5C/gi, "\\");
1099
+ return encoded;
1100
+ }
826
1101
  function hashString(content, length = 16) {
827
1102
  let hash = 0;
828
1103
  for (let i = 0; i < content.length; i++) {
@@ -832,14 +1107,35 @@ function hashString(content, length = 16) {
832
1107
  const hex = Math.abs(hash).toString(16).padStart(8, "0");
833
1108
  return hex.slice(0, length);
834
1109
  }
835
- function generateObservableKey(obsType, value) {
1110
+ function generateObservableKey(obsType, value, subtype, namespace) {
836
1111
  const normalizedType = normalizeValue(obsType);
837
- const normalizedValue = normalizeValue(value);
838
- return `obs:${normalizedType}:${normalizedValue}`;
1112
+ const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
1113
+ const normalizedNamespace = namespace?.trim().toLowerCase() || void 0;
1114
+ const normalizedValue = normalizeObservableValue(
1115
+ normalizedType,
1116
+ value,
1117
+ normalizedSubtype
1118
+ );
1119
+ const identity = JSON.stringify({
1120
+ namespace: normalizedNamespace ?? null,
1121
+ subtype: normalizedSubtype ?? null,
1122
+ type: normalizedType,
1123
+ value: normalizedValue
1124
+ });
1125
+ if (normalizedType === "command_line" || new TextEncoder().encode(identity).length > 128) {
1126
+ return `obs:${normalizedType}:sha256:${sha256(identity)}`;
1127
+ }
1128
+ if (!normalizedSubtype && !normalizedNamespace) {
1129
+ return `obs:${normalizedType}:${normalizedValue.toLowerCase()}`;
1130
+ }
1131
+ const parts = ["obs", encodeKeyPart(normalizedType), normalizedSubtype ? encodeKeyPart(normalizedSubtype) : "_"];
1132
+ if (normalizedNamespace) parts.push(encodeKeyPart(normalizedNamespace));
1133
+ parts.push(encodeKeyPart(normalizedValue, true));
1134
+ return parts.join(":");
839
1135
  }
840
- function generateCheckKey(checkName) {
841
- const normalizedName = normalizeValue(checkName);
842
- return `chk:${normalizedName}`;
1136
+ function generateFindingKey(findingName) {
1137
+ const normalizedName = normalizeValue(findingName);
1138
+ return `fnd:${normalizedName}`;
843
1139
  }
844
1140
  function generateThreatIntelKey(source, observableKey) {
845
1141
  const normalizedSource = normalizeValue(source);
@@ -878,7 +1174,7 @@ function isTagDescendantOf(descendantName, ancestorName) {
878
1174
  function parseKeyType(key) {
879
1175
  if (key.includes(":")) {
880
1176
  const prefix = key.split(":", 1)[0];
881
- if (["obs", "chk", "ti", "enr", "tag"].includes(prefix)) {
1177
+ if (["obs", "fnd", "evd", "ti", "enr", "tag"].includes(prefix)) {
882
1178
  return prefix;
883
1179
  }
884
1180
  }
@@ -911,14 +1207,14 @@ function parseObservableKey(key) {
911
1207
  }
912
1208
  return null;
913
1209
  }
914
- function parseCheckKey(key) {
915
- if (!validateKey(key, "chk")) {
1210
+ function parseFindingKey(key) {
1211
+ if (!validateKey(key, "fnd")) {
916
1212
  return null;
917
1213
  }
918
1214
  const parts = key.split(":");
919
1215
  if (parts.length >= 2) {
920
1216
  return {
921
- checkName: parts.slice(1).join(":")
1217
+ findingName: parts.slice(1).join(":")
922
1218
  };
923
1219
  }
924
1220
  return null;
@@ -1051,15 +1347,8 @@ function getEntityLevel(entity) {
1051
1347
  function getObservable(inv, key) {
1052
1348
  return inv.observables[key];
1053
1349
  }
1054
- function getObservableByTypeValue(inv, type, value) {
1055
- const normalizedType = type.trim().toLowerCase();
1056
- const normalizedValue = value.trim().toLowerCase();
1057
- for (const obs of Object.values(inv.observables)) {
1058
- if (obs.type.toLowerCase() === normalizedType && obs.value.toLowerCase() === normalizedValue) {
1059
- return obs;
1060
- }
1061
- }
1062
- return void 0;
1350
+ function getObservableByTypeValue(inv, type, value, subtype, namespace) {
1351
+ return inv.observables[generateObservableKey(type, value, subtype, namespace)];
1063
1352
  }
1064
1353
  function getRootObservable(inv) {
1065
1354
  const rootType = inv.data_extraction.root_type;
@@ -1069,15 +1358,21 @@ function getRootObservable(inv) {
1069
1358
  const rootKey = generateObservableKey(rootType, "root");
1070
1359
  return inv.observables[rootKey];
1071
1360
  }
1072
- function getCheck(inv, key) {
1073
- return inv.checks[key];
1361
+ function getFinding(inv, key) {
1362
+ return inv.findings[key];
1363
+ }
1364
+ function getFindingByName(inv, findingName) {
1365
+ const key = generateFindingKey(findingName);
1366
+ return inv.findings[key];
1367
+ }
1368
+ function getAllFindings(inv) {
1369
+ return Object.values(inv.findings);
1074
1370
  }
1075
- function getCheckByName(inv, checkName) {
1076
- const key = generateCheckKey(checkName);
1077
- return inv.checks[key];
1371
+ function getEvidence(inv, key) {
1372
+ return inv.evidences[key];
1078
1373
  }
1079
- function getAllChecks(inv) {
1080
- return Object.values(inv.checks);
1374
+ function getAllEvidences(inv) {
1375
+ return Object.values(inv.evidences);
1081
1376
  }
1082
1377
  function getThreatIntel(inv, key) {
1083
1378
  return inv.threat_intels[key];
@@ -1134,7 +1429,8 @@ function getDataExtraction(inv) {
1134
1429
  function getCounts(inv) {
1135
1430
  return {
1136
1431
  observables: Object.keys(inv.observables).length,
1137
- checks: getAllChecks(inv).length,
1432
+ findings: getAllFindings(inv).length,
1433
+ evidences: getAllEvidences(inv).length,
1138
1434
  threatIntels: Object.keys(inv.threat_intels).length,
1139
1435
  enrichments: Object.keys(inv.enrichments).length,
1140
1436
  tags: getAllTags(inv).length,
@@ -1216,18 +1512,18 @@ function findObservablesWithThreatIntel(inv) {
1216
1512
  (obs) => obs.threat_intels.length > 0
1217
1513
  );
1218
1514
  }
1219
- function findChecksByLevel(inv, level) {
1220
- return Object.values(inv.checks).filter((check) => check.level === level);
1515
+ function findFindingsByLevel(inv, level) {
1516
+ return Object.values(inv.findings).filter((finding) => finding.level === level);
1221
1517
  }
1222
- function findChecksAtLeast(inv, minLevel2) {
1223
- return Object.values(inv.checks).filter(
1224
- (check) => isLevelAtLeast(check.level, minLevel2)
1518
+ function findFindingsAtLeast(inv, minLevel2) {
1519
+ return Object.values(inv.findings).filter(
1520
+ (finding) => isLevelAtLeast(finding.level, minLevel2)
1225
1521
  );
1226
1522
  }
1227
- function findCheckByName(inv, checkName) {
1228
- const normalizedName = checkName.trim().toLowerCase();
1229
- return Object.values(inv.checks).find(
1230
- (check) => check.check_name.toLowerCase() === normalizedName
1523
+ function findFindingByName(inv, findingName) {
1524
+ const normalizedName = findingName.trim().toLowerCase();
1525
+ return Object.values(inv.findings).find(
1526
+ (finding) => finding.finding_name.toLowerCase() === normalizedName
1231
1527
  );
1232
1528
  }
1233
1529
  function findThreatIntelBySource(inv, source) {
@@ -1255,26 +1551,26 @@ function findTagsAtLeast(inv, minLevel2) {
1255
1551
  function findTagsByNamePattern(inv, pattern) {
1256
1552
  return Object.values(inv.tags).filter((tag) => pattern.test(tag.name));
1257
1553
  }
1258
- function findChecksForObservable(inv, observableKey) {
1554
+ function findFindingsForObservable(inv, observableKey) {
1259
1555
  const result = [];
1260
1556
  const seen = /* @__PURE__ */ new Set();
1261
1557
  const observable = inv.observables[observableKey];
1262
1558
  if (observable) {
1263
- for (const checkKey of observable.check_links) {
1264
- const check = inv.checks[checkKey];
1265
- if (check && !seen.has(check.key)) {
1266
- result.push(check);
1267
- seen.add(check.key);
1559
+ for (const findingKey of observable.finding_links) {
1560
+ const finding = inv.findings[findingKey];
1561
+ if (finding && !seen.has(finding.key)) {
1562
+ result.push(finding);
1563
+ seen.add(finding.key);
1268
1564
  }
1269
1565
  }
1270
1566
  }
1271
- for (const check of Object.values(inv.checks)) {
1272
- if (seen.has(check.key)) {
1567
+ for (const finding of Object.values(inv.findings)) {
1568
+ if (seen.has(finding.key)) {
1273
1569
  continue;
1274
1570
  }
1275
- if (check.observable_links.some((link) => link.observable_key === observableKey)) {
1276
- result.push(check);
1277
- seen.add(check.key);
1571
+ if (finding.observable_links.some((link) => link.observable_key === observableKey)) {
1572
+ result.push(finding);
1573
+ seen.add(finding.key);
1278
1574
  }
1279
1575
  }
1280
1576
  return result;
@@ -1288,37 +1584,37 @@ function findThreatIntelsForObservable(inv, observableKey) {
1288
1584
  (ti) => ti.observable_key === observableKey
1289
1585
  );
1290
1586
  }
1291
- function findObservablesForCheck(inv, checkKey) {
1292
- const check = inv.checks[checkKey];
1293
- if (check) {
1587
+ function findObservablesForFinding(inv, findingKey) {
1588
+ const finding = inv.findings[findingKey];
1589
+ if (finding) {
1294
1590
  const keys = /* @__PURE__ */ new Set();
1295
- for (const link of check.observable_links) {
1591
+ for (const link of finding.observable_links) {
1296
1592
  keys.add(link.observable_key);
1297
1593
  }
1298
1594
  return Array.from(keys).map((obsKey) => inv.observables[obsKey]).filter((obs) => obs !== void 0);
1299
1595
  }
1300
1596
  return [];
1301
1597
  }
1302
- function findChecksForTag(inv, tagKey, recursive = false) {
1598
+ function findFindingsForTag(inv, tagKey, recursive = false) {
1303
1599
  const result = [];
1304
1600
  const tag = inv.tags[tagKey];
1305
1601
  if (!tag) {
1306
1602
  return result;
1307
1603
  }
1308
- for (const checkKey of tag.checks) {
1309
- const check = inv.checks[checkKey];
1310
- if (check) {
1311
- result.push(check);
1604
+ for (const findingKey of tag.findings) {
1605
+ const finding = inv.findings[findingKey];
1606
+ if (finding) {
1607
+ result.push(finding);
1312
1608
  }
1313
1609
  }
1314
1610
  if (recursive) {
1315
1611
  const prefix = tag.name + ":";
1316
1612
  for (const otherTag of Object.values(inv.tags)) {
1317
1613
  if (otherTag.name.startsWith(prefix)) {
1318
- for (const checkKey of otherTag.checks) {
1319
- const check = inv.checks[checkKey];
1320
- if (check) {
1321
- result.push(check);
1614
+ for (const findingKey of otherTag.findings) {
1615
+ const finding = inv.findings[findingKey];
1616
+ if (finding) {
1617
+ result.push(finding);
1322
1618
  }
1323
1619
  }
1324
1620
  }
@@ -1329,24 +1625,24 @@ function findChecksForTag(inv, tagKey, recursive = false) {
1329
1625
  function sortObservablesByScore(observables) {
1330
1626
  return [...observables].sort((a, b) => b.score - a.score);
1331
1627
  }
1332
- function sortChecksByScore(checks) {
1333
- return [...checks].sort((a, b) => b.score - a.score);
1628
+ function sortFindingsByScore(findings) {
1629
+ return [...findings].sort((a, b) => b.score - a.score);
1334
1630
  }
1335
1631
  function sortObservablesByLevel(observables) {
1336
1632
  return [...observables].sort(
1337
1633
  (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1338
1634
  );
1339
1635
  }
1340
- function sortChecksByLevel(checks) {
1341
- return [...checks].sort(
1636
+ function sortFindingsByLevel(findings) {
1637
+ return [...findings].sort(
1342
1638
  (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1343
1639
  );
1344
1640
  }
1345
1641
  function findHighestScoringObservables(inv, n = 10) {
1346
1642
  return sortObservablesByScore(Object.values(inv.observables)).slice(0, n);
1347
1643
  }
1348
- function findHighestScoringChecks(inv, n = 10) {
1349
- return sortChecksByScore(Object.values(inv.checks)).slice(0, n);
1644
+ function findHighestScoringFindings(inv, n = 10) {
1645
+ return sortFindingsByScore(Object.values(inv.findings)).slice(0, n);
1350
1646
  }
1351
1647
  function findMaliciousObservables(inv) {
1352
1648
  return findObservablesByLevel(inv, "MALICIOUS");
@@ -1354,14 +1650,14 @@ function findMaliciousObservables(inv) {
1354
1650
  function findSuspiciousObservables(inv) {
1355
1651
  return findObservablesByLevel(inv, "SUSPICIOUS");
1356
1652
  }
1357
- function findMaliciousChecks(inv) {
1358
- return findChecksByLevel(inv, "MALICIOUS");
1653
+ function findMaliciousFindings(inv) {
1654
+ return findFindingsByLevel(inv, "MALICIOUS");
1359
1655
  }
1360
- function findSuspiciousChecks(inv) {
1361
- return findChecksByLevel(inv, "SUSPICIOUS");
1656
+ function findSuspiciousFindings(inv) {
1657
+ return findFindingsByLevel(inv, "SUSPICIOUS");
1362
1658
  }
1363
- function getAllCheckKeys(inv) {
1364
- return Object.keys(inv.checks);
1659
+ function getAllFindingKeys(inv) {
1660
+ return Object.keys(inv.findings);
1365
1661
  }
1366
1662
  function getAllObservableTypes(inv) {
1367
1663
  const types = /* @__PURE__ */ new Set();
@@ -1645,30 +1941,30 @@ export {
1645
1941
  areConnected,
1646
1942
  compareLevels,
1647
1943
  countRelationshipsByType,
1648
- findCheckByName,
1649
- findChecksAtLeast,
1650
- findChecksByLevel,
1651
- findChecksForObservable,
1652
- findChecksForTag,
1653
1944
  findExternalObservables,
1654
- findHighestScoringChecks,
1945
+ findFindingByName,
1946
+ findFindingsAtLeast,
1947
+ findFindingsByLevel,
1948
+ findFindingsForObservable,
1949
+ findFindingsForTag,
1950
+ findHighestScoringFindings,
1655
1951
  findHighestScoringObservables,
1656
1952
  findInternalObservables,
1657
1953
  findLeafObservables,
1658
- findMaliciousChecks,
1954
+ findMaliciousFindings,
1659
1955
  findMaliciousObservables,
1660
1956
  findObservablesAtLeast,
1661
1957
  findObservablesByLevel,
1662
1958
  findObservablesByType,
1663
1959
  findObservablesByValue,
1664
1960
  findObservablesContaining,
1665
- findObservablesForCheck,
1961
+ findObservablesForFinding,
1666
1962
  findObservablesMatching,
1667
1963
  findObservablesWithThreatIntel,
1668
1964
  findOrphanObservables,
1669
1965
  findPath,
1670
1966
  findSourceObservables,
1671
- findSuspiciousChecks,
1967
+ findSuspiciousFindings,
1672
1968
  findSuspiciousObservables,
1673
1969
  findTagsAtLeast,
1674
1970
  findTagsByLevel,
@@ -1678,22 +1974,21 @@ export {
1678
1974
  findThreatIntelBySource,
1679
1975
  findThreatIntelsForObservable,
1680
1976
  findWhitelistedObservables,
1681
- generateCheckKey,
1682
1977
  generateEnrichmentKey,
1978
+ generateFindingKey,
1683
1979
  generateObservableKey,
1684
1980
  generateTagKey,
1685
1981
  generateThreatIntelKey,
1686
- getAllCheckKeys,
1687
- getAllChecks,
1688
1982
  getAllEnrichments,
1983
+ getAllEvidences,
1984
+ getAllFindingKeys,
1985
+ getAllFindings,
1689
1986
  getAllObservableTypes,
1690
1987
  getAllObservables,
1691
1988
  getAllRelationshipTypes,
1692
1989
  getAllTags,
1693
1990
  getAllThreatIntelSources,
1694
1991
  getAllThreatIntels,
1695
- getCheck,
1696
- getCheckByName,
1697
1992
  getColorForLevel,
1698
1993
  getColorForScore,
1699
1994
  getCounts,
@@ -1701,6 +1996,9 @@ export {
1701
1996
  getEnrichment,
1702
1997
  getEnrichmentByName,
1703
1998
  getEntityLevel,
1999
+ getEvidence,
2000
+ getFinding,
2001
+ getFindingByName,
1704
2002
  getLevelFromScore,
1705
2003
  getObservable,
1706
2004
  getObservableByTypeValue,
@@ -1736,13 +2034,13 @@ export {
1736
2034
  maxLevel,
1737
2035
  minLevel,
1738
2036
  normalizeLevel,
1739
- parseCheckKey,
1740
2037
  parseCyvest,
2038
+ parseFindingKey,
1741
2039
  parseKeyType,
1742
2040
  parseObservableKey,
1743
2041
  parseThreatIntelKey,
1744
- sortChecksByLevel,
1745
- sortChecksByScore,
2042
+ sortFindingsByLevel,
2043
+ sortFindingsByScore,
1746
2044
  sortObservablesByLevel,
1747
2045
  sortObservablesByScore,
1748
2046
  validateKey