tenantpilot/worker/jobs/policyParser.ts

234 lines
6.8 KiB
TypeScript

import { humanizeSettingId } from '../utils/humanizer';
export interface FlattenedSetting {
policyName: string;
policyType: string;
settingName: string;
settingValue: string;
graphPolicyId: string;
}
type GraphPolicy = Record<string, any>;
/**
* Detect policy type from @odata.type field
*/
export function detectPolicyType(policy: GraphPolicy): string {
const odataType = policy['@odata.type'] || '';
if (odataType.includes('deviceManagementConfigurationPolicy')) {
return 'deviceConfiguration';
}
if (odataType.includes('deviceCompliancePolicy') || odataType.includes('windows10CompliancePolicy')) {
return 'compliancePolicy';
}
if (odataType.includes('windowsUpdateForBusinessConfiguration')) {
return 'windowsUpdateForBusiness';
}
if (odataType.includes('configurationPolicy')) {
return 'endpointSecurity';
}
// Default fallback
return 'deviceConfiguration';
}
/**
* Parse Settings Catalog policies (deviceManagementConfigurationPolicy)
*/
function parseSettingsCatalog(policy: GraphPolicy): FlattenedSetting[] {
const results: FlattenedSetting[] = [];
const policyName = policy.name || policy.displayName || 'Unnamed Policy';
const graphPolicyId = policy.id;
const policyType = detectPolicyType(policy);
const settings = policy.settings || [];
for (const setting of settings) {
const instances = setting.settingInstance || [];
for (const instance of instances) {
const defId = instance.settingDefinitionId || '';
const settingName = humanizeSettingId(defId);
// Extract value based on value type
let value = '';
if (instance.simpleSettingValue) {
value = String(instance.simpleSettingValue.value ?? '');
} else if (instance.choiceSettingValue) {
value = String(instance.choiceSettingValue.value ?? '');
} else if (instance.simpleSettingCollectionValue) {
const values = (instance.simpleSettingCollectionValue || []).map((v: any) => v.value);
value = values.join(', ');
} else if (instance.groupSettingCollectionValue) {
// Nested group settings - flatten recursively
const children = instance.groupSettingCollectionValue || [];
for (const child of children) {
const childSettings = child.children || [];
for (const childSetting of childSettings) {
const childDefId = childSetting.settingDefinitionId || '';
const childName = humanizeSettingId(childDefId);
let childValue = '';
if (childSetting.simpleSettingValue) {
childValue = String(childSetting.simpleSettingValue.value ?? '');
} else if (childSetting.choiceSettingValue) {
childValue = String(childSetting.choiceSettingValue.value ?? '');
}
if (childValue) {
results.push({
policyName,
policyType,
settingName: `${settingName} > ${childName}`,
settingValue: childValue,
graphPolicyId,
});
}
}
}
continue;
} else {
value = JSON.stringify(instance);
}
if (value) {
results.push({
policyName,
policyType,
settingName,
settingValue: value,
graphPolicyId,
});
}
}
}
return results;
}
/**
* Parse OMA-URI policies (legacy deviceConfiguration)
*/
function parseOmaUri(policy: GraphPolicy): FlattenedSetting[] {
const results: FlattenedSetting[] = [];
const policyName = policy.displayName || policy.name || 'Unnamed Policy';
const graphPolicyId = policy.id;
const policyType = detectPolicyType(policy);
const omaSettings = policy.omaSettings || [];
for (const setting of omaSettings) {
const omaUri = setting.omaUri || '';
const settingName = humanizeSettingId(omaUri.split('/').pop() || omaUri);
let value = '';
if (setting.value !== undefined && setting.value !== null) {
value = String(setting.value);
} else if (setting.stringValue) {
value = setting.stringValue;
} else if (setting.intValue !== undefined) {
value = String(setting.intValue);
} else if (setting.boolValue !== undefined) {
value = String(setting.boolValue);
}
if (value) {
results.push({
policyName,
policyType,
settingName,
settingValue: value,
graphPolicyId,
});
}
}
return results;
}
/**
* Parse standard property-based policies (compliance, etc.)
*/
function parseStandardProperties(policy: GraphPolicy): FlattenedSetting[] {
const results: FlattenedSetting[] = [];
const policyName = policy.displayName || policy.name || 'Unnamed Policy';
const graphPolicyId = policy.id;
const policyType = detectPolicyType(policy);
// Common properties to extract
const ignoredKeys = ['@odata.type', '@odata.context', 'id', 'displayName', 'name',
'description', 'createdDateTime', 'lastModifiedDateTime',
'version', 'assignments'];
for (const [key, value] of Object.entries(policy)) {
if (ignoredKeys.includes(key) || value === null || value === undefined) {
continue;
}
const settingName = humanizeSettingId(key);
let settingValue = '';
if (typeof value === 'object') {
settingValue = JSON.stringify(value);
} else {
settingValue = String(value);
}
if (settingValue && settingValue !== 'false' && settingValue !== '0') {
results.push({
policyName,
policyType,
settingName,
settingValue,
graphPolicyId,
});
}
}
return results;
}
/**
* Default empty setting for policies with no extractable settings
*/
function defaultEmptySetting(policy: GraphPolicy): FlattenedSetting[] {
const policyName = policy.displayName || policy.name || 'Unnamed Policy';
const graphPolicyId = policy.id;
const policyType = detectPolicyType(policy);
return [{
policyName,
policyType,
settingName: '(No settings found)',
settingValue: 'Policy exists but no extractable settings',
graphPolicyId,
}];
}
/**
* Main parser router - detects type and calls appropriate parser
*/
export function parsePolicySettings(policy: GraphPolicy): FlattenedSetting[] {
const odataType = policy['@odata.type'] || '';
// Settings Catalog
if (odataType.includes('deviceManagementConfigurationPolicy')) {
const settings = parseSettingsCatalog(policy);
return settings.length > 0 ? settings : defaultEmptySetting(policy);
}
// OMA-URI based
if (policy.omaSettings && Array.isArray(policy.omaSettings) && policy.omaSettings.length > 0) {
return parseOmaUri(policy);
}
// Standard properties
const settings = parseStandardProperties(policy);
return settings.length > 0 ? settings : defaultEmptySetting(policy);
}
export default parsePolicySettings;