@cyvest/cyvest-js 6.1.2 → 7.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.cts CHANGED
@@ -1,403 +1,546 @@
1
- /**
2
- * Optional human-readable investigation name.
3
- */
4
- type InvestigationName = string | null;
5
- /**
6
- * Security level classification for findings, observables, and threat intelligence.
7
- *
8
- * Levels are ordered from lowest (NONE) to highest (MALICIOUS) severity.
9
- */
10
- type Level = "NONE" | "TRUSTED" | "INFO" | "SAFE" | "NOTABLE" | "SUSPICIOUS" | "MALICIOUS";
11
- type Justification = string | null;
12
- /**
13
- * List of whitelist entries applied to this investigation.
14
- */
15
- type Whitelists = InvestigationWhitelist[];
16
- /**
17
- * Append-only investigation audit log. Null when serialization disabled audit.
18
- */
19
- type AuditLog = AuditEvent[] | null;
20
- type Actor = string | null;
21
- type Reason = string | null;
22
- type Tool = string | null;
23
- type ObjectType = string | null;
24
- type ObjectKey = string | null;
25
- type Subtype = string | null;
26
- type Namespace = string | null;
27
- type Subtype1 = string | null;
28
- type Namespace1 = string | null;
29
- type Aliases = ObservableAlias[];
30
- type ThreatIntels = string[];
31
- /**
32
- * Direction of a relationship between observables.
33
- */
34
- type RelationshipDirection = "outbound" | "inbound" | "bidirectional";
35
- type Relationships = Relationship[];
36
- /**
37
- * Findings that currently link to this observable (navigation-only).
38
- */
39
- type FindingLinks = string[];
40
- /**
41
- * Controls how a Finding↔Observable link propagates across merged investigations.
42
- */
43
- type PropagationMode = "LOCAL_ONLY" | "GLOBAL";
44
- type ObservableLinks = ObservableLink[];
45
- type EvidenceLinks = EvidenceLink[];
46
- type ExternalId = string | null;
47
- type Uri = string | null;
48
- /**
49
- * Findings that currently link to this evidence (navigation-only).
50
- */
51
- type FindingLinks1 = string[];
52
- type Taxonomies = Taxonomy[];
53
- type Findings1 = string[];
54
- /**
55
- * Root observable type used during data extraction.
56
- */
57
- type RootType = ("file" | "artifact") | null;
58
- /**
59
- * Score calculation mode for observables.
60
- */
61
- type ScoreMode = "max" | "sum";
62
- /**
63
- * Schema for a complete serialized investigation.
64
- *
65
- * This model describes the output of `serialize_investigation()` from
66
- * `cyvest.io_serialization`. It is the top-level schema for exported investigations.
67
- *
68
- * Entity types reference the runtime models directly. When generating schemas with
69
- * `mode='serialization'`, Pydantic respects field_serializer decorators and produces
70
- * schemas matching the actual model_dump() output.
71
- */
72
- interface CyvestInvestigation {
73
- schema_version?: "6.0.0";
74
- /**
75
- * Stable investigation identity (ULID).
76
- */
77
- investigation_id: string;
78
- investigation_name?: InvestigationName;
79
- /**
80
- * Global investigation score.
81
- */
82
- score: number;
83
- level: Level;
84
- /**
85
- * Whether the investigation is whitelisted.
86
- */
87
- whitelisted: boolean;
88
- whitelists: Whitelists;
89
- audit_log?: AuditLog;
90
- observables: Observables;
91
- findings: Findings;
92
- evidences: Evidences;
93
- threat_intels: ThreatIntels1;
94
- enrichments: Enrichments;
95
- tags: Tags;
96
- stats: StatisticsSchema;
97
- data_extraction: DataExtractionSchema;
98
- /**
99
- * Global investigation score formatted as fixed-point x.xx.
100
- */
101
- score_display: string;
102
- }
103
- /**
104
- * Represents a whitelist entry on an investigation.
105
- */
106
- interface InvestigationWhitelist {
107
- identifier: string;
108
- name: string;
109
- justification?: Justification;
110
- [k: string]: unknown;
111
- }
112
- /**
113
- * Centralized audit event for investigation-level changes.
114
- */
115
- interface AuditEvent {
116
- event_id: string;
117
- timestamp: string;
118
- event_type: string;
119
- actor?: Actor;
120
- reason?: Reason;
121
- tool?: Tool;
122
- object_type?: ObjectType;
123
- object_key?: ObjectKey;
124
- details?: Details;
125
- [k: string]: unknown;
126
- }
127
- interface Details {
128
- [k: string]: unknown;
129
- }
130
- /**
131
- * Observables keyed by their unique key.
132
- */
133
- interface Observables {
134
- [k: string]: Observable;
135
- }
136
- /**
137
- * Represents a cyber observable (IP, URL, domain, hash, etc.).
138
- *
139
- * Observables can be linked to threat intelligence, findings, and other observables
140
- * through relationships.
141
- */
142
- interface Observable {
143
- type: string;
144
- subtype?: Subtype;
145
- namespace?: Namespace;
146
- value: string;
147
- internal: boolean;
148
- whitelisted: boolean;
149
- comment: string;
150
- extra: Extra;
151
- score: number;
152
- level: Level;
153
- aliases?: Aliases;
154
- occurrence_count?: number;
155
- threat_intels: ThreatIntels;
156
- relationships: Relationships;
157
- key: string;
158
- finding_links: FindingLinks;
159
- score_display: string;
160
- [k: string]: unknown;
161
- }
162
- interface Extra {
163
- [k: string]: unknown;
164
- }
165
- /**
166
- * Source observable identity attached to a canonical observable.
167
- */
168
- interface ObservableAlias {
169
- type: string;
170
- subtype?: Subtype1;
171
- namespace?: Namespace1;
172
- value: string;
173
- count?: number;
174
- [k: string]: unknown;
175
- }
176
- /**
177
- * Represents a relationship between observables.
178
- */
179
- interface Relationship {
180
- target_key: string;
181
- relationship_type: string;
182
- direction: RelationshipDirection;
183
- [k: string]: unknown;
184
- }
185
- /**
186
- * Findings keyed by their unique key.
187
- */
188
- interface Findings {
189
- [k: string]: Finding;
190
- }
191
- /**
192
- * Represents a verification step in the investigation.
193
- *
194
- * A finding validates a specific aspect of the data under investigation
195
- * and contributes to the overall investigation score.
196
- */
197
- interface Finding {
198
- finding_name: string;
199
- description: string;
200
- comment: string;
201
- extra: Extra1;
202
- score: number;
203
- level: Level;
204
- origin_investigation_id: string;
205
- observable_links: ObservableLinks;
206
- evidence_links: EvidenceLinks;
207
- key: string;
208
- score_display: string;
209
- [k: string]: unknown;
210
- }
211
- interface Extra1 {
212
- [k: string]: unknown;
213
- }
214
- /**
215
- * Edge metadata for a Finding↔Observable association.
216
- */
217
- interface ObservableLink {
218
- observable_key: string;
219
- propagation_mode?: PropagationMode;
220
- }
221
- /**
222
- * Edge metadata for a Finding↔Evidence association.
223
- */
224
- interface EvidenceLink {
225
- evidence_key: string;
226
- }
227
- /**
228
- * Evidence objects keyed by their unique key.
229
- */
230
- interface Evidences {
231
- [k: string]: Evidence;
232
- }
233
- /**
234
- * Structured material supporting one or more findings.
235
- */
236
- interface Evidence {
237
- type: string;
238
- title: string;
239
- description: string;
240
- source: string;
241
- external_id: ExternalId;
242
- content: unknown;
243
- uri: Uri;
244
- captured_at: string;
245
- extra: Extra2;
246
- key: string;
247
- finding_links: FindingLinks1;
248
- [k: string]: unknown;
249
- }
250
- interface Extra2 {
251
- [k: string]: unknown;
252
- }
253
- /**
254
- * Threat intelligence entries keyed by their unique key.
255
- */
256
- interface ThreatIntels1 {
257
- [k: string]: ThreatIntel;
258
- }
259
- /**
260
- * Represents threat intelligence from an external source.
261
- *
262
- * Threat intelligence provides verdicts about observables from sources
263
- * like VirusTotal, URLScan.io, etc.
264
- */
265
- interface ThreatIntel {
266
- source: string;
267
- observable_key: string;
268
- comment: string;
269
- extra: Extra3;
270
- score: number;
271
- level: Level;
272
- taxonomies: Taxonomies;
273
- key: string;
274
- score_display: string;
275
- [k: string]: unknown;
276
- }
277
- interface Extra3 {
278
- [k: string]: unknown;
279
- }
280
- /**
281
- * Represents a structured taxonomy entry for threat intelligence.
282
- */
283
- interface Taxonomy {
284
- level: Level;
285
- name: string;
286
- value: string;
287
- }
288
- /**
289
- * Enrichment entries keyed by their unique key.
1
+ //#region src/types.generated.d.ts
2
+ export type RootKey = string | null;
3
+ export type FragmentIds = string[];
4
+ export type OccurredAt = string | null;
5
+ /**
6
+ * Family a source belongs to, used by the policy to weigh its reliability.
290
7
  */
