import type { GpoPolicyScope } from './gpo-ingestion'; export const GPO_POLICY_IDENTITY_RESOLVER = { id: 'gpo-technical-registry-target', version: '1.0.0' } as const; export const GPO_NATIVE_POLICY_IDENTITY_RESOLVER = { id: 'gpo-native-policy-target', version: '1.0.0' } as const; export const ADMX_POLICY_CATALOG_PARSER = { id: 'admx-policy-metadata-catalog', version: '1.0.0' } as const; export type ResolvableGpoPolicyScope = Exclude; export interface GpoRegistryTechnicalTarget { kind: 'registry-key' | 'registry-value'; hive: 'HKEY_LOCAL_MACHINE' | 'HKEY_CURRENT_USER'; key: string; valueName?: string; } export interface AdmxPolicyRegistryTarget { version: 1; scope: ResolvableGpoPolicyScope; key: string; match: 'exact-value' | 'key-values'; valueName?: string; role: 'policy-state' | 'element' | 'enabled-list' | 'disabled-list'; elementId?: string; } export interface AdmxPolicyDefinition { version: 1; technicalId: string; targetNamespace: string; name: string; class: 'machine' | 'user' | 'both'; displayNameResourceId?: string; explainTextResourceId?: string; sourcePath: string; sourceSha256: string; registryTargets: AdmxPolicyRegistryTarget[]; } export interface AdmxLanguageResource { version: 1; sourcePath: string; sourceSha256: string; admxFileName: string; locale: string; strings: Record; } export interface AdmxPolicyCatalog { version: 1; id: string; parser: typeof ADMX_POLICY_CATALOG_PARSER; source: { kind: 'microsoft-security-baseline'; baselineId: string; packageSha256: string }; status: 'complete' | 'partial'; policies: AdmxPolicyDefinition[]; languageResources: AdmxLanguageResource[]; diagnosticCodes: string[]; } export interface AdmxPolicyReference { technicalId: string; targetNamespace: string; policyName: string; settingId: string; targetRole: AdmxPolicyRegistryTarget['role']; } export type AdmxPolicyResolution = | { status: 'matched'; catalogId: string; reference: AdmxPolicyReference } | { status: 'not-found'; catalogId?: string } | { status: 'ambiguous'; catalogId: string; candidates: AdmxPolicyReference[] }; export interface GpoTechnicalPolicyIdentity { version: 1; id: string; resolver: typeof GPO_POLICY_IDENTITY_RESOLVER | typeof GPO_NATIVE_POLICY_IDENTITY_RESOLVER; scope: ResolvableGpoPolicyScope; target: GpoRegistryTechnicalTarget | { kind: 'security-template' | 'advanced-audit-policy'; section: string; key: string; hive?: never; valueName?: never; }; admx: AdmxPolicyResolution; } export type GpoPolicyIdentityResolution = | { version: 1; status: 'resolved'; identity: GpoTechnicalPolicyIdentity } | { version: 1; status: 'unresolved'; reasonCode: string }; function safeTechnicalText(value: string): boolean { return Boolean(value.trim()) && value.length <= 32_767 && !/[\u0000-\u001f]/.test(value); } export function admxPolicyCatalogValidationErrors(catalog: AdmxPolicyCatalog): string[] { const errors: string[] = []; if (catalog.version !== 1 || !catalog.id.trim() || !/^[a-f0-9]{64}$/.test(catalog.source.packageSha256)) { errors.push('Der ADMX-Katalog besitzt keine gültige Version, ID oder Paketprüfsumme.'); } if (!catalog.source.baselineId.trim() || catalog.parser.id !== ADMX_POLICY_CATALOG_PARSER.id || catalog.parser.version !== ADMX_POLICY_CATALOG_PARSER.version) { errors.push('Der ADMX-Katalog besitzt keine gültige Quelle oder Parserprovenienz.'); } const policyIds = new Set(); for (const policy of catalog.policies) { if (policy.version !== 1 || !safeTechnicalText(policy.technicalId) || !safeTechnicalText(policy.targetNamespace) || !safeTechnicalText(policy.name) || !safeTechnicalText(policy.sourcePath) || !/^[a-f0-9]{64}$/.test(policy.sourceSha256) || policyIds.has(policy.technicalId)) { errors.push('Der ADMX-Katalog enthält eine ungültige oder doppelte Policydefinition.'); continue; } policyIds.add(policy.technicalId); for (const target of policy.registryTargets) { if (target.version !== 1 || !safeTechnicalText(target.key) || (target.match === 'exact-value' && target.valueName === undefined) || (target.match === 'key-values' && target.valueName !== undefined) || (target.role === 'element' && !target.elementId?.trim())) { errors.push('Eine ADMX-Registryzuordnung ist ungültig.'); } } } for (const resource of catalog.languageResources) { if (resource.version !== 1 || !safeTechnicalText(resource.sourcePath) || !/^[a-f0-9]{64}$/.test(resource.sourceSha256) || !safeTechnicalText(resource.admxFileName) || !safeTechnicalText(resource.locale) || Object.entries(resource.strings).some(([id, value]) => !safeTechnicalText(id) || typeof value !== 'string')) { errors.push('Der ADML-Ressourcenkatalog ist ungültig.'); } } return [...new Set(errors)]; } export function gpoTechnicalPolicyIdentityValidationErrors(identity: GpoTechnicalPolicyIdentity): string[] { const errors: string[] = []; if (identity.version !== 1 || !/^gpo-policy-identity-[a-f0-9]{32}$/.test(identity.id) || ![GPO_POLICY_IDENTITY_RESOLVER.id, GPO_NATIVE_POLICY_IDENTITY_RESOLVER.id].includes(identity.resolver.id) || identity.resolver.version !== GPO_POLICY_IDENTITY_RESOLVER.version) { errors.push('Die technische Policy-Identität besitzt eine ungültige Version oder Resolverprovenienz.'); } const expectedHive = identity.scope === 'computer' ? 'HKEY_LOCAL_MACHINE' : 'HKEY_CURRENT_USER'; const registry = identity.target.kind === 'registry-key' || identity.target.kind === 'registry-value'; if (!['computer', 'user'].includes(identity.scope) || identity.resolver.id !== (registry ? GPO_POLICY_IDENTITY_RESOLVER.id : GPO_NATIVE_POLICY_IDENTITY_RESOLVER.id) || !['registry-key', 'registry-value', 'security-template', 'advanced-audit-policy'].includes(identity.target.kind) || (registry && identity.target.hive !== expectedHive) || !safeTechnicalText(identity.target.key) || (!registry && (!('section' in identity.target) || !safeTechnicalText(identity.target.section) || identity.target.hive !== undefined)) || (identity.target.kind === 'registry-value' && identity.target.valueName === undefined) || (identity.target.kind === 'registry-key' && identity.target.valueName !== undefined)) { errors.push('Die technische Registry-Zielidentität ist ungültig.'); } if (identity.admx.status === 'matched' && (!identity.admx.catalogId.trim() || !identity.admx.reference.technicalId.trim() || !identity.admx.reference.settingId.trim())) { errors.push('Die ADMX-Zuordnung der Policy-Identität ist ungültig.'); } if (identity.admx.status === 'ambiguous' && (!identity.admx.catalogId.trim() || identity.admx.candidates.length < 2)) { errors.push('Eine mehrdeutige ADMX-Zuordnung benötigt mindestens zwei Kandidaten.'); } return errors; }