import type { AdmxPolicyCatalog, GpoPolicyIdentityResolution } from './gpo-policy-identity'; import type { GpoPolicyObservation } from './gpo-policy'; export const MICROSOFT_BASELINE_SETTINGS_ANALYZER = { id: 'microsoft-baseline-gpo-settings', version: '1.4.0' } as const; export interface MicrosoftSecurityBaselineSetting { version: 1; id: string; baselineId: string; backupId: string; template?: { names: Array<{ value: string; sourcePath: string; sourceSha256: string }>; context?: { productFamily: string; productVersion: string; role: 'Client' | 'Member Server' | 'Domain Controller' }; }; observation: Pick; identity: GpoPolicyIdentityResolution; } export interface MicrosoftSecurityBaselineAnalysis { version: 1; id: string; baselineId: string; packageSha256: string; analyzer: { id: typeof MICROSOFT_BASELINE_SETTINGS_ANALYZER.id; version: '1.0.0' | '1.1.0' | '1.2.0' | '1.3.0' | '1.4.0' }; analyzedAt: string; status: 'complete' | 'partial'; admxCatalog: AdmxPolicyCatalog; backupCount: number; registryPolicyFileCount: number; settings: MicrosoftSecurityBaselineSetting[]; diagnosticCodes: string[]; } export interface StoredMicrosoftSecurityBaselineAnalysis { version: 1; analysis: MicrosoftSecurityBaselineAnalysis; supersedesAnalysisId?: string; } export function microsoftSecurityBaselineAnalysisValidationErrors(analysis: MicrosoftSecurityBaselineAnalysis): string[] { const errors: string[] = []; if (analysis.version !== 1 || !analysis.id.trim() || !analysis.baselineId.trim() || !/^[a-f0-9]{64}$/.test(analysis.packageSha256) || analysis.analyzer.id !== MICROSOFT_BASELINE_SETTINGS_ANALYZER.id || !['1.0.0', '1.1.0', '1.2.0', '1.3.0', '1.4.0'].includes(analysis.analyzer.version) || !Number.isFinite(Date.parse(analysis.analyzedAt)) || analysis.admxCatalog.source.baselineId !== analysis.baselineId || analysis.admxCatalog.source.packageSha256 !== analysis.packageSha256) { errors.push('Die Microsoft-Baselineanalyse besitzt ungültige Identität oder Provenienz.'); } if (![analysis.backupCount, analysis.registryPolicyFileCount].every(value => Number.isSafeInteger(value) && value >= 0) || new Set(analysis.settings.map(setting => setting.id)).size !== analysis.settings.length) { errors.push('Die Microsoft-Baselineanalyse besitzt ungültige Zählwerte oder doppelte Einstellungen.'); } for (const setting of analysis.settings) { const template = setting.template; if (template && (!Array.isArray(template.names) || template.names.some(name => typeof name.value !== 'string' || !name.value.trim() || name.value.length > 2048 || typeof name.sourcePath !== 'string' || !name.sourcePath.trim() || !/^[a-f0-9]{64}$/.test(name.sourceSha256)) || (template.context && (!template.names.length || !['Client', 'Member Server', 'Domain Controller'].includes(template.context.role) || !template.context.productFamily?.trim() || !template.context.productVersion?.trim())))) { errors.push('Die Baselinevorlage besitzt ungueltige Namen, Rollen oder Quellenreferenzen.'); } if (setting.version !== 1 || !setting.id.trim() || setting.baselineId !== analysis.baselineId || !setting.backupId.trim() || !['registry-policy', 'security-template', 'advanced-audit-policy'].includes(setting.observation.deliveryMechanism) || (setting.observation.deliveryMechanism === 'registry-policy' ? setting.observation.state !== 'instruction' : !['configured', 'conflicted'].includes(setting.observation.state)) || !setting.observation.sourcePath.trim() || !/^[a-f0-9]{64}$/.test(setting.observation.sourceSha256) || setting.observation.values.length !== 1 || setting.observation.effectiveState !== 'unknown') { errors.push('Die Microsoft-Baselineanalyse enthält eine ungültige Registry-Policy-Einstellung.'); } } return [...new Set(errors)]; } export function storedMicrosoftSecurityBaselineAnalysisValidationErrors(record: StoredMicrosoftSecurityBaselineAnalysis): string[] { const errors = microsoftSecurityBaselineAnalysisValidationErrors(record.analysis); if (record.version !== 1) errors.push('Die persistierte Microsoft-Baselineanalyse besitzt eine ungültige Version.'); if (record.supersedesAnalysisId === record.analysis.id) errors.push('Eine Microsoft-Baselineanalyse darf sich nicht selbst ersetzen.'); return [...new Set(errors)]; }