291
- interface Enrichments {
292
- [k: string]: Enrichment;
293
- }
8
+ export type SourceClass = "vendor_feed" | "sandbox" | "osint" | "internal_tool" | "org_analyst" | "org_policy" | "unknown";
9
+ export type ExternalId = string | null;
10
+ export type EvidenceKeys = string[];
11
+ export type Subtype = string | null;
12
+ export type Namespace = string | null;
13
+ export type Subtype1 = string | null;
14
+ export type Namespace1 = string | null;
15
+ export type Aliases = ObservableAlias[];
16
+ export type OccurredAt1 = string | null;
17
+ export type ExternalId1 = string | null;
18
+ export type EvidenceKeys1 = string[];
294
19
  /**
295
- * Represents structured data enrichment for the investigation.
20
+ * The analyst pivot that produced the target from the source.
296
21
  *
297
- * Enrichments store arbitrary structured data that provides additional
298
- * context but doesn't directly contribute to scoring.
299
- */
300
- interface Enrichment {
301
- name: string;
302
- data: Data;
303
- context: string;
304
- key: string;
305
- [k: string]: unknown;
306
- }
307
- interface Data {
308
- [k: string]: unknown;
309
- }
310
- /**
311
- * Tags keyed by their unique key.
312
- */
313
- interface Tags {
314
- [k: string]: Tag;
315
- }
316
- /**
317
- * Groups findings for categorical organization.
22
+ * Direction is implied: ``source_key`` is the parent, ``target_key`` the child. ``RELATED_TO``
23
+ * is symmetric and excluded from propagation, which makes v6's ``EXTRACTION`` +
24
+ * ``BIDIRECTIONAL`` combination inexpressible.
25
+ */
26
+ export type RelationKind = "extraction" | "pivot" | "related-to";
27
+ export type ObservedAt = string | null;
28
+ /**
29
+ * Direction of a judgment, and the displayed level — they are the same thing.
318
30
  *
319
- * Tags allow structuring the investigation into logical sections
320
- * with aggregated scores and levels. Hierarchy is automatic based on
321
- * the ":" delimiter in tag names (e.g., "header:auth:dkim").
322
- */
323
- interface Tag {
324
- name: string;
325
- description?: string;
326
- findings: Findings1;
327
- key: string;
328
- /**
329
- * Calculate the score from direct findings only (no hierarchy).
330
- *
331
- * For hierarchical aggregation (including descendant tags), use
332
- * Investigation.get_tag_aggregated_score() or TagProxy.get_aggregated_score().
333
- *
334
- * Returns:
335
- * Total score from direct findings
336
- */
337
- direct_score: number;
338
- direct_level: Level;
339
- }
340
- /**
341
- * Schema for investigation statistics.
31
+ * v7 merges the former ``Level`` into ``Verdict``. The five values line up one-for-one with
32
+ * the score bands ``basic-v1`` inherits from v6 (``< 0``, ``= 0``, ``]0,3[``, ``[3,5[``,
33
+ * ``>= 5``), which makes a verdict/level divergence structurally impossible.
34
+ *
35
+ * Those bands are ``basic-v1``'s convention, **not** part of the enum's contract: a
36
+ * probabilistic engine maps its own posterior thresholds onto the same labels.
37
+ *
38
+ * Two v6 levels deliberately left this axis: ``NONE`` became :class:`Status` and ``TRUSTED``
39
+ * became a :class:`DecisionKind` (or plain ``SAFE`` when it was merely a negative score).
40
+ */
41
+ export type Verdict = "SAFE" | "INFO" | "NOTABLE" | "SUSPICIOUS" | "MALICIOUS";
42
+ export type Weight = number | null;
43
+ export type OccurredAt2 = string | null;
44
+ export type ExternalId2 = string | null;
45
+ export type EvidenceKeys2 = string[];
46
+ export type ObservedAt1 = string | null;
47
+ export type Labels = Label[];
48
+ export type Taxonomies = string[];
49
+ export type OccurredAt3 = string | null;
50
+ export type ExternalId3 = string | null;
51
+ export type EvidenceKeys3 = string[];
52
+ export type Uri = string | null;
53
+ export type CapturedAt = string | null;
54
+ export type Weight1 = number | null;
55
+ export type OccurredAt4 = string | null;
56
+ export type ExternalId4 = string | null;
57
+ export type EvidenceKeys4 = string[];
58
+ /**
59
+ * Whether a finding takes part in the evaluation at all.
60
+ *
61
+ * Anything other than ``EVALUATED`` is excluded from the score *and* from aggregation
62
+ * denominators, while staying visible in the report.
63
+ */
64
+ export type Status = "NOT_APPLICABLE" | "PENDING" | "EVALUATED";
65
+ /**
66
+ * How a finding enters the investigation total. :class:`Status` says *whether*, this says *how*.
67
+ *
68
+ * ``ADDITIVE`` is every finding v6 ever had: a term of the sum.
69
+ *
70
+ * ``FLOOR`` and ``CEILING`` are the two halves of a **conclusion** — typically an analysis that
71
+ * read the other findings. Neither is a term: a floor raises the total just enough to reach the
72
+ * verdict it asserts, a ceiling lowers it just enough. Both add nothing once the investigation
73
+ * is already there, so conclusions never compound and several analysers may conclude on the
74
+ * same case without inflating — or deflating — each other.
75
+ *
76
+ * A ceiling is what states a **declared benign context**: an awareness campaign, a sanctioned
77
+ * pentest window, an authorised scanner. Without it the model could force a case up but never
78
+ * down, and the only way to say "whatever the evidence, this is benign" would be to guess a
79
+ * large negative weight — the v6 mistake.
80
+ *
81
+ * The band a verdict maps to is ``basic-v1``'s convention, like every other number here — see
82
+ * :mod:`cyvest.evaluation.projection`.
83
+ */
84
+ export type Effect = "ADDITIVE" | "FLOOR" | "CEILING";
85
+ /**
86
+ * What a Finding→Observable link scores on.
87
+ *
88
+ * One question, three answers, none of which depends on how the run was threaded:
89
+ *
90
+ * - ``OBSERVABLE`` — the observable as it stands, whoever contributed to it;
91
+ * - ``SIGNALS`` — the signals the link names, and nothing else, which is how a finding that
92
+ * fetched its own threat intel holds that value while the observable keeps accumulating;
93
+ * - ``NONE`` — nothing: the edge is kept for the graph and the narrative, but it is inert.
94
+ *
95
+ * v7.0 briefly carried a fourth, ``FRAGMENT``, gating the observable on the fragment that wrote
96
+ * each fact. It was dropped before release: it damped a merged total but never a local one, so
97
+ * the same rules scored differently depending on whether enrichment ran in its own worker.
98
+ * ``SIGNALS`` states that intent directly, and ``NONE`` covers the inert link it was standing in
99
+ * for when migrating v6 documents.
100
+ */
101
+ export type LinkBasis = "OBSERVABLE" | "SIGNALS" | "NONE";
102
+ export type SignalKeys = string[];
103
+ export type ObservableLinks = ObservableLink[];
104
+ export type Labels1 = Label[];
105
+ /**
106
+ * A MITRE ATT&CK Enterprise tactic — the phase of the kill chain a finding demonstrates.
107
+ *
108
+ * Kebab-case values, in kill-chain order. A tactic is a classification the timeline displays,
109
+ * never a term the engine scores: whether the activity is malicious is the verdict's job.
110
+ */
111
+ export type Tactic = "reconnaissance" | "resource-development" | "initial-access" | "execution" | "persistence" | "privilege-escalation" | "defense-evasion" | "credential-access" | "discovery" | "lateral-movement" | "collection" | "command-and-control" | "exfiltration" | "impact";
112
+ export type OccurredAt5 = string | null;
113
+ export type ExternalId5 = string | null;
114
+ export type EvidenceKeys5 = string[];
115
+ /**
116
+ * A named override of the computation.
117
+ *
118
+ * Forcing a score has to be a declared act — never the side effect of an inflated weight.
342
119
  *
343
- * Mirrors the output of `InvestigationStats.get_summary()`.
344
- */
345
- interface StatisticsSchema {
346
- total_observables: number;
347
- internal_observables: number;
348
- external_observables: number;
349
- whitelisted_observables: number;
350
- observables_by_type?: ObservablesByType;
351
- observables_by_level?: ObservablesByLevel;
352
- observables_by_type_and_level?: ObservablesByTypeAndLevel;
353
- total_findings: number;
354
- applied_findings: number;
355
- findings_by_level?: FindingsByLevel;
356
- total_evidences: number;
357
- evidences_by_type?: EvidencesByType;
358
- evidences_by_source?: EvidencesBySource;
359
- total_threat_intel: number;
360
- threat_intel_by_source?: ThreatIntelBySource;
361
- threat_intel_by_level?: ThreatIntelByLevel;
362
- total_tags: number;
363
- }
364
- interface ObservablesByType {
365
- [k: string]: number;
366
- }
367
- interface ObservablesByLevel {
368
- [k: string]: number;
369
- }
370
- interface ObservablesByTypeAndLevel {
371
- [k: string]: {
372
- [k: string]: number;
373
- };
374
- }
375
- interface FindingsByLevel {
376
- [k: string]: string[];
377
- }
378
- interface EvidencesByType {
379
- [k: string]: number;
380
- }
381
- interface EvidencesBySource {
382
- [k: string]: number;
383
- }
384
- interface ThreatIntelBySource {
385
- [k: string]: number;
386
- }
387
- interface ThreatIntelByLevel {
388
- [k: string]: number;
389
- }
390
- /**
391
- * Schema for data extraction metadata.
120
+ * The kind states the **intent**; the mechanism follows from the family of the target, which
121
+ * the key already carries. An earlier design enumerated one value per ``(intent, family)``
122
+ * pair — ``ALLOWLISTED``/``BLOCKLISTED``/``CONFIRMED``/``DISMISSED`` — and then needed a
123
+ * validator to forbid the half of that product which made no sense. An enum requiring a
124
+ * validator to reject half its combinations encodes one axis too many: the family is the
125
+ * target's business, not the decision's.
126
+ *
127
+ * The domain vocabulary survives untouched on the façade (``allowlist``, ``blocklist``,
128
+ * ``confirm``, ``dismiss``), where it belongs.
129
+ */
130
+ export type DecisionKind = "UPHOLD" | "REFUTE" | "VACATED";
131
+ export type OccurredAt6 = string | null;
132
+ export type ExternalId6 = string | null;
133
+ export type EvidenceKeys6 = string[];
134
+ export type FindingKeys = string[];
135
+ export type Score = number | null;
136
+ export type Contributions = Contribution[];
137
+ export type Score1 = number | null;
138
+ export type Contributions1 = Contribution[];
139
+ export type Score2 = number | null;
140
+ export type Contributions2 = Contribution[];
141
+ /**
142
+ * A complete serialized investigation.
143
+ */
144
+ export interface InvestigationSchema {
145
+ schema_version?: string;
146
+ header: InvestigationHeader;
147
+ policy_version?: string;
148
+ engine_id?: string;
149
+ facts?: FactsSchema;
150
+ decisions?: Decisions;
151
+ tags?: Tags;
152
+ report: Report;
153
+ }
154
+ /**
155
+ * What used to be a ``Case`` fact: metadata about the store rather than a fact inside it.
156
+ *
157
+ * ``engine_id`` is denormalized here so an investigation stays replayable identically years
158
+ * later, even after a newer stable engine ships.
392
159
  */
