import { DEFENDER_ALERT_SEVERITIES, DEFENDER_FOR_IOT_ALERTS_PROFILE_ID } from '../../domain/defender-for-iot-alerts'; import type { ToolProfileDefinition } from '../../domain/tool-profile-definition'; export const defenderForIotAlertsDefinition: ToolProfileDefinition = { schemaVersion: 1, id: DEFENDER_FOR_IOT_ALERTS_PROFILE_ID, securityScoring: { version: '1.0.0', native: { kind: 'unavailable', reason: 'The alert export lists detected alerts only; it carries no native overall score and no passed checks.' }, targets: [], resultPopulation: 'findings-only' }, priorityBasis: { version: '1.0.0', // Every alert states its native sensor severity; that is the only ordering the source declares. basis: { kind: 'severity', properties: ['alert.severity'] }, excludedProperties: [ { property: 'alert.count', reason: 'How often an alert type fired, not its criticality.' } ] }, timeslotComparison: { version: '1.0.0', kind: 'unavailable', reason: 'The Defender for IoT alert export lists the alerts present at export time without a declared monitoring scope; an absent alert does not prove remediation.' }, name: 'Microsoft Defender for IoT Alerts', version: '1.6.0', processing: { mappingVersion: '1.2.0', normalizationVersion: '1.0.0', presentationVersion: '1.5.0', compatibilityKey: 'defender-for-iot-alerts-v1', changeClass: 'compatible', // The Acknowledged Alerts count is no longer retained; the export lists failed (unacknowledged) alerts. reimportRequired: true, affectedDimensions: ['evidence', 'presentation'] }, sourceSignals: [ { scope: 'header', pattern: /^Acknowledged$/i, contribution: 0.3, message: 'The alert export exposes the Acknowledged state.' }, { scope: 'header', pattern: /^Last Activity$/i, contribution: 0.2, message: 'The alert export exposes Last Activity.' }, { scope: 'header', pattern: /^Additional Information$/i, contribution: 0.15, message: 'The alert export exposes Additional Information.' }, { scope: 'header', pattern: /^(?:Source|Destination) Address$/i, contribution: 0.15, message: 'The alert export exposes source and destination addresses.' }, // A single-column workbook yields no usable header candidate, so the wrapped header is found among the cells. { scope: 'cell-value', pattern: /^Id,Title,First Detection,Last Detection,Last Activity,Severity,Description,Acknowledged,/i, contribution: 0.6, message: 'The workbook holds the alert export header as one CSV line.' } ], tableRules: { preferredNames: [{ pattern: /alert/i, contribution: 0.45, message: 'Likely alert table.' }], discouragedNames: [], // A workbook with one CSV line per cell is a single unrecognizable text column. selectExtractedTables: true }, fieldRules: [ { role: 'rule-id', headers: [{ pattern: /^Title$/i, contribution: 1, message: 'The native alert title identifies the alert type.' }] }, { role: 'severity', headers: [{ pattern: /^Severity$/i, contribution: 1, message: 'The field contains the alert severity.' }] }, { role: 'status', headers: [{ pattern: /^Status$/i, contribution: 1, message: 'The field contains the acknowledgement state of the alert type.' }] }, { role: 'description', headers: [{ pattern: /^Description$/i, contribution: 1, message: 'The field contains the native alert description or the wording shared by all alert descriptions of this type.' }] }, { role: 'evidence', headers: [{ pattern: /^Source Observations$/i, contribution: 1, message: 'The field preserves every source row and row locator.' }] } ], normalization: { severity: DEFENDER_ALERT_SEVERITIES.map(item => ({ normalizedValue: item.normalized, // Native and normalized labels are plain words without regex syntax. patterns: [new RegExp(`^(?:${item.native}|${item.label})$`, 'i')] })), status: [ // An open alert nobody acknowledged is a deviation; an acknowledged one stays visible without being one. { normalizedValue: 'open', outcome: 'warning', patterns: [/^unacknowledged$/i] }, { normalizedValue: 'open', outcome: 'informational', patterns: [/^acknowledged$/i] }, { normalizedValue: 'unknown', patterns: [/^acknowledgement unknown$/i] } ] }, presentation: { titleHeaders: [/^Title$/i], severityHeaders: [/^Severity$/i], sortHeaders: [/^Severity$/i], sortDirection: 'desc', defaultStatusFilter: 'deviation', statusHeaders: [/^Status$/i], statusFilters: [ { value: 'all', label: 'All Alerts', patterns: [] }, { value: 'deviation', label: 'Unacknowledged', patterns: [/^unacknowledged$/i] }, { value: 'acknowledged', label: 'Acknowledged', patterns: [/^acknowledged$/i] } ], resultSectionHeaders: [/^Alerts$/i] }, comparisonKeys: [['rule-id']] };