@cyvest/cyvest-js 5.4.1 → 6.1.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"
@@ -301,6 +437,19 @@ var cyvest_schema_default = {
301
437
  level: {
302
438
  $ref: "#/$defs/Level"
303
439
  },
440
+ aliases: {
441
+ items: {
442
+ $ref: "#/$defs/ObservableAlias"
443
+ },
444
+ title: "Aliases",
445
+ type: "array"
446
+ },
447
+ occurrence_count: {
448
+ default: 1,
449
+ minimum: 1,
450
+ title: "Occurrence Count",
451
+ type: "integer"
452
+ },
304
453
  threat_intels: {
305
454
  items: {
306
455
  type: "string"
@@ -319,13 +468,13 @@ var cyvest_schema_default = {
319
468
  title: "Key",
320
469
  type: "string"
321
470
  },
322
- check_links: {
323
- description: "Checks that currently link to this observable (navigation-only).",
471
+ finding_links: {
472
+ description: "Findings that currently link to this observable (navigation-only).",
324
473
  items: {
325
474
  type: "string"
326
475
  },
327
476
  readOnly: true,
328
- title: "Check Links",
477
+ title: "Finding Links",
329
478
  type: "array"
330
479
  },
331
480
  score_display: {
@@ -343,18 +492,67 @@ var cyvest_schema_default = {
343
492
  "extra",
344
493
  "score",
345
494
  "level",
495
+ "aliases",
346
496
  "threat_intels",
347
497
  "relationships",
348
498
  "key",
349
- "check_links",
499
+ "finding_links",
350
500
  "score_display"
351
501
  ],
352
502
  title: "Observable",
353
503
  type: "object"
354
504
  },
505
+ ObservableAlias: {
506
+ description: "Source observable identity attached to a canonical observable.",
507
+ properties: {
508
+ type: {
509
+ title: "Type",
510
+ type: "string"
511
+ },
512
+ subtype: {
513
+ anyOf: [
514
+ {
515
+ type: "string"
516
+ },
517
+ {
518
+ type: "null"
519
+ }
520
+ ],
521
+ title: "Subtype"
522
+ },
523
+ namespace: {
524
+ anyOf: [
525
+ {
526
+ type: "string"
527
+ },
528
+ {
529
+ type: "null"
530
+ }
531
+ ],
532
+ default: null,
533
+ title: "Namespace"
534
+ },
535
+ value: {
536
+ title: "Value",
537
+ type: "string"
538
+ },
539
+ count: {
540
+ default: 1,
541
+ minimum: 1,
542
+ title: "Count",
543
+ type: "integer"
544
+ }
545
+ },
546
+ required: [
547
+ "type",
548
+ "value"
549
+ ],
550
+ title: "ObservableAlias",
551
+ type: "object"
552
+ },
355
553
  ObservableLink: {
356
554
  additionalProperties: false,
357
- description: "Edge metadata for a Check\u2194Observable association.",
555
+ description: "Edge metadata for a Finding\u2194Observable association.",
358
556
  properties: {
359
557
  observable_key: {
360
558
  title: "Observable Key",
@@ -372,7 +570,7 @@ var cyvest_schema_default = {
372
570
  type: "object"
373
571
  },
374
572
  PropagationMode: {
375
- description: "Controls how a Check\u2194Observable link propagates across merged investigations.",
573
+ description: "Controls how a Finding\u2194Observable link propagates across merged investigations.",
376
574
  enum: [
377
575
  "LOCAL_ONLY",
378
576
  "GLOBAL"
@@ -473,24 +671,45 @@ var cyvest_schema_default = {
473
671
  title: "Observables By Type And Level",
474
672
  type: "object"
475
673
  },
476
- total_checks: {
674
+ total_findings: {
477
675
  minimum: 0,
478
- title: "Total Checks",
676
+ title: "Total Findings",
479
677
  type: "integer"
480
678
  },
481
- applied_checks: {
679
+ applied_findings: {
482
680
  minimum: 0,
483
- title: "Applied Checks",
681
+ title: "Applied Findings",
484
682
  type: "integer"
485
683
  },
486
- checks_by_level: {
684
+ findings_by_level: {
487
685
  additionalProperties: {
488
686
  items: {
489
687
  type: "string"
490
688
  },
491
689
  type: "array"
492
690
  },
493
- title: "Checks By Level",
691
+ title: "Findings By Level",
692
+ type: "object"
693
+ },
694
+ total_evidences: {
695
+ minimum: 0,
696
+ title: "Total Evidences",
697
+ type: "integer"
698
+ },
699
+ evidences_by_type: {
700
+ additionalProperties: {
701
+ minimum: 0,
702
+ type: "integer"
703
+ },
704
+ title: "Evidences By Type",
705
+ type: "object"
706
+ },
707
+ evidences_by_source: {
708
+ additionalProperties: {
709
+ minimum: 0,
710
+ type: "integer"
711
+ },
712
+ title: "Evidences By Source",
494
713
  type: "object"
495
714
  },
496
715
  total_threat_intel: {
@@ -525,8 +744,9 @@ var cyvest_schema_default = {
525
744
  "internal_observables",
526
745
  "external_observables",
527
746
  "whitelisted_observables",
528
- "total_checks",
529
- "applied_checks",
747
+ "total_findings",
748
+ "applied_findings",
749
+ "total_evidences",
530
750
  "total_threat_intel",
531
751
  "total_tags"
532
752
  ],
@@ -535,7 +755,7 @@ var cyvest_schema_default = {
535
755
  },
536
756
  Tag: {
537
757
  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").',
758
+ 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
759
  properties: {
540
760
  name: {
541
761
  title: "Name",
@@ -546,11 +766,11 @@ var cyvest_schema_default = {
546
766
  title: "Description",
547
767
  type: "string"
548
768
  },
549
- checks: {
769
+ findings: {
550
770
  items: {
551
771
  type: "string"
552
772
  },
553
- title: "Checks",
773
+ title: "Findings",
554
774
  type: "array"
555
775
  },
556
776
  key: {
@@ -558,20 +778,20 @@ var cyvest_schema_default = {
558
778
  type: "string"
559
779
  },
560
780
  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",
781
+ 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
782
  readOnly: true,
563
783
  title: "Direct Score",
564
784
  type: "number"
565
785
  },
566
786
  direct_level: {
567
787
  $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",
788
+ 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
789
  readOnly: true
570
790
  }
571
791
  },
572
792
  required: [
573
793
  "name",
574
- "checks",
794
+ "findings",
575
795
  "key",
576
796
  "direct_score",
577
797
  "direct_level"
@@ -667,6 +887,12 @@ var cyvest_schema_default = {
667
887
  additionalProperties: false,
668
888
  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
889
  properties: {
890
+ schema_version: {
891
+ const: "6.0.0",
892
+ default: "6.0.0",
893
+ title: "Schema Version",
894
+ type: "string"
895
+ },
670
896
  investigation_id: {
671
897
  description: "Stable investigation identity (ULID).",
672
898
  title: "Investigation Id",
@@ -730,12 +956,20 @@ var cyvest_schema_default = {
730
956
  title: "Observables",
731
957
  type: "object"
732
958
  },
733
- checks: {
959
+ findings: {
960
+ additionalProperties: {
961
+ $ref: "#/$defs/Finding"
962
+ },
963
+ description: "Findings keyed by their unique key.",
964
+ title: "Findings",
965
+ type: "object"
966
+ },
967
+ evidences: {
734
968
  additionalProperties: {
735
- $ref: "#/$defs/Check"
969
+ $ref: "#/$defs/Evidence"
736
970
  },
737
- description: "Checks keyed by their unique key.",
738
- title: "Checks",
971
+ description: "Evidence objects keyed by their unique key.",
972
+ title: "Evidences",
739
973
  type: "object"
740
974
  },
741
975
  threat_intels: {
@@ -784,7 +1018,8 @@ var cyvest_schema_default = {
784
1018
  "whitelisted",
785
1019
  "whitelists",
786
1020
  "observables",
787
- "checks",
1021
+ "findings",
1022
+ "evidences",
788
1023
  "threat_intels",
789
1024
  "enrichments",
790
1025
  "tags",
@@ -823,6 +1058,108 @@ function isCyvest(json) {
823
1058
  function normalizeValue(value) {
824
1059
  return value.trim().toLowerCase();
825
1060
  }
1061
+ function normalizeObservableValue(obsType, value, subtype) {
1062
+ const normalizedType = normalizeValue(obsType);
1063
+ const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
1064
+ const stripped = value.trim();
1065
+ if (normalizedType === "command_line") return stripped;
1066
+ if (normalizedType === "email" || normalizedType === "host") {
1067
+ return stripped.toLowerCase();
1068
+ }
1069
+ if (normalizedType === "user" && (normalizedSubtype === "email" || normalizedSubtype === "upn")) {
1070
+ return stripped.toLowerCase();
1071
+ }
1072
+ if (normalizedSubtype === "uid" || normalizedSubtype === "pid") {
1073
+ if (!/^[+-]?\d+$/.test(stripped)) {
1074
+ throw new Error(`${normalizedSubtype} observable values must be base-10 integers`);
1075
+ }
1076
+ return BigInt(stripped).toString(10);
1077
+ }
1078
+ return stripped;
1079
+ }
1080
+ function sha256(content) {
1081
+ const bytes = new TextEncoder().encode(content);
1082
+ const words = [];
1083
+ const bitLength = bytes.length * 8;
1084
+ for (const byte of bytes) {
1085
+ words.push(byte);
1086
+ }
1087
+ words.push(128);
1088
+ while (words.length % 64 !== 56) words.push(0);
1089
+ for (let i = 7; i >= 0; i--) {
1090
+ words.push(Math.floor(bitLength / 2 ** (i * 8)) & 255);
1091
+ }
1092
+ const h = [
1093
+ 1779033703,
1094
+ 3144134277,
1095
+ 1013904242,
1096
+ 2773480762,
1097
+ 1359893119,
1098
+ 2600822924,
1099
+ 528734635,
1100
+ 1541459225
1101
+ ];
1102
+ const k = Array.from({ length: 64 }, (_, index) => {
1103
+ let primeCount = 0;
1104
+ let candidate = 2;
1105
+ while (true) {
1106
+ let prime = true;
1107
+ for (let divisor = 2; divisor * divisor <= candidate; divisor++) {
1108
+ if (candidate % divisor === 0) {
1109
+ prime = false;
1110
+ break;
1111
+ }
1112
+ }
1113
+ if (prime && primeCount++ === index) {
1114
+ return Math.floor(Math.cbrt(candidate) % 1 * 2 ** 32) >>> 0;
1115
+ }
1116
+ candidate++;
1117
+ }
1118
+ });
1119
+ const rotateRight = (value, amount) => value >>> amount | value << 32 - amount;
1120
+ for (let offset = 0; offset < words.length; offset += 64) {
1121
+ const schedule = new Array(64);
1122
+ for (let i = 0; i < 16; i++) {
1123
+ const base = offset + i * 4;
1124
+ schedule[i] = (words[base] << 24 | words[base + 1] << 16 | words[base + 2] << 8 | words[base + 3]) >>> 0;
1125
+ }
1126
+ for (let i = 16; i < 64; i++) {
1127
+ const s0 = rotateRight(schedule[i - 15], 7) ^ rotateRight(schedule[i - 15], 18) ^ schedule[i - 15] >>> 3;
1128
+ const s1 = rotateRight(schedule[i - 2], 17) ^ rotateRight(schedule[i - 2], 19) ^ schedule[i - 2] >>> 10;
1129
+ schedule[i] = schedule[i - 16] + s0 + schedule[i - 7] + s1 >>> 0;
1130
+ }
1131
+ let [a, b, c, d, e, f, g, hh] = h;
1132
+ for (let i = 0; i < 64; i++) {
1133
+ const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
1134
+ const choice = e & f ^ ~e & g;
1135
+ const temp1 = hh + s1 + choice + k[i] + schedule[i] >>> 0;
1136
+ const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
1137
+ const majority = a & b ^ a & c ^ b & c;
1138
+ const temp2 = s0 + majority >>> 0;
1139
+ hh = g;
1140
+ g = f;
1141
+ f = e;
1142
+ e = d + temp1 >>> 0;
1143
+ d = c;
1144
+ c = b;
1145
+ b = a;
1146
+ a = temp1 + temp2 >>> 0;
1147
+ }
1148
+ [a, b, c, d, e, f, g, hh].forEach((value, index) => {
1149
+ h[index] = h[index] + value >>> 0;
1150
+ });
1151
+ }
1152
+ return h.map((value) => value.toString(16).padStart(8, "0")).join("");
1153
+ }
1154
+ function encodeKeyPart(value, keepSlash = false) {
1155
+ let encoded = encodeURIComponent(value).replace(
1156
+ /[!'()*]/g,
1157
+ (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
1158
+ );
1159
+ encoded = encoded.replace(/%40/gi, "@");
1160
+ if (keepSlash) encoded = encoded.replace(/%2F/gi, "/").replace(/%5C/gi, "\\");
1161
+ return encoded;
1162
+ }
826
1163
  function hashString(content, length = 16) {
827
1164
  let hash = 0;
828
1165
  for (let i = 0; i < content.length; i++) {
@@ -832,14 +1169,35 @@ function hashString(content, length = 16) {
832
1169
  const hex = Math.abs(hash).toString(16).padStart(8, "0");
833
1170
  return hex.slice(0, length);
834
1171
  }
835
- function generateObservableKey(obsType, value) {
1172
+ function generateObservableKey(obsType, value, subtype, namespace) {
836
1173
  const normalizedType = normalizeValue(obsType);
837
- const normalizedValue = normalizeValue(value);
838
- return `obs:${normalizedType}:${normalizedValue}`;
1174
+ const normalizedSubtype = subtype ? normalizeValue(subtype) : void 0;
1175
+ const normalizedNamespace = namespace?.trim().toLowerCase() || void 0;
1176
+ const normalizedValue = normalizeObservableValue(
1177
+ normalizedType,
1178
+ value,
1179
+ normalizedSubtype
1180
+ );
1181
+ const identity = JSON.stringify({
1182
+ namespace: normalizedNamespace ?? null,
1183
+ subtype: normalizedSubtype ?? null,
1184
+ type: normalizedType,
1185
+ value: normalizedValue
1186
+ });
1187
+ if (normalizedType === "command_line" || new TextEncoder().encode(identity).length > 128) {
1188
+ return `obs:${normalizedType}:sha256:${sha256(identity)}`;
1189
+ }
1190
+ if (!normalizedSubtype && !normalizedNamespace) {
1191
+ return `obs:${normalizedType}:${normalizedValue.toLowerCase()}`;
1192
+ }
1193
+ const parts = ["obs", encodeKeyPart(normalizedType), normalizedSubtype ? encodeKeyPart(normalizedSubtype) : "_"];
1194
+ if (normalizedNamespace) parts.push(encodeKeyPart(normalizedNamespace));
1195
+ parts.push(encodeKeyPart(normalizedValue, true));
1196
+ return parts.join(":");
839
1197
  }
840
- function generateCheckKey(checkName) {
841
- const normalizedName = normalizeValue(checkName);
842
- return `chk:${normalizedName}`;
1198
+ function generateFindingKey(findingName) {
1199
+ const normalizedName = normalizeValue(findingName);
1200
+ return `fnd:${normalizedName}`;
843
1201
  }
844
1202
  function generateThreatIntelKey(source, observableKey) {
845
1203
  const normalizedSource = normalizeValue(source);
@@ -878,7 +1236,7 @@ function isTagDescendantOf(descendantName, ancestorName) {
878
1236
  function parseKeyType(key) {
879
1237
  if (key.includes(":")) {
880
1238
  const prefix = key.split(":", 1)[0];
881
- if (["obs", "chk", "ti", "enr", "tag"].includes(prefix)) {
1239
+ if (["obs", "fnd", "evd", "ti", "enr", "tag"].includes(prefix)) {
882
1240
  return prefix;
883
1241
  }
884
1242
  }
@@ -911,14 +1269,14 @@ function parseObservableKey(key) {
911
1269
  }
912
1270
  return null;
913
1271
  }
914
- function parseCheckKey(key) {
915
- if (!validateKey(key, "chk")) {
1272
+ function parseFindingKey(key) {
1273
+ if (!validateKey(key, "fnd")) {
916
1274
  return null;
917
1275
  }
918
1276
  const parts = key.split(":");
919
1277
  if (parts.length >= 2) {
920
1278
  return {
921
- checkName: parts.slice(1).join(":")
1279
+ findingName: parts.slice(1).join(":")
922
1280
  };
923
1281
  }
924
1282
  return null;
@@ -1051,15 +1409,8 @@ function getEntityLevel(entity) {
1051
1409
  function getObservable(inv, key) {
1052
1410
  return inv.observables[key];
1053
1411
  }
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;
1412
+ function getObservableByTypeValue(inv, type, value, subtype, namespace) {
1413
+ return inv.observables[generateObservableKey(type, value, subtype, namespace)];
1063
1414
  }
1064
1415
  function getRootObservable(inv) {
1065
1416
  const rootType = inv.data_extraction.root_type;
@@ -1069,15 +1420,21 @@ function getRootObservable(inv) {
1069
1420
  const rootKey = generateObservableKey(rootType, "root");
1070
1421
  return inv.observables[rootKey];
1071
1422
  }
1072
- function getCheck(inv, key) {
1073
- return inv.checks[key];
1423
+ function getFinding(inv, key) {
1424
+ return inv.findings[key];
1425
+ }
1426
+ function getFindingByName(inv, findingName) {
1427
+ const key = generateFindingKey(findingName);
1428
+ return inv.findings[key];
1429
+ }
1430
+ function getAllFindings(inv) {
1431
+ return Object.values(inv.findings);
1074
1432
  }
1075
- function getCheckByName(inv, checkName) {
1076
- const key = generateCheckKey(checkName);
1077
- return inv.checks[key];
1433
+ function getEvidence(inv, key) {
1434
+ return inv.evidences[key];
1078
1435
  }
1079
- function getAllChecks(inv) {
1080
- return Object.values(inv.checks);
1436
+ function getAllEvidences(inv) {
1437
+ return Object.values(inv.evidences);
1081
1438
  }
1082
1439
  function getThreatIntel(inv, key) {
1083
1440
  return inv.threat_intels[key];
@@ -1134,7 +1491,8 @@ function getDataExtraction(inv) {
1134
1491
  function getCounts(inv) {
1135
1492
  return {
1136
1493
  observables: Object.keys(inv.observables).length,
1137
- checks: getAllChecks(inv).length,
1494
+ findings: getAllFindings(inv).length,
1495
+ evidences: getAllEvidences(inv).length,
1138
1496
  threatIntels: Object.keys(inv.threat_intels).length,
1139
1497
  enrichments: Object.keys(inv.enrichments).length,
1140
1498
  tags: getAllTags(inv).length,
@@ -1216,18 +1574,18 @@ function findObservablesWithThreatIntel(inv) {
1216
1574
  (obs) => obs.threat_intels.length > 0
1217
1575
  );
1218
1576
  }
1219
- function findChecksByLevel(inv, level) {
1220
- return Object.values(inv.checks).filter((check) => check.level === level);
1577
+ function findFindingsByLevel(inv, level) {
1578
+ return Object.values(inv.findings).filter((finding) => finding.level === level);
1221
1579
  }
1222
- function findChecksAtLeast(inv, minLevel2) {
1223
- return Object.values(inv.checks).filter(
1224
- (check) => isLevelAtLeast(check.level, minLevel2)
1580
+ function findFindingsAtLeast(inv, minLevel2) {
1581
+ return Object.values(inv.findings).filter(
1582
+ (finding) => isLevelAtLeast(finding.level, minLevel2)
1225
1583
  );
1226
1584
  }
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
1585
+ function findFindingByName(inv, findingName) {
1586
+ const normalizedName = findingName.trim().toLowerCase();
1587
+ return Object.values(inv.findings).find(
1588
+ (finding) => finding.finding_name.toLowerCase() === normalizedName
1231
1589
  );
1232
1590
  }
1233
1591
  function findThreatIntelBySource(inv, source) {
@@ -1255,26 +1613,26 @@ function findTagsAtLeast(inv, minLevel2) {
1255
1613
  function findTagsByNamePattern(inv, pattern) {
1256
1614
  return Object.values(inv.tags).filter((tag) => pattern.test(tag.name));
1257
1615
  }
1258
- function findChecksForObservable(inv, observableKey) {
1616
+ function findFindingsForObservable(inv, observableKey) {
1259
1617
  const result = [];
1260
1618
  const seen = /* @__PURE__ */ new Set();
1261
1619
  const observable = inv.observables[observableKey];
1262
1620
  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);
1621
+ for (const findingKey of observable.finding_links) {
1622
+ const finding = inv.findings[findingKey];
1623
+ if (finding && !seen.has(finding.key)) {
1624
+ result.push(finding);
1625
+ seen.add(finding.key);
1268
1626
  }
1269
1627
  }
1270
1628
  }
1271
- for (const check of Object.values(inv.checks)) {
1272
- if (seen.has(check.key)) {
1629
+ for (const finding of Object.values(inv.findings)) {
1630
+ if (seen.has(finding.key)) {
1273
1631
  continue;
1274
1632
  }
1275
- if (check.observable_links.some((link) => link.observable_key === observableKey)) {
1276
- result.push(check);
1277
- seen.add(check.key);
1633
+ if (finding.observable_links.some((link) => link.observable_key === observableKey)) {
1634
+ result.push(finding);
1635
+ seen.add(finding.key);
1278
1636
  }
1279
1637
  }
1280
1638
  return result;
@@ -1288,37 +1646,37 @@ function findThreatIntelsForObservable(inv, observableKey) {
1288
1646
  (ti) => ti.observable_key === observableKey
1289
1647
  );
1290
1648
  }
1291
- function findObservablesForCheck(inv, checkKey) {
1292
- const check = inv.checks[checkKey];
1293
- if (check) {
1649
+ function findObservablesForFinding(inv, findingKey) {
1650
+ const finding = inv.findings[findingKey];
1651
+ if (finding) {
1294
1652
  const keys = /* @__PURE__ */ new Set();
1295
- for (const link of check.observable_links) {
1653
+ for (const link of finding.observable_links) {
1296
1654
  keys.add(link.observable_key);
1297
1655
  }
1298
1656
  return Array.from(keys).map((obsKey) => inv.observables[obsKey]).filter((obs) => obs !== void 0);
1299
1657
  }
1300
1658
  return [];
1301
1659
  }
1302
- function findChecksForTag(inv, tagKey, recursive = false) {
1660
+ function findFindingsForTag(inv, tagKey, recursive = false) {
1303
1661
  const result = [];
1304
1662
  const tag = inv.tags[tagKey];
1305
1663
  if (!tag) {
1306
1664
  return result;
1307
1665
  }
1308
- for (const checkKey of tag.checks) {
1309
- const check = inv.checks[checkKey];
1310
- if (check) {
1311
- result.push(check);
1666
+ for (const findingKey of tag.findings) {
1667
+ const finding = inv.findings[findingKey];
1668
+ if (finding) {
1669
+ result.push(finding);
1312
1670
  }
1313
1671
  }
1314
1672
  if (recursive) {
1315
1673
  const prefix = tag.name + ":";
1316
1674
  for (const otherTag of Object.values(inv.tags)) {
1317
1675
  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);
1676
+ for (const findingKey of otherTag.findings) {
1677
+ const finding = inv.findings[findingKey];
1678
+ if (finding) {
1679
+ result.push(finding);
1322
1680
  }
1323
1681
  }
1324
1682
  }
@@ -1329,24 +1687,24 @@ function findChecksForTag(inv, tagKey, recursive = false) {
1329
1687
  function sortObservablesByScore(observables) {
1330
1688
  return [...observables].sort((a, b) => b.score - a.score);
1331
1689
  }
1332
- function sortChecksByScore(checks) {
1333
- return [...checks].sort((a, b) => b.score - a.score);
1690
+ function sortFindingsByScore(findings) {
1691
+ return [...findings].sort((a, b) => b.score - a.score);
1334
1692
  }
1335
1693
  function sortObservablesByLevel(observables) {
1336
1694
  return [...observables].sort(
1337
1695
  (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1338
1696
  );
1339
1697
  }
1340
- function sortChecksByLevel(checks) {
1341
- return [...checks].sort(
1698
+ function sortFindingsByLevel(findings) {
1699
+ return [...findings].sort(
1342
1700
  (a, b) => LEVEL_VALUES[b.level] - LEVEL_VALUES[a.level]
1343
1701
  );
1344
1702
  }
1345
1703
  function findHighestScoringObservables(inv, n = 10) {
1346
1704
  return sortObservablesByScore(Object.values(inv.observables)).slice(0, n);
1347
1705
  }
1348
- function findHighestScoringChecks(inv, n = 10) {
1349
- return sortChecksByScore(Object.values(inv.checks)).slice(0, n);
1706
+ function findHighestScoringFindings(inv, n = 10) {
1707
+ return sortFindingsByScore(Object.values(inv.findings)).slice(0, n);
1350
1708
  }
1351
1709
  function findMaliciousObservables(inv) {
1352
1710
  return findObservablesByLevel(inv, "MALICIOUS");
@@ -1354,14 +1712,14 @@ function findMaliciousObservables(inv) {
1354
1712
  function findSuspiciousObservables(inv) {
1355
1713
  return findObservablesByLevel(inv, "SUSPICIOUS");
1356
1714
  }
1357
- function findMaliciousChecks(inv) {
1358
- return findChecksByLevel(inv, "MALICIOUS");
1715
+ function findMaliciousFindings(inv) {
1716
+ return findFindingsByLevel(inv, "MALICIOUS");
1359
1717
  }
1360
- function findSuspiciousChecks(inv) {
1361
- return findChecksByLevel(inv, "SUSPICIOUS");
1718
+ function findSuspiciousFindings(inv) {
1719
+ return findFindingsByLevel(inv, "SUSPICIOUS");
1362
1720
  }
1363
- function getAllCheckKeys(inv) {
1364
- return Object.keys(inv.checks);
1721
+ function getAllFindingKeys(inv) {
1722
+ return Object.keys(inv.findings);
1365
1723
  }
1366
1724
  function getAllObservableTypes(inv) {
1367
1725
  const types = /* @__PURE__ */ new Set();
@@ -1645,30 +2003,30 @@ export {
1645
2003
  areConnected,
1646
2004
  compareLevels,
1647
2005
  countRelationshipsByType,
1648
- findCheckByName,
1649
- findChecksAtLeast,
1650
- findChecksByLevel,
1651
- findChecksForObservable,
1652
- findChecksForTag,
1653
2006
  findExternalObservables,
1654
- findHighestScoringChecks,
2007
+ findFindingByName,
2008
+ findFindingsAtLeast,
2009
+ findFindingsByLevel,
2010
+ findFindingsForObservable,
2011
+ findFindingsForTag,
2012
+ findHighestScoringFindings,
1655
2013
  findHighestScoringObservables,
1656
2014
  findInternalObservables,
1657
2015
  findLeafObservables,
1658
- findMaliciousChecks,
2016
+ findMaliciousFindings,
1659
2017
  findMaliciousObservables,
1660
2018
  findObservablesAtLeast,
1661
2019
  findObservablesByLevel,
1662
2020
  findObservablesByType,
1663
2021
  findObservablesByValue,
1664
2022
  findObservablesContaining,
1665
- findObservablesForCheck,
2023
+ findObservablesForFinding,
1666
2024
  findObservablesMatching,
1667
2025
  findObservablesWithThreatIntel,
1668
2026
  findOrphanObservables,
1669
2027
  findPath,
1670
2028
  findSourceObservables,
1671
- findSuspiciousChecks,
2029
+ findSuspiciousFindings,
1672
2030
  findSuspiciousObservables,
1673
2031
  findTagsAtLeast,
1674
2032
  findTagsByLevel,
@@ -1678,22 +2036,21 @@ export {
1678
2036
  findThreatIntelBySource,
1679
2037
  findThreatIntelsForObservable,
1680
2038
  findWhitelistedObservables,
1681
- generateCheckKey,
1682
2039
  generateEnrichmentKey,
2040
+ generateFindingKey,
1683
2041
  generateObservableKey,
1684
2042
  generateTagKey,
1685
2043
  generateThreatIntelKey,
1686
- getAllCheckKeys,
1687
- getAllChecks,
1688
2044
  getAllEnrichments,
2045
+ getAllEvidences,
2046
+ getAllFindingKeys,
2047
+ getAllFindings,
1689
2048
  getAllObservableTypes,
1690
2049
  getAllObservables,
1691
2050
  getAllRelationshipTypes,
1692
2051
  getAllTags,
1693
2052
  getAllThreatIntelSources,
1694
2053
  getAllThreatIntels,
1695
- getCheck,
1696
- getCheckByName,
1697
2054
  getColorForLevel,
1698
2055
  getColorForScore,
1699
2056
  getCounts,
@@ -1701,6 +2058,9 @@ export {
1701
2058
  getEnrichment,
1702
2059
  getEnrichmentByName,
1703
2060
  getEntityLevel,
2061
+ getEvidence,
2062
+ getFinding,
2063
+ getFindingByName,
1704
2064
  getLevelFromScore,
1705
2065
  getObservable,
1706
2066
  getObservableByTypeValue,
@@ -1736,13 +2096,13 @@ export {
1736
2096
  maxLevel,
1737
2097
  minLevel,
1738
2098
  normalizeLevel,
1739
- parseCheckKey,
1740
2099
  parseCyvest,
2100
+ parseFindingKey,
1741
2101
  parseKeyType,
1742
2102
  parseObservableKey,
1743
2103
  parseThreatIntelKey,
1744
- sortChecksByLevel,
1745
- sortChecksByScore,
2104
+ sortFindingsByLevel,
2105
+ sortFindingsByScore,
1746
2106
  sortObservablesByLevel,
1747
2107
  sortObservablesByScore,
1748
2108
  validateKey