393
- interface DataExtractionSchema {
394
- root_type?: RootType;
395
- score_mode_obs: ScoreMode;
396
- }
397
-
398
- declare function parseCyvest(json: unknown): CyvestInvestigation;
399
- declare function isCyvest(json: unknown): json is CyvestInvestigation;
400
-
160
+ export interface InvestigationHeader {
161
+ investigation_id: string;
162
+ name?: string;
163
+ root_key?: RootKey;
164
+ opened_at?: string;
165
+ policy_version?: string;
166
+ engine_id?: string;
167
+ fragment_ids?: FragmentIds;
168
+ [k: string]: unknown;
169
+ }
170
+ /**
171
+ * The fact collections, each keyed by its semantic key.
172
+ */
173
+ export interface FactsSchema {
174
+ observables?: Observables;
175
+ relations?: Relations;
176
+ signals?: Signals;
177
+ evidences?: Evidences;
178
+ findings?: Findings;
179
+ }
180
+ export interface Observables {
181
+ [k: string]: Observable;
182
+ }
183
+ /**
184
+ * A cyber observable. Identity is ``(type, subtype, namespace, value)``, nothing else.
185
+ */
186
+ export interface Observable {
187
+ key: string;
188
+ seq: string;
189
+ asserted_at: string;
190
+ occurred_at?: OccurredAt;
191
+ source: SourceRef;
192
+ fragment_id: string;
193
+ external_id?: ExternalId;
194
+ evidence_keys?: EvidenceKeys;
195
+ type: string;
196
+ subtype?: Subtype;
197
+ namespace?: Namespace;
198
+ value: string;
199
+ internal?: boolean;
200
+ comment?: string;
201
+ extra?: Extra;
202
+ aliases?: Aliases;
203
+ occurrences?: Occurrences;
204
+ }
205
+ /**
206
+ * Who or what asserted a fact.
207
+ */
208
+ export interface SourceRef {
209
+ name: string;
210
+ source_class?: SourceClass;
211
+ [k: string]: unknown;
212
+ }
213
+ export interface Extra {
214
+ [k: string]: unknown;
215
+ }
216
+ /**
217
+ * A source identity that resolved to a canonical observable.
218
+ */
219
+ export interface ObservableAlias {
220
+ type: string;
221
+ subtype?: Subtype1;
222
+ namespace?: Namespace1;
223
+ value: string;
224
+ counts?: Counts;
225
+ [k: string]: unknown;
226
+ }
227
+ export interface Counts {
228
+ [k: string]: number;
229
+ }
230
+ export interface Occurrences {
231
+ [k: string]: number;
232
+ }
233
+ export interface Relations {
234
+ [k: string]: Relation;
235
+ }
236
+ /**
237
+ * A directed edge between two observables, labelled by the analyst pivot that produced it.
238
+ */
239
+ export interface Relation {
240
+ key: string;
241
+ seq: string;
242
+ asserted_at: string;
243
+ occurred_at?: OccurredAt1;
244
+ source: SourceRef;
245
+ fragment_id: string;
246
+ external_id?: ExternalId1;
247
+ evidence_keys?: EvidenceKeys1;
248
+ source_key: string;
249
+ target_key: string;
250
+ kind?: RelationKind;
251
+ observed_at?: ObservedAt;
252
+ confidence?: number;
253
+ comment?: string;
254
+ }
255
+ export interface Signals {
256
+ [k: string]: ThreatIntel;
257
+ }
258
+ /**
259
+ * A verdict from a threat-intelligence source.
260
+ *
261
+ * Identity is ``(source, subject_key)``, so a source re-asserting the same observable updates
262
+ * in place instead of piling up duplicates. Pass ``external_id`` to keep history on purpose.
263
+ */
264
+ export interface ThreatIntel {
265
+ verdict?: Verdict;
266
+ confidence?: number;
267
+ weight?: Weight;
268
+ key: string;
269
+ seq: string;
270
+ asserted_at: string;
271
+ occurred_at?: OccurredAt2;
272
+ source: SourceRef;
273
+ fragment_id: string;
274
+ external_id?: ExternalId2;
275
+ evidence_keys?: EvidenceKeys2;
276
+ subject_key: string;
277
+ kind?: "threat_intel";
278
+ observed_at?: ObservedAt1;
279
+ labels?: Labels;
280
+ payload?: Payload;
281
+ source_class?: SourceClass;
282
+ taxonomies?: Taxonomies;
283
+ comment?: string;
284
+ }
285
+ /**
286
+ * A typed tag on a fact: ``axis`` says what kind of statement ``value`` makes.
287
+ */
288
+ export interface Label {
289
+ axis: string;
290
+ value: string;
291
+ [k: string]: unknown;
292
+ }
293
+ export interface Payload {
294
+ [k: string]: unknown;
295
+ }
296
+ export interface Evidences {
297
+ [k: string]: Evidence;
298
+ }
299
+ /**
300
+ * A captured artefact: an API response, a header dump, an enrichment payload.
301
+ */
302
+ export interface Evidence {
303
+ key: string;
304
+ seq: string;
305
+ asserted_at: string;
306
+ occurred_at?: OccurredAt3;
307
+ source: SourceRef;
308
+ fragment_id: string;
309
+ external_id?: ExternalId3;
310
+ evidence_keys?: EvidenceKeys3;
311
+ evidence_type: string;
312
+ title?: string;
313
+ content?: Content;
314
+ uri?: Uri;
315
+ captured_at?: CapturedAt;
316
+ }
317
+ export interface Content {
318
+ [k: string]: unknown;
319
+ }
320
+ export interface Findings {
321
+ [k: string]: Finding;
322
+ }
323
+ /**
324
+ * A rule outcome. Identity is ``rule_id`` alone, plus ``external_id`` when one is given.
325
+ *
326
+ * A finding names no subject: what it is about is its ``observable_links``, which are also what
327
+ * it scores on. Use ``external_id`` when the same rule must yield several findings — typically
328
+ * once per observable, ``external_id=url.key``.
329
+ *
330
+ * A finding that describes an activity is **dated** through the envelope's ``occurred_at`` —
331
+ * when the activity happened, as opposed to when the rule fired — and may name the ATT&CK
332
+ * ``tactic`` it demonstrates. Both are what the timeline reads; neither enters the score.
333
+ */
334
+ export interface Finding {
335
+ verdict?: Verdict;
336
+ confidence?: number;
337
+ weight?: Weight1;
338
+ key: string;
339
+ seq: string;
340
+ asserted_at: string;
341
+ occurred_at?: OccurredAt4;
342
+ source: SourceRef;
343
+ fragment_id: string;
344
+ external_id?: ExternalId4;
345
+ evidence_keys?: EvidenceKeys4;
346
+ rule_id: string;
347
+ rule_version?: string;
348
+ name?: string;
349
+ comment?: string;
350
+ status?: Status;
351
+ effect?: Effect;
352
+ observable_links?: ObservableLinks;
353
+ labels?: Labels1;
354
+ tactic?: Tactic | null;
355
+ extra?: Extra1;
356
+ }
357
+ /**
358
+ * A link from a finding to one of its observables, with the basis it is evaluated on.
359
+ *
360
+ * Basis is **per link**, exactly like v6's ``propagation_mode``: a finding may mix bases, and
361
+ * may even link the same observable twice under two of them. Deduplication is on the triple
362
+ * ``(observable_key, basis, signal_keys)``.
363
+ *
364
+ * ``signal_keys`` is sorted and deduplicated so that two links naming the same signals in a
365
+ * different order are the same link, and merging stays idempotent.
366
+ */
367
+ export interface ObservableLink {
368
+ observable_key: string;
369
+ basis?: LinkBasis;
370
+ signal_keys?: SignalKeys;
371
+ [k: string]: unknown;
372
+ }
373
+ export interface Extra1 {
374
+ [k: string]: unknown;
375
+ }
376
+ export interface Decisions {
377
+ [k: string]: Decision;
378
+ }
379
+ /**
380
+ * A human (or automated) call that overrides the computed result for one target.
381
+ *
382
+ * ``UPHOLD`` forces the target to the policy floor, ``REFUTE`` neutralises it, ``VACATED``
383
+ * withdraws a previous stance and restores the computed value. How each is applied depends on
384
+ * the family of the target — an observable is bounded, a claim is taken out of the count — but
385
+ * that is the engine's dispatch, not a second axis of this model.
386
+ *
387
+ * ``justification`` is required: an override whose reason is optional is an override that
388
+ * cannot be audited, which defeats the point of recording it as a fact at all.
389
+ */
390
+ export interface Decision {
391
+ key: string;
392
+ seq: string;
393
+ asserted_at: string;
394
+ occurred_at?: OccurredAt5;
395
+ source: SourceRef;
396
+ fragment_id: string;
397
+ external_id?: ExternalId5;
398
+ evidence_keys?: EvidenceKeys5;
399
+ target_key: string;
400
+ kind: DecisionKind;
401
+ justification: string;
402
+ }
403
+ export interface Tags {
404
+ [k: string]: Tag;
405
+ }
406
+ /**
407
+ * A label grouping findings. Merging two tags unions their finding keys.
408
+ */
409
+ export interface Tag {
410
+ key: string;
411
+ seq: string;
412
+ asserted_at: string;
413
+ occurred_at?: OccurredAt6;
414
+ source: SourceRef;
415
+ fragment_id: string;
416
+ external_id?: ExternalId6;
417
+ evidence_keys?: EvidenceKeys6;
418
+ name: string;
419
+ description?: string;
420
+ finding_keys?: FindingKeys;
421
+ }
422
+ /**
423
+ * A full evaluation. Derived, never stored on the facts, recomputed from them.
424
+ */
425
+ export interface Report {
426
+ engine_id: string;
427
+ policy_version: string;
428
+ investigation: InvestigationResult;
429
+ findings?: Findings1;
430
+ observables?: Observables1;
431
+ [k: string]: unknown;
432
+ }
433
+ /**
434
+ * The investigation-level verdict.
435
+ */
436
+ export interface InvestigationResult {
437
+ key: string;
438
+ verdict?: Verdict;
439
+ confidence?: number;
440
+ score?: Score;
441
+ contributions?: Contributions;
442
+ suppressed_by_decision?: boolean;
443
+ raw?: Raw;
444
+ [k: string]: unknown;
445
+ }
446
+ /**
447
+ * One named term that fed a result, kept so the report can explain itself.
448
+ */
449
+ export interface Contribution {
450
+ source_key: string;
451
+ label: string;
452
+ value: number;
453
+ retained?: boolean;
454
+ detail?: string;
455
+ [k: string]: unknown;
456
+ }
457
+ export interface Raw {
458
+ [k: string]: unknown;
459
+ }
460
+ export interface Findings1 {
461
+ [k: string]: FindingResult;
462
+ }
463
+ /**
464
+ * A finding's verdict.
465
+ *
466
+ * ``own_term_suppressed`` flags that the rule's own claim was overridden by a stronger link —
467
+ * a contradiction worth surfacing rather than silently dropping.
468
+ *
469
+ * Three combinations of ``(counted, score)`` are meaningful, and a consumer must not conflate
470
+ * the last two:
471
+ *
472
+ * - ``(True, float)`` — an additive finding, a term of the total;
473
+ * - ``(False, None)`` — dismissed or not evaluated: visible, but out of the evaluation;
474
+ * - ``(True, None)`` — a conclusion (``effect`` is ``FLOOR`` or ``CEILING``): it takes part, but
475
+ * it has no magnitude of its own. Its effect is a bound on the investigation total, reported
476
+ * as a contribution of :class:`InvestigationResult`.
477
+ */
478
+ export interface FindingResult {
479
+ key: string;
480
+ verdict?: Verdict;
481
+ confidence?: number;
482
+ score?: Score1;
483
+ contributions?: Contributions1;
484
+ suppressed_by_decision?: boolean;
485
+ raw?: Raw1;
486
+ status?: Status;
487
+ effect?: Effect;
488
+ own_term_suppressed?: boolean;
489
+ counted?: boolean;
490
+ [k: string]: unknown;
491
+ }
492
+ export interface Raw1 {
493
+ [k: string]: unknown;
494
+ }
495
+ export interface Observables1 {
496
+ [k: string]: ObservableResult;
497
+ }
498
+ /**
499
+ * An observable's verdict. One per observable: the graph holds every fact anyone contributed.
500
+ */
501
+ export interface ObservableResult {
502
+ key: string;
503
+ verdict?: Verdict;
504
+ confidence?: number;
505
+ score?: Score2;
506
+ contributions?: Contributions2;
507
+ suppressed_by_decision?: boolean;
508
+ raw?: Raw2;
509
+ [k: string]: unknown;
510
+ }
511
+ export interface Raw2 {
512
+ [k: string]: unknown;
513
+ }
514
+ //#endregion
515
+ //#region src/types.d.ts
516
+ type Investigation = InvestigationSchema;
517
+ type Observable$1 = Observable;
518
+ type Relation$1 = Relation;
519
+ type ThreatIntel$1 = ThreatIntel;
520
+ type Evidence$1 = Evidence;
521
+ type Finding$1 = Finding;
522
+ type Decision$1 = Decision;
523
+ type Tag$1 = Tag;
524
+ type ObservableResult$1 = ObservableResult;
525
+ type FindingResult$1 = FindingResult;
526
+ type InvestigationResult$1 = InvestigationResult;
527
+ //#endregion
528
+ //#region src/helpers.d.ts
529
+ export declare const SCHEMA_VERSION = "7.0.0";
530
+ /**
531
+ * Read the declared schema version, falling back to `"5"` for anything unversioned.
532
+ *
533
+ * A document with no `schema_version` is a pre-v7 document, not a current one: `schema_version`
534
+ * is not in the schema's `required` list, so defaulting it to `SCHEMA_VERSION` would wave every
535
+ * legacy payload straight through. Python's `detect_schema_version` makes the same choice.
536
+ */
537
+ export declare function detectSchemaVersion(json: unknown): string;
538
+ /** Upward compatibility only: read older documents, never newer ones. */
539
+ export declare function assertReadableVersion(version: string): void;
540
+ export declare function parseCyvest(json: unknown): Investigation;
541
+ export declare function isCyvest(json: unknown): json is Investigation;
542
+ //#endregion
543
+ //#region src/keys.d.ts
401
544
  /**
402
545
  * Key generation utilities for Cyvest objects.
403
546
  *
@@ -407,7 +550,9 @@ declare function isCyvest(json: unknown): json is CyvestInvestigation;
407
550
  /**
408
551
  * Key type prefixes used in Cyvest.
409
552
  */
410
- type KeyType = "obs" | "fnd" | "evd" | "ti" | "enr" | "tag";
553
+ export type KeyType = "obs" | "fnd" | "evd" | "sig" | "rel" | "dec" | "tag";
554
+ /** Every prefix a v7 document can carry. `enr:` is gone — enrichments are evidence now. */
555
+ export declare const KEY_PREFIXES: readonly KeyType[];
411
556
  /**
412
557
  * Generate a unique key for an observable.
413
558
  *
@@ -423,57 +568,53 @@ type KeyType = "obs" | "fnd" | "evd" | "ti" | "enr" | "tag";
423
568
  * // => "obs:ipv4:192.168.1.1"
424
569
  * ```
425
570
  */
