This commit is contained in:
2026-06-25 12:05:53 -05:00
commit b58e50e423
141 changed files with 28190 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
// Pure drift computation: compares the POSHManager plan (expected) against what
// Microsoft Graph currently reports (live), for the win32LobApp metadata, its
// assignments, and its supersedence/dependency relationships. No I/O — the
// controller fetches live state and feeds it here, so this is fully unit-tested.
// Fields on the win32LobApp we treat as authoritative from the plan.
const APP_DRIFT_FIELDS = [
'displayName',
'publisher',
'installCommandLine',
'uninstallCommandLine',
'applicableArchitectures'
];
function fieldDrift(expected = {}, actual = {}, fields = APP_DRIFT_FIELDS) {
const drift = [];
for (const field of fields) {
const want = expected[field] ?? '';
const got = actual[field] ?? '';
if (String(want) !== String(got)) drift.push({ field, expected: want, actual: got });
}
return drift;
}
function assignmentKey(assignment = {}) {
const target = assignment.target || {};
const type = (target['@odata.type'] || '').replace('#microsoft.graph.', '');
return `${assignment.intent || ''}|${type}|${target.groupId || ''}`;
}
function relationshipKey(rel = {}) {
const type = (rel['@odata.type'] || '').replace('#microsoft.graph.', '');
return `${type}|${rel.targetId || ''}`;
}
// Generic set diff by key: returns items present only in expected (missing in
// tenant) and only in actual (extra in tenant).
function setDiff(expected, actual, keyFn) {
const expectedKeys = new Map(expected.map((item) => [keyFn(item), item]));
const actualKeys = new Map(actual.map((item) => [keyFn(item), item]));
const missing = [...expectedKeys.keys()].filter((k) => !actualKeys.has(k));
const extra = [...actualKeys.keys()].filter((k) => !expectedKeys.has(k));
return { missing, extra };
}
export function computeDrift({
expectedApp = {},
liveApp = {},
expectedAssignments = [],
liveAssignments = [],
expectedRelationships = [],
liveRelationships = []
} = {}) {
const appDrift = fieldDrift(expectedApp, liveApp);
const assignmentDrift = setDiff(expectedAssignments, liveAssignments, assignmentKey);
const relationshipDrift = setDiff(expectedRelationships, liveRelationships, relationshipKey);
const inSync =
appDrift.length === 0 &&
assignmentDrift.missing.length === 0 &&
assignmentDrift.extra.length === 0 &&
relationshipDrift.missing.length === 0 &&
relationshipDrift.extra.length === 0;
return { inSync, appDrift, assignmentDrift, relationshipDrift };
}