@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.
@@ -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 };