426
- declare function generateObservableKey(obsType: string, value: string, subtype?: string, namespace?: string): string;
571
+ export declare function generateObservableKey(obsType: string, value: string, subtype?: string, namespace?: string): string;
427
572
  /**
428
- * Generate a unique key for a finding.
573
+ * Generate a finding key.
429
574
  *
430
- * Format: fnd:{finding_name}
575
+ * Format: `fnd:{rule_id}`, or `fnd:{rule_id}:{external_id}`.
431
576
  *
432
- * @param findingName - Name of the finding
433
- * @returns Unique finding key
577
+ * A finding is identified by the rule that produced it. Running the same rule on several
578
+ * observables means several findings, so pass an `externalId` to keep them apart — usually the
579
+ * observable key.
434
580
  *
435
581
  * @example
436
582
  * ```ts
437
- * generateFindingKey("sender_verification")
438
- * // => "fnd:sender_verification"
583
+ * generateFindingKey("url_in_body")
584
+ * // => "fnd:url_in_body"
439
585
  * ```
440
586
  */
441
- declare function generateFindingKey(findingName: string): string;
587
+ export declare function generateFindingKey(ruleId: string, externalId?: string): string;
442
588
  /**
443
- * Generate a unique key for threat intelligence.
444
- *
445
- * Format: ti:{normalized_source}:{observable_key}
589
+ * Generate an observable-signal key.
446
590
  *
447
- * @param source - Name of the threat intel source
448
- * @param observableKey - Key of the related observable
449
- * @returns Unique threat intel key
591
+ * Format: `sig:{source}:{subject_key}`. The prefix names the *family*, not its first member:
592
+ * v6's `ti:` would have locked every future signal kind behind a threat-intel name.
450
593
  *
451
594
  * @example
452
595
  * ```ts
453
- * generateThreatIntelKey("virustotal", "obs:ipv4:192.168.1.1")
454
- * // => "ti:virustotal:obs:ipv4:192.168.1.1"
596
+ * generateSignalKey("virustotal", "obs:ipv4:192.168.1.1")
597
+ * // => "sig:virustotal:obs:ipv4:192.168.1.1"
455
598
  * ```
456
599
  */
457
- declare function generateThreatIntelKey(source: string, observableKey: string): string;
600
+ export declare function generateSignalKey(source: string, subjectKey: string, externalId?: string): string;
601
+ /** Kept under its v6 name; new code calls {@link generateSignalKey}. */
602
+ export declare const generateThreatIntelKey: typeof generateSignalKey;
458
603
  /**
459
- * Generate a unique key for an enrichment.
604
+ * Generate a relation key.
460
605
  *
461
- * Format: enr:{name} or enr:{name}:{context_hash}
462
- *
463
- * @param name - Name of the enrichment
464
- * @param context - Optional context string for disambiguation
465
- * @returns Unique enrichment key
466
- *
467
- * @example
468
- * ```ts
469
- * generateEnrichmentKey("whois_data")
470
- * // => "enr:whois_data"
606
+ * Format: `rel:{kind}:{source_key}>{target_key}` — direction lives in the key itself, so no
607
+ * `direction` field is needed to disambiguate.
608
+ */
609
+ export declare function generateRelationKey(sourceKey: string, targetKey: string, kind: string, externalId?: string): string;
610
+ /**
611
+ * Generate a decision key.
471
612
  *
472
- * generateEnrichmentKey("whois_data", "domain:example.com")
473
- * // => "enr:whois_data:a1b2c3d4"
474
- * ```
613
+ * Format: `dec:{target_key}` — one decision per target, whatever it says. The kind is content,
614
+ * not identity: a target holds a single current stance, and changing one's mind is a
615
+ * re-assertion the merge law settles by freshness.
475
616
  */
476
- declare function generateEnrichmentKey(name: string, context?: string): string;
617
+ export declare function generateDecisionKey(targetKey: string): string;
477
618
  /**
478
619
  * Generate a unique key for a tag.
479
620
  *
@@ -488,7 +629,7 @@ declare function generateEnrichmentKey(name: string, context?: string): string;
488
629
  * // => "tag:header:auth:dkim"
489
630
  * ```
490
631
  */
491
- declare function generateTagKey(name: string): string;
632
+ export declare function generateTagKey(name: string): string;
492
633
  /**
493
634
  * Get all ancestor tag names from a hierarchical tag name.
494
635
  *
@@ -501,7 +642,7 @@ declare function generateTagKey(name: string): string;
501
642
  * // => ["header", "header:auth"]
502
643
  * ```
503
644
  */
504
- declare function getTagAncestors(name: string): string[];
645
+ export declare function getTagAncestors(name: string): string[];
505
646
  /**
506
647
  * Check if a tag is a direct child of another tag.
507
648
  *
@@ -515,7 +656,7 @@ declare function getTagAncestors(name: string): string[];
515
656
  * isTagChildOf("header:auth:dkim", "header") // => false (grandchild)
516
657
  * ```
517
658
  */
518
- declare function isTagChildOf(childName: string, parentName: string): boolean;
659
+ export declare function isTagChildOf(childName: string, parentName: string): boolean;
519
660
  /**
520
661
  * Check if a tag is a descendant of another tag (any depth).
521
662
  *
@@ -529,12 +670,12 @@ declare function isTagChildOf(childName: string, parentName: string): boolean;
529
670
  * isTagDescendantOf("header", "header") // => false (same)
530
671
  * ```
531
672
  */
532
- declare function isTagDescendantOf(descendantName: string, ancestorName: string): boolean;
673
+ export declare function isTagDescendantOf(descendantName: string, ancestorName: string): boolean;
533
674
  /**
534
675
  * Extract the type prefix from a key.
535
676
  *
536
677
  * @param key - The key to parse
537
- * @returns Type prefix (obs, fnd, evd, ti, enr, tag) or null if invalid
678
+ * @returns Type prefix (see {@link KEY_PREFIXES}) or null if invalid
538
679
  *
539
680
  * @example
540
681
  * ```ts
@@ -542,7 +683,7 @@ declare function isTagDescendantOf(descendantName: string, ancestorName: string)
542
683
  * parseKeyType("invalid") // => null
543
684
  * ```
544
685
  */
545
- declare function parseKeyType(key: string): KeyType | null;
686
+ export declare function parseKeyType(key: string): KeyType | null;
546
687
  /**
547
688
  * Validate a key format and optionally finding its type.
548
689
  *
@@ -558,10 +699,15 @@ declare function parseKeyType(key: string): KeyType | null;
558
699
  * validateKey("invalid") // => false
559
700
  * ```
560
701
  */
561
- declare function validateKey(key: string, expectedType?: KeyType): boolean;
702
+ export declare function validateKey(key: string, expectedType?: KeyType): boolean;
562
703
  /**
563
704
  * Extract components from an observable key.
564
705
  *
706
+ * Only reliable for the simple form `obs:{type}:{value}`. A key carrying a subtype or a
707
+ * namespace, and a `command_line` or oversized key folded into `obs:{type}:sha256:{digest}`,
708
+ * both return the remaining segments verbatim as `value` — a key is an identity token, not a
709
+ * record. Read the observable from the document instead of parsing its key.
710
+ *
565
711
  * @param key - Observable key to parse
566
712
  * @returns Object with type and value, or null if invalid
567
713
  *
@@ -571,1009 +717,155 @@ declare function validateKey(key: string, expectedType?: KeyType): boolean;
571
717
  * // => { type: "ipv4", value: "192.168.1.1" }
572
718
  * ```
573
719
  */
574
- declare function parseObservableKey(key: string): {
575
- type: string;
576
- value: string;
577
- } | null;
578
- /**
579
- * Extract components from a finding key.
580
- *
581
- * @param key - Finding key to parse
582
- * @returns Object with findingName, or null if invalid
583
- *
584
- * @example
585
- * ```ts
586
- * parseFindingKey("fnd:sender_verification")
587
- * // => { findingName: "sender_verification" }
588
- * ```
589
- */
590
- declare function parseFindingKey(key: string): {
591
- findingName: string;
592
- } | null;
593
- /**
594
- * Extract components from a threat intel key.
595
- *
596
- * @param key - Threat intel key to parse
597
- * @returns Object with source and observableKey, or null if invalid
598
- *
599
- * @example
600
- * ```ts
601
- * parseThreatIntelKey("ti:virustotal:obs:ipv4:192.168.1.1")
602
- * // => { source: "virustotal", observableKey: "obs:ipv4:192.168.1.1" }
603
- * ```
604
- */
605
- declare function parseThreatIntelKey(key: string): {
606
- source: string;
607
- observableKey: string;
720
+ export declare function parseObservableKey(key: string): {
721
+ type: string;
722
+ value: string;
608
723
  } | null;
609
-
610
- /**
611
- * Level enumeration and scoring logic for Cyvest.
612
- *
613
- * This module defines the security level classification system and the algorithm
614
- * for determining levels from scores.
615
- */
616
-
617
- /**
618
- * Ordered array of levels from lowest to highest severity.
619
- */
620
- declare const LEVEL_ORDER: readonly Level[];
621
- /**
622
- * Numeric values for each level (for comparison purposes).
623
- */
624
- declare const LEVEL_VALUES: Record<Level, number>;
625
- /**
626
- * Color mapping for display purposes.
627
- */
628
- declare const LEVEL_COLORS: Record<Level, string>;
629
- /**
630
- * Normalize a level input to the Level type.
631
- *
632
- * Accepts a case-insensitive string and returns the normalized Level.
633
- *
634
- * @param level - Level string (e.g., "malicious", "MALICIOUS")
635
- * @returns The normalized Level
636
- * @throws Error if the string does not match a valid Level
637
- *
638
- * @example
639
- * ```ts
640
- * normalizeLevel("malicious") // => "MALICIOUS"
641
- * normalizeLevel("TRUSTED") // => "TRUSTED"
642
- * ```
643
- */
644
- declare function normalizeLevel(level: string): Level;
645
- /**
646
- * Check if a string is a valid Level.
647
- *
648
- * @param level - String to finding
649
- * @returns True if valid Level
650
- */
651
- declare function isValidLevel(level: string): level is Level;
652
- /**
653
- * Calculate the security level from a numeric score.
654
- *
655
- * Algorithm:
656
- * - score < 0.0 -> TRUSTED
657
- * - score === 0.0 -> INFO
658
- * - score < 3.0 -> NOTABLE
659
- * - score < 5.0 -> SUSPICIOUS
660
- * - score >= 5.0 -> MALICIOUS
661
- *
662
- * @param score - The numeric score to evaluate
663
- * @returns The appropriate Level based on the score
664
- *
665
- * @example
666
- * ```ts
667
- * getLevelFromScore(-1) // => "TRUSTED"
668
- * getLevelFromScore(0) // => "INFO"
669
- * getLevelFromScore(2.5) // => "NOTABLE"
670
- * getLevelFromScore(4) // => "SUSPICIOUS"
671
- * getLevelFromScore(5) // => "MALICIOUS"
672
- * ```
673
- */
674
- declare function getLevelFromScore(score: number): Level;
675
- /**
676
- * Compare two levels.
677
- *
678
- * @param a - First level
679
- * @param b - Second level
680
- * @returns -1 if a < b, 0 if a === b, 1 if a > b
681
- *
682
- * @example
683
- * ```ts
684
- * compareLevels("INFO", "MALICIOUS") // => -1
685
- * compareLevels("MALICIOUS", "INFO") // => 1
686
- * compareLevels("INFO", "INFO") // => 0
687
- * ```
688
- */
689
- declare function compareLevels(a: Level, b: Level): -1 | 0 | 1;
690
- /**
691
- * Check if level a is higher (more severe) than level b.
692
- *
693
- * @param a - First level
694
- * @param b - Second level
695
- * @returns True if a is higher than b
696
- *
697
- * @example
698
- * ```ts
699
- * isLevelHigherThan("MALICIOUS", "SUSPICIOUS") // => true
700
- * isLevelHigherThan("INFO", "MALICIOUS") // => false
701
- * ```
702
- */
703
- declare function isLevelHigherThan(a: Level, b: Level): boolean;
704
- /**
705
- * Check if level a is lower (less severe) than level b.
706
- *
707
- * @param a - First level
708
- * @param b - Second level
709
- * @returns True if a is lower than b
710
- */
711
- declare function isLevelLowerThan(a: Level, b: Level): boolean;
712
- /**
713
- * Check if level a is at least as severe as level b.
714
- *
715
- * @param a - Level to finding
716
- * @param minLevel - Minimum required level
717
- * @returns True if a is at least minLevel
718
- *
719
- * @example
720
- * ```ts
721
- * isLevelAtLeast("MALICIOUS", "SUSPICIOUS") // => true
722
- * isLevelAtLeast("SUSPICIOUS", "SUSPICIOUS") // => true
723
- * isLevelAtLeast("INFO", "SUSPICIOUS") // => false
724
- * ```
725
- */
726
- declare function isLevelAtLeast(a: Level, minLevel: Level): boolean;
727
- /**
728
- * Get the maximum (most severe) level from an array of levels.
729
- *
730
- * @param levels - Array of levels
731
- * @returns The most severe level, or "NONE" if array is empty
732
- */
733
- declare function maxLevel(levels: Level[]): Level;
734
- /**
735
- * Get the minimum (least severe) level from an array of levels.
736
- *
737
- * @param levels - Array of levels
738
- * @returns The least severe level, or "MALICIOUS" if array is empty
739
- */
740
- declare function minLevel(levels: Level[]): Level;
741
- /**
742
- * Get the color associated with a level for display purposes.
743
- *
744
- * @param level - Level to get color for
745
- * @returns Hex color string
746
- */
747
- declare function getColorForLevel(level: Level): string;
748
- /**
749
- * Get the color associated with a score for display purposes.
750
- *
751
- * @param score - Score to get color for
752
- * @returns Hex color string
753
- */
754
- declare function getColorForScore(score: number): string;
755
- /**
756
- * Type guard to check if an object has a level property.
757
- */
758
- declare function hasLevel(obj: unknown): obj is {
759
- level: Level;
760
- };
761
- /**
762
- * Extract level from an entity (Observable, Finding, ThreatIntel, Tag).
763
- */
764
- declare function getEntityLevel(entity: Observable | Finding | ThreatIntel | Tag): Level;
765
-
766
- /**
767
- * Get an observable by its key.
768
- *
769
- * @param inv - The investigation to search
770
- * @param key - Observable key (e.g., "obs:ipv4:192.168.1.1")
771
- * @returns The observable or undefined if not found
772
- *
773
- * @example
774
- * ```ts
775
- * const obs = getObservable(investigation, "obs:ipv4:192.168.1.1");
776
- * if (obs) {
777
- * console.log(obs.value, obs.level);
778
- * }
779
- * ```
780
- */
781
- declare function getObservable(inv: CyvestInvestigation, key: string): Observable | undefined;
782
- /**
783
- * Get an observable by type and value.
784
- *
785
- * @param inv - The investigation to search
786
- * @param type - Observable type (e.g., "ipv4", "url")
787
- * @param value - Observable value
788
- * @returns The observable or undefined if not found
789
- *
790
- * @example
791
- * ```ts
792
- * const obs = getObservableByTypeValue(investigation, "ipv4", "192.168.1.1");
793
- * ```
794
- */
795
- declare function getObservableByTypeValue(inv: CyvestInvestigation, type: string, value: string, subtype?: string, namespace?: string): Observable | undefined;
796
- /**
797
- * Get the root observable of the investigation.
798
- *
799
- * The root observable is identified using the `root_type` from data extraction
800
- * metadata combined with value="root".
801
- *
802
- * @param inv - The investigation
803
- * @returns The root observable, or undefined if not found
804
- *
805
- * @example
806
- * ```ts
807
- * const root = getRootObservable(investigation);
808
- * if (root) {
809
- * console.log(`Root: ${root.type} = ${root.value}`);
810
- * }
811
- * ```
812
- */
813
- declare function getRootObservable(inv: CyvestInvestigation): Observable | undefined;
814
- /**
815
- * Get a finding by its key.
816
- *
817
- * @param inv - The investigation to search
818
- * @param key - Finding key (e.g., "fnd:sender_verification:email_headers")
819
- * @returns The finding or undefined if not found
820
- *
821
- * @example
822
- * ```ts
823
- * const finding = getFinding(investigation, "fnd:sender_verification:email_headers");
824
- * ```
825
- */
826
- declare function getFinding(inv: CyvestInvestigation, key: string): Finding | undefined;
827
- /**
828
- * Get a finding by its name.
829
- *
830
- * @param inv - The investigation to search
831
- * @param findingName - Finding name
832
- * @returns The finding or undefined if not found
833
- *
834
- * @example
835
- * ```ts
836
- * const finding = getFindingByName(investigation, "sender_verification");
837
- * ```
838
- */
839
- declare function getFindingByName(inv: CyvestInvestigation, findingName: string): Finding | undefined;
840
- /**
841
- * Get all findings as an array.
842
- *
843
- * @param inv - The investigation
844
- * @returns Array of all findings
845
- *
846
- * @example
847
- * ```ts
848
- * const allFindings = getAllFindings(investigation);
849
- * console.log(`Total findings: ${allFindings.length}`);
850
- * ```
851
- */
852
- declare function getAllFindings(inv: CyvestInvestigation): Finding[];
853
- declare function getEvidence(inv: CyvestInvestigation, key: string): Evidence | undefined;
854
- declare function getAllEvidences(inv: CyvestInvestigation): Evidence[];
855
- /**
856
- * Get a threat intel entry by its key.
857
- *
858
- * @param inv - The investigation to search
859
- * @param key - Threat intel key (e.g., "ti:virustotal:obs:ipv4:192.168.1.1")
860
- * @returns The threat intel or undefined if not found
861
- */
862
- declare function getThreatIntel(inv: CyvestInvestigation, key: string): ThreatIntel | undefined;
863
- /**
864
- * Get a threat intel entry by source and observable key.
865
- *
866
- * @param inv - The investigation to search
867
- * @param source - Threat intel source name
868
- * @param observableKey - Key of the related observable
869
- * @returns The threat intel or undefined if not found
870
- */
871
- declare function getThreatIntelBySourceObservable(inv: CyvestInvestigation, source: string, observableKey: string): ThreatIntel | undefined;
872
- /**
873
- * Get all threat intel entries as an array.
874
- *
875
- * @param inv - The investigation
876
- * @returns Array of all threat intel entries
877
- */
878
- declare function getAllThreatIntels(inv: CyvestInvestigation): ThreatIntel[];
879
- /**
880
- * Get an enrichment by its key.
881
- *
882
- * @param inv - The investigation to search
883
- * @param key - Enrichment key (e.g., "enr:whois_data")
884
- * @returns The enrichment or undefined if not found
885
- */
886
- declare function getEnrichment(inv: CyvestInvestigation, key: string): Enrichment | undefined;
887
- /**
888
- * Get an enrichment by name.
889
- *
890
- * @param inv - The investigation to search
891
- * @param name - Enrichment name
892
- * @returns The first matching enrichment or undefined if not found
893
- */
894
- declare function getEnrichmentByName(inv: CyvestInvestigation, name: string): Enrichment | undefined;
895
- /**
896
- * Get all enrichments as an array.
897
- *
898
- * @param inv - The investigation
899
- * @returns Array of all enrichments
900
- */
901
- declare function getAllEnrichments(inv: CyvestInvestigation): Enrichment[];
902
- /**
903
- * Get a tag by its key.
904
- *
905
- * @param inv - The investigation to search
906
- * @param key - Tag key (e.g., "tag:header:auth")
907
- * @returns The tag or undefined if not found
908
- *
909
- * @example
910
- * ```ts
911
- * const tag = getTag(investigation, "tag:header:auth");
912
- * if (tag) {
913
- * console.log(tag.name, tag.direct_level);
914
- * }
915
- * ```
916
- */
917
- declare function getTag(inv: CyvestInvestigation, key: string): Tag | undefined;
918
- /**
919
- * Get a tag by its name.
920
- *
921
- * @param inv - The investigation to search
922
- * @param name - Tag name (e.g., "header:auth:dkim")
923
- * @returns The tag or undefined if not found
924
- *
925
- * @example
926
- * ```ts
927
- * const tag = getTagByName(investigation, "header:auth:dkim");
928
- * ```
929
- */
930
- declare function getTagByName(inv: CyvestInvestigation, name: string): Tag | undefined;
931
- /**
932
- * Get all tags as an array.
933
- *
934
- * @param inv - The investigation
935
- * @returns Array of all tags
936
- *
937
- * @example
938
- * ```ts
939
- * const allTags = getAllTags(investigation);
940
- * console.log(`Total tags: ${allTags.length}`);
941
- * ```
942
- */
943
- declare function getAllTags(inv: CyvestInvestigation): Tag[];
944
- /**
945
- * Get all observables as an array.
946
- *
947
- * @param inv - The investigation
948
- * @returns Array of all observables
949
- */
950
- declare function getAllObservables(inv: CyvestInvestigation): Observable[];
951
- /**
952
- * Get all whitelists from the investigation.
953
- *
954
- * @param inv - The investigation
955
- * @returns Array of all whitelists
956
- */
957
- declare function getWhitelists(inv: CyvestInvestigation): Whitelists;
958
- /**
959
- * Get the investigation statistics.
960
- *
961
- * @param inv - The investigation
962
- * @returns Statistics object
963
- */
964
- declare function getStats(inv: CyvestInvestigation): StatisticsSchema;
965
- /**
966
- * Get the data extraction configuration.
967
- *
968
- * @param inv - The investigation
969
- * @returns Data extraction config
970
- */
971
- declare function getDataExtraction(inv: CyvestInvestigation): DataExtractionSchema;
972
- /**
973
- * Count entities in the investigation.
974
- */
975
- interface InvestigationCounts {
976
- observables: number;
977
- findings: number;
978
- evidences: number;
979
- threatIntels: number;
980
- enrichments: number;
981
- tags: number;
982
- whitelists: number;
983
- }
984
- /**
985
- * Get counts of all entities in the investigation.
986
- *
987
- * @param inv - The investigation
988
- * @returns Object with counts for each entity type
989
- */
990
- declare function getCounts(inv: CyvestInvestigation): InvestigationCounts;
991
- /**
992
- * Get the investigation start time from the event log.
993
- *
994
- * Looks for the INVESTIGATION_STARTED event and returns its timestamp.
995
- *
996
- * @param inv - The investigation
997
- * @returns The start timestamp string or undefined if not found
998
- *
999
- * @example
1000
- * ```ts
1001
- * const startedAt = getStartedAt(investigation);
1002
- * if (startedAt) {
1003
- * console.log(`Started: ${startedAt}`);
1004
- * }
1005
- * ```
1006
- */
1007
- declare function getStartedAt(inv: CyvestInvestigation): string | undefined;
1008
- /**
1009
- * Get direct child tags of a given tag.
1010
- *
1011
- * @param inv - The investigation
1012
- * @param tagName - Parent tag name
1013
- * @returns Array of direct child tags
1014
- *
1015
- * @example
1016
- * ```ts
1017
- * const children = getTagChildren(investigation, "bodies");
1018
- * // Returns tags like "bodies:urls", "bodies:domains" (but not "bodies:urls:something")
1019
- * ```
1020
- */
1021
- declare function getTagChildren(inv: CyvestInvestigation, tagName: string): Tag[];
1022
- /**
1023
- * Get all descendant tags of a given tag (any depth).
1024
- *
1025
- * @param inv - The investigation
1026
- * @param tagName - Ancestor tag name
1027
- * @returns Array of all descendant tags
1028
- *
1029
- * @example
1030
- * ```ts
1031
- * const descendants = getTagDescendants(investigation, "bodies");
1032
- * // Returns all tags starting with "bodies:"
1033
- * ```
1034
- */
1035
- declare function getTagDescendants(inv: CyvestInvestigation, tagName: string): Tag[];
1036
- /**
1037
- * Get the aggregated score for a tag including all descendant tags.
1038
- *
1039
- * The aggregated score includes:
1040
- * - The tag's direct_score (from its direct findings)
1041
- * - Recursively, the aggregated scores of all child tags
1042
- *
1043
- * @param inv - The investigation
1044
- * @param tagName - Name of the tag
1045
- * @returns Total aggregated score, or 0 if tag not found
1046
- *
1047
- * @example
1048
- * ```ts
1049
- * const score = getTagAggregatedScore(investigation, "bodies");
1050
- * // Includes scores from bodies, bodies:urls, bodies:domains, etc.
1051
- * ```
1052
- */
1053
- declare function getTagAggregatedScore(inv: CyvestInvestigation, tagName: string): number;
1054
- /**
1055
- * Get the aggregated level for a tag including all descendant tags.
1056
- *
1057
- * The level is calculated from the aggregated score using the standard
1058
- * score-to-level mapping.
1059
- *
1060
- * @param inv - The investigation
1061
- * @param tagName - Name of the tag
1062
- * @returns Level based on aggregated score
1063
- *
1064
- * @example
1065
- * ```ts
1066
- * const level = getTagAggregatedLevel(investigation, "bodies");
1067
- * // Returns "MALICIOUS" if aggregated score >= 5, etc.
1068
- * ```
1069
- */
1070
- declare function getTagAggregatedLevel(inv: CyvestInvestigation, tagName: string): Level;
1071
-
1072
- /**
1073
- * Finder utilities for querying and filtering Cyvest Investigation data.
1074
- *
1075
- * These functions provide filtering, searching, and cross-referencing
1076
- * capabilities for observables, findings, and threat intel.
1077
- */
1078
-
1079
- /**
1080
- * Find all observables of a specific type.
1081
- *
1082
- * @param inv - The investigation to search
1083
- * @param type - Observable type (e.g., "ipv4", "url", "domain")
1084
- * @returns Array of matching observables
1085
- *
1086
- * @example
1087
- * ```ts
1088
- * const ips = findObservablesByType(investigation, "ipv4");
1089
- * const urls = findObservablesByType(investigation, "url");
1090
- * ```
1091
- */
1092
- declare function findObservablesByType(inv: CyvestInvestigation, type: string): Observable[];
1093
- /**
1094
- * Find all observables at a specific level.
1095
- *
1096
- * @param inv - The investigation to search
1097
- * @param level - Security level to filter by
1098
- * @returns Array of matching observables
1099
- *
1100
- * @example
1101
- * ```ts
1102
- * const malicious = findObservablesByLevel(investigation, "MALICIOUS");
1103
- * ```
1104
- */
1105
- declare function findObservablesByLevel(inv: CyvestInvestigation, level: Level): Observable[];
1106
- /**
1107
- * Find all observables at or above a minimum level.
1108
- *
1109
- * @param inv - The investigation to search
1110
- * @param minLevel - Minimum security level
1111
- * @returns Array of matching observables
1112
- *
1113
- * @example
1114
- * ```ts
1115
- * const suspicious = findObservablesAtLeast(investigation, "SUSPICIOUS");
1116
- * // Returns SUSPICIOUS and MALICIOUS observables
1117
- * ```
1118
- */
1119
- declare function findObservablesAtLeast(inv: CyvestInvestigation, minLevel: Level): Observable[];
1120
- /**
1121
- * Find observables by exact value match.
1122
- *
1123
- * @param inv - The investigation to search
1124
- * @param value - Value to search for
1125
- * @param caseSensitive - Whether to perform case-sensitive match (default: false)
1126
- * @returns Array of matching observables
1127
- */
1128
- declare function findObservablesByValue(inv: CyvestInvestigation, value: string, caseSensitive?: boolean): Observable[];
1129
- /**
1130
- * Find observables containing a substring in their value.
1131
- *
1132
- * @param inv - The investigation to search
1133
- * @param substring - Substring to search for
1134
- * @param caseSensitive - Whether to perform case-sensitive match (default: false)
1135
- * @returns Array of matching observables
1136
- */
1137
- declare function findObservablesContaining(inv: CyvestInvestigation, substring: string, caseSensitive?: boolean): Observable[];
1138
- /**
1139
- * Find observables matching a regular expression.
1140
- *
1141
- * @param inv - The investigation to search
1142
- * @param pattern - Regular expression pattern
1143
- * @returns Array of matching observables
1144
- */
1145
- declare function findObservablesMatching(inv: CyvestInvestigation, pattern: RegExp): Observable[];
1146
- /**
1147
- * Find internal observables.
1148
- *
1149
- * @param inv - The investigation to search
1150
- * @returns Array of internal observables
1151
- */
1152
- declare function findInternalObservables(inv: CyvestInvestigation): Observable[];
1153
- /**
1154
- * Find external (non-internal) observables.
1155
- *
1156
- * @param inv - The investigation to search
1157
- * @returns Array of external observables
1158
- */
1159
- declare function findExternalObservables(inv: CyvestInvestigation): Observable[];
1160
- /**
1161
- * Find whitelisted observables.
1162
- *
1163
- * @param inv - The investigation to search
1164
- * @returns Array of whitelisted observables
1165
- */
1166
- declare function findWhitelistedObservables(inv: CyvestInvestigation): Observable[];
1167
- /**
1168
- * Find observables with threat intelligence data.
1169
- *
1170
- * @param inv - The investigation to search
1171
- * @returns Array of observables that have associated threat intel
1172
- */
1173
- declare function findObservablesWithThreatIntel(inv: CyvestInvestigation): Observable[];
1174
- /**
1175
- * Find all findings at a specific level.
1176
- *
1177
- * @param inv - The investigation to search
1178
- * @param level - Security level to filter by
1179
- * @returns Array of matching findings
1180
- */
1181
- declare function findFindingsByLevel(inv: CyvestInvestigation, level: Level): Finding[];
1182
- /**
1183
- * Find all findings at or above a minimum level.
1184
- *
1185
- * @param inv - The investigation to search
1186
- * @param minLevel - Minimum security level
1187
- * @returns Array of matching findings
1188
- */
1189
- declare function findFindingsAtLeast(inv: CyvestInvestigation, minLevel: Level): Finding[];
1190
- /**
1191
- * Find findings by finding name.
1192
- *
1193
- * @param inv - The investigation to search
1194
- * @param findingName - Finding name to search for
1195
- * @returns The matching finding or undefined
1196
- */
1197
- declare function findFindingByName(inv: CyvestInvestigation, findingName: string): Finding | undefined;
1198
- /**
1199
- * Find all threat intel from a specific source.
1200
- *
1201
- * @param inv - The investigation to search
1202
- * @param source - Source name (e.g., "virustotal", "otx")
1203
- * @returns Array of threat intel from the source
1204
- */
1205
- declare function findThreatIntelBySource(inv: CyvestInvestigation, source: string): ThreatIntel[];
1206
- /**
1207
- * Find all threat intel at a specific level.
1208
- *
1209
- * @param inv - The investigation to search
1210
- * @param level - Security level to filter by
1211
- * @returns Array of matching threat intel
1212
- */
1213
- declare function findThreatIntelByLevel(inv: CyvestInvestigation, level: Level): ThreatIntel[];
1214
- /**
1215
- * Find all threat intel at or above a minimum level.
1216
- *
1217
- * @param inv - The investigation to search
1218
- * @param minLevel - Minimum security level
1219
- * @returns Array of matching threat intel
1220
- */
1221
- declare function findThreatIntelAtLeast(inv: CyvestInvestigation, minLevel: Level): ThreatIntel[];
1222
- /**
1223
- * Find tags at a specific direct level.
1224
- *
1225
- * @param inv - The investigation to search
1226
- * @param level - Direct level to filter by
1227
- * @returns Array of matching tags
1228
- */
1229
- declare function findTagsByLevel(inv: CyvestInvestigation, level: Level): Tag[];
1230
- /**
1231
- * Find tags at or above a minimum direct level.
1232
- *
1233
- * @param inv - The investigation to search
1234
- * @param minLevel - Minimum direct level
1235
- * @returns Array of matching tags
1236
- */
1237
- declare function findTagsAtLeast(inv: CyvestInvestigation, minLevel: Level): Tag[];
1238
- /**
1239
- * Find tags by name pattern.
1240
- *
1241
- * @param inv - The investigation to search
1242
- * @param pattern - Pattern to match against tag names
1243
- * @returns Array of matching tags
1244
- */
1245
- declare function findTagsByNamePattern(inv: CyvestInvestigation, pattern: RegExp): Tag[];
1246
- /**
1247
- * Find all findings that generated or reference a specific observable.
1248
- *
1249
- * @param inv - The investigation to search
1250
- * @param observableKey - Key of the observable
1251
- * @returns Array of findings that reference this observable
1252
- *
1253
- * @example
1254
- * ```ts
1255
- * const findings = findFindingsForObservable(investigation, "obs:ipv4:192.168.1.1");
1256
- * ```
1257
- */
1258
- declare function findFindingsForObservable(inv: CyvestInvestigation, observableKey: string): Finding[];
1259
- /**
1260
- * Find all threat intel entries for a specific observable.
1261
- *
1262
- * @param inv - The investigation to search
1263
- * @param observableKey - Key of the observable
1264
- * @returns Array of threat intel for this observable
1265
- */
1266
- declare function findThreatIntelsForObservable(inv: CyvestInvestigation, observableKey: string): ThreatIntel[];
1267
- /**
1268
- * Find all observables referenced by a specific finding.
1269
- *
1270
- * @param inv - The investigation to search
1271
- * @param findingKey - Key of the finding
1272
- * @returns Array of observables referenced by this finding
1273
- */
1274
- declare function findObservablesForFinding(inv: CyvestInvestigation, findingKey: string): Observable[];
1275
- /**
1276
- * Find all findings for a specific tag.
1277
- *
1278
- * @param inv - The investigation to search
1279
- * @param tagKey - Key of the tag
1280
- * @param recursive - Include findings from descendant tags (default: false)
1281
- * @returns Array of findings in the tag
1282
- */
1283
- declare function findFindingsForTag(inv: CyvestInvestigation, tagKey: string, recursive?: boolean): Finding[];
1284
- /**
1285
- * Sort observables by score (descending - highest first).
1286
- *
1287
- * @param observables - Array of observables to sort
1288
- * @returns Sorted array (new array, doesn't mutate input)
1289
- */
1290
- declare function sortObservablesByScore(observables: Observable[]): Observable[];
1291
- /**
1292
- * Sort findings by score (descending - highest first).
1293
- *
1294
- * @param findings - Array of findings to sort
1295
- * @returns Sorted array (new array, doesn't mutate input)
1296
- */
1297
- declare function sortFindingsByScore(findings: Finding[]): Finding[];
1298
- /**
1299
- * Sort observables by level (descending - most severe first).
1300
- *
1301
- * @param observables - Array of observables to sort
1302
- * @returns Sorted array (new array, doesn't mutate input)
1303
- */
1304
- declare function sortObservablesByLevel(observables: Observable[]): Observable[];
1305
- /**
1306
- * Sort findings by level (descending - most severe first).
1307
- *
1308
- * @param findings - Array of findings to sort
1309
- * @returns Sorted array (new array, doesn't mutate input)
1310
- */
1311
- declare function sortFindingsByLevel(findings: Finding[]): Finding[];
1312
- /**
1313
- * Find the highest scoring observables.
1314
- *
1315
- * @param inv - The investigation to search
1316
- * @param n - Number of results to return (default: 10)
1317
- * @returns Array of highest scoring observables
1318
- */
1319
- declare function findHighestScoringObservables(inv: CyvestInvestigation, n?: number): Observable[];
1320
- /**
1321
- * Find the highest scoring findings.
1322
- *
1323
- * @param inv - The investigation to search
1324
- * @param n - Number of results to return (default: 10)
1325
- * @returns Array of highest scoring findings
1326
- */
1327
- declare function findHighestScoringFindings(inv: CyvestInvestigation, n?: number): Finding[];
1328
- /**
1329
- * Find all malicious observables (convenience function).
1330
- *
1331
- * @param inv - The investigation to search
1332
- * @returns Array of malicious observables
1333
- */
1334
- declare function findMaliciousObservables(inv: CyvestInvestigation): Observable[];
1335
- /**
1336
- * Find all suspicious observables (convenience function).
1337
- *
1338
- * @param inv - The investigation to search
1339
- * @returns Array of suspicious observables
1340
- */
1341
- declare function findSuspiciousObservables(inv: CyvestInvestigation): Observable[];
1342
- /**
1343
- * Find all malicious findings (convenience function).
1344
- *
1345
- * @param inv - The investigation to search
1346
- * @returns Array of malicious findings
1347
- */
1348
- declare function findMaliciousFindings(inv: CyvestInvestigation): Finding[];
1349
- /**
1350
- * Find all suspicious findings (convenience function).
1351
- *
1352
- * @param inv - The investigation to search
1353
- * @returns Array of suspicious findings
1354
- */
1355
- declare function findSuspiciousFindings(inv: CyvestInvestigation): Finding[];
1356
- /**
1357
- * Get all finding keys in the investigation.
1358
- *
1359
- * @param inv - The investigation
1360
- * @returns Array of finding keys
1361
- */
1362
- declare function getAllFindingKeys(inv: CyvestInvestigation): string[];
1363
- /**
1364
- * Get all observable types present in the investigation.
1365
- *
1366
- * @param inv - The investigation
1367
- * @returns Array of unique observable types
1368
- */
1369
- declare function getAllObservableTypes(inv: CyvestInvestigation): string[];
1370
- /**
1371
- * Get all threat intel sources present in the investigation.
1372
- *
1373
- * @param inv - The investigation
1374
- * @returns Array of unique source names
1375
- */
1376
- declare function getAllThreatIntelSources(inv: CyvestInvestigation): string[];
1377
-
1378
- /**
1379
- * Graph and relationship traversal utilities for Cyvest Investigation.
1380
- *
1381
- * These functions provide graph-like traversal of observable relationships,
1382
- * useful for understanding connections and preparing data for visualization.
1383
- */
1384
-
1385
- /**
1386
- * Edge representation for graph operations.
1387
- */
1388
- interface GraphEdge {
1389
- /** Source observable key */
1390
- source: string;
1391
- /** Target observable key */
1392
- target: string;
1393
- /** Relationship type label */
1394
- type: string;
1395
- /** Relationship direction */
1396
- direction: RelationshipDirection;
1397
- }
1398
- /**
1399
- * Graph node representation.
1400
- */
1401
- interface GraphNode {
1402
- /** Observable key (unique identifier) */
1403
- id: string;
1404
- /** Observable type */
1405
- type: string;
1406
- /** Observable value */
1407
- value: string;
1408
- /** Security level */
1409
- level: Level;
1410
- /** Numeric score */
1411
- score: number;
1412
- /** Whether internal */
1413
- internal: boolean;
1414
- /** Whether whitelisted */
1415
- whitelisted: boolean;
1416
- }
1417
- /**
1418
- * Full graph representation of an investigation.
1419
- */
1420
- interface InvestigationGraph {
1421
- /** All nodes (observables) */
1422
- nodes: GraphNode[];
1423
- /** All edges (relationships) */
1424
- edges: GraphEdge[];
1425
- }
1426
- /**
1427
- * Get all related observables for a given observable.
1428
- *
1429
- * Returns observables that are directly connected via any relationship,
1430
- * regardless of direction.
1431
- *
1432
- * @param inv - The investigation to search
1433
- * @param observableKey - Key of the source observable
1434
- * @returns Array of related observables
1435
- *
1436
- * @example
1437
- * ```ts
1438
- * const related = getRelatedObservables(investigation, "obs:email:test@example.com");
1439
- * ```
1440
- */
1441
- declare function getRelatedObservables(inv: CyvestInvestigation, observableKey: string): Observable[];
1442
- /**
1443
- * Get observables related by outbound relationships (children).
1444
- *
1445
- * @param inv - The investigation to search
1446
- * @param observableKey - Key of the source observable
1447
- * @returns Array of child observables
1448
- */
1449
- declare function getObservableChildren(inv: CyvestInvestigation, observableKey: string): Observable[];
1450
- /**
1451
- * Get observables related by inbound relationships (parents).
1452
- *
1453
- * @param inv - The investigation to search
1454
- * @param observableKey - Key of the target observable
1455
- * @returns Array of parent observables
1456
- */
1457
- declare function getObservableParents(inv: CyvestInvestigation, observableKey: string): Observable[];
1458
- /**
1459
- * Get related observables filtered by relationship type.
1460
- *
1461
- * @param inv - The investigation to search
1462
- * @param observableKey - Key of the source observable
1463
- * @param relationshipType - Type of relationship to filter (e.g., "related-to", "uses")
1464
- * @returns Array of related observables
1465
- */
1466
- declare function getRelatedObservablesByType(inv: CyvestInvestigation, observableKey: string, relationshipType: string): Observable[];
1467
- /**
1468
- * Get related observables filtered by direction.
1469
- *
1470
- * @param inv - The investigation to search
1471
- * @param observableKey - Key of the source observable
1472
- * @param direction - Direction to filter by
1473
- * @returns Array of related observables
1474
- */
1475
- declare function getRelatedObservablesByDirection(inv: CyvestInvestigation, observableKey: string, direction: RelationshipDirection): Observable[];
1476
- /**
1477
- * Build a graph representation of all observables and their relationships.
1478
- *
1479
- * Useful for visualization libraries like vis.js, d3, or cytoscape.
1480
- *
1481
- * @param inv - The investigation
1482
- * @returns Graph with nodes and edges
1483
- *
1484
- * @example
1485
- * ```ts
1486
- * const graph = getObservableGraph(investigation);
1487
- * console.log(`Nodes: ${graph.nodes.length}, Edges: ${graph.edges.length}`);
1488
- *
1489
- * // Use with vis.js:
1490
- * const network = new vis.Network(container, {
1491
- * nodes: graph.nodes.map(n => ({ id: n.id, label: n.value })),
1492
- * edges: graph.edges.map(e => ({ from: e.source, to: e.target, label: e.type }))
1493
- * });
1494
- * ```
1495
- */
1496
- declare function getObservableGraph(inv: CyvestInvestigation): InvestigationGraph;
1497
- /**
1498
- * Find source observables in the investigation graph.
1499
- *
1500
- * Source observables are those that have no incoming relationships
1501
- * (nothing points to them as a target).
1502
- *
1503
- * @param inv - The investigation
1504
- * @returns Array of source observables
1505
- */
1506
- declare function findSourceObservables(inv: CyvestInvestigation): Observable[];
1507
- /**
1508
- * Find orphan observables (not connected to any other observable).
1509
- *
1510
- * @param inv - The investigation
1511
- * @returns Array of orphan observables
1512
- */
1513
- declare function findOrphanObservables(inv: CyvestInvestigation): Observable[];
1514
- /**
1515
- * Find leaf observables (have incoming but no outgoing relationships).
1516
- *
1517
- * @param inv - The investigation
1518
- * @returns Array of leaf observables
1519
- */
1520
- declare function findLeafObservables(inv: CyvestInvestigation): Observable[];
1521
- /**
1522
- * Check if two observables are connected (directly or transitively).
1523
- *
1524
- * @param inv - The investigation
1525
- * @param sourceKey - Starting observable key
1526
- * @param targetKey - Target observable key
1527
- * @returns True if a path exists from source to target
1528
- */
1529
- declare function areConnected(inv: CyvestInvestigation, sourceKey: string, targetKey: string): boolean;
1530
- /**
1531
- * Find the shortest path between two observables.
1532
- *
1533
- * @param inv - The investigation
1534
- * @param sourceKey - Starting observable key
1535
- * @param targetKey - Target observable key
1536
- * @returns Array of observable keys representing the path, or null if no path exists
1537
- */
1538
- declare function findPath(inv: CyvestInvestigation, sourceKey: string, targetKey: string): string[] | null;
1539
- /**
1540
- * Get all observables reachable from a starting point.
1541
- *
1542
- * @param inv - The investigation
1543
- * @param startKey - Starting observable key
1544
- * @param maxDepth - Maximum traversal depth (default: Infinity)
1545
- * @returns Array of reachable observables
1546
- */
1547
- declare function getReachableObservables(inv: CyvestInvestigation, startKey: string, maxDepth?: number): Observable[];
1548
- /**
1549
- * Get all unique relationship types used in the investigation.
1550
- *
1551
- * @param inv - The investigation
1552
- * @returns Array of unique relationship type strings
1553
- */
1554
- declare function getAllRelationshipTypes(inv: CyvestInvestigation): string[];
1555
- /**
1556
- * Count relationships by type.
1557
- *
1558
- * @param inv - The investigation
1559
- * @returns Object mapping relationship type to count
1560
- */
1561
- declare function countRelationshipsByType(inv: CyvestInvestigation): Record<string, number>;
1562
- /**
1563
- * Get all relationships for an observable.
1564
- *
1565
- * @param inv - The investigation
1566
- * @param observableKey - Observable key
1567
- * @returns Object with outbound, inbound, and all relationships
1568
- */
1569
- declare function getRelationshipsForObservable(inv: CyvestInvestigation, observableKey: string): {
1570
- outbound: Relationship[];
1571
- inbound: Array<Relationship & {
1572
- source_key: string;
1573
- }>;
1574
- all: Array<Relationship & {
1575
- source_key?: string;
1576
- }>;
1577
- };
1578
-
1579
- export { type Actor, type Aliases, type AuditEvent, type AuditLog, type CyvestInvestigation, type Data, type DataExtractionSchema, type Details, type Enrichment, type Enrichments, type Evidence, type EvidenceLink, type EvidenceLinks, type Evidences, type EvidencesBySource, type EvidencesByType, type ExternalId, type Extra, type Extra1, type Extra2, type Extra3, type Finding, type FindingLinks, type FindingLinks1, type Findings, type Findings1, type FindingsByLevel, type GraphEdge, type GraphNode, type InvestigationCounts, type InvestigationGraph, type InvestigationName, type InvestigationWhitelist, type Justification, type KeyType, LEVEL_COLORS, LEVEL_ORDER, LEVEL_VALUES, type Level, type Namespace, type Namespace1, type ObjectKey, type ObjectType, type Observable, type ObservableAlias, type ObservableLink, type ObservableLinks, type Observables, type ObservablesByLevel, type ObservablesByType, type ObservablesByTypeAndLevel, type PropagationMode, type Reason, type Relationship, type RelationshipDirection, type Relationships, type RootType, type ScoreMode, type StatisticsSchema, type Subtype, type Subtype1, type Tag, type Tags, type Taxonomies, type Taxonomy, type ThreatIntel, type ThreatIntelByLevel, type ThreatIntelBySource, type ThreatIntels, type ThreatIntels1, type Tool, type Uri, type Whitelists, areConnected, compareLevels, countRelationshipsByType, findExternalObservables, findFindingByName, findFindingsAtLeast, findFindingsByLevel, findFindingsForObservable, findFindingsForTag, findHighestScoringFindings, findHighestScoringObservables, findInternalObservables, findLeafObservables, findMaliciousFindings, findMaliciousObservables, findObservablesAtLeast, findObservablesByLevel, findObservablesByType, findObservablesByValue, findObservablesContaining, findObservablesForFinding, findObservablesMatching, findObservablesWithThreatIntel, findOrphanObservables, findPath, findSourceObservables, findSuspiciousFindings, findSuspiciousObservables, findTagsAtLeast, findTagsByLevel, findTagsByNamePattern, findThreatIntelAtLeast, findThreatIntelByLevel, findThreatIntelBySource, findThreatIntelsForObservable, findWhitelistedObservables, generateEnrichmentKey, generateFindingKey, generateObservableKey, generateTagKey, generateThreatIntelKey, getAllEnrichments, getAllEvidences, getAllFindingKeys, getAllFindings, getAllObservableTypes, getAllObservables, getAllRelationshipTypes, getAllTags, getAllThreatIntelSources, getAllThreatIntels, getColorForLevel, getColorForScore, getCounts, getDataExtraction, getEnrichment, getEnrichmentByName, getEntityLevel, getEvidence, getFinding, getFindingByName, getLevelFromScore, getObservable, getObservableByTypeValue, getObservableChildren, getObservableGraph, getObservableParents, getReachableObservables, getRelatedObservables, getRelatedObservablesByDirection, getRelatedObservablesByType, getRelationshipsForObservable, getRootObservable, getStartedAt, getStats, getTag, getTagAggregatedLevel, getTagAggregatedScore, getTagAncestors, getTagByName, getTagChildren, getTagDescendants, getThreatIntel, getThreatIntelBySourceObservable, getWhitelists, hasLevel, isCyvest, isLevelAtLeast, isLevelHigherThan, isLevelLowerThan, isTagChildOf, isTagDescendantOf, isValidLevel, maxLevel, minLevel, normalizeLevel, parseCyvest, parseFindingKey, parseKeyType, parseObservableKey, parseThreatIntelKey, sortFindingsByLevel, sortFindingsByScore, sortObservablesByLevel, sortObservablesByScore, validateKey };
724
+ //#endregion
725
+ //#region src/verdicts.d.ts
726
+ /** Ordered from most exculpatory to most inculpatory. */
727
+ export declare const VERDICT_ORDER: readonly Verdict[];
728
+ /**
729
+ * Rich style names, mirroring the Python terminal renderer.
730
+ *
731
+ * These are *not* CSS colours: a browser cannot draw `orange3`. Use {@link VERDICT_HEX_COLORS}
732
+ * for anything rendered on screen.
733
+ */
734
+ export declare const VERDICT_TERMINAL_STYLES: Record<Verdict, string>;
735
+ /** The web palette: muted enough that a wall of NOTABLE nodes stays readable. */
736
+ export declare const VERDICT_HEX_COLORS: Record<Verdict, string>;
737
+ /** Direction the judgment pushes: -1 exculpatory, 0 neutral, +1 inculpatory. */
738
+ export declare function verdictPolarity(verdict: Verdict): -1 | 0 | 1;
739
+ export declare function isValidVerdict(value: unknown): value is Verdict;
740
+ export declare function normalizeVerdict(value: unknown): Verdict;
741
+ export declare function compareVerdicts(a: Verdict, b: Verdict): number;
742
+ export declare function isVerdictAtLeast(verdict: Verdict, floor: Verdict): boolean;
743
+ export declare function maxVerdict(verdicts: readonly Verdict[]): Verdict;
744
+ export declare function minVerdict(verdicts: readonly Verdict[]): Verdict;
745
+ export declare function getColorForVerdict(verdict: Verdict): string;
746
+ /** Coarse bands for display; the engine works in floats. */
747
+ export declare function confidenceBand(confidence: number): "low" | "medium" | "high";
748
+ //#endregion
749
+ //#region src/getters.d.ts
750
+ export declare function getObservable(inv: Investigation, key: string): Observable$1 | undefined;
751
+ export declare function getAllObservables(inv: Investigation): Record<string, Observable$1>;
752
+ export declare function getRootObservable(inv: Investigation): Observable$1 | undefined;
753
+ export declare function getRelation(inv: Investigation, key: string): Relation$1 | undefined;
754
+ export declare function getAllRelations(inv: Investigation): Record<string, Relation$1>;
755
+ export declare function getThreatIntel(inv: Investigation, key: string): ThreatIntel$1 | undefined;
756
+ export declare function getAllThreatIntels(inv: Investigation): Record<string, ThreatIntel$1>;
757
+ /** Signals attached to one observable. */
758
+ export declare function getThreatIntelsFor(inv: Investigation, observableKey: string): ThreatIntel$1[];
759
+ export declare function getFinding(inv: Investigation, key: string): Finding$1 | undefined;
760
+ export declare function getAllFindings(inv: Investigation): Record<string, Finding$1>;
761
+ export declare function getEvidence(inv: Investigation, key: string): Evidence$1 | undefined;
762
+ export declare function getAllEvidences(inv: Investigation): Record<string, Evidence$1>;
763
+ /** The v6 `Enrichment` is just an evidence type; filter instead of a dedicated accessor. */
764
+ export declare function getEvidencesByType(inv: Investigation, evidenceType: string): Evidence$1[];
765
+ export declare function getDecision(inv: Investigation, key: string): Decision$1 | undefined;
766
+ export declare function getAllDecisions(inv: Investigation): Record<string, Decision$1>;
767
+ /** The single stance standing on a target — the key carries the target alone. */
768
+ export declare function getDecisionFor(inv: Investigation, targetKey: string): Decision$1 | undefined;
769
+ export declare function isAllowlisted(inv: Investigation, observableKey: string): boolean;
770
+ export declare function isBlocklisted(inv: Investigation, observableKey: string): boolean;
771
+ export declare function isConfirmed(inv: Investigation, findingKey: string): boolean;
772
+ export declare function isDismissed(inv: Investigation, findingKey: string): boolean;
773
+ /** True when a stance was withdrawn and the computed value applies again. */
774
+ export declare function isVacated(inv: Investigation, targetKey: string): boolean;
775
+ /**
776
+ * The analyst's word for a stance, rebuilt from the intent and the family of its target.
777
+ *
778
+ * The model carries one axis on purpose; the vocabulary that reads naturally carries two, and
779
+ * the display layer is the right place to pay for that.
780
+ */
781
+ export declare function decisionLabel(decision: Decision$1): string;
782
+ export declare function getTag(inv: Investigation, key: string): Tag$1 | undefined;
783
+ export declare function getTagByName(inv: Investigation, name: string): Tag$1 | undefined;
784
+ export declare function getAllTags(inv: Investigation): Record<string, Tag$1>;
785
+ export declare function getInvestigationResult(inv: Investigation): InvestigationResult$1;
786
+ export declare function getObservableResult(inv: Investigation, observableKey: string): ObservableResult$1 | undefined;
787
+ export declare function getFindingResult(inv: Investigation, findingKey: string): FindingResult$1 | undefined;
788
+ export declare function getObservableScore(inv: Investigation, observableKey: string): number;
789
+ export declare function getObservableVerdict(inv: Investigation, observableKey: string): Verdict;
790
+ export declare function getFindingScore(inv: Investigation, findingKey: string): number;
791
+ export declare function getFindingVerdict(inv: Investigation, findingKey: string): Verdict;
792
+ export declare function getGlobalScore(inv: Investigation): number;
793
+ export declare function getGlobalVerdict(inv: Investigation): Verdict;
794
+ /** True when a decision or a stronger link overrode the computed value. */
795
+ export declare function wasSuppressed(inv: Investigation, key: string): boolean;
796
+ /** Findings a tag points at, plus those of every descendant tag. */
797
+ export declare function getTagFindingKeys(inv: Investigation, tagName: string): string[];
798
+ /**
799
+ * A tag's aggregated score.
800
+ *
801
+ * This sums values the engine produced; it does not re-derive them. Uncounted findings — not
802
+ * applicable, pending or dismissed — are absent from the sum *and* from any ratio built on it.
803
+ */
804
+ export declare function getTagAggregatedScore(inv: Investigation, tagName: string): number;
805
+ export interface InvestigationCounts {
806
+ observables: number;
807
+ relations: number;
808
+ signals: number;
809
+ evidences: number;
810
+ findings: number;
811
+ evaluatedFindings: number;
812
+ decisions: number;
813
+ tags: number;
814
+ }
815
+ export declare function getCounts(inv: Investigation): InvestigationCounts;
816
+ //#endregion
817
+ //#region src/finders.d.ts
818
+ export declare function findObservablesByType(inv: Investigation, type: string): Observable$1[];
819
+ export declare function findObservablesByValue(inv: Investigation, value: string): Observable$1[];
820
+ export declare function findObservablesContaining(inv: Investigation, fragment: string): Observable$1[];
821
+ export declare function findInternalObservables(inv: Investigation): Observable$1[];
822
+ export declare function findExternalObservables(inv: Investigation): Observable$1[];
823
+ export declare function findObservablesByVerdict(inv: Investigation, verdict: Verdict): Observable$1[];
824
+ export declare function findObservablesAtLeast(inv: Investigation, floor: Verdict): Observable$1[];
825
+ export declare function findObservablesWithThreatIntel(inv: Investigation): Observable$1[];
826
+ export declare function findFindingsByVerdict(inv: Investigation, verdict: Verdict): Finding$1[];
827
+ export declare function findFindingsAtLeast(inv: Investigation, floor: Verdict): Finding$1[];
828
+ export declare function findFindingsByRule(inv: Investigation, ruleId: string): Finding$1[];
829
+ export declare function findFindingsByConfidence(inv: Investigation, band: "low" | "medium" | "high"): Finding$1[];
830
+ /** Findings excluded from the score but still worth showing, with their reason. */
831
+ export declare function findUncountedFindings(inv: Investigation): Finding$1[];
832
+ /** Findings whose own claim was outweighed by one of their observables — worth surfacing. */
833
+ export declare function findContradictedFindings(inv: Investigation): Finding$1[];
834
+ export declare function findThreatIntelBySource(inv: Investigation, source: string): ThreatIntel$1[];
835
+ export declare function findThreatIntelByVerdict(inv: Investigation, verdict: Verdict): ThreatIntel$1[];
836
+ export declare function findThreatIntelForObservable(inv: Investigation, observableKey: string): ThreatIntel$1[];
837
+ //#endregion
838
+ //#region src/graph.d.ts
839
+ export interface GraphEdge {
840
+ key: string;
841
+ source: string;
842
+ target: string;
843
+ kind: string;
844
+ confidence: number;
845
+ /** True when the edge actually carried score, per the report's contributions. */
846
+ carriedScore: boolean;
847
+ }
848
+ export interface GraphNode {
849
+ key: string;
850
+ observable: Observable$1;
851
+ score: number;
852
+ verdict: string;
853
+ }
854
+ export interface InvestigationGraph {
855
+ nodes: GraphNode[];
856
+ edges: GraphEdge[];
857
+ }
858
+ export declare function getObservableChildren(inv: Investigation, observableKey: string): Observable$1[];
859
+ export declare function getObservableParents(inv: Investigation, observableKey: string): Observable$1[];
860
+ export declare function getRelatedObservables(inv: Investigation, observableKey: string): Observable$1[];
861
+ export declare function getRelationsForObservable(inv: Investigation, observableKey: string): Relation$1[];
862
+ export declare function countRelationsByKind(inv: Investigation): Record<string, number>;
863
+ export declare function getObservableGraph(inv: Investigation): InvestigationGraph;
864
+ export declare function areConnected(inv: Investigation, a: string, b: string): boolean;
865
+ /** Undirected reachability — the same walk `finalize_relationships` uses to spot orphans. */
866
+ export declare function getReachableObservables(inv: Investigation, start: string): Set<string>;
867
+ export declare function findOrphanObservables(inv: Investigation): Observable$1[];
868
+ export declare function findLeafObservables(inv: Investigation): Observable$1[];
869
+ export declare function findSourceObservables(inv: Investigation): Observable$1[];
870
+ //#endregion
871
+ export type { Investigation };