Assessor_2.0/server/gpo/policy-target-resolver.ts

28 lines
1.9 KiB
TypeScript

import { createHash } from 'node:crypto';
import { GPO_NATIVE_POLICY_IDENTITY_RESOLVER, gpoTechnicalPolicyIdentityValidationErrors,
type AdmxPolicyCatalog, type GpoPolicyIdentityResolution } from '../../src/domain/gpo-policy-identity';
import type { GpoPolicyObservation } from '../../src/domain/gpo-policy';
import { resolveRegistryPolicyIdentity } from './admx-policy-catalog';
export function resolvePolicyTarget(observation: GpoPolicyObservation, catalog?: AdmxPolicyCatalog): GpoPolicyIdentityResolution {
if (observation.deliveryMechanism === 'registry-policy') return resolveRegistryPolicyIdentity(observation, catalog);
if (!['security-template', 'advanced-audit-policy'].includes(observation.deliveryMechanism)) {
return { version: 1, status: 'unresolved', reasonCode: `identity-resolver-unsupported-${observation.deliveryMechanism}` };
}
const kind = observation.deliveryMechanism as 'security-template' | 'advanced-audit-policy';
const section = observation.identity.section.normalize('NFC');
const key = observation.identity.key.normalize('NFC');
// The digest stays case-folded so one technical setting keeps one identity across
// differently written sources. The retained target keeps the written form, exactly as
// the registry resolver already does, so the value stays recognisable and searchable.
const digest = createHash('sha256').update(['native-policy-target-v1', kind, observation.scope, section.toLowerCase(), key.toLowerCase()].join('\0')).digest('hex');
const identity = {
version: 1 as const, id: `gpo-policy-identity-${digest.slice(0, 32)}`, resolver: GPO_NATIVE_POLICY_IDENTITY_RESOLVER,
scope: observation.scope, target: { kind, section, key }, admx: { status: 'not-found' as const }
};
if (gpoTechnicalPolicyIdentityValidationErrors(identity).length) {
return { version: 1, status: 'unresolved', reasonCode: 'policy-technical-target-invalid' };
}
return { version: 1, status: 'resolved', identity };
}