224 lines
14 KiB
TypeScript
224 lines
14 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import type { UnifiedResultProjection } from '../../src/domain/unified-result';
|
||
import { discloseResultDbProjection, removeResultDbScopeIdentifiers, RESULT_DB_DISCLOSURE_POLICY_VERSION } from '../../src/domain/result-db-disclosure';
|
||
|
||
function unsafeScanner(): UnifiedResultProjection {
|
||
return {
|
||
resultProjectionId: 'scanner-finding:private-occurrence', sourceKind: 'scanner-finding',
|
||
sourceResultId: 'private-occurrence', projectId: 'private-company', assessmentId: 'private-assessment',
|
||
collectionRunId: 'private-run', scanRunId: 'private-run', sourceTool: 'maester', sourceRuleId: 'MT.1001',
|
||
sourceToolVersion: 'private-build', sourceProfileId: 'maester', canonicalDefinitionId: 'private-definition',
|
||
importArtifactId: 'private-artifact', sourceViewId: 'private-view', sourceLocator: { objectPath: 'private/path' },
|
||
title: 'Kerberos preauthentication is disabled for person@private-company.example',
|
||
description: 'Private Company GmbH tenant permits legacy authentication.',
|
||
recommendation: 'Disable legacy authentication and contact Jane Doe.', affectedAsset: 'private-company.example',
|
||
severityOriginal: 'Private severity', severityNormalized: 'high', outcomeOriginal: 'Private outcome',
|
||
outcomeNormalized: 'fail', technicalExecutionState: 'completed', resultType: 'compliance_check',
|
||
isIoe: false, isDeviation: true, lifecycleState: 'unknown', mappingConfidence: 1,
|
||
reviewStatus: 'open', reviewOwner: 'Jane Doe', reviewDueDate: '2026-10-01',
|
||
sourceObservedAt: '2026-09-22T08:00:00.000Z', importedAt: '2026-09-22T08:00:00.000Z',
|
||
createdAt: '2026-09-22T08:00:00.000Z',
|
||
frameworkReferences: [],
|
||
categories: [{ namespace: 'private-company', categoryCode: 'private', categoryLabel: 'Private Company',
|
||
categoryType: 'source', isPrimary: true }]
|
||
};
|
||
}
|
||
|
||
describe(`Result DB disclosure ${RESULT_DB_DISCLOSURE_POLICY_VERSION}`, () => {
|
||
it('keeps useful known-scanner guidance while redacting customer identifiers', () => {
|
||
const disclosed = discloseResultDbProjection(unsafeScanner());
|
||
expect(disclosed).toMatchObject({
|
||
title: 'Kerberos preauthentication is disabled for [email]', sourceTool: 'maester', sourceRuleId: 'MT.1001',
|
||
description: '[organization] tenant permits legacy authentication.',
|
||
recommendation: 'Disable legacy authentication and contact [redacted].',
|
||
severityOriginal: 'high', outcomeOriginal: 'fail', importedAt: '1970-01-01T00:00:00.000Z',
|
||
categories: [{ namespace: 'source-tool', categoryCode: 'maester', categoryLabel: 'Maester' }]
|
||
});
|
||
const serialized = JSON.stringify(disclosed);
|
||
for (const privateValue of ['person@private-company.example', 'Private Company GmbH', 'Jane Doe',
|
||
'private-company.example', 'private/path', 'private-build', 'private-definition', 'private-artifact']) {
|
||
expect(serialized).not.toContain(privateValue);
|
||
}
|
||
});
|
||
|
||
it('retains Purple Knight native rule identity and remediation text', () => {
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceTool: 'purple-knight', sourceRuleId: 'SI000055',
|
||
title: 'Privileged accounts have weak delegation settings',
|
||
description: 'Review delegation on PRIVATE\\admin-user and private-company.example.',
|
||
recommendation: '<p>Remove unconstrained delegation from the <b>affected account</b>.</p>',
|
||
affectedAsset: 'PRIVATE\\admin-user'
|
||
});
|
||
|
||
expect(disclosed).toMatchObject({
|
||
sourceTool: 'purple-knight', sourceRuleId: 'SI000055',
|
||
title: 'Privileged accounts have weak delegation settings',
|
||
description: 'Review delegation on [account] and [domain].',
|
||
recommendation: 'Remove unconstrained delegation from the affected account.'
|
||
});
|
||
});
|
||
|
||
it('publishes Purple Knight for Entra ID as its own Result DB source scope', () => {
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceTool: 'purple-knight', sourceToolScope: 'entra-id', sourceRuleId: 'SI000055',
|
||
title: 'Synthetic Entra control', description: 'Synthetic Entra description.'
|
||
});
|
||
|
||
expect(disclosed).toMatchObject({
|
||
sourceTool: 'purple-knight-entra', sourceToolScope: 'entra-id', sourceRuleId: 'SI000055',
|
||
title: 'Synthetic Entra control',
|
||
categories: [{ namespace: 'source-tool', categoryCode: 'purple-knight-entra', categoryLabel: 'Purple Knight for Entra ID' }]
|
||
});
|
||
});
|
||
|
||
it('shows a publicly documented PingCastle ID in its native spelling and rejects an unknown ID', () => {
|
||
const item = { ...unsafeScanner(), sourceTool: 'pingcastle', sourceRuleId: 'S-oldNtlm',
|
||
title: 'The LAN Manager Authentication Level allows the use of NTLMv1 or LM.' };
|
||
expect(discloseResultDbProjection(item)).toMatchObject({
|
||
sourceRuleId: 'S-oldNtlm', title: item.title
|
||
});
|
||
expect(discloseResultDbProjection({ ...item, sourceRuleId: 'S-PrivateCustomerRule' }).sourceRuleId)
|
||
.toBeUndefined();
|
||
});
|
||
|
||
it('releases documented Maester suite IDs but keeps unknown and instance-specific IDs private', () => {
|
||
for (const sourceRuleId of ['CIS.M365.1.1.1', 'CISA.MS.AAD.2.3', 'EIDSCA.AF01', 'ORCA.100', 'MT.1025']) {
|
||
expect(discloseResultDbProjection({ ...unsafeScanner(), sourceRuleId }).sourceRuleId)
|
||
.toBe(sourceRuleId);
|
||
}
|
||
for (const sourceRuleId of ['CT001', 'MT.INV.001', 'MT.1024.private-customer-key',
|
||
'MT.1024.applicationCredentialExpiry.private-tenant', 'MT.1033.0', 'CIS.M365.99.99.99']) {
|
||
expect(discloseResultDbProjection({ ...unsafeScanner(), sourceRuleId }).sourceRuleId)
|
||
.toBeUndefined();
|
||
}
|
||
});
|
||
|
||
it('keeps a CIS-CAT control number and public policy path while hiding an actual address and account', () => {
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceTool: 'cis-cat', sourceRuleId: '18.10.36.1',
|
||
title: "18.10.36.1 Ensure 'Turn off location' is set to 'Enabled'",
|
||
recommendation: 'Computer Configuration\\Administrative Templates\\System\\Location and Sensors\\Turn off location; CONTOSO\\jane\n'
|
||
+ 'Use the public policy file Windows.adml.\n'
|
||
+ 'Review CONTOSO\\jane at 10.20.30.40 and jane@contoso.example.'
|
||
});
|
||
|
||
expect(disclosed.sourceRuleId).toBe('18.10.36.1');
|
||
expect(disclosed.title).toContain('18.10.36.1');
|
||
expect(disclosed.title).not.toContain('[ip]');
|
||
expect(disclosed.recommendation).toContain('Computer Configuration\\Administrative Templates\\System\\Location and Sensors\\Turn off location');
|
||
expect(disclosed.recommendation).toContain('Turn off location; [account]');
|
||
expect(disclosed.recommendation).toContain('Windows.adml');
|
||
expect(disclosed.recommendation).toContain('[account] at [ip] and [email]');
|
||
expect(disclosed.recommendation).not.toMatch(/CONTOSO|jane|10\.20\.30\.40/);
|
||
});
|
||
|
||
it('keeps GPO Ist and Soll values while consistently redacting a non-public system SID', () => {
|
||
const systemSid = 'S-1-5-82-123456789-234567890-345678901-456789012-567890123';
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceKind: 'policy-evaluation', sourceTool: 'GPOs',
|
||
title: 'System Access · LockoutBadCount',
|
||
policyActualValue: { kind: 'text', value: '5', principals: [systemSid, 'S-1-5-32-544'] },
|
||
policyBaselineValue: { kind: 'text', value: '10' },
|
||
policyBaselineVariantAssessment: {
|
||
version: 1, scope: 'backup-configuration', decision: 'all-fail',
|
||
actualValues: [{ kind: 'principal-set', principals: [systemSid] }],
|
||
variants: [{ settingId: 'private-setting', baselineValues: [], comparator: {
|
||
version: 1, comparator: { kind: 'set', mode: 'exact' }, relation: 'different',
|
||
actual: { kind: 'string-set', values: [systemSid] },
|
||
baseline: { kind: 'string-set', values: ['S-1-5-32-544'] }, diagnosticCodes: []
|
||
}}], diagnosticCodes: []
|
||
}
|
||
});
|
||
|
||
expect(disclosed.policyActualValue).toMatchObject({ kind: 'text', value: '5',
|
||
principals: ['[SYSTEM_PRINCIPAL_1]', 'S-1-5-32-544'] });
|
||
expect(disclosed.policyBaselineValue).toMatchObject({ kind: 'text', value: '10' });
|
||
expect(JSON.stringify(disclosed)).not.toContain(systemSid);
|
||
expect(JSON.stringify(disclosed).match(/\[SYSTEM_PRINCIPAL_1\]/g)).toHaveLength(3);
|
||
});
|
||
|
||
it('keeps the complete technical GPO deviation without customer or source identity', () => {
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceKind: 'policy-evaluation', sourceTool: 'GPOs',
|
||
sourceRuleId: 'registry:machine:software\\policies\\microsoft\\windows nt\\printers\\pointandprint:restrictdriverinstallationtoadministrators',
|
||
title: 'Restrict driver installation to administrators',
|
||
description: 'Private Company GmbH configures this setting for dummy.local.',
|
||
recommendation: 'Set RestrictDriverInstallationToAdministrators to 1.',
|
||
policyDeliveryMechanism: 'registry-policy', policyClassification: 'misconfigured',
|
||
policyActualValue: {
|
||
kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint',
|
||
valueName: 'RestrictDriverInstallationToAdministrators', typeCode: 4, data: { kind: 'uint32', value: 0 },
|
||
principals: ['S-1-5-18', 'S-1-5-32-544', 'BUILTIN\\Administrators', 'DUMMY\\Domain Admins',
|
||
'DUMMY\\jane.doe', 'S-1-5-21-123456789-234567890-345678901-512'],
|
||
note: 'Configured by {A1B2C3D4-1111-2222-3333-444455556666}',
|
||
gpoName: 'DUMMY – Domain Controllers Security', gpoId: '{A1B2C3D4-1111-2222-3333-444455556666}',
|
||
sourcePath: '\\\\fileserver\\backups\\dummy.local\\gpo.zip'
|
||
},
|
||
policyBaselineValue: {
|
||
kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint',
|
||
valueName: 'RestrictDriverInstallationToAdministrators', typeCode: 4, data: { kind: 'uint32', value: 1 }
|
||
},
|
||
policyIdentityKey: 'private-company-policy', policyGpoId: '{A1B2C3D4-1111-2222-3333-444455556666}',
|
||
policyNativeBackupId: '{99999999-1111-2222-3333-444455556666}',
|
||
policyBaselineId: 'private-baseline-id', policyBaselineLabel: 'Private Company Microsoft Security Baseline Windows Server 2022 v1',
|
||
policyDiagnosticCodes: ['policy-safe-code', 'Private Company'], policyComparisonRelation: 'different',
|
||
policyBaselineVariantAssessment: {
|
||
version: 1, scope: 'backup-configuration', decision: 'all-fail',
|
||
actualValues: [{ kind: 'principal-set', principals: ['DUMMY\\named.user'] }],
|
||
variants: [{
|
||
settingId: 'private-company-baseline-setting',
|
||
baselineValues: [{ kind: 'principal-set', principals: ['BUILTIN\\Administrators'] }],
|
||
comparator: { version: 1, comparator: { kind: 'set', mode: 'exact' }, relation: 'different',
|
||
actual: { kind: 'string-set', values: ['DUMMY\\named.user'] },
|
||
baseline: { kind: 'string-set', values: ['BUILTIN\\Administrators'] }, diagnosticCodes: [] }
|
||
}], diagnosticCodes: []
|
||
}
|
||
});
|
||
expect(disclosed).toMatchObject({
|
||
title: 'Restrict driver installation to administrators', sourceTool: 'GPOs',
|
||
sourceRuleId: 'registry:machine:software\\policies\\microsoft\\windows nt\\printers\\pointandprint:restrictdriverinstallationtoadministrators',
|
||
policyActualValue: {
|
||
kind: 'registry-policy', operation: 'set-value', key: 'Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint',
|
||
valueName: 'RestrictDriverInstallationToAdministrators', typeCode: 4, data: { kind: 'uint32', value: 0 },
|
||
principals: ['S-1-5-18', 'S-1-5-32-544', 'BUILTIN\\Administrators', '[DOMAIN]\\Domain Admins',
|
||
'[DOMAIN_PRINCIPAL_1]', 'S-1-5-21-[DOMAIN]-512']
|
||
},
|
||
policyBaselineValue: { data: { kind: 'uint32', value: 1 } },
|
||
policyBaselineLabel: 'Microsoft Security Baseline Windows Server 2022 v1',
|
||
recommendation: 'Set RestrictDriverInstallationToAdministrators to 1.',
|
||
policyDiagnosticCodes: ['policy-safe-code'],
|
||
policyBaselineVariantAssessment: {
|
||
variants: [{ settingId: 'baseline-variant-1', comparator: {
|
||
actual: { kind: 'string-set', values: ['[DOMAIN_PRINCIPAL_2]'] },
|
||
baseline: { kind: 'string-set', values: ['BUILTIN\\Administrators'] }
|
||
}}]
|
||
}
|
||
});
|
||
expect(disclosed.policyIdentityKey).toBeUndefined();
|
||
expect(disclosed.policyBaselineId).toBeUndefined();
|
||
const serialized = JSON.stringify(disclosed);
|
||
for (const privateValue of ['Private Company', 'dummy.local', 'DUMMY – Domain Controllers Security',
|
||
'A1B2C3D4', '99999999', 'fileserver', 'jane.doe', '123456789', '234567890', '345678901']) {
|
||
expect(serialized).not.toContain(privateValue);
|
||
}
|
||
expect(serialized).toContain('Backup comparison; effective endpoint state not verified');
|
||
});
|
||
|
||
it('removes generated GPO identity hashes instead of presenting them as rule IDs', () => {
|
||
const disclosed = discloseResultDbProjection({
|
||
...unsafeScanner(), sourceKind: 'policy-evaluation', sourceTool: 'GPOs',
|
||
sourceRuleId: 'gpo-policy-identity-deadbeef', title: 'Synthetic setting',
|
||
policyBaselineLabel: 'Microsoft Security Baseline', policyActualValue: 0, policyBaselineValue: 1
|
||
});
|
||
expect(disclosed.sourceRuleId).toBeUndefined();
|
||
expect(disclosed.policyIdentityKey).toBeUndefined();
|
||
});
|
||
|
||
it('replaces customer scope handles after query filtering', () => {
|
||
expect(removeResultDbScopeIdentifiers(discloseResultDbProjection(unsafeScanner()))).toMatchObject({
|
||
projectId: 'scoped-project', assessmentId: 'scoped-assessment', collectionRunId: 'scoped-collection',
|
||
scanRunId: 'scoped-scan'
|
||
});
|
||
});
|
||
});
|