@cyvest/cyvest-js 3.2.0 → 4.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.d.mts +53 -16
- package/dist/index.d.ts +53 -16
- package/dist/index.js +184 -36
- package/dist/index.mjs +184 -35
- package/package.json +5 -5
- package/src/finders.ts +29 -20
- package/src/types.generated.ts +52 -8
- package/tests/getters-finders.test.ts +38 -18
- package/tests/graph.test.ts +19 -10
- package/vitest.config.ts +8 -0
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,97 @@ import addFormats from "ajv-formats";
|
|
|
5
5
|
// ../../../schema/cyvest.schema.json
|
|
6
6
|
var cyvest_schema_default = {
|
|
7
7
|
$defs: {
|
|
8
|
+
AuditEvent: {
|
|
9
|
+
additionalProperties: true,
|
|
10
|
+
description: "Centralized audit event for investigation-level changes.",
|
|
11
|
+
properties: {
|
|
12
|
+
event_id: {
|
|
13
|
+
title: "Event Id",
|
|
14
|
+
type: "string"
|
|
15
|
+
},
|
|
16
|
+
timestamp: {
|
|
17
|
+
format: "date-time",
|
|
18
|
+
title: "Timestamp",
|
|
19
|
+
type: "string"
|
|
20
|
+
},
|
|
21
|
+
event_type: {
|
|
22
|
+
title: "Event Type",
|
|
23
|
+
type: "string"
|
|
24
|
+
},
|
|
25
|
+
actor: {
|
|
26
|
+
anyOf: [
|
|
27
|
+
{
|
|
28
|
+
type: "string"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: "null"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
default: null,
|
|
35
|
+
title: "Actor"
|
|
36
|
+
},
|
|
37
|
+
reason: {
|
|
38
|
+
anyOf: [
|
|
39
|
+
{
|
|
40
|
+
type: "string"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: "null"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
default: null,
|
|
47
|
+
title: "Reason"
|
|
48
|
+
},
|
|
49
|
+
tool: {
|
|
50
|
+
anyOf: [
|
|
51
|
+
{
|
|
52
|
+
type: "string"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: "null"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
default: null,
|
|
59
|
+
title: "Tool"
|
|
60
|
+
},
|
|
61
|
+
object_type: {
|
|
62
|
+
anyOf: [
|
|
63
|
+
{
|
|
64
|
+
type: "string"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: "null"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
default: null,
|
|
71
|
+
title: "Object Type"
|
|
72
|
+
},
|
|
73
|
+
object_key: {
|
|
74
|
+
anyOf: [
|
|
75
|
+
{
|
|
76
|
+
type: "string"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
type: "null"
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
default: null,
|
|
83
|
+
title: "Object Key"
|
|
84
|
+
},
|
|
85
|
+
details: {
|
|
86
|
+
additionalProperties: true,
|
|
87
|
+
title: "Details",
|
|
88
|
+
type: "object"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
required: [
|
|
92
|
+
"event_id",
|
|
93
|
+
"timestamp",
|
|
94
|
+
"event_type"
|
|
95
|
+
],
|
|
96
|
+
title: "AuditEvent",
|
|
97
|
+
type: "object"
|
|
98
|
+
},
|
|
8
99
|
Check: {
|
|
9
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.",
|
|
10
101
|
properties: {
|
|
@@ -36,17 +127,17 @@ var cyvest_schema_default = {
|
|
|
36
127
|
level: {
|
|
37
128
|
$ref: "#/$defs/Level"
|
|
38
129
|
},
|
|
39
|
-
|
|
130
|
+
origin_investigation_id: {
|
|
131
|
+
title: "Origin Investigation Id",
|
|
132
|
+
type: "string"
|
|
133
|
+
},
|
|
134
|
+
observable_links: {
|
|
40
135
|
items: {
|
|
41
|
-
|
|
136
|
+
$ref: "#/$defs/ObservableLink"
|
|
42
137
|
},
|
|
43
|
-
title: "
|
|
138
|
+
title: "Observable Links",
|
|
44
139
|
type: "array"
|
|
45
140
|
},
|
|
46
|
-
score_policy: {
|
|
47
|
-
$ref: "#/$defs/CheckScorePolicy",
|
|
48
|
-
default: "auto"
|
|
49
|
-
},
|
|
50
141
|
key: {
|
|
51
142
|
title: "Key",
|
|
52
143
|
type: "string"
|
|
@@ -65,22 +156,14 @@ var cyvest_schema_default = {
|
|
|
65
156
|
"extra",
|
|
66
157
|
"score",
|
|
67
158
|
"level",
|
|
68
|
-
"
|
|
159
|
+
"origin_investigation_id",
|
|
160
|
+
"observable_links",
|
|
69
161
|
"key",
|
|
70
162
|
"score_display"
|
|
71
163
|
],
|
|
72
164
|
title: "Check",
|
|
73
165
|
type: "object"
|
|
74
166
|
},
|
|
75
|
-
CheckScorePolicy: {
|
|
76
|
-
description: "Controls how a check reacts to linked observables.",
|
|
77
|
-
enum: [
|
|
78
|
-
"auto",
|
|
79
|
-
"manual"
|
|
80
|
-
],
|
|
81
|
-
title: "CheckScorePolicy",
|
|
82
|
-
type: "string"
|
|
83
|
-
},
|
|
84
167
|
Container: {
|
|
85
168
|
additionalProperties: false,
|
|
86
169
|
description: "Groups checks and sub-containers for hierarchical organization.\n\nContainers allow structuring the investigation into logical sections\nwith aggregated scores and levels.",
|
|
@@ -290,13 +373,13 @@ var cyvest_schema_default = {
|
|
|
290
373
|
title: "Key",
|
|
291
374
|
type: "string"
|
|
292
375
|
},
|
|
293
|
-
|
|
294
|
-
description: "Checks that
|
|
376
|
+
check_links: {
|
|
377
|
+
description: "Checks that currently link to this observable (navigation-only).",
|
|
295
378
|
items: {
|
|
296
379
|
type: "string"
|
|
297
380
|
},
|
|
298
381
|
readOnly: true,
|
|
299
|
-
title: "
|
|
382
|
+
title: "Check Links",
|
|
300
383
|
type: "array"
|
|
301
384
|
},
|
|
302
385
|
score_display: {
|
|
@@ -317,12 +400,40 @@ var cyvest_schema_default = {
|
|
|
317
400
|
"threat_intels",
|
|
318
401
|
"relationships",
|
|
319
402
|
"key",
|
|
320
|
-
"
|
|
403
|
+
"check_links",
|
|
321
404
|
"score_display"
|
|
322
405
|
],
|
|
323
406
|
title: "Observable",
|
|
324
407
|
type: "object"
|
|
325
408
|
},
|
|
409
|
+
ObservableLink: {
|
|
410
|
+
additionalProperties: false,
|
|
411
|
+
description: "Edge metadata for a Check\u2194Observable association.",
|
|
412
|
+
properties: {
|
|
413
|
+
observable_key: {
|
|
414
|
+
title: "Observable Key",
|
|
415
|
+
type: "string"
|
|
416
|
+
},
|
|
417
|
+
propagation_mode: {
|
|
418
|
+
$ref: "#/$defs/PropagationMode",
|
|
419
|
+
default: "LOCAL_ONLY"
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
required: [
|
|
423
|
+
"observable_key"
|
|
424
|
+
],
|
|
425
|
+
title: "ObservableLink",
|
|
426
|
+
type: "object"
|
|
427
|
+
},
|
|
428
|
+
PropagationMode: {
|
|
429
|
+
description: "Controls how a Check\u2194Observable link propagates across merged investigations.",
|
|
430
|
+
enum: [
|
|
431
|
+
"LOCAL_ONLY",
|
|
432
|
+
"GLOBAL"
|
|
433
|
+
],
|
|
434
|
+
title: "PropagationMode",
|
|
435
|
+
type: "string"
|
|
436
|
+
},
|
|
326
437
|
Relationship: {
|
|
327
438
|
description: "Represents a relationship between observables.",
|
|
328
439
|
properties: {
|
|
@@ -569,6 +680,24 @@ var cyvest_schema_default = {
|
|
|
569
680
|
additionalProperties: false,
|
|
570
681
|
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.",
|
|
571
682
|
properties: {
|
|
683
|
+
investigation_id: {
|
|
684
|
+
description: "Stable investigation identity (ULID).",
|
|
685
|
+
title: "Investigation Id",
|
|
686
|
+
type: "string"
|
|
687
|
+
},
|
|
688
|
+
investigation_name: {
|
|
689
|
+
anyOf: [
|
|
690
|
+
{
|
|
691
|
+
type: "string"
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
type: "null"
|
|
695
|
+
}
|
|
696
|
+
],
|
|
697
|
+
default: null,
|
|
698
|
+
description: "Optional human-readable investigation name.",
|
|
699
|
+
title: "Investigation Name"
|
|
700
|
+
},
|
|
572
701
|
started_at: {
|
|
573
702
|
description: "Investigation start time (UTC).",
|
|
574
703
|
format: "date-time",
|
|
@@ -597,6 +726,14 @@ var cyvest_schema_default = {
|
|
|
597
726
|
title: "Whitelists",
|
|
598
727
|
type: "array"
|
|
599
728
|
},
|
|
729
|
+
event_log: {
|
|
730
|
+
description: "Append-only investigation audit log.",
|
|
731
|
+
items: {
|
|
732
|
+
$ref: "#/$defs/AuditEvent"
|
|
733
|
+
},
|
|
734
|
+
title: "Event Log",
|
|
735
|
+
type: "array"
|
|
736
|
+
},
|
|
600
737
|
observables: {
|
|
601
738
|
additionalProperties: {
|
|
602
739
|
$ref: "#/$defs/Observable"
|
|
@@ -671,6 +808,7 @@ var cyvest_schema_default = {
|
|
|
671
808
|
}
|
|
672
809
|
},
|
|
673
810
|
required: [
|
|
811
|
+
"investigation_id",
|
|
674
812
|
"started_at",
|
|
675
813
|
"score",
|
|
676
814
|
"level",
|
|
@@ -1165,17 +1303,6 @@ function findChecksByCheckId(inv, checkId) {
|
|
|
1165
1303
|
}
|
|
1166
1304
|
return result;
|
|
1167
1305
|
}
|
|
1168
|
-
function findManuallyScored(inv) {
|
|
1169
|
-
const result = [];
|
|
1170
|
-
for (const checks of Object.values(inv.checks)) {
|
|
1171
|
-
for (const check of checks) {
|
|
1172
|
-
if (check.score_policy === "manual") {
|
|
1173
|
-
result.push(check);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
return result;
|
|
1178
|
-
}
|
|
1179
1306
|
function findThreatIntelBySource(inv, source) {
|
|
1180
1307
|
const normalizedSource = source.trim().toLowerCase();
|
|
1181
1308
|
return Object.values(inv.threat_intels).filter(
|
|
@@ -1218,13 +1345,32 @@ function findContainersAtLeast(inv, minLevel2) {
|
|
|
1218
1345
|
}
|
|
1219
1346
|
function getChecksForObservable(inv, observableKey) {
|
|
1220
1347
|
const result = [];
|
|
1348
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1349
|
+
const checkLookup = /* @__PURE__ */ new Map();
|
|
1221
1350
|
for (const checks of Object.values(inv.checks)) {
|
|
1222
1351
|
for (const check of checks) {
|
|
1223
|
-
|
|
1352
|
+
checkLookup.set(check.key, check);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
const observable = inv.observables[observableKey];
|
|
1356
|
+
if (observable) {
|
|
1357
|
+
for (const checkKey of observable.check_links) {
|
|
1358
|
+
const check = checkLookup.get(checkKey);
|
|
1359
|
+
if (check && !seen.has(check.key)) {
|
|
1224
1360
|
result.push(check);
|
|
1361
|
+
seen.add(check.key);
|
|
1225
1362
|
}
|
|
1226
1363
|
}
|
|
1227
1364
|
}
|
|
1365
|
+
for (const check of checkLookup.values()) {
|
|
1366
|
+
if (seen.has(check.key)) {
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
if (check.observable_links.some((link) => link.observable_key === observableKey)) {
|
|
1370
|
+
result.push(check);
|
|
1371
|
+
seen.add(check.key);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1228
1374
|
return result;
|
|
1229
1375
|
}
|
|
1230
1376
|
function getThreatIntelsForObservable(inv, observableKey) {
|
|
@@ -1240,7 +1386,11 @@ function getObservablesForCheck(inv, checkKey) {
|
|
|
1240
1386
|
for (const checks of Object.values(inv.checks)) {
|
|
1241
1387
|
for (const check of checks) {
|
|
1242
1388
|
if (check.key === checkKey) {
|
|
1243
|
-
|
|
1389
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1390
|
+
for (const link of check.observable_links) {
|
|
1391
|
+
keys.add(link.observable_key);
|
|
1392
|
+
}
|
|
1393
|
+
return Array.from(keys).map((obsKey) => inv.observables[obsKey]).filter((obs) => obs !== void 0);
|
|
1244
1394
|
}
|
|
1245
1395
|
}
|
|
1246
1396
|
}
|
|
@@ -1612,7 +1762,6 @@ export {
|
|
|
1612
1762
|
findExternalObservables,
|
|
1613
1763
|
findInternalObservables,
|
|
1614
1764
|
findLeafObservables,
|
|
1615
|
-
findManuallyScored,
|
|
1616
1765
|
findObservablesAtLeast,
|
|
1617
1766
|
findObservablesByLevel,
|
|
1618
1767
|
findObservablesByType,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyvest/cyvest-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"main": "dist/index.cjs",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
"ajv-formats": "^3.0.1"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"json-schema-to-typescript": "^
|
|
14
|
-
"tsup": "^8.
|
|
15
|
-
"typescript": "^5.
|
|
16
|
-
"vitest": "^
|
|
13
|
+
"json-schema-to-typescript": "^15.0.4",
|
|
14
|
+
"tsup": "^8.5.1",
|
|
15
|
+
"typescript": "^5.9.3",
|
|
16
|
+
"vitest": "^4.0.16"
|
|
17
17
|
},
|
|
18
18
|
"engines": {
|
|
19
19
|
"node": ">=20"
|
package/src/finders.ts
CHANGED
|
@@ -288,24 +288,6 @@ export function findChecksByCheckId(
|
|
|
288
288
|
return result;
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
/**
|
|
292
|
-
* Find checks with score policy set to manual.
|
|
293
|
-
*
|
|
294
|
-
* @param inv - The investigation to search
|
|
295
|
-
* @returns Array of manually scored checks
|
|
296
|
-
*/
|
|
297
|
-
export function findManuallyScored(inv: CyvestInvestigation): Check[] {
|
|
298
|
-
const result: Check[] = [];
|
|
299
|
-
for (const checks of Object.values(inv.checks)) {
|
|
300
|
-
for (const check of checks) {
|
|
301
|
-
if (check.score_policy === "manual") {
|
|
302
|
-
result.push(check);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return result;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
291
|
// ============================================================================
|
|
310
292
|
// Threat Intel Finders
|
|
311
293
|
// ============================================================================
|
|
@@ -434,15 +416,37 @@ export function getChecksForObservable(
|
|
|
434
416
|
observableKey: string
|
|
435
417
|
): Check[] {
|
|
436
418
|
const result: Check[] = [];
|
|
419
|
+
const seen = new Set<string>();
|
|
420
|
+
const checkLookup = new Map<string, Check>();
|
|
437
421
|
|
|
438
422
|
for (const checks of Object.values(inv.checks)) {
|
|
439
423
|
for (const check of checks) {
|
|
440
|
-
|
|
424
|
+
checkLookup.set(check.key, check);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const observable = inv.observables[observableKey];
|
|
429
|
+
if (observable) {
|
|
430
|
+
for (const checkKey of observable.check_links) {
|
|
431
|
+
const check = checkLookup.get(checkKey);
|
|
432
|
+
if (check && !seen.has(check.key)) {
|
|
441
433
|
result.push(check);
|
|
434
|
+
seen.add(check.key);
|
|
442
435
|
}
|
|
443
436
|
}
|
|
444
437
|
}
|
|
445
438
|
|
|
439
|
+
for (const check of checkLookup.values()) {
|
|
440
|
+
if (seen.has(check.key)) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (check.observable_links.some((link) => link.observable_key === observableKey)) {
|
|
445
|
+
result.push(check);
|
|
446
|
+
seen.add(check.key);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
446
450
|
return result;
|
|
447
451
|
}
|
|
448
452
|
|
|
@@ -486,7 +490,12 @@ export function getObservablesForCheck(
|
|
|
486
490
|
for (const checks of Object.values(inv.checks)) {
|
|
487
491
|
for (const check of checks) {
|
|
488
492
|
if (check.key === checkKey) {
|
|
489
|
-
|
|
493
|
+
const keys = new Set<string>();
|
|
494
|
+
for (const link of check.observable_links) {
|
|
495
|
+
keys.add(link.observable_key);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return Array.from(keys)
|
|
490
499
|
.map((obsKey) => inv.observables[obsKey])
|
|
491
500
|
.filter((obs): obs is Observable => obs !== undefined);
|
|
492
501
|
}
|
package/src/types.generated.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// AUTO-GENERATED FROM cyvest.schema.json — DO NOT EDIT
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Optional human-readable investigation name.
|
|
5
|
+
*/
|
|
6
|
+
export type InvestigationName = string | null;
|
|
3
7
|
/**
|
|
4
8
|
* Security level classification for checks, observables, and threat intelligence.
|
|
5
9
|
*
|
|
@@ -11,6 +15,15 @@ export type Justification = string | null;
|
|
|
11
15
|
* List of whitelist entries applied to this investigation.
|
|
12
16
|
*/
|
|
13
17
|
export type Whitelists = InvestigationWhitelist[];
|
|
18
|
+
export type Actor = string | null;
|
|
19
|
+
export type Reason = string | null;
|
|
20
|
+
export type Tool = string | null;
|
|
21
|
+
export type ObjectType = string | null;
|
|
22
|
+
export type ObjectKey = string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Append-only investigation audit log.
|
|
25
|
+
*/
|
|
26
|
+
export type EventLog = AuditEvent[];
|
|
14
27
|
export type ThreatIntels = string[];
|
|
15
28
|
/**
|
|
16
29
|
* Direction of a relationship between observables.
|
|
@@ -18,14 +31,14 @@ export type ThreatIntels = string[];
|
|
|
18
31
|
export type RelationshipDirection = "outbound" | "inbound" | "bidirectional";
|
|
19
32
|
export type Relationships = Relationship[];
|
|
20
33
|
/**
|
|
21
|
-
* Checks that
|
|
34
|
+
* Checks that currently link to this observable (navigation-only).
|
|
22
35
|
*/
|
|
23
|
-
export type
|
|
24
|
-
export type Observables1 = string[];
|
|
36
|
+
export type CheckLinks = string[];
|
|
25
37
|
/**
|
|
26
|
-
* Controls how a
|
|
38
|
+
* Controls how a Check↔Observable link propagates across merged investigations.
|
|
27
39
|
*/
|
|
28
|
-
export type
|
|
40
|
+
export type PropagationMode = "LOCAL_ONLY" | "GLOBAL";
|
|
41
|
+
export type ObservableLinks = ObservableLink[];
|
|
29
42
|
export type Taxonomies = {
|
|
30
43
|
[k: string]: unknown;
|
|
31
44
|
}[];
|
|
@@ -50,6 +63,11 @@ export type ScoreMode = "max" | "sum";
|
|
|
50
63
|
* schemas matching the actual model_dump() output.
|
|
51
64
|
*/
|
|
52
65
|
export interface CyvestInvestigation {
|
|
66
|
+
/**
|
|
67
|
+
* Stable investigation identity (ULID).
|
|
68
|
+
*/
|
|
69
|
+
investigation_id: string;
|
|
70
|
+
investigation_name?: InvestigationName;
|
|
53
71
|
/**
|
|
54
72
|
* Investigation start time (UTC).
|
|
55
73
|
*/
|
|
@@ -64,6 +82,7 @@ export interface CyvestInvestigation {
|
|
|
64
82
|
*/
|
|
65
83
|
whitelisted: boolean;
|
|
66
84
|
whitelists: Whitelists;
|
|
85
|
+
event_log?: EventLog;
|
|
67
86
|
observables: Observables;
|
|
68
87
|
checks: Checks;
|
|
69
88
|
checks_by_level: ChecksByLevel;
|
|
@@ -87,6 +106,24 @@ export interface InvestigationWhitelist {
|
|
|
87
106
|
justification?: Justification;
|
|
88
107
|
[k: string]: unknown;
|
|
89
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Centralized audit event for investigation-level changes.
|
|
111
|
+
*/
|
|
112
|
+
export interface AuditEvent {
|
|
113
|
+
event_id: string;
|
|
114
|
+
timestamp: string;
|
|
115
|
+
event_type: string;
|
|
116
|
+
actor?: Actor;
|
|
117
|
+
reason?: Reason;
|
|
118
|
+
tool?: Tool;
|
|
119
|
+
object_type?: ObjectType;
|
|
120
|
+
object_key?: ObjectKey;
|
|
121
|
+
details?: Details;
|
|
122
|
+
[k: string]: unknown;
|
|
123
|
+
}
|
|
124
|
+
export interface Details {
|
|
125
|
+
[k: string]: unknown;
|
|
126
|
+
}
|
|
90
127
|
/**
|
|
91
128
|
* Observables keyed by their unique key.
|
|
92
129
|
*/
|
|
@@ -111,7 +148,7 @@ export interface Observable {
|
|
|
111
148
|
threat_intels: ThreatIntels;
|
|
112
149
|
relationships: Relationships;
|
|
113
150
|
key: string;
|
|
114
|
-
|
|
151
|
+
check_links: CheckLinks;
|
|
115
152
|
score_display: string;
|
|
116
153
|
[k: string]: unknown;
|
|
117
154
|
}
|
|
@@ -147,8 +184,8 @@ export interface Check {
|
|
|
147
184
|
extra: Extra1;
|
|
148
185
|
score: number;
|
|
149
186
|
level: Level;
|
|
150
|
-
|
|
151
|
-
|
|
187
|
+
origin_investigation_id: string;
|
|
188
|
+
observable_links: ObservableLinks;
|
|
152
189
|
key: string;
|
|
153
190
|
score_display: string;
|
|
154
191
|
[k: string]: unknown;
|
|
@@ -156,6 +193,13 @@ export interface Check {
|
|
|
156
193
|
export interface Extra1 {
|
|
157
194
|
[k: string]: unknown;
|
|
158
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Edge metadata for a Check↔Observable association.
|
|
198
|
+
*/
|
|
199
|
+
export interface ObservableLink {
|
|
200
|
+
observable_key: string;
|
|
201
|
+
propagation_mode?: PropagationMode;
|
|
202
|
+
}
|
|
159
203
|
/**
|
|
160
204
|
* Check keys organized by level name.
|
|
161
205
|
*/
|
|
@@ -41,7 +41,11 @@ import {
|
|
|
41
41
|
// Test fixture
|
|
42
42
|
function createTestInvestigation(): CyvestInvestigation {
|
|
43
43
|
return {
|
|
44
|
+
investigation_id: "01HXYZTESTINVESTIGATION",
|
|
45
|
+
investigation_name: "Test Investigation",
|
|
46
|
+
started_at: "2024-01-01T00:00:00Z",
|
|
44
47
|
score: 7.5,
|
|
48
|
+
score_display: "7.50",
|
|
45
49
|
level: "MALICIOUS",
|
|
46
50
|
whitelisted: false,
|
|
47
51
|
whitelists: [
|
|
@@ -59,8 +63,9 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
59
63
|
internal: true,
|
|
60
64
|
whitelisted: false,
|
|
61
65
|
comment: "",
|
|
62
|
-
extra:
|
|
66
|
+
extra: {},
|
|
63
67
|
score: 0,
|
|
68
|
+
score_display: "0.00",
|
|
64
69
|
level: "INFO",
|
|
65
70
|
relationships: [
|
|
66
71
|
{
|
|
@@ -70,7 +75,7 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
70
75
|
},
|
|
71
76
|
],
|
|
72
77
|
threat_intels: [],
|
|
73
|
-
|
|
78
|
+
check_links: ["chk:ip_check:network"],
|
|
74
79
|
},
|
|
75
80
|
"obs:ipv4-addr:8.8.8.8": {
|
|
76
81
|
key: "obs:ipv4-addr:8.8.8.8",
|
|
@@ -79,12 +84,13 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
79
84
|
internal: false,
|
|
80
85
|
whitelisted: true,
|
|
81
86
|
comment: "Google DNS",
|
|
82
|
-
extra:
|
|
87
|
+
extra: {},
|
|
83
88
|
score: -1,
|
|
89
|
+
score_display: "-1.00",
|
|
84
90
|
level: "TRUSTED",
|
|
85
91
|
relationships: [],
|
|
86
92
|
threat_intels: [],
|
|
87
|
-
|
|
93
|
+
check_links: [],
|
|
88
94
|
},
|
|
89
95
|
"obs:domain-name:example.com": {
|
|
90
96
|
key: "obs:domain-name:example.com",
|
|
@@ -93,12 +99,13 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
93
99
|
internal: false,
|
|
94
100
|
whitelisted: false,
|
|
95
101
|
comment: "",
|
|
96
|
-
extra:
|
|
102
|
+
extra: {},
|
|
97
103
|
score: 5,
|
|
104
|
+
score_display: "5.00",
|
|
98
105
|
level: "MALICIOUS",
|
|
99
106
|
relationships: [],
|
|
100
107
|
threat_intels: ["ti:virustotal:obs:domain-name:example.com"],
|
|
101
|
-
|
|
108
|
+
check_links: ["chk:domain_check:dns"],
|
|
102
109
|
},
|
|
103
110
|
"obs:url:http://malware.com/bad": {
|
|
104
111
|
key: "obs:url:http://malware.com/bad",
|
|
@@ -107,12 +114,13 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
107
114
|
internal: false,
|
|
108
115
|
whitelisted: false,
|
|
109
116
|
comment: "",
|
|
110
|
-
extra:
|
|
117
|
+
extra: {},
|
|
111
118
|
score: 7.5,
|
|
119
|
+
score_display: "7.50",
|
|
112
120
|
level: "MALICIOUS",
|
|
113
121
|
relationships: [],
|
|
114
122
|
threat_intels: [],
|
|
115
|
-
|
|
123
|
+
check_links: [],
|
|
116
124
|
},
|
|
117
125
|
},
|
|
118
126
|
checks: {
|
|
@@ -123,11 +131,16 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
123
131
|
scope: "network",
|
|
124
132
|
description: "IP address check",
|
|
125
133
|
comment: "",
|
|
126
|
-
extra:
|
|
134
|
+
extra: {},
|
|
127
135
|
score: 0,
|
|
136
|
+
score_display: "0.00",
|
|
128
137
|
level: "INFO",
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
origin_investigation_id: "01HXYZTESTINVESTIGATION",
|
|
139
|
+
observable_links: [
|
|
140
|
+
{
|
|
141
|
+
observable_key: "obs:ipv4-addr:192.168.1.1",
|
|
142
|
+
},
|
|
143
|
+
],
|
|
131
144
|
},
|
|
132
145
|
],
|
|
133
146
|
dns: [
|
|
@@ -137,11 +150,16 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
137
150
|
scope: "dns",
|
|
138
151
|
description: "Domain reputation check",
|
|
139
152
|
comment: "",
|
|
140
|
-
extra:
|
|
153
|
+
extra: {},
|
|
141
154
|
score: 5,
|
|
155
|
+
score_display: "5.00",
|
|
142
156
|
level: "MALICIOUS",
|
|
143
|
-
|
|
144
|
-
|
|
157
|
+
origin_investigation_id: "01HXYZTESTINVESTIGATION",
|
|
158
|
+
observable_links: [
|
|
159
|
+
{
|
|
160
|
+
observable_key: "obs:domain-name:example.com",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
145
163
|
},
|
|
146
164
|
{
|
|
147
165
|
key: "chk:dns_lookup:dns",
|
|
@@ -149,11 +167,12 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
149
167
|
scope: "dns",
|
|
150
168
|
description: "DNS lookup",
|
|
151
169
|
comment: "",
|
|
152
|
-
extra:
|
|
170
|
+
extra: {},
|
|
153
171
|
score: 0,
|
|
172
|
+
score_display: "0.00",
|
|
154
173
|
level: "INFO",
|
|
155
|
-
|
|
156
|
-
|
|
174
|
+
origin_investigation_id: "01HXYZTESTINVESTIGATION",
|
|
175
|
+
observable_links: [],
|
|
157
176
|
},
|
|
158
177
|
],
|
|
159
178
|
},
|
|
@@ -167,8 +186,9 @@ function createTestInvestigation(): CyvestInvestigation {
|
|
|
167
186
|
source: "virustotal",
|
|
168
187
|
observable_key: "obs:domain-name:example.com",
|
|
169
188
|
comment: "",
|
|
170
|
-
extra:
|
|
189
|
+
extra: {},
|
|
171
190
|
score: 5,
|
|
191
|
+
score_display: "5.00",
|
|
172
192
|
level: "MALICIOUS",
|
|
173
193
|
taxonomies: [{ verdict: "malicious" }],
|
|
174
194
|
},
|