81 lines
3.6 KiB
TypeScript
81 lines
3.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import type { EnvironmentObservation } from '../../src/domain/environment-context';
|
|
import {
|
|
discloseSupplementalObservation,
|
|
RESULT_DB_SUPPLEMENTAL_DISCLOSURE_POLICY_VERSION
|
|
} from '../../src/domain/result-db-supplemental-disclosure';
|
|
|
|
function observation(overrides: Partial<EnvironmentObservation> = {}): EnvironmentObservation {
|
|
return {
|
|
version: 1,
|
|
id: 'synthetic-observation',
|
|
scanRunId: 'synthetic-run',
|
|
importFileId: 'synthetic-file',
|
|
tool: { id: 'pingcastle', name: 'PingCastle', version: 'synthetic' },
|
|
subject: { type: 'domain-information', identity: 'private.synthetic.example', label: 'Private Customer' },
|
|
property: 'domain.functional_level',
|
|
label: 'Customer supplied label',
|
|
originalValue: 'Windows Server 2016 for Private Customer',
|
|
normalizedValue: 2016,
|
|
valueType: 'number',
|
|
state: 'observed',
|
|
source: { objectPath: 'html/private/customer/path' },
|
|
mappingVersion: 'synthetic',
|
|
attributes: { customer: 'Private Customer' },
|
|
...overrides
|
|
};
|
|
}
|
|
|
|
describe('Result DB supplemental disclosure boundary', () => {
|
|
it('rebuilds an approved value from controlled metadata without carrying source identity or raw context', () => {
|
|
const disclosed = discloseSupplementalObservation(observation({
|
|
property: 'domain.recycle_bin_enabled', normalizedValue: true, originalValue: 'Enabled for Private Customer',
|
|
valueType: 'boolean'
|
|
}));
|
|
|
|
expect(disclosed).toEqual({
|
|
policyVersion: RESULT_DB_SUPPLEMENTAL_DISCLOSURE_POLICY_VERSION,
|
|
disclosureClass: 'configuration-state',
|
|
property: 'domain.recycle_bin_enabled',
|
|
title: 'AD Recycle Bin enabled',
|
|
subjectType: 'active-directory-environment',
|
|
value: true,
|
|
valueType: 'boolean',
|
|
state: 'observed'
|
|
});
|
|
expect(JSON.stringify(disclosed)).not.toMatch(/Private Customer|private\.synthetic|customer\/path/i);
|
|
});
|
|
|
|
it('fails closed for identifying, unknown, future-tool and malformed supplemental values', () => {
|
|
expect(discloseSupplementalObservation(observation({
|
|
property: 'domain.fqdn', normalizedValue: 'private.synthetic.example', valueType: 'string'
|
|
}))).toBeUndefined();
|
|
expect(discloseSupplementalObservation(observation({
|
|
property: 'future.private.field', normalizedValue: 'Private Customer', valueType: 'string'
|
|
}))).toBeUndefined();
|
|
expect(discloseSupplementalObservation(observation({
|
|
tool: { id: 'future-scanner', name: 'Future Scanner' }
|
|
}))).toBeUndefined();
|
|
expect(discloseSupplementalObservation(observation({
|
|
normalizedValue: '2016.private.synthetic.example', valueType: 'string'
|
|
}))).toBeUndefined();
|
|
});
|
|
|
|
it('withholds counts, scores, levels and versions that fingerprint the environment', () => {
|
|
for (const [property, value] of [['risk.domain', 42], ['domain.controller_count', 1], ['domain.functional_level', 2016],
|
|
['forest.schema_version', 88], ['kerberos.krbtgt.version', 3], ['report.engine_version', '3.3.0.0'],
|
|
['logging.wef.configuration_count', 0]] as const) {
|
|
expect(discloseSupplementalObservation(observation({ property, normalizedValue: value }))).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
it('allows bounded boolean configuration values only', () => {
|
|
expect(discloseSupplementalObservation(observation({
|
|
property: 'domain.recycle_bin_enabled', normalizedValue: true, originalValue: 'Private enabled', valueType: 'boolean'
|
|
}))).toMatchObject({ value: true, disclosureClass: 'configuration-state' });
|
|
expect(discloseSupplementalObservation(observation({
|
|
property: 'risk.domain', normalizedValue: 101
|
|
}))).toBeUndefined();
|
|
});
|
|
});
|