import type { ImportedDataset } from '../../domain/dataset'; import type { UnifiedResultProjection } from '../../domain/unified-result'; import { POLICY_EVALUATION_ENGINE, type StoredPolicyEvaluation } from '../../domain/policy-evaluation'; import { buildPolicyWorkResults } from '../../evaluation/policy-work-results'; import { rowsToCsv } from '../../exports/csv-export'; import { makeSheet } from '../../importers/sheet-factory'; import { buildPolicyGuidance, type PolicyGuidanceMap } from '../../profiles/group-policy/guidance'; import { formatPolicySources } from '../../profiles/group-policy/source-presentation'; import { buildPolicyConflictPresentation, buildPolicyDuplicatePresentation, serializePolicyConflictPresentation, POLICY_CONFLICT_DETAILS, POLICY_DUPLICATE_DETAILS } from '../../profiles/group-policy/conflict-presentation'; function display(value: unknown): string { if (value === undefined) return ''; if (value === null) return 'null'; return typeof value === 'object' ? JSON.stringify(value) : String(value); } export function appendPolicyObservationsToDataset( dataset: ImportedDataset | null, projectName: string, results: UnifiedResultProjection[], evaluations: StoredPolicyEvaluation[] = [], guidance: PolicyGuidanceMap = buildPolicyGuidance(evaluations) ): ImportedDataset | null { const entries = buildPolicyWorkResults(results, evaluations); if (!entries.length) return dataset; const previousVersions = new Map(evaluations.filter(evaluation => evaluation.run.evaluator?.version && evaluation.run.evaluator.version !== POLICY_EVALUATION_ENGINE.version) .flatMap(evaluation => evaluation.results.map(result => [result.id, evaluation.run.evaluator.version] as const))); const headers = [ 'Title', 'Category', 'Status', 'Scope', 'Configured Value', 'Baseline value', 'Baseline', 'Comparison', 'Registry path', 'Sources', 'Technical Identity', 'Imported', 'Diagnostics', 'Policy type', 'Policy section', 'Description', 'Remediation', 'Description source', 'Conflict', POLICY_CONFLICT_DETAILS, 'Duplicates', POLICY_DUPLICATE_DETAILS, 'Evaluated', 'Source: Scan', 'Evaluation readiness' ]; const policyEntries = entries.map(entry => { const comparison = entry.comparison; const previousVersion = comparison && previousVersions.get(comparison.id); const readiness = previousVersion ? `Re-evaluation required: showing saved results from engine ${previousVersion}; current engine is ${POLICY_EVALUATION_ENGINE.version}.` : ''; const conflict = buildPolicyConflictPresentation(entry); const duplicate = buildPolicyDuplicatePresentation(entry); const configured = comparison?.customerState === 'missing' ? 'Not configured' : comparison?.comparator.actual ?? entry.sources.flatMap(source => source.policyValues ?? []); const target = comparison?.identity.target; const rawRegistry = entry.sources.flatMap(source => source.policyValues ?? []) .find(value => value && typeof value === 'object' && !Array.isArray(value) && value.kind === 'registry-policy'); const registryPath = target && 'hive' in target && target.hive ? `${target.hive}\\${target.key}` : rawRegistry && typeof rawRegistry === 'object' && !Array.isArray(rawRegistry) ? `${entry.scope === 'user' ? 'HKEY_CURRENT_USER' : 'HKEY_LOCAL_MACHINE'}\\${rawRegistry.key}` : ''; return { importedAt: entry.importedAt, row: [ entry.title, 'GPOs', entry.status, entry.scope, display(configured), display(comparison?.comparator.baseline), comparison?.baselineLabel ?? '', comparison?.baselineTemplateSelection?.status === 'no-match' ? 'No baseline template matches the specified comparison context' : comparison?.diagnosticCodes.includes('policy-evaluation-template-context-required') ? 'Different template recommendations; customer target role not established' : comparison?.diagnosticCodes.includes('policy-evaluation-baseline-consensus-conflict') ? 'Conflicting baseline recommendations' : entry.status === 'Conflicts' ? 'Different values or types for the same setting' : entry.status === 'Duplicates' ? 'Identical setting in multiple source entries' : comparison?.customerState === 'missing' ? 'Baseline setting is not configured' : entry.status === 'Pass' ? 'Matches baseline' : 'Differs from baseline', registryPath, formatPolicySources(entry.sources), entry.identity, entry.importedAt, [...new Set([...(comparison?.diagnosticCodes ?? []), ...entry.sources.flatMap(source => source.policyDiagnosticCodes ?? [])])].join(', '), target?.kind ?? entry.sources[0]?.policyDeliveryMechanism ?? '', target && 'section' in target ? target.section : '', comparison ? [readiness, guidance.get(comparison.id)?.description || 'Not available in imported baseline metadata.'].filter(Boolean).join('\n\n') : '', comparison ? guidance.get(comparison.id)?.remediation ?? '' : '', comparison ? guidance.get(comparison.id)?.source ?? '' : '', conflict?.summary ?? '', conflict ? serializePolicyConflictPresentation(conflict) : '', duplicate?.summary ?? '', duplicate ? serializePolicyConflictPresentation(duplicate) : '', entry.evaluatedAt ?? '', entry.importedAt ? `GPOs · ${entry.importedAt}` : 'GPOs', readiness ] }; }); const policyRows = policyEntries.map(entry => entry.row); const rows = [headers, ...policyRows]; const sheet = makeSheet( 'GPOs', rows, rowsToCsv(rows), projectName, { id: `gpo-policy-observations-${projectName}`, sourceFile: projectName, sourceSheet: 'GPOs', toolId: 'group-policy' } ); if (!dataset) { const lastModified = Math.max( ...policyEntries.map(entry => Date.parse(entry.importedAt)).filter(Number.isFinite), 0 ); return { fileName: `${projectName} · GPOs`, fileSize: 0, lastModified, format: 'GPO Backup', rawText: '', sheets: [sheet], profileId: 'generic', profileVersion: 'gpo-work-comparison-1.2.1', scanTool: 'GPOs' }; } const [first, ...rest] = dataset.sheets; const aggregate = first?.isProjectSheet ? (() => { const sourceHeaders = first.rows[0] ?? []; const aggregateHeaders = [...sourceHeaders]; for (const header of headers) if (!aggregateHeaders.includes(header)) aggregateHeaders.push(header); const projectRows = first.rows.slice(1).map(row => { const source = new Map(sourceHeaders.map((header, index) => [header, row[index] ?? ''])); return aggregateHeaders.map(header => source.get(header) ?? ''); }); const aggregatePolicyRows = policyRows.map(row => { const source = new Map(headers.map((header, index) => [header, row[index] ?? ''])); source.set('Source: File', projectName); source.set('Source: Sheet', 'GPOs'); return aggregateHeaders.map(header => source.get(header) ?? ''); }); const aggregateRows = [aggregateHeaders, ...projectRows, ...aggregatePolicyRows]; const combined = makeSheet(first.name, aggregateRows, rowsToCsv(aggregateRows), first.sourceFile ?? projectName, { id: first.id, sourceFile: first.sourceFile, sourceSheet: first.sourceSheet, isProjectSheet: true }); // Keep exact scanner provenance when policy rows extend the aggregate. combined.analysis.records = combined.analysis.records.map((record, index) => { const original = first.analysis.records[index]; return original ? { ...record, findingOccurrenceId: original.findingOccurrenceId, findingDefinitionId: original.findingDefinitionId, scanRunId: original.scanRunId, importFileId: original.importFileId } : record; }); return combined; })() : first; return { ...dataset, sheets: aggregate ? [aggregate, sheet, ...rest] : [sheet], scanTool: dataset.scanTool === 'GPOs' ? dataset.scanTool : 'Multiple Tools' }; }