59 lines
3.9 KiB
TypeScript
59 lines
3.9 KiB
TypeScript
import { RELEASED_ASSESSMENT_CONTEXT_CATALOG } from '../../src/assessment-context/context-catalog';
|
|
import { buildAssessmentContext } from '../../src/assessment-context/context-engine';
|
|
|
|
export function emptyHeatmapContext() {
|
|
return buildAssessmentContext({
|
|
projectId: 'synthetic-client', assessmentIds: ['synthetic-timeslot'], scanRunIds: ['synthetic-run'],
|
|
generatedAt: '2026-10-02T12:00:00Z', repositoryRevision: 1, observations: [], analyses: [],
|
|
catalog: RELEASED_ASSESSMENT_CONTEXT_CATALOG
|
|
});
|
|
}
|
|
|
|
/** Reproduces the reported 31-vs-2 mismatch: 29 GPO settings already left Other. */
|
|
export function reassignedHeatmapContext() {
|
|
const context = emptyHeatmapContext();
|
|
const conditionId = context.clusters.find(item => item.clusterId === 'other-deviations')!.conditions.at(-1)!.conditionId;
|
|
for (let index = 0; index < 29; index++) {
|
|
const identityKey = `synthetic-setting-${index}`;
|
|
context.evaluations.push({ id: identityKey, conditionId, identityKey, scope: 'computer',
|
|
settingName: 'Synthetic reassigned setting', verdict: 'deviation', matchedBy: 'assigned-by-recognition',
|
|
resultProjectionIds: [identityKey], assertion: 'evaluated-by-assessor' });
|
|
context.recognitions.push({ id: identityKey, subject: 'gpo-setting', identityKey, scope: 'computer',
|
|
resultProjectionIds: [identityKey], tool: 'gpo', text: 'Synthetic reassigned setting',
|
|
clusterId: 'lateral-movement-exposure', confidence: 'recognized', method: 'title-term',
|
|
termId: 'synthetic', matchedText: 'Synthetic', assertion: 'automatically-recognized' });
|
|
context.settings.push({ identityKey, scope: 'computer', settingName: 'Synthetic reassigned setting',
|
|
factIds: [], evaluationIds: [identityKey], conditionIds: [], clusterIds: ['lateral-movement-exposure'] });
|
|
}
|
|
const scannerCondition = context.clusters.find(item => item.clusterId === 'other-deviations')!.conditions[0].conditionId;
|
|
for (let index = 0; index < 2; index++) {
|
|
const occurrenceId = `synthetic-other-${index}`;
|
|
context.observations.push({ id: occurrenceId, conditionId: scannerCondition, tool: 'pingcastle',
|
|
sourceRuleId: 'SYNTHETIC', ruleText: 'Synthetic uncatalogued deviation', matchedBy: 'uncatalogued-deviation',
|
|
resultProjectionId: occurrenceId, occurrenceId, outcome: 'fail', assertion: 'observed-by-scanner' });
|
|
context.findings.push({ occurrenceId, resultProjectionId: occurrenceId, tool: 'pingcastle', sourceRuleId: 'SYNTHETIC',
|
|
observationIds: [occurrenceId], conditionIds: [scannerCondition], clusterIds: ['other-deviations'],
|
|
declaredReferenceIds: [], cisControlAreaIds: [] });
|
|
}
|
|
return context;
|
|
}
|
|
|
|
/** Explicitly synthetic conditions for visual and interaction acceptance; no client data. */
|
|
export function syntheticHeatmapContext() {
|
|
const context = emptyHeatmapContext();
|
|
context.clusters = context.clusters.map((cluster, index) => {
|
|
const satisfied = index % 4 === 0 ? 0 : Math.min(cluster.conditions.length, index % 3 + 1);
|
|
return { ...cluster, satisfied, unknown: cluster.conditions.length - satisfied,
|
|
state: satisfied >= cluster.minimumSatisfied ? 'present' : 'undetermined',
|
|
conditions: cluster.conditions.map((condition, i) => ({ ...condition, conditionId: `synthetic-${index}-${i}`,
|
|
...(i < satisfied ? { state: 'satisfied' as const, satisfiedBy: [`synthetic-${index}-${i}`] } : {}) }))
|
|
};
|
|
});
|
|
context.observations = context.clusters.flatMap(cluster => cluster.conditions.filter(condition => condition.state === 'satisfied').map(condition => ({
|
|
id: condition.conditionId, conditionId: condition.conditionId, tool: 'purple-knight' as const,
|
|
sourceRuleId: 'SYNTHETIC', ruleText: 'Synthetic preview deviation', matchedBy: 'rule-id' as const,
|
|
resultProjectionId: condition.conditionId, occurrenceId: condition.conditionId, outcome: 'fail' as const, assertion: 'observed-by-scanner' as const
|
|
})));
|
|
return context;
|
|
}
|