@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parser/index.ts","../src/validator/index.ts","../src/client/index.ts","../src/grouping/index.ts"],"sourcesContent":["/**\n * YAML frontmatter parser for detection files\n *\n * Parses detection files in the format:\n * ---\n * title: detection_name\n * severity: medium\n * ...\n * ---\n * source_type=logs | where status=500\n */\n\nimport { parse as parseYaml } from 'yaml';\nimport type { Detection, DetectionFrontmatter } from '../schema/types.js';\n\n/** Parse error types */\nexport type ParseErrorType =\n | 'frontmatter_missing'\n | 'frontmatter_malformed'\n | 'yaml_invalid'\n | 'query_missing';\n\n/** Parse error with location information */\nexport interface ParseError {\n /** Error type */\n type: ParseErrorType;\n /** Human-readable error message */\n message: string;\n /** Line number where error occurred (1-indexed) */\n line?: number;\n /** Column number where error occurred (1-indexed) */\n column?: number;\n}\n\n/** Result of parsing a detection file */\nexport interface ParseResult {\n /** Whether parsing succeeded */\n success: boolean;\n /** Parsed detection (if successful) */\n detection?: Detection;\n /** Parse errors (if any) */\n errors: ParseError[];\n}\n\n/** Regex to match YAML frontmatter delimited by --- */\nconst FRONTMATTER_REGEX = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/;\n\n/**\n * Parse a single detection file\n *\n * @param content - Raw file content\n * @param filePath - Path to the file (for error reporting and Detection.filePath)\n * @returns Parse result with detection or errors\n */\nexport function parseDetectionFile(\n content: string,\n filePath: string\n): ParseResult {\n const errors: ParseError[] = [];\n\n // Check for frontmatter delimiters\n const match = content.match(FRONTMATTER_REGEX);\n if (!match) {\n // Try to give a more helpful error message\n if (!content.startsWith('---')) {\n return {\n success: false,\n errors: [\n {\n type: 'frontmatter_missing',\n message:\n 'Detection file must start with YAML frontmatter delimited by ---',\n line: 1,\n },\n ],\n };\n }\n\n // Has opening --- but missing closing ---\n const closingIndex = content.indexOf('\\n---', 4);\n if (closingIndex === -1) {\n return {\n success: false,\n errors: [\n {\n type: 'frontmatter_malformed',\n message: 'Missing closing --- delimiter for frontmatter',\n line: 1,\n },\n ],\n };\n }\n\n return {\n success: false,\n errors: [\n {\n type: 'frontmatter_malformed',\n message:\n 'Invalid frontmatter format. Expected: ---\\\\n<yaml>\\\\n---\\\\n<query>',\n },\n ],\n };\n }\n\n const [, yamlContent, queryContent] = match;\n\n // Parse YAML\n let metadata: DetectionFrontmatter;\n try {\n const parsed = parseYaml(yamlContent);\n if (typeof parsed !== 'object' || parsed === null) {\n return {\n success: false,\n errors: [\n {\n type: 'yaml_invalid',\n message: 'Frontmatter must be a YAML object',\n },\n ],\n };\n }\n metadata = parsed as DetectionFrontmatter;\n } catch (e) {\n const yamlError = e as Error & { linePos?: [{ line: number; col: number }] };\n const line = yamlError.linePos?.[0]?.line;\n const col = yamlError.linePos?.[0]?.col;\n\n return {\n success: false,\n errors: [\n {\n type: 'yaml_invalid',\n message: `Invalid YAML: ${yamlError.message}`,\n line: line ? line + 1 : undefined, // +1 for the opening ---\n column: col,\n },\n ],\n };\n }\n\n // Normalize arrays - allow single string or array for mitre fields\n if (typeof metadata.mitre_tactics === 'string') {\n metadata.mitre_tactics = [metadata.mitre_tactics];\n }\n if (typeof metadata.mitre_techniques === 'string') {\n metadata.mitre_techniques = [metadata.mitre_techniques];\n }\n\n // Normalize tags\n if (typeof metadata.tags === 'string') {\n metadata.tags = [metadata.tags];\n }\n\n // Check for query\n const query = queryContent.trim();\n if (!query) {\n return {\n success: false,\n errors: [\n {\n type: 'query_missing',\n message: 'Detection file must include a query after the frontmatter',\n },\n ],\n };\n }\n\n return {\n success: true,\n detection: {\n filePath,\n metadata,\n query,\n raw: content,\n },\n errors,\n };\n}\n\n/**\n * Parse multiple detection files\n *\n * @param files - Array of file paths and contents\n * @returns Map of file path to parse result\n */\nexport function parseMultipleFiles(\n files: Array<{ path: string; content: string }>\n): Map<string, ParseResult> {\n const results = new Map<string, ParseResult>();\n for (const file of files) {\n results.set(file.path, parseDetectionFile(file.content, file.path));\n }\n return results;\n}\n\n/**\n * Serialize a detection back to file format\n *\n * @param detection - Detection to serialize\n * @returns File content as string\n */\nexport function serializeDetection(detection: Detection): string {\n const { stringify } = require('yaml') as { stringify: (obj: unknown) => string };\n const yaml = stringify(detection.metadata);\n return `---\\n${yaml}---\\n${detection.query}\\n`;\n}\n","/**\n * Detection validation logic\n *\n * Validates detection metadata and query against schema requirements\n */\n\nimport type { Detection, DetectionFrontmatter } from '../schema/types.js';\n\n/** Validation error */\nexport interface ValidationError {\n /** Field that failed validation */\n field: string;\n /** Error message */\n message: string;\n /** Error code for programmatic handling */\n code: string;\n}\n\n/** Validation warning (non-fatal issue) */\nexport interface ValidationWarning {\n /** Field with warning */\n field: string;\n /** Warning message */\n message: string;\n /** Warning code */\n code: string;\n}\n\n/** Result of validating a detection */\nexport interface ValidationResult {\n /** Whether the detection is valid (no errors) */\n valid: boolean;\n /** Validation errors (fatal issues) */\n errors: ValidationError[];\n /** Validation warnings (non-fatal issues) */\n warnings: ValidationWarning[];\n}\n\n// Valid values for enums\nconst VALID_SEVERITIES = [\n 'critical',\n 'high',\n 'medium',\n 'low',\n 'informational',\n] as const;\nconst VALID_MODES = ['staging', 'live', 'alerting', 'paused'] as const;\nconst VALID_DETECTION_MODES = ['real-time', 'scheduled'] as const;\nconst VALID_CASE_VISIBILITIES = ['public', 'group', 'private'] as const;\nconst VALID_ALERT_MODES = ['grouped', 'per_event'] as const;\nconst VALID_AUTO_TUNING_MODES = ['off', 'proposals', 'auto_approve'] as const;\n\n// Regex patterns for validation\n// Cron field pattern: *, number, */n, range (n-m), list (n,m), or combinations\nconst CRON_FIELD = '(\\\\*|\\\\*\\\\/\\\\d+|\\\\d+|\\\\d+-\\\\d+|[\\\\d,\\\\-\\\\/\\\\*]+)';\nconst CRON_5_FIELD = new RegExp(\n `^${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}$`\n);\nconst CRON_6_FIELD = new RegExp(\n `^${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}\\\\s+${CRON_FIELD}$`\n);\nconst LOOKBACK_REGEX = /^(\\d+)(s|m|h|d)$/;\nconst MITRE_TACTIC_REGEX = /^TA\\d{4}$/;\nconst MITRE_TECHNIQUE_REGEX = /^T\\d{4}(\\.\\d{3})?$/;\n\n/**\n * Validate a parsed detection\n *\n * @param detection - Parsed detection to validate\n * @returns Validation result with errors and warnings\n */\nexport function validateDetection(detection: Detection): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n const { metadata, query } = detection;\n\n // Required fields\n validateRequired(metadata, errors);\n\n // Enum values\n validateEnums(metadata, errors, warnings);\n\n // Schedule validation\n validateSchedule(metadata, errors, warnings);\n\n // Lookback validation\n validateLookback(metadata, errors);\n\n // MITRE ATT&CK validation\n validateMitre(metadata, warnings);\n\n // AI triage hints validation\n validateAiTriageHints(metadata, warnings);\n\n // Folder validation\n validateFolder(metadata, errors);\n\n // Case visibility validation\n validateCaseVisibility(metadata, errors);\n\n // Auto-tuning validation\n validateAutoTuning(metadata, errors);\n\n // Requires validation\n validateRequires(metadata, warnings);\n\n // Query validation (basic)\n validateQuery(query, errors, warnings);\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nfunction validateRequired(\n metadata: DetectionFrontmatter,\n errors: ValidationError[]\n): void {\n if (!metadata.title || metadata.title.trim() === '') {\n errors.push({\n field: 'title',\n message: 'Title is required',\n code: 'REQUIRED_FIELD',\n });\n }\n\n if (!metadata.severity) {\n errors.push({\n field: 'severity',\n message: 'Severity is required',\n code: 'REQUIRED_FIELD',\n });\n }\n\n if (!metadata.mode) {\n errors.push({\n field: 'mode',\n message: 'Mode is required',\n code: 'REQUIRED_FIELD',\n });\n }\n\n if (!metadata.detection_mode) {\n errors.push({\n field: 'detection_mode',\n message: 'Detection mode is required',\n code: 'REQUIRED_FIELD',\n });\n }\n}\n\nfunction validateEnums(\n metadata: DetectionFrontmatter,\n errors: ValidationError[],\n warnings: ValidationWarning[]\n): void {\n if (\n metadata.severity &&\n !VALID_SEVERITIES.includes(metadata.severity as (typeof VALID_SEVERITIES)[number])\n ) {\n errors.push({\n field: 'severity',\n message: `Invalid severity: \"${metadata.severity}\". Must be one of: ${VALID_SEVERITIES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n if (\n metadata.mode &&\n !VALID_MODES.includes(metadata.mode as (typeof VALID_MODES)[number])\n ) {\n errors.push({\n field: 'mode',\n message: `Invalid mode: \"${metadata.mode}\". Must be one of: ${VALID_MODES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n if (\n metadata.detection_mode &&\n !VALID_DETECTION_MODES.includes(\n metadata.detection_mode as (typeof VALID_DETECTION_MODES)[number]\n )\n ) {\n errors.push({\n field: 'detection_mode',\n message: `Invalid detection_mode: \"${metadata.detection_mode}\". Must be one of: ${VALID_DETECTION_MODES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n if (\n metadata.alert_mode &&\n !VALID_ALERT_MODES.includes(\n metadata.alert_mode as (typeof VALID_ALERT_MODES)[number]\n )\n ) {\n errors.push({\n field: 'alert_mode',\n message: `Invalid alert_mode: \"${metadata.alert_mode}\". Must be one of: ${VALID_ALERT_MODES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n if (\n metadata.alert_mode === 'per_event' &&\n metadata.detection_mode === 'real-time'\n ) {\n warnings.push({\n field: 'alert_mode',\n message:\n 'per_event alert_mode with real-time detection_mode is redundant — real-time rules already process events individually',\n code: 'REDUNDANT_CONFIG',\n });\n }\n}\n\nfunction validateSchedule(\n metadata: DetectionFrontmatter,\n errors: ValidationError[],\n warnings: ValidationWarning[]\n): void {\n if (metadata.detection_mode === 'scheduled') {\n if (!metadata.schedule) {\n warnings.push({\n field: 'schedule',\n message:\n 'No schedule specified for scheduled detection. Will use default (every minute)',\n code: 'MISSING_OPTIONAL',\n });\n } else {\n // Validate cron expression (5 or 6 field)\n const isCron5 = CRON_5_FIELD.test(metadata.schedule);\n const isCron6 = CRON_6_FIELD.test(metadata.schedule);\n\n if (!isCron5 && !isCron6) {\n errors.push({\n field: 'schedule',\n message: `Invalid cron expression: \"${metadata.schedule}\". Expected 5 or 6 field cron format`,\n code: 'INVALID_CRON',\n });\n }\n }\n }\n}\n\nfunction validateLookback(\n metadata: DetectionFrontmatter,\n errors: ValidationError[]\n): void {\n if (metadata.lookback && !LOOKBACK_REGEX.test(metadata.lookback)) {\n errors.push({\n field: 'lookback',\n message: `Invalid lookback format: \"${metadata.lookback}\". Expected format like \"15m\", \"1h\", \"24h\", \"7d\"`,\n code: 'INVALID_FORMAT',\n });\n }\n}\n\nfunction validateMitre(\n metadata: DetectionFrontmatter,\n warnings: ValidationWarning[]\n): void {\n const tactics = Array.isArray(metadata.mitre_tactics)\n ? metadata.mitre_tactics\n : metadata.mitre_tactics\n ? [metadata.mitre_tactics]\n : [];\n\n const techniques = Array.isArray(metadata.mitre_techniques)\n ? metadata.mitre_techniques\n : metadata.mitre_techniques\n ? [metadata.mitre_techniques]\n : [];\n\n // Check for missing MITRE mappings\n if (tactics.length === 0 && techniques.length === 0) {\n warnings.push({\n field: 'mitre',\n message: 'No MITRE ATT&CK mappings specified',\n code: 'MISSING_MITRE',\n });\n }\n\n // Validate tactic format\n for (const tactic of tactics) {\n if (!MITRE_TACTIC_REGEX.test(tactic)) {\n warnings.push({\n field: 'mitre_tactics',\n message: `Non-standard tactic format: \"${tactic}\" (expected TAxxxx)`,\n code: 'INVALID_MITRE_FORMAT',\n });\n }\n }\n\n // Validate technique format\n for (const technique of techniques) {\n if (!MITRE_TECHNIQUE_REGEX.test(technique)) {\n warnings.push({\n field: 'mitre_techniques',\n message: `Non-standard technique format: \"${technique}\" (expected Txxxx or Txxxx.xxx)`,\n code: 'INVALID_MITRE_FORMAT',\n });\n }\n }\n}\n\nfunction validateAiTriageHints(\n metadata: DetectionFrontmatter,\n warnings: ValidationWarning[]\n): void {\n const hints = metadata.ai_triage_hints;\n if (!hints) return;\n\n // Check for empty arrays\n if (hints.ignore_when && hints.ignore_when.length === 0) {\n warnings.push({\n field: 'ai_triage_hints.ignore_when',\n message: 'ignore_when array is empty. Consider adding benign conditions or removing the field',\n code: 'EMPTY_ARRAY',\n });\n }\n\n if (hints.suspicious_when && hints.suspicious_when.length === 0) {\n warnings.push({\n field: 'ai_triage_hints.suspicious_when',\n message: 'suspicious_when array is empty. Consider adding suspicious conditions or removing the field',\n code: 'EMPTY_ARRAY',\n });\n }\n\n // Check for very long hints (may be too verbose)\n const allHints = [...(hints.ignore_when || []), ...(hints.suspicious_when || [])];\n for (const hint of allHints) {\n if (hint.length > 200) {\n warnings.push({\n field: 'ai_triage_hints',\n message: `Hint is very long (${hint.length} chars). Consider being more concise`,\n code: 'HINT_TOO_LONG',\n });\n break; // Only warn once\n }\n }\n}\n\nconst FOLDER_REGEX = /^[a-z0-9][a-z0-9_-]{0,49}$/;\n\nfunction validateFolder(\n metadata: DetectionFrontmatter,\n errors: ValidationError[]\n): void {\n if (metadata.folder === undefined) return;\n if (!FOLDER_REGEX.test(metadata.folder)) {\n errors.push({\n field: 'folder',\n message: `Invalid folder: \"${metadata.folder}\". Must be lowercase alphanumeric with hyphens/underscores, max 50 chars`,\n code: 'INVALID_FORMAT',\n });\n }\n}\n\nfunction validateCaseVisibility(\n metadata: DetectionFrontmatter,\n errors: ValidationError[]\n): void {\n if (metadata.case_visibility) {\n if (\n !VALID_CASE_VISIBILITIES.includes(\n metadata.case_visibility as (typeof VALID_CASE_VISIBILITIES)[number]\n )\n ) {\n errors.push({\n field: 'case_visibility',\n message: `Invalid case_visibility: \"${metadata.case_visibility}\". Must be one of: ${VALID_CASE_VISIBILITIES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n // case_groups is required when visibility is 'group'\n if (metadata.case_visibility === 'group') {\n if (!metadata.case_groups || metadata.case_groups.length === 0) {\n errors.push({\n field: 'case_groups',\n message: 'case_groups is required when case_visibility is \"group\"',\n code: 'REQUIRED_FIELD',\n });\n }\n }\n }\n\n // Validate case_groups format (slugs or UUIDs)\n if (metadata.case_groups) {\n const SLUG_REGEX = /^[a-z0-9-]+$/;\n const UUID_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n for (const group of metadata.case_groups) {\n if (!SLUG_REGEX.test(group) && !UUID_REGEX.test(group)) {\n errors.push({\n field: 'case_groups',\n message: `Invalid group identifier: \"${group}\". Must be lowercase slug or UUID`,\n code: 'INVALID_FORMAT',\n });\n }\n }\n }\n}\n\nfunction validateAutoTuning(\n metadata: DetectionFrontmatter,\n errors: ValidationError[]\n): void {\n const autoTuning = metadata.auto_tuning;\n if (!autoTuning) return;\n\n // Validate mode enum\n if (\n autoTuning.mode &&\n !VALID_AUTO_TUNING_MODES.includes(\n autoTuning.mode as (typeof VALID_AUTO_TUNING_MODES)[number]\n )\n ) {\n errors.push({\n field: 'auto_tuning.mode',\n message: `Invalid auto_tuning mode: \"${autoTuning.mode}\". Must be one of: ${VALID_AUTO_TUNING_MODES.join(', ')}`,\n code: 'INVALID_ENUM',\n });\n }\n\n // Validate min_confidence range\n if (autoTuning.min_confidence !== undefined) {\n if (\n typeof autoTuning.min_confidence !== 'number' ||\n autoTuning.min_confidence < 0 ||\n autoTuning.min_confidence > 1\n ) {\n errors.push({\n field: 'auto_tuning.min_confidence',\n message: `min_confidence must be a number between 0.0 and 1.0. Got: ${autoTuning.min_confidence}`,\n code: 'OUT_OF_RANGE',\n });\n }\n }\n\n // Validate boolean fields\n if (autoTuning.enabled !== undefined && typeof autoTuning.enabled !== 'boolean') {\n errors.push({\n field: 'auto_tuning.enabled',\n message: 'auto_tuning.enabled must be a boolean',\n code: 'INVALID_TYPE',\n });\n }\n\n if (autoTuning.critical !== undefined && typeof autoTuning.critical !== 'boolean') {\n errors.push({\n field: 'auto_tuning.critical',\n message: 'auto_tuning.critical must be a boolean',\n code: 'INVALID_TYPE',\n });\n }\n}\n\nfunction validateRequires(\n metadata: DetectionFrontmatter,\n warnings: ValidationWarning[]\n): void {\n const requires = metadata.requires;\n if (!requires) return;\n\n // Check that fields array exists and is not empty\n if (!requires.fields || requires.fields.length === 0) {\n warnings.push({\n field: 'requires.fields',\n message: 'requires.fields is empty. Consider specifying required UDM fields',\n code: 'EMPTY_ARRAY',\n });\n }\n\n // Validate field names are valid UDM fields (basic check - lowercase with underscores)\n const FIELD_REGEX = /^[a-z][a-z0-9_]*$/;\n if (requires.fields) {\n for (const field of requires.fields) {\n if (!FIELD_REGEX.test(field)) {\n warnings.push({\n field: 'requires.fields',\n message: `Potentially invalid UDM field name: \"${field}\". Expected lowercase with underscores`,\n code: 'INVALID_FORMAT',\n });\n }\n }\n }\n\n // Validate source_types if provided\n if (requires.source_types) {\n for (const sourceType of requires.source_types) {\n if (!FIELD_REGEX.test(sourceType.toLowerCase())) {\n warnings.push({\n field: 'requires.source_types',\n message: `Potentially invalid source_type: \"${sourceType}\"`,\n code: 'INVALID_FORMAT',\n });\n }\n }\n }\n}\n\nfunction validateQuery(\n query: string,\n errors: ValidationError[],\n warnings: ValidationWarning[]\n): void {\n if (!query || query.trim() === '') {\n errors.push({\n field: 'query',\n message: 'Query body is required',\n code: 'REQUIRED_FIELD',\n });\n return;\n }\n\n // Basic query validation - check for common issues\n const trimmed = query.trim();\n\n // Warn if query doesn't start with a source filter\n if (!trimmed.startsWith('source_type=') && !trimmed.startsWith('*')) {\n warnings.push({\n field: 'query',\n message: 'Query should typically start with source_type= filter or *',\n code: 'QUERY_NO_SOURCE',\n });\n }\n\n // Check for unclosed quotes\n const singleQuotes = (trimmed.match(/'/g) || []).length;\n const doubleQuotes = (trimmed.match(/\"/g) || []).length;\n\n if (singleQuotes % 2 !== 0) {\n errors.push({\n field: 'query',\n message: 'Unclosed single quote in query',\n code: 'UNCLOSED_QUOTE',\n });\n }\n\n if (doubleQuotes % 2 !== 0) {\n errors.push({\n field: 'query',\n message: 'Unclosed double quote in query',\n code: 'UNCLOSED_QUOTE',\n });\n }\n}\n\n/**\n * Parse and convert lookback string to minutes\n *\n * @param lookback - Lookback string (e.g., \"15m\", \"1h\", \"7d\")\n * @returns Number of minutes, or undefined if invalid\n */\nexport function parseLookbackToMinutes(lookback: string): number | undefined {\n const match = lookback.match(LOOKBACK_REGEX);\n if (!match) return undefined;\n\n const value = parseInt(match[1], 10);\n const unit = match[2];\n\n switch (unit) {\n case 's':\n return Math.ceil(value / 60);\n case 'm':\n return value;\n case 'h':\n return value * 60;\n case 'd':\n return value * 60 * 24;\n default:\n return undefined;\n }\n}\n","/**\n * NanoSIEM API client\n *\n * Handles communication with the NanoSIEM detection and search APIs\n */\n\nimport type {\n Detection,\n DetectionApiPayload,\n DetectionFrontmatter,\n DetectionRule,\n DetectionResponse,\n HistoricalAnalysisResult,\n SearchResult,\n ValidateDetectionResponse,\n FormatQueryResponse,\n DetectionMatchesResponse,\n BulkUpdateRulesResponse,\n ImportRulesResponse,\n} from '../schema/types.js';\nimport { parseLookbackToMinutes } from '../validator/index.js';\n\n/** Client configuration */\nexport interface NanosiemClientConfig {\n /** NanoSIEM API base URL (e.g., \"https://nanosiem.example.com:3001\") */\n apiUrl: string;\n /** Search service URL (e.g., \"https://nanosiem.example.com:3002\") */\n searchUrl?: string;\n /** API key for authentication */\n apiKey: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n}\n\n/** API response wrapper */\nexport interface ApiResponse<T> {\n /** Whether the request succeeded */\n success: boolean;\n /** Response data (if successful) */\n data?: T;\n /** Error information (if failed) */\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n };\n}\n\n/**\n * NanoSIEM API client\n */\nexport class NanosiemClient {\n private apiUrl: string;\n private searchUrl: string;\n private apiKey: string;\n private timeout: number;\n\n constructor(config: NanosiemClientConfig) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.searchUrl = config.searchUrl?.replace(/\\/$/, '') || this.apiUrl;\n this.apiKey = config.apiKey;\n this.timeout = config.timeout ?? 30000;\n }\n\n /**\n * Make an API request\n */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n useSearchUrl = false\n ): Promise<ApiResponse<T>> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const baseUrl = useSearchUrl ? this.searchUrl : this.apiUrl;\n\n try {\n const response = await fetch(`${baseUrl}${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({}));\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message:\n (errorBody as { error?: { message?: string } }).error?.message ||\n (errorBody as { message?: string }).message ||\n response.statusText,\n details: errorBody as Record<string, unknown>,\n },\n };\n }\n\n const data = (await response.json()) as T;\n return { success: true, data };\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof Error && error.name === 'AbortError') {\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Unknown error',\n },\n };\n }\n }\n\n // ==================== Detection Endpoints ====================\n\n /**\n * List all detection rules\n */\n async listDetections(): Promise<ApiResponse<DetectionRule[]>> {\n return this.request<DetectionRule[]>('GET', '/api/rules');\n }\n\n /**\n * Get a single detection rule by ID\n */\n async getDetection(id: string): Promise<ApiResponse<DetectionRule>> {\n return this.request<DetectionRule>('GET', `/api/rules/${id}`);\n }\n\n /**\n * Create a new detection rule\n */\n async createDetection(\n payload: DetectionApiPayload\n ): Promise<ApiResponse<DetectionResponse>> {\n return this.request<DetectionResponse>('POST', '/api/rules', payload);\n }\n\n /**\n * Update an existing detection rule\n */\n async updateDetection(\n id: string,\n payload: Partial<DetectionApiPayload>\n ): Promise<ApiResponse<DetectionResponse>> {\n return this.request<DetectionResponse>(\n 'PUT',\n `/api/rules/${id}`,\n payload\n );\n }\n\n /**\n * Delete a detection rule\n */\n async deleteDetection(\n id: string\n ): Promise<ApiResponse<{ deleted: boolean }>> {\n return this.request<{ deleted: boolean }>(\n 'DELETE',\n `/api/rules/${id}`\n );\n }\n\n /**\n * Pause a detection rule (set mode to paused)\n */\n async pauseDetection(id: string): Promise<ApiResponse<DetectionRule>> {\n return this.request<DetectionRule>('POST', `/api/rules/${id}/pause`);\n }\n\n /**\n * Resume a paused detection rule (set mode back to alerting)\n */\n async resumeDetection(id: string): Promise<ApiResponse<DetectionRule>> {\n return this.request<DetectionRule>('POST', `/api/rules/${id}/resume`);\n }\n\n /**\n * Test a detection rule against historical data\n */\n async testDetection(\n id: string,\n days?: number\n ): Promise<ApiResponse<HistoricalAnalysisResult>> {\n return this.request<HistoricalAnalysisResult>(\n 'POST',\n `/api/rules/${id}/test`,\n { days: days ?? 7 }\n );\n }\n\n /**\n * Test a query without creating a detection\n */\n async testQuery(\n query: string,\n days?: number\n ): Promise<ApiResponse<HistoricalAnalysisResult>> {\n return this.request<HistoricalAnalysisResult>(\n 'POST',\n '/api/rules/test',\n { query, days: days ?? 7 }\n );\n }\n\n // ==================== Search Endpoints ====================\n\n /**\n * Execute a search query\n */\n async search(\n query: string,\n timeRange: { start: string; end: string },\n options?: { limit?: number; includeSQL?: boolean }\n ): Promise<ApiResponse<SearchResult>> {\n return this.request<SearchResult>(\n 'POST',\n '/api/search',\n {\n query,\n time_range: timeRange,\n limit: options?.limit,\n include_sql: options?.includeSQL,\n },\n true // Use search URL\n );\n }\n\n // ==================== Health Check ====================\n\n /**\n * Check API health\n */\n async healthCheck(): Promise<\n ApiResponse<{ status: string; version?: string }>\n > {\n return this.request<{ status: string; version?: string }>('GET', '/health');\n }\n\n // ==================== Rule Lifecycle ====================\n\n /**\n * Promote a rule (staging -> live -> alerting)\n */\n async promoteDetection(id: string): Promise<ApiResponse<DetectionRule>> {\n return this.request<DetectionRule>('POST', `/api/rules/${id}/promote`);\n }\n\n /**\n * Demote a rule (alerting -> live)\n */\n async demoteDetection(id: string): Promise<ApiResponse<DetectionRule>> {\n return this.request<DetectionRule>('POST', `/api/rules/${id}/demote`);\n }\n\n /**\n * Manually trigger a rule to execute now\n */\n async triggerDetection(\n id: string\n ): Promise<ApiResponse<{ triggered: boolean; rule_id: string }>> {\n return this.request<{ triggered: boolean; rule_id: string }>(\n 'POST',\n `/api/rules/${id}/trigger`\n );\n }\n\n // ==================== Query Tools ====================\n\n /**\n * Validate a query using server-side validation\n */\n async validateQuery(\n query: string,\n detectionMode?: string\n ): Promise<ApiResponse<ValidateDetectionResponse>> {\n return this.request<ValidateDetectionResponse>('POST', '/api/rules/validate', {\n query,\n detection_mode: detectionMode,\n });\n }\n\n /**\n * Format a query with pretty-printing\n */\n async formatQuery(query: string): Promise<ApiResponse<FormatQueryResponse>> {\n return this.request<FormatQueryResponse>('POST', '/api/rules/format', {\n query,\n });\n }\n\n // ==================== Matches & Stats ====================\n\n /**\n * Get detection matches for a rule\n */\n async getMatches(\n id: string,\n params?: { limit?: number; offset?: number; start_time?: string; end_time?: string }\n ): Promise<ApiResponse<DetectionMatchesResponse>> {\n const query = new URLSearchParams();\n if (params?.limit) query.set('limit', String(params.limit));\n if (params?.offset) query.set('offset', String(params.offset));\n if (params?.start_time) query.set('start_time', params.start_time);\n if (params?.end_time) query.set('end_time', params.end_time);\n const qs = query.toString();\n return this.request<DetectionMatchesResponse>(\n 'GET',\n `/api/rules/${id}/matches${qs ? `?${qs}` : ''}`\n );\n }\n\n /**\n * Get detection stats (match counts by day)\n */\n async getStats(\n days?: number\n ): Promise<ApiResponse<Record<string, unknown>>> {\n const qs = days ? `?days=${days}` : '';\n return this.request<Record<string, unknown>>('GET', `/api/rules/stats${qs}`);\n }\n\n // ==================== Bulk Operations ====================\n\n /**\n * Bulk update rule modes\n */\n async bulkUpdate(\n ruleIds: string[],\n mode: string\n ): Promise<ApiResponse<BulkUpdateRulesResponse>> {\n return this.request<BulkUpdateRulesResponse>('POST', '/api/rules/bulk-update', {\n rule_ids: ruleIds,\n mode,\n });\n }\n\n /**\n * Import rules in bulk\n */\n async importRules(\n rules: DetectionApiPayload[]\n ): Promise<ApiResponse<ImportRulesResponse>> {\n return this.request<ImportRulesResponse>('POST', '/api/rules/import', {\n rules,\n });\n }\n\n /**\n * Export all rules\n */\n async exportRules(): Promise<ApiResponse<DetectionRule[]>> {\n return this.request<DetectionRule[]>('GET', '/api/rules/export');\n }\n\n}\n\n// ==================== Conversion Utilities ====================\n\n/**\n * Convert a parsed Detection to API payload format\n */\nexport function detectionToApiPayload(detection: Detection): DetectionApiPayload {\n const { metadata, query } = detection;\n\n // Parse lookback to minutes\n let lookbackMinutes: number | undefined;\n if (metadata.lookback) {\n lookbackMinutes = parseLookbackToMinutes(metadata.lookback);\n }\n\n // Normalize arrays\n const mitreTactics = Array.isArray(metadata.mitre_tactics)\n ? metadata.mitre_tactics\n : metadata.mitre_tactics\n ? [metadata.mitre_tactics]\n : [];\n\n const mitreTechniques = Array.isArray(metadata.mitre_techniques)\n ? metadata.mitre_techniques\n : metadata.mitre_techniques\n ? [metadata.mitre_techniques]\n : [];\n\n return {\n name: metadata.title,\n description: metadata.description,\n query,\n severity: metadata.severity,\n mode: metadata.mode,\n detection_mode: metadata.detection_mode,\n schedule_cron: metadata.schedule,\n lookback_minutes: lookbackMinutes,\n mitre_tactics: mitreTactics,\n mitre_techniques: mitreTechniques,\n tags: metadata.tags ?? [],\n reference_url: metadata.reference_url,\n author: metadata.author,\n realtime_enabled: metadata.realtime_enabled,\n ai_triage_hints: metadata.ai_triage_hints,\n alert_mode: metadata.alert_mode,\n folder: metadata.folder,\n case_visibility: metadata.case_visibility,\n case_group_ids: metadata.case_groups,\n // Flatten auto_tuning for API (server expects flat fields)\n auto_tuning_enabled: metadata.auto_tuning?.enabled,\n auto_tuning_min_confidence: metadata.auto_tuning?.min_confidence,\n auto_tuning_critical: metadata.auto_tuning?.critical,\n // Playbook auto-attach at firing time. Server enforces that\n // playbook_id is set iff selector_mode is 'specific'. Accepts either\n // the two-field form (`playbook_selector_mode` + `playbook_id`) or the\n // NAN-453 shorthand (`playbook:`). Shorthand wins when both are set.\n ...decodePlaybook(metadata),\n };\n}\n\nfunction decodePlaybook(metadata: DetectionFrontmatter): {\n playbook_selector_mode: 'none' | 'specific' | 'adaptive' | undefined;\n playbook_id: string | null;\n} {\n const shorthand = metadata.playbook?.trim();\n if (shorthand !== undefined) {\n if (shorthand === '' || shorthand === 'none') {\n return { playbook_selector_mode: 'none', playbook_id: null };\n }\n if (shorthand === 'adaptive') {\n return { playbook_selector_mode: 'adaptive', playbook_id: null };\n }\n if (/^pb_[0-9a-z]+$/i.test(shorthand)) {\n return { playbook_selector_mode: 'specific', playbook_id: shorthand };\n }\n // Unrecognised — fall through to two-field form below. Don't throw;\n // sync-time errors are opaque. The server will reject if it's garbage.\n }\n return {\n playbook_selector_mode: metadata.playbook_selector_mode,\n playbook_id:\n metadata.playbook_selector_mode === 'specific'\n ? (metadata.playbook_id ?? null)\n : null,\n };\n}\n\n/**\n * Convert an API DetectionRule back to Detection format (for diffing)\n */\nexport function detectionRuleToDetection(\n rule: DetectionRule,\n filePath: string\n): Detection {\n // Convert lookback_minutes back to string format\n let lookback: string | undefined;\n if (rule.lookback_minutes) {\n if (rule.lookback_minutes >= 1440 && rule.lookback_minutes % 1440 === 0) {\n lookback = `${rule.lookback_minutes / 1440}d`;\n } else if (rule.lookback_minutes >= 60 && rule.lookback_minutes % 60 === 0) {\n lookback = `${rule.lookback_minutes / 60}h`;\n } else {\n lookback = `${rule.lookback_minutes}m`;\n }\n }\n\n const metadata = {\n title: rule.name,\n description: rule.description,\n author: rule.author,\n severity: rule.severity,\n mode: rule.mode,\n detection_mode: rule.detection_mode,\n schedule: rule.schedule_cron,\n lookback,\n mitre_tactics: rule.mitre_tactics,\n mitre_techniques: rule.mitre_techniques,\n tags: rule.tags,\n reference_url: rule.reference_url,\n realtime_enabled: rule.realtime_enabled,\n ai_triage_hints: rule.ai_triage_hints,\n alert_mode: rule.alert_mode,\n folder: rule.folder,\n case_visibility: rule.case_visibility,\n case_groups: rule.case_group_ids as string[] | undefined,\n // Reconstruct nested auto_tuning from flat API fields\n auto_tuning:\n rule.auto_tuning_enabled !== undefined ||\n rule.auto_tuning_min_confidence !== undefined ||\n rule.auto_tuning_critical !== undefined\n ? {\n enabled: rule.auto_tuning_enabled,\n min_confidence: rule.auto_tuning_min_confidence,\n critical: rule.auto_tuning_critical,\n }\n : undefined,\n };\n\n return {\n filePath,\n metadata,\n query: rule.query,\n raw: '', // Not available from API\n };\n}\n","/**\n * Event grouping logic for alert_mode=grouped detection testing\n *\n * Matches the in-product rule tester's bucketing behavior:\n * events are grouped into clock-aligned windows based on lookback_minutes,\n * and each bucket surfaces the dominant entity.\n */\n\nimport type { GroupedTestBucket } from '../schema/types.js';\n\n/**\n * Entity fields scanned in priority order for dominant entity detection.\n * Matches the in-product rule tester's ENTITY_FIELDS list.\n */\nexport const ENTITY_FIELDS_PRIORITY = [\n 'src_ip',\n 'dest_ip',\n 'user',\n 'src_user',\n 'dest_user',\n 'src_host',\n 'dest_host',\n 'host',\n 'hostname',\n 'process_name',\n 'file_hash',\n 'process_hash',\n] as const;\n\n/**\n * Get the dominant entity from a set of events.\n * Scans entity fields in priority order, returns the most frequent value\n * from the first field that has any values.\n */\nexport function getDominantEntity(\n events: Record<string, unknown>[]\n): GroupedTestBucket['dominant_entity'] {\n for (const field of ENTITY_FIELDS_PRIORITY) {\n const counts = new Map<string, number>();\n\n for (const event of events) {\n const val = event[field];\n if (val !== undefined && val !== null && val !== '') {\n const key = String(val);\n counts.set(key, (counts.get(key) || 0) + 1);\n }\n }\n\n if (counts.size > 0) {\n let maxVal = '';\n let maxCount = 0;\n for (const [val, count] of counts) {\n if (count > maxCount) {\n maxVal = val;\n maxCount = count;\n }\n }\n return {\n field,\n value: maxVal,\n others_count: counts.size - 1,\n };\n }\n }\n\n return null;\n}\n\n/**\n * Bucket events into clock-aligned time windows based on lookback minutes.\n *\n * Uses the same algorithm as the in-product rule tester:\n * windowStart = Math.floor(epochMs / windowMs) * windowMs\n *\n * This aligns windows to clock boundaries (e.g., 14:45, 15:00, 15:15 for 15m windows)\n * matching how the cron scheduler fires in production.\n */\nexport function bucketEventsByLookback(\n events: Record<string, unknown>[],\n lookbackMinutes: number\n): GroupedTestBucket[] {\n if (events.length === 0 || lookbackMinutes <= 0) return [];\n\n const windowMs = lookbackMinutes * 60 * 1000;\n const bucketMap = new Map<number, Record<string, unknown>[]>();\n\n for (const event of events) {\n const ts = event.timestamp || event.ingest_time || event._nano_detected_at;\n if (!ts) continue;\n\n const epochMs = new Date(String(ts)).getTime();\n if (isNaN(epochMs)) continue;\n\n const windowStart = Math.floor(epochMs / windowMs) * windowMs;\n if (!bucketMap.has(windowStart)) bucketMap.set(windowStart, []);\n bucketMap.get(windowStart)!.push(event);\n }\n\n // Sort by window start time (most recent first)\n const sorted = [...bucketMap.entries()].sort((a, b) => b[0] - a[0]);\n\n return sorted.map(([windowStartMs, bucketEvents]) => ({\n window_start: new Date(windowStartMs).toISOString(),\n window_end: new Date(windowStartMs + windowMs).toISOString(),\n event_count: bucketEvents.length,\n dominant_entity: getDominantEntity(bucketEvents),\n sample_events: bucketEvents.slice(0, 3),\n }));\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nano-rs/dac-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core library for NanoSIEM detection-as-code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"yaml": "^2.6.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.0.0",
|
|
24
|
+
"tsup": "^8.3.0",
|
|
25
|
+
"typescript": "^5.7.0",
|
|
26
|
+
"vitest": "^2.1.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"nanosiem",
|
|
30
|
+
"detection",
|
|
31
|
+
"security",
|
|
32
|
+
"siem"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"dev": "tsup --watch",
|
|
41
|
+
"test": "vitest",
|
|
42
|
+
"typecheck": "tsc --noEmit",
|
|
43
|
+
"clean": "rm -rf dist"
|
|
44
|
+
}
|
|
45
|
+
}
|