import type { UnifiedResultProjection } from '../domain/unified-result'; const SAFE_ENVIRONMENT_PROPERTIES = new Set([ 'domain.controller_count', 'domain.functional_level', 'domain.recycle_bin_enabled', 'forest.functional_level', 'logging.wef.configuration_count', 'operating_system.count', 'operating_system.name' ]); export function privacySafeResultJsonFileName(generatedAt: string): string { const timestamp = generatedAt.replace(/\.\d{3}Z$/, 'Z').replaceAll(':', '-'); return `assessor-result-db-privacy-safe-${timestamp}.json`; } export function resultsToPrivacySafeExportJson(items: UnifiedResultProjection[]): string { const findings = items.filter(item => item.sourceKind !== 'environment-observation'); const environment = items.filter(item => item.sourceKind === 'environment-observation'); const actionable = findings.filter(item => item.isDeviation || item.isIoe || ['fail', 'warning', 'execution_error'].includes(item.outcomeNormalized)); const notRun = findings.filter(item => item.outcomeNormalized === 'not_run'); return JSON.stringify({ schemaVersion: 1, summary: { totalResults: items.length, findingResults: findings.length, environmentResults: environment.length, actionableFindings: actionable.length, notRunChecks: notRun.length, findingOutcomes: countBy(findings, item => item.outcomeNormalized), findingSeverities: countBy(findings, item => item.severityNormalized), findingTools: countBy(findings, item => item.sourceTool ?? 'unknown'), environmentStates: countBy(environment, item => item.environmentState ?? 'unknown') }, findings: actionable.map(item => { const description = copiedText(item.description); const recommendation = copiedText(item.recommendation); return { id: item.sourceRuleId ?? null, title: privacySafeText(item.title), ...(description ? { description } : {}), ...(recommendation ? { recommendation } : {}), severity: item.severityNormalized, outcome: item.outcomeNormalized, resultType: item.resultType, isIoe: item.isIoe, deviation: item.isDeviation, tool: item.sourceTool ?? 'unknown' }; }), notRunChecks: notRun.map(item => ({ id: item.sourceRuleId ?? null, title: privacySafeText(item.title), severity: item.severityNormalized, resultType: item.resultType, tool: item.sourceTool ?? 'unknown' })), environmentFacts: groupedEnvironmentFacts(environment) }, null, 2); } function groupedEnvironmentFacts(items: UnifiedResultProjection[]) { const grouped = new Map(); items.forEach(item => { const property = copiedEnvironmentProperty(item); if (!property) return; const fact = { title: privacySafeText(item.title), property, value: item.environmentNormalizedValue ?? null, state: item.environmentState ?? 'unknown', tool: item.sourceTool ?? 'unknown' }; const key = JSON.stringify(fact); const existing = grouped.get(key); if (existing) existing.count += 1; else grouped.set(key, { ...fact, count: 1 }); }); return [...grouped.values()]; } function countBy(items: UnifiedResultProjection[], valueOf: (item: UnifiedResultProjection) => string): Record { const counts: Record = {}; items.forEach(item => { const value = valueOf(item); counts[value] = (counts[value] ?? 0) + 1; }); return counts; } function copiedText(value: string | undefined): string | undefined { const trimmed = value?.trim(); return !trimmed || trimmed.toLocaleLowerCase('en-US') === 'none' ? undefined : privacySafeText(trimmed); } function privacySafeText(value: string): string { return value.replace(/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, '[redacted-email]'); } function copiedEnvironmentProperty(item: UnifiedResultProjection): string | undefined { if (item.sourceKind !== 'environment-observation' || !item.environmentProperty) return undefined; if (SAFE_ENVIRONMENT_PROPERTIES.has(item.environmentProperty) || item.environmentProperty.endsWith('.row_count')) { return item.environmentProperty; } const aggregateAccountValue = item.environmentValueType === 'number' && ['user-information.account-analysis', 'computer-information.account-analysis'].includes(item.environmentSubjectType ?? ''); return aggregateAccountValue ? item.environmentProperty : undefined; }