82 lines
4.7 KiB
TypeScript
82 lines
4.7 KiB
TypeScript
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']]
|
|
};
|