@nano-rs/dac-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +960 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +672 -0
- package/dist/index.d.ts +672 -0
- package/dist/index.js +930 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detection schema types for NanoSIEM
|
|
3
|
+
* These types match the NanoSIEM API schema defined in nanosiem-web/src/lib/api/types.ts
|
|
4
|
+
*/
|
|
5
|
+
/** Severity levels for detection rules */
|
|
6
|
+
type Severity = 'critical' | 'high' | 'medium' | 'low' | 'informational';
|
|
7
|
+
/** Rule lifecycle mode */
|
|
8
|
+
type RuleMode = 'staging' | 'live' | 'alerting' | 'paused';
|
|
9
|
+
/** Detection execution mode */
|
|
10
|
+
type DetectionMode = 'real-time' | 'scheduled';
|
|
11
|
+
/** Alert mode for how matched events map to alerts */
|
|
12
|
+
type AlertMode = 'grouped' | 'per_event';
|
|
13
|
+
/**
|
|
14
|
+
* AI triage hints help analysts identify false positives vs true positives
|
|
15
|
+
* These hints are used by the AI triage system and displayed to analysts
|
|
16
|
+
*/
|
|
17
|
+
interface AiTriageHints {
|
|
18
|
+
/** Conditions indicating benign/expected activity (false positive indicators) */
|
|
19
|
+
ignore_when: string[];
|
|
20
|
+
/** Conditions indicating especially suspicious activity (true positive indicators) */
|
|
21
|
+
suspicious_when: string[];
|
|
22
|
+
/** Additional context about this detection for the AI and analysts */
|
|
23
|
+
context?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Case visibility levels for cases created by this rule */
|
|
26
|
+
type CaseVisibility = 'public' | 'group' | 'private';
|
|
27
|
+
/** Auto-tuning mode for detection rules */
|
|
28
|
+
type AutoTuningMode = 'off' | 'proposals' | 'auto_approve';
|
|
29
|
+
/**
|
|
30
|
+
* Auto-tuning configuration for detection rules
|
|
31
|
+
* Controls how AI-driven tuning behaves for this rule
|
|
32
|
+
*/
|
|
33
|
+
interface AutoTuningConfig {
|
|
34
|
+
/** Whether auto-tuning is enabled for this rule (default: true) */
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
/** Minimum AI confidence score required to consider a tuning proposal (0.0-1.0, default: 0.8) */
|
|
37
|
+
min_confidence?: number;
|
|
38
|
+
/** If true, prevents auto-tuning regardless of other settings (for critical rules) */
|
|
39
|
+
critical?: boolean;
|
|
40
|
+
/** How tuning proposals are handled: 'off', 'proposals' (require approval), or 'auto_approve' */
|
|
41
|
+
mode?: AutoTuningMode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* UDM field requirements for a detection rule
|
|
45
|
+
* Used for coverage analysis and validation
|
|
46
|
+
*/
|
|
47
|
+
interface RequiresConfig {
|
|
48
|
+
/** UDM fields required for this detection to work */
|
|
49
|
+
fields: string[];
|
|
50
|
+
/** Suggested source types that typically provide these fields */
|
|
51
|
+
source_types?: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Repository metadata for imported rules
|
|
55
|
+
* Set automatically during import, not user-authored
|
|
56
|
+
*/
|
|
57
|
+
interface RepositoryMetadata {
|
|
58
|
+
/** Repository slug (e.g., "sigma-hq/sigma") */
|
|
59
|
+
source: string;
|
|
60
|
+
/** Rule path within the repository */
|
|
61
|
+
rule_id: string;
|
|
62
|
+
/** Commit SHA when imported/last synced */
|
|
63
|
+
commit: string;
|
|
64
|
+
/** Whether this rule stays in sync with upstream changes */
|
|
65
|
+
linked: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* YAML frontmatter schema for detection files
|
|
69
|
+
* This is the format users write in their .yaml detection files
|
|
70
|
+
*/
|
|
71
|
+
interface DetectionFrontmatter {
|
|
72
|
+
/** Detection name/title (required) */
|
|
73
|
+
title: string;
|
|
74
|
+
/** Description of what the detection finds */
|
|
75
|
+
description?: string;
|
|
76
|
+
/** Author name or email */
|
|
77
|
+
author?: string;
|
|
78
|
+
/** Severity level */
|
|
79
|
+
severity: Severity;
|
|
80
|
+
/** Rule lifecycle mode */
|
|
81
|
+
mode: RuleMode;
|
|
82
|
+
/** Detection execution mode */
|
|
83
|
+
detection_mode: DetectionMode;
|
|
84
|
+
/** Cron schedule for scheduled detections (e.g., every minute: "* 1 * * * *") */
|
|
85
|
+
schedule?: string;
|
|
86
|
+
/** Lookback period (e.g., "15m", "1h", "24h") */
|
|
87
|
+
lookback?: string;
|
|
88
|
+
/** MITRE ATT&CK tactics (single or array, e.g., "TA0011" or ["TA0011", "TA0001"]) */
|
|
89
|
+
mitre_tactics?: string | string[];
|
|
90
|
+
/** MITRE ATT&CK techniques (single or array, e.g., "T1071" or ["T1071", "T1059.001"]) */
|
|
91
|
+
mitre_techniques?: string | string[];
|
|
92
|
+
/** Tags for categorization */
|
|
93
|
+
tags?: string[];
|
|
94
|
+
/** Reference URL for more information about the threat */
|
|
95
|
+
reference_url?: string;
|
|
96
|
+
/** Whether real-time detection is enabled (for real-time mode) */
|
|
97
|
+
realtime_enabled?: boolean;
|
|
98
|
+
/** AI triage hints for false positive identification */
|
|
99
|
+
ai_triage_hints?: AiTriageHints;
|
|
100
|
+
/** Case visibility for cases created by this rule */
|
|
101
|
+
case_visibility?: CaseVisibility;
|
|
102
|
+
/** Group slugs for case permissions (when visibility = 'group') */
|
|
103
|
+
case_groups?: string[];
|
|
104
|
+
/** Alert mode: grouped (all matches → 1 alert) or per_event (each match → 1 alert) */
|
|
105
|
+
alert_mode?: AlertMode;
|
|
106
|
+
/** Organizational folder (e.g., "identity", "endpoint", "network", "cloud") */
|
|
107
|
+
folder?: string;
|
|
108
|
+
/** Auto-tuning configuration */
|
|
109
|
+
auto_tuning?: AutoTuningConfig;
|
|
110
|
+
/** UDM field requirements */
|
|
111
|
+
requires?: RequiresConfig;
|
|
112
|
+
/**
|
|
113
|
+
* Playbook auto-attach mode for alerts produced by this rule.
|
|
114
|
+
* 'none' — no playbook (default)
|
|
115
|
+
* 'specific' — attach `playbook_id` at case-creation time
|
|
116
|
+
* 'adaptive' — let the Shadow Investigator compose on investigation wrap
|
|
117
|
+
*
|
|
118
|
+
* Prefer the `playbook:` shorthand below for new rules — this two-field
|
|
119
|
+
* form is kept so older rules keep parsing.
|
|
120
|
+
*/
|
|
121
|
+
playbook_selector_mode?: 'none' | 'specific' | 'adaptive';
|
|
122
|
+
/** Library playbook id (typeid `pb_...`) — required when `playbook_selector_mode` is 'specific' */
|
|
123
|
+
playbook_id?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Shorthand for `playbook_selector_mode` + `playbook_id`. When set, wins
|
|
126
|
+
* over the two-field form above. Encoded as:
|
|
127
|
+
* omitted / "" / "none" — mode='none'
|
|
128
|
+
* "adaptive" — Shadow Investigator composes on wrap
|
|
129
|
+
* "pb_<typeid>" — attach that specific library playbook
|
|
130
|
+
*/
|
|
131
|
+
playbook?: string;
|
|
132
|
+
/** Repository metadata (set by import, not user-authored) */
|
|
133
|
+
_repository?: RepositoryMetadata;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Complete parsed detection file
|
|
137
|
+
* Combines the frontmatter metadata with the query body
|
|
138
|
+
*/
|
|
139
|
+
interface Detection {
|
|
140
|
+
/** File path relative to detections directory */
|
|
141
|
+
filePath: string;
|
|
142
|
+
/** Parsed frontmatter metadata */
|
|
143
|
+
metadata: DetectionFrontmatter;
|
|
144
|
+
/** Query body (SPL-like query after frontmatter) */
|
|
145
|
+
query: string;
|
|
146
|
+
/** Raw file content (for diffing) */
|
|
147
|
+
raw: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Detection payload ready to send to NanoSIEM API
|
|
151
|
+
* Normalized version of Detection for API compatibility
|
|
152
|
+
*/
|
|
153
|
+
interface DetectionApiPayload {
|
|
154
|
+
/** Detection name (from title) */
|
|
155
|
+
name: string;
|
|
156
|
+
/** Description */
|
|
157
|
+
description?: string;
|
|
158
|
+
/** SPL-like query */
|
|
159
|
+
query: string;
|
|
160
|
+
/** Severity level */
|
|
161
|
+
severity: Severity;
|
|
162
|
+
/** Rule lifecycle mode */
|
|
163
|
+
mode: RuleMode;
|
|
164
|
+
/** Detection execution mode */
|
|
165
|
+
detection_mode: DetectionMode;
|
|
166
|
+
/** Cron schedule expression */
|
|
167
|
+
schedule_cron?: string;
|
|
168
|
+
/** Lookback period in minutes */
|
|
169
|
+
lookback_minutes?: number;
|
|
170
|
+
/** MITRE ATT&CK tactics (normalized to array) */
|
|
171
|
+
mitre_tactics: string[];
|
|
172
|
+
/** MITRE ATT&CK techniques (normalized to array) */
|
|
173
|
+
mitre_techniques: string[];
|
|
174
|
+
/** Tags */
|
|
175
|
+
tags: string[];
|
|
176
|
+
/** Reference URL */
|
|
177
|
+
reference_url?: string;
|
|
178
|
+
/** Author */
|
|
179
|
+
author?: string;
|
|
180
|
+
/** Real-time enabled */
|
|
181
|
+
realtime_enabled?: boolean;
|
|
182
|
+
/** AI triage hints */
|
|
183
|
+
ai_triage_hints?: AiTriageHints;
|
|
184
|
+
/** Case visibility for cases created by this rule */
|
|
185
|
+
case_visibility?: CaseVisibility;
|
|
186
|
+
/** Group IDs for case permissions (UUIDs, when case_visibility = 'group') */
|
|
187
|
+
case_group_ids?: string[];
|
|
188
|
+
/** Alert mode: grouped (all matches → 1 alert) or per_event (each match → 1 alert) */
|
|
189
|
+
alert_mode?: AlertMode;
|
|
190
|
+
/** Organizational folder (e.g., "identity", "endpoint", "network", "cloud") */
|
|
191
|
+
folder?: string;
|
|
192
|
+
/** Whether auto-tuning is enabled for this rule */
|
|
193
|
+
auto_tuning_enabled?: boolean;
|
|
194
|
+
/** Minimum AI confidence score for tuning proposals (0.0-1.0) */
|
|
195
|
+
auto_tuning_min_confidence?: number;
|
|
196
|
+
/** If true, prevents auto-tuning regardless of other settings */
|
|
197
|
+
auto_tuning_critical?: boolean;
|
|
198
|
+
/** UDM field requirements (local-only, not sent to API) */
|
|
199
|
+
requires?: RequiresConfig;
|
|
200
|
+
/** Repository source (for linked/forked rules) */
|
|
201
|
+
source_repository_slug?: string;
|
|
202
|
+
/** Rule path in source repository */
|
|
203
|
+
source_rule_path?: string;
|
|
204
|
+
/** Whether the rule is linked to upstream */
|
|
205
|
+
source_linked?: boolean;
|
|
206
|
+
/** Playbook auto-attach mode: 'none' | 'specific' | 'adaptive' */
|
|
207
|
+
playbook_selector_mode?: 'none' | 'specific' | 'adaptive';
|
|
208
|
+
/** Library playbook id when selector mode is 'specific' */
|
|
209
|
+
playbook_id?: string | null;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Detection rule returned from NanoSIEM API
|
|
213
|
+
* Includes server-generated fields like id, created_at, etc.
|
|
214
|
+
*/
|
|
215
|
+
interface DetectionRule extends DetectionApiPayload {
|
|
216
|
+
/** Unique rule ID (UUID) */
|
|
217
|
+
id: string;
|
|
218
|
+
/** Materialized view name (for real-time detections) */
|
|
219
|
+
materialized_view_name?: string;
|
|
220
|
+
/** AI-generated narrative explaining the detection */
|
|
221
|
+
narrative?: string;
|
|
222
|
+
/** Whether this rule was AI-generated */
|
|
223
|
+
ai_generated?: boolean;
|
|
224
|
+
/** Whether this rule is archived */
|
|
225
|
+
archived?: boolean;
|
|
226
|
+
/** Timestamp when rule was created */
|
|
227
|
+
created_at: string;
|
|
228
|
+
/** Timestamp when rule was last updated */
|
|
229
|
+
updated_at: string;
|
|
230
|
+
/** Timestamp when rule last ran */
|
|
231
|
+
last_run_at?: string;
|
|
232
|
+
/** Timestamp when rule last matched */
|
|
233
|
+
last_match_at?: string;
|
|
234
|
+
/** Total match count */
|
|
235
|
+
match_count: number;
|
|
236
|
+
/** Match count during live/bake-in mode */
|
|
237
|
+
live_match_count?: number;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Response from create/update operations that may include warnings
|
|
241
|
+
*/
|
|
242
|
+
interface DetectionResponse extends DetectionRule {
|
|
243
|
+
/** Warning message from backend (e.g., auto-correction from real-time to scheduled) */
|
|
244
|
+
warning?: string;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Daily match count for trend analysis
|
|
248
|
+
*/
|
|
249
|
+
interface DailyMatchCount {
|
|
250
|
+
date: string;
|
|
251
|
+
count: number;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Historical analysis result from testing a detection
|
|
255
|
+
*/
|
|
256
|
+
interface HistoricalAnalysisResult {
|
|
257
|
+
/** Rule ID (if testing existing rule) */
|
|
258
|
+
rule_id?: string;
|
|
259
|
+
/** Rule name */
|
|
260
|
+
rule_name?: string;
|
|
261
|
+
/** Time range analyzed */
|
|
262
|
+
time_range?: {
|
|
263
|
+
start: string;
|
|
264
|
+
end: string;
|
|
265
|
+
};
|
|
266
|
+
/** Total matches found */
|
|
267
|
+
total_matches: number;
|
|
268
|
+
/** Sample events from matches */
|
|
269
|
+
sample_events: Record<string, unknown>[];
|
|
270
|
+
/** Matches grouped by day */
|
|
271
|
+
matches_by_day?: DailyMatchCount[];
|
|
272
|
+
/** Execution time in milliseconds */
|
|
273
|
+
execution_time_ms?: number;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Search result from executing a query
|
|
277
|
+
*/
|
|
278
|
+
interface SearchResult {
|
|
279
|
+
/** Matching records */
|
|
280
|
+
results: Record<string, unknown>[];
|
|
281
|
+
/** Total count of matches */
|
|
282
|
+
total_count: number;
|
|
283
|
+
/** Query execution time in milliseconds */
|
|
284
|
+
execution_time_ms: number;
|
|
285
|
+
/** Generated SQL (if requested) */
|
|
286
|
+
generated_sql?: string;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Response from server-side query validation
|
|
290
|
+
*/
|
|
291
|
+
interface ValidateDetectionResponse {
|
|
292
|
+
/** Whether the query is valid */
|
|
293
|
+
valid: boolean;
|
|
294
|
+
/** The effective detection mode after auto-correction */
|
|
295
|
+
effective_mode: string;
|
|
296
|
+
/** Whether a materialized view will be created */
|
|
297
|
+
creates_materialized_view: boolean;
|
|
298
|
+
/** Explanation of mode selection */
|
|
299
|
+
mode_reason: string;
|
|
300
|
+
/** Warning about auto-correction */
|
|
301
|
+
warning?: string;
|
|
302
|
+
/** Validation errors */
|
|
303
|
+
errors: string[];
|
|
304
|
+
/** Fields referenced in the query */
|
|
305
|
+
referenced_fields: string[];
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Response from query formatting
|
|
309
|
+
*/
|
|
310
|
+
interface FormatQueryResponse {
|
|
311
|
+
formatted_query: string;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Detection match record from /rules/{id}/matches
|
|
315
|
+
*/
|
|
316
|
+
interface DetectionMatch {
|
|
317
|
+
id: string;
|
|
318
|
+
detected_at: string;
|
|
319
|
+
severity: string;
|
|
320
|
+
status: string;
|
|
321
|
+
event_count: number;
|
|
322
|
+
events: Record<string, unknown>[];
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Paginated detection matches response
|
|
326
|
+
*/
|
|
327
|
+
interface DetectionMatchesResponse {
|
|
328
|
+
total: number;
|
|
329
|
+
matches: DetectionMatch[];
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Bulk update rules request
|
|
333
|
+
*/
|
|
334
|
+
interface BulkUpdateRulesRequest {
|
|
335
|
+
rule_ids: string[];
|
|
336
|
+
mode: string;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Bulk update rules response
|
|
340
|
+
*/
|
|
341
|
+
interface BulkUpdateRulesResponse {
|
|
342
|
+
updated: number;
|
|
343
|
+
skipped: number;
|
|
344
|
+
failed: Array<{
|
|
345
|
+
rule_id: string;
|
|
346
|
+
error: string;
|
|
347
|
+
}>;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Import rules response
|
|
351
|
+
*/
|
|
352
|
+
interface ImportRulesResponse {
|
|
353
|
+
imported: number;
|
|
354
|
+
failed: number;
|
|
355
|
+
errors: string[];
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Grouped test result bucket for alert_mode=grouped
|
|
359
|
+
* Matches the in-product rule tester's bucketing behavior
|
|
360
|
+
*/
|
|
361
|
+
interface GroupedTestBucket {
|
|
362
|
+
/** Window start time (ISO 8601) */
|
|
363
|
+
window_start: string;
|
|
364
|
+
/** Window end time (ISO 8601) */
|
|
365
|
+
window_end: string;
|
|
366
|
+
/** Number of events in this bucket */
|
|
367
|
+
event_count: number;
|
|
368
|
+
/** Most frequent entity in this bucket */
|
|
369
|
+
dominant_entity: {
|
|
370
|
+
field: string;
|
|
371
|
+
value: string;
|
|
372
|
+
others_count: number;
|
|
373
|
+
} | null;
|
|
374
|
+
/** Sample events from this bucket */
|
|
375
|
+
sample_events: Record<string, unknown>[];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* YAML frontmatter parser for detection files
|
|
380
|
+
*
|
|
381
|
+
* Parses detection files in the format:
|
|
382
|
+
* ---
|
|
383
|
+
* title: detection_name
|
|
384
|
+
* severity: medium
|
|
385
|
+
* ...
|
|
386
|
+
* ---
|
|
387
|
+
* source_type=logs | where status=500
|
|
388
|
+
*/
|
|
389
|
+
|
|
390
|
+
/** Parse error types */
|
|
391
|
+
type ParseErrorType = 'frontmatter_missing' | 'frontmatter_malformed' | 'yaml_invalid' | 'query_missing';
|
|
392
|
+
/** Parse error with location information */
|
|
393
|
+
interface ParseError {
|
|
394
|
+
/** Error type */
|
|
395
|
+
type: ParseErrorType;
|
|
396
|
+
/** Human-readable error message */
|
|
397
|
+
message: string;
|
|
398
|
+
/** Line number where error occurred (1-indexed) */
|
|
399
|
+
line?: number;
|
|
400
|
+
/** Column number where error occurred (1-indexed) */
|
|
401
|
+
column?: number;
|
|
402
|
+
}
|
|
403
|
+
/** Result of parsing a detection file */
|
|
404
|
+
interface ParseResult {
|
|
405
|
+
/** Whether parsing succeeded */
|
|
406
|
+
success: boolean;
|
|
407
|
+
/** Parsed detection (if successful) */
|
|
408
|
+
detection?: Detection;
|
|
409
|
+
/** Parse errors (if any) */
|
|
410
|
+
errors: ParseError[];
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Parse a single detection file
|
|
414
|
+
*
|
|
415
|
+
* @param content - Raw file content
|
|
416
|
+
* @param filePath - Path to the file (for error reporting and Detection.filePath)
|
|
417
|
+
* @returns Parse result with detection or errors
|
|
418
|
+
*/
|
|
419
|
+
declare function parseDetectionFile(content: string, filePath: string): ParseResult;
|
|
420
|
+
/**
|
|
421
|
+
* Parse multiple detection files
|
|
422
|
+
*
|
|
423
|
+
* @param files - Array of file paths and contents
|
|
424
|
+
* @returns Map of file path to parse result
|
|
425
|
+
*/
|
|
426
|
+
declare function parseMultipleFiles(files: Array<{
|
|
427
|
+
path: string;
|
|
428
|
+
content: string;
|
|
429
|
+
}>): Map<string, ParseResult>;
|
|
430
|
+
/**
|
|
431
|
+
* Serialize a detection back to file format
|
|
432
|
+
*
|
|
433
|
+
* @param detection - Detection to serialize
|
|
434
|
+
* @returns File content as string
|
|
435
|
+
*/
|
|
436
|
+
declare function serializeDetection(detection: Detection): string;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Detection validation logic
|
|
440
|
+
*
|
|
441
|
+
* Validates detection metadata and query against schema requirements
|
|
442
|
+
*/
|
|
443
|
+
|
|
444
|
+
/** Validation error */
|
|
445
|
+
interface ValidationError {
|
|
446
|
+
/** Field that failed validation */
|
|
447
|
+
field: string;
|
|
448
|
+
/** Error message */
|
|
449
|
+
message: string;
|
|
450
|
+
/** Error code for programmatic handling */
|
|
451
|
+
code: string;
|
|
452
|
+
}
|
|
453
|
+
/** Validation warning (non-fatal issue) */
|
|
454
|
+
interface ValidationWarning {
|
|
455
|
+
/** Field with warning */
|
|
456
|
+
field: string;
|
|
457
|
+
/** Warning message */
|
|
458
|
+
message: string;
|
|
459
|
+
/** Warning code */
|
|
460
|
+
code: string;
|
|
461
|
+
}
|
|
462
|
+
/** Result of validating a detection */
|
|
463
|
+
interface ValidationResult {
|
|
464
|
+
/** Whether the detection is valid (no errors) */
|
|
465
|
+
valid: boolean;
|
|
466
|
+
/** Validation errors (fatal issues) */
|
|
467
|
+
errors: ValidationError[];
|
|
468
|
+
/** Validation warnings (non-fatal issues) */
|
|
469
|
+
warnings: ValidationWarning[];
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Validate a parsed detection
|
|
473
|
+
*
|
|
474
|
+
* @param detection - Parsed detection to validate
|
|
475
|
+
* @returns Validation result with errors and warnings
|
|
476
|
+
*/
|
|
477
|
+
declare function validateDetection(detection: Detection): ValidationResult;
|
|
478
|
+
/**
|
|
479
|
+
* Parse and convert lookback string to minutes
|
|
480
|
+
*
|
|
481
|
+
* @param lookback - Lookback string (e.g., "15m", "1h", "7d")
|
|
482
|
+
* @returns Number of minutes, or undefined if invalid
|
|
483
|
+
*/
|
|
484
|
+
declare function parseLookbackToMinutes(lookback: string): number | undefined;
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* NanoSIEM API client
|
|
488
|
+
*
|
|
489
|
+
* Handles communication with the NanoSIEM detection and search APIs
|
|
490
|
+
*/
|
|
491
|
+
|
|
492
|
+
/** Client configuration */
|
|
493
|
+
interface NanosiemClientConfig {
|
|
494
|
+
/** NanoSIEM API base URL (e.g., "https://nanosiem.example.com:3001") */
|
|
495
|
+
apiUrl: string;
|
|
496
|
+
/** Search service URL (e.g., "https://nanosiem.example.com:3002") */
|
|
497
|
+
searchUrl?: string;
|
|
498
|
+
/** API key for authentication */
|
|
499
|
+
apiKey: string;
|
|
500
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
501
|
+
timeout?: number;
|
|
502
|
+
}
|
|
503
|
+
/** API response wrapper */
|
|
504
|
+
interface ApiResponse<T> {
|
|
505
|
+
/** Whether the request succeeded */
|
|
506
|
+
success: boolean;
|
|
507
|
+
/** Response data (if successful) */
|
|
508
|
+
data?: T;
|
|
509
|
+
/** Error information (if failed) */
|
|
510
|
+
error?: {
|
|
511
|
+
code: string;
|
|
512
|
+
message: string;
|
|
513
|
+
details?: Record<string, unknown>;
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* NanoSIEM API client
|
|
518
|
+
*/
|
|
519
|
+
declare class NanosiemClient {
|
|
520
|
+
private apiUrl;
|
|
521
|
+
private searchUrl;
|
|
522
|
+
private apiKey;
|
|
523
|
+
private timeout;
|
|
524
|
+
constructor(config: NanosiemClientConfig);
|
|
525
|
+
/**
|
|
526
|
+
* Make an API request
|
|
527
|
+
*/
|
|
528
|
+
private request;
|
|
529
|
+
/**
|
|
530
|
+
* List all detection rules
|
|
531
|
+
*/
|
|
532
|
+
listDetections(): Promise<ApiResponse<DetectionRule[]>>;
|
|
533
|
+
/**
|
|
534
|
+
* Get a single detection rule by ID
|
|
535
|
+
*/
|
|
536
|
+
getDetection(id: string): Promise<ApiResponse<DetectionRule>>;
|
|
537
|
+
/**
|
|
538
|
+
* Create a new detection rule
|
|
539
|
+
*/
|
|
540
|
+
createDetection(payload: DetectionApiPayload): Promise<ApiResponse<DetectionResponse>>;
|
|
541
|
+
/**
|
|
542
|
+
* Update an existing detection rule
|
|
543
|
+
*/
|
|
544
|
+
updateDetection(id: string, payload: Partial<DetectionApiPayload>): Promise<ApiResponse<DetectionResponse>>;
|
|
545
|
+
/**
|
|
546
|
+
* Delete a detection rule
|
|
547
|
+
*/
|
|
548
|
+
deleteDetection(id: string): Promise<ApiResponse<{
|
|
549
|
+
deleted: boolean;
|
|
550
|
+
}>>;
|
|
551
|
+
/**
|
|
552
|
+
* Pause a detection rule (set mode to paused)
|
|
553
|
+
*/
|
|
554
|
+
pauseDetection(id: string): Promise<ApiResponse<DetectionRule>>;
|
|
555
|
+
/**
|
|
556
|
+
* Resume a paused detection rule (set mode back to alerting)
|
|
557
|
+
*/
|
|
558
|
+
resumeDetection(id: string): Promise<ApiResponse<DetectionRule>>;
|
|
559
|
+
/**
|
|
560
|
+
* Test a detection rule against historical data
|
|
561
|
+
*/
|
|
562
|
+
testDetection(id: string, days?: number): Promise<ApiResponse<HistoricalAnalysisResult>>;
|
|
563
|
+
/**
|
|
564
|
+
* Test a query without creating a detection
|
|
565
|
+
*/
|
|
566
|
+
testQuery(query: string, days?: number): Promise<ApiResponse<HistoricalAnalysisResult>>;
|
|
567
|
+
/**
|
|
568
|
+
* Execute a search query
|
|
569
|
+
*/
|
|
570
|
+
search(query: string, timeRange: {
|
|
571
|
+
start: string;
|
|
572
|
+
end: string;
|
|
573
|
+
}, options?: {
|
|
574
|
+
limit?: number;
|
|
575
|
+
includeSQL?: boolean;
|
|
576
|
+
}): Promise<ApiResponse<SearchResult>>;
|
|
577
|
+
/**
|
|
578
|
+
* Check API health
|
|
579
|
+
*/
|
|
580
|
+
healthCheck(): Promise<ApiResponse<{
|
|
581
|
+
status: string;
|
|
582
|
+
version?: string;
|
|
583
|
+
}>>;
|
|
584
|
+
/**
|
|
585
|
+
* Promote a rule (staging -> live -> alerting)
|
|
586
|
+
*/
|
|
587
|
+
promoteDetection(id: string): Promise<ApiResponse<DetectionRule>>;
|
|
588
|
+
/**
|
|
589
|
+
* Demote a rule (alerting -> live)
|
|
590
|
+
*/
|
|
591
|
+
demoteDetection(id: string): Promise<ApiResponse<DetectionRule>>;
|
|
592
|
+
/**
|
|
593
|
+
* Manually trigger a rule to execute now
|
|
594
|
+
*/
|
|
595
|
+
triggerDetection(id: string): Promise<ApiResponse<{
|
|
596
|
+
triggered: boolean;
|
|
597
|
+
rule_id: string;
|
|
598
|
+
}>>;
|
|
599
|
+
/**
|
|
600
|
+
* Validate a query using server-side validation
|
|
601
|
+
*/
|
|
602
|
+
validateQuery(query: string, detectionMode?: string): Promise<ApiResponse<ValidateDetectionResponse>>;
|
|
603
|
+
/**
|
|
604
|
+
* Format a query with pretty-printing
|
|
605
|
+
*/
|
|
606
|
+
formatQuery(query: string): Promise<ApiResponse<FormatQueryResponse>>;
|
|
607
|
+
/**
|
|
608
|
+
* Get detection matches for a rule
|
|
609
|
+
*/
|
|
610
|
+
getMatches(id: string, params?: {
|
|
611
|
+
limit?: number;
|
|
612
|
+
offset?: number;
|
|
613
|
+
start_time?: string;
|
|
614
|
+
end_time?: string;
|
|
615
|
+
}): Promise<ApiResponse<DetectionMatchesResponse>>;
|
|
616
|
+
/**
|
|
617
|
+
* Get detection stats (match counts by day)
|
|
618
|
+
*/
|
|
619
|
+
getStats(days?: number): Promise<ApiResponse<Record<string, unknown>>>;
|
|
620
|
+
/**
|
|
621
|
+
* Bulk update rule modes
|
|
622
|
+
*/
|
|
623
|
+
bulkUpdate(ruleIds: string[], mode: string): Promise<ApiResponse<BulkUpdateRulesResponse>>;
|
|
624
|
+
/**
|
|
625
|
+
* Import rules in bulk
|
|
626
|
+
*/
|
|
627
|
+
importRules(rules: DetectionApiPayload[]): Promise<ApiResponse<ImportRulesResponse>>;
|
|
628
|
+
/**
|
|
629
|
+
* Export all rules
|
|
630
|
+
*/
|
|
631
|
+
exportRules(): Promise<ApiResponse<DetectionRule[]>>;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Convert a parsed Detection to API payload format
|
|
635
|
+
*/
|
|
636
|
+
declare function detectionToApiPayload(detection: Detection): DetectionApiPayload;
|
|
637
|
+
/**
|
|
638
|
+
* Convert an API DetectionRule back to Detection format (for diffing)
|
|
639
|
+
*/
|
|
640
|
+
declare function detectionRuleToDetection(rule: DetectionRule, filePath: string): Detection;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Event grouping logic for alert_mode=grouped detection testing
|
|
644
|
+
*
|
|
645
|
+
* Matches the in-product rule tester's bucketing behavior:
|
|
646
|
+
* events are grouped into clock-aligned windows based on lookback_minutes,
|
|
647
|
+
* and each bucket surfaces the dominant entity.
|
|
648
|
+
*/
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Entity fields scanned in priority order for dominant entity detection.
|
|
652
|
+
* Matches the in-product rule tester's ENTITY_FIELDS list.
|
|
653
|
+
*/
|
|
654
|
+
declare const ENTITY_FIELDS_PRIORITY: readonly ["src_ip", "dest_ip", "user", "src_user", "dest_user", "src_host", "dest_host", "host", "hostname", "process_name", "file_hash", "process_hash"];
|
|
655
|
+
/**
|
|
656
|
+
* Get the dominant entity from a set of events.
|
|
657
|
+
* Scans entity fields in priority order, returns the most frequent value
|
|
658
|
+
* from the first field that has any values.
|
|
659
|
+
*/
|
|
660
|
+
declare function getDominantEntity(events: Record<string, unknown>[]): GroupedTestBucket['dominant_entity'];
|
|
661
|
+
/**
|
|
662
|
+
* Bucket events into clock-aligned time windows based on lookback minutes.
|
|
663
|
+
*
|
|
664
|
+
* Uses the same algorithm as the in-product rule tester:
|
|
665
|
+
* windowStart = Math.floor(epochMs / windowMs) * windowMs
|
|
666
|
+
*
|
|
667
|
+
* This aligns windows to clock boundaries (e.g., 14:45, 15:00, 15:15 for 15m windows)
|
|
668
|
+
* matching how the cron scheduler fires in production.
|
|
669
|
+
*/
|
|
670
|
+
declare function bucketEventsByLookback(events: Record<string, unknown>[], lookbackMinutes: number): GroupedTestBucket[];
|
|
671
|
+
|
|
672
|
+
export { type AiTriageHints, type AlertMode, type ApiResponse, type AutoTuningConfig, type AutoTuningMode, type BulkUpdateRulesRequest, type BulkUpdateRulesResponse, type CaseVisibility, type DailyMatchCount, type Detection, type DetectionApiPayload, type DetectionFrontmatter, type DetectionMatch, type DetectionMatchesResponse, type DetectionMode, type DetectionResponse, type DetectionRule, ENTITY_FIELDS_PRIORITY, type FormatQueryResponse, type GroupedTestBucket, type HistoricalAnalysisResult, type ImportRulesResponse, NanosiemClient, type NanosiemClientConfig, type ParseError, type ParseErrorType, type ParseResult, type RepositoryMetadata, type RequiresConfig, type RuleMode, type SearchResult, type Severity, type ValidateDetectionResponse, type ValidationError, type ValidationResult, type ValidationWarning, bucketEventsByLookback, detectionRuleToDetection, detectionToApiPayload, getDominantEntity, parseDetectionFile, parseLookbackToMinutes, parseMultipleFiles, serializeDetection, validateDetection };
|