From 6d2cb5b2fb4a308e9140d6f77f7c3ec975ddd57f Mon Sep 17 00:00:00 2001 From: Garima Garg <211866541+ggarima01@users.noreply.github.com> Date: Thu, 10 Sep 2026 13:48:57 -0700 Subject: [PATCH] Update Standard Logic App templates and scripts (logic-app-changes) Update the Standard Logic App workflow templates and onboarding agent documentation from the confirmed logic-app-changes export. Normalize workflow JSON files to LF line endings and bump StandardLogicApp VERSION from 10.0 to 11.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../StandardLogicApp/GroupTests_Workflow.json | 240 +++++++++++------- .../Orchestrator_Workflow.json | 77 +++--- .../StandardLogicApp/SCIMTests_Workflow.json | 117 ++++++--- .../StandardLogicApp/UserTests_Workflow.json | 2 +- .../StandardLogicApp/VERSION | 2 +- .../StandardLogicApp/scim-onboarding.agent.md | 76 ++++-- 6 files changed, 333 insertions(+), 181 deletions(-) diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json index 0c45b728..5322cd3b 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/GroupTests_Workflow.json @@ -649,23 +649,33 @@ "actions": {} }, "expression": { - "or": [ + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "All" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Create_Group_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Create_Group_Test" + ] + } ] } ] @@ -1281,23 +1291,33 @@ "actions": {} }, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Update_Group_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Update_Group_Test" + ] + } ] } ] @@ -1883,23 +1903,33 @@ "actions": {} }, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Delete_Group_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Delete_Group_Test" + ] + } ] } ] @@ -2639,23 +2669,33 @@ "actions": {} }, "expression": { - "or": [ + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "All" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Group_Update_Add_Member_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Group_Update_Add_Member_Test" + ] + } ] } ] @@ -3410,23 +3450,33 @@ "actions": {} }, "expression": { - "or": [ + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "All" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Group_Update_Remove_Member_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Group_Update_Remove_Member_Test" + ] + } ] } ] @@ -3761,23 +3811,33 @@ }, "runAfter": {}, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "POD_Group_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "POD_Group_Test" + ] + } ] } ] @@ -4567,7 +4627,7 @@ "inputs": { "name": "RestoreGroupTestOutputs", "value": { - "result": "@if(and(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success (UnassignReassign)', if(startsWith(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Reassign Phase] ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Reassign Phase] Provisioning: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''))))", + "result": "@if(and(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Reassign Phase] ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Reassign Phase] Provisioning: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''))))", "overallResult": "@outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['overallResult']", "provisioningLogsResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), 'success', 'failure')", "scimCheckResult": "@if(equals(coalesce(outputs('RestoreGroupTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", @@ -4659,23 +4719,33 @@ "actions": {} }, "expression": { - "or": [ + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "All" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "GroupTests" - ] - }, - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "Restore_Group_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "GroupTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "Restore_Group_Test" + ] + } ] } ] diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json index aadd6285..3d2a3c1b 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/Orchestrator_Workflow.json @@ -504,9 +504,9 @@ "GroupTests_Workflow": "@outputs('Compose_GroupTests_RunLink')", "SCIMTests_Workflow": "@outputs('Compose_SCIMTests_RunLink')" }, - "overallLogicAppResult": "@if(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(or(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'],'SKIPPED'),'FAILED'),equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),or(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'],'SKIPPED'),'FAILED'),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'],'SKIPPED'),'FAILED'))),equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')),equals(actions('Call_Initialization_Workflow')?['status'],'Failed')),equals(coalesce(body('Poll_UserTests_Status')?['properties']?['status'],''),'Failed')),equals(coalesce(body('Poll_GroupTests_Status')?['properties']?['status'],''),'Failed')),or(and(not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),and(contains(string(coalesce(body('Call_Initialization_Workflow')?['targetDirectoryUserAttributes'],json('[]'))),'manager'),equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['overallResult'],'SKIPPED'),'FAILED')))),'Failed',if(equals(coalesce(body('Poll_SCIMTests_Status')?['properties']?['status'],''),'Failed'),'Failed','Succeeded'))", - "optionalTestsResult": "@if(or(or(or(equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED')), 'WARNING', 'PASSED')", - "authenticationModelResult": "@if(or(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED'), equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED')), 'PASSED', 'FAILED')" + "overallLogicAppResult": "@if(or(not(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),and(coalesce(body('Call_Initialization_Workflow')?['isManagerAttributeSupported'],false),not(equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),not(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),not(equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'],'SKIPPED'),'PASSED')),and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'],false),not(equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))),equals(actions('Call_Initialization_Workflow')?['status'],'Failed'),equals(coalesce(body('Poll_UserTests_Status')?['properties']?['status'],''),'Failed'),equals(coalesce(body('Poll_GroupTests_Status')?['properties']?['status'],''),'Failed'),or(equals(coalesce(body('Get_SCIMTests_Output_Content')?['authenticationModelResult'],'FAILED'),'FAILED'),and(coalesce(body('Call_Initialization_Workflow')?['isManagerAttributeSupported'],false),contains(string(coalesce(body('Call_Initialization_Workflow')?['targetDirectoryUserAttributes'],json('[]'))),'manager'),not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['overallResult'],'SKIPPED'),'PASSED'))))),'Failed',if(equals(coalesce(body('Poll_SCIMTests_Status')?['properties']?['status'],''),'Failed'),'Failed','Succeeded'))", + "optionalSuccessTestsResult": "@if(or(not(equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED')), and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false), not(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED'))), and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false), not(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED'))), and(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false), not(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'PASSED')))), 'WARNING', 'PASSED')", + "authenticationModelResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['authenticationModelResult'], 'FAILED')" } }, "Final_TestResults": { @@ -520,7 +520,7 @@ "testResults": [ { "testName": "Create_User_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['CreateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -529,7 +529,7 @@ }, { "testName": "Update_User_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['UpdateUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -538,7 +538,7 @@ }, { "testName": "Disable_User_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['DisableUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -547,7 +547,7 @@ }, { "testName": "Delete_User_Test", - "testCategory": "optional", + "testCategory": "Mandatory/OptionalSuccess", "testResult": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['DeleteUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -556,7 +556,7 @@ }, { "testName": "User_Update_Manager_Test", - "testCategory": "mandatory", + "testCategory": "Skippable/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['result'], if(not(body('Call_Initialization_Workflow')?['isManagerAttributeSupported']), 'SKIPPED - IsManagerAttributeSupported is false', 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['ManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -565,7 +565,7 @@ }, { "testName": "Restore_User_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['RestoreUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -574,8 +574,8 @@ }, { "testName": "Create_Group_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['CreateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -583,8 +583,8 @@ }, { "testName": "Update_Group_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['UpdateGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -592,8 +592,8 @@ }, { "testName": "Delete_Group_Test", - "testCategory": "optional", - "testResult": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['result'], 'SKIPPED'))", + "testCategory": "Skippable/OptionalSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', if(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['result'], 'SKIPPED')))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['DeleteGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -601,8 +601,8 @@ }, { "testName": "Group_Update_Add_Member_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['AddMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -610,8 +610,8 @@ }, { "testName": "Group_Update_Remove_Member_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RemoveMemberTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -619,7 +619,7 @@ }, { "testName": "Schema_Discoverability_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SchemaDiscoverabilityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -628,7 +628,7 @@ }, { "testName": "SCIM_Null_Update_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMNullUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -637,7 +637,7 @@ }, { "testName": "SCIM_User_Create_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -646,8 +646,8 @@ }, { "testName": "SCIM_Group_Create_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupCreateTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))", @@ -655,7 +655,7 @@ }, { "testName": "SCIM_User_Update_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -664,8 +664,8 @@ }, { "testName": "SCIM_Group_Update_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupUpdateTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))", @@ -673,7 +673,7 @@ }, { "testName": "Validate_Credentials_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictOneSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['ValidateCredentialsTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -682,7 +682,7 @@ }, { "testName": "Federated_Identity_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictOneSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['FederatedIdentityTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -691,7 +691,7 @@ }, { "testName": "SCIM_User_Pagination_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUserPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -700,8 +700,8 @@ }, { "testName": "SCIM_Group_Pagination_Test", - "testCategory": "optional", - "testResult": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['result'], 'SKIPPED'))", + "testCategory": "Skippable/OptionalSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['result'], 'SKIPPED')))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMGroupPaginationTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_SCIMTests_RunLink'))", @@ -709,7 +709,7 @@ }, { "testName": "SCIM_Update_Manager_Test", - "testCategory": "mandatory", + "testCategory": "Skippable/StrictSuccess", "testResult": "@if(not(contains(string(coalesce(body('Call_Initialization_Workflow')?['targetDirectoryUserAttributes'], json('[]'))), 'manager')), 'SKIPPED - manager attribute not in target directory', coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_SCIMTests_Output_Content')?['SCIMUpdateManagerTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -718,7 +718,7 @@ }, { "testName": "POD_User_Test", - "testCategory": "mandatory", + "testCategory": "Mandatory/StrictSuccess", "testResult": "@coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['result'], 'SKIPPED')", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_UserTests_Output_Content')?['PODUserTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", @@ -727,8 +727,8 @@ }, { "testName": "POD_Group_Test", - "testCategory": "mandatory", - "testResult": "@coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['result'], if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'FAILED - [Initialization Phase] Schema_Discovery - /Schemas did not return Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). Group provisioning is mandatory.', 'SKIPPED'))", + "testCategory": "Skippable/StrictSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['result'], 'SKIPPED'))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['PODGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -736,8 +736,8 @@ }, { "testName": "Restore_Group_Test", - "testCategory": "optional", - "testResult": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['result'], 'SKIPPED'))", + "testCategory": "Skippable/OptionalSuccess", + "testResult": "@if(not(coalesce(body('Call_Initialization_Workflow')?['isGroupSupported'], false)), 'SKIPPED - Group object mapping disabled in Entra sync schema', if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), replace(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['result'], 'SKIPPED'), 'FAILED', 'WARNING'), coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['result'], 'SKIPPED')))", "provisioningErrorDetails": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['errorDetails'], '')", "recommendationUrl": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'FAILED'), 'https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/known-issues', '')", "runLink": "@if(equals(coalesce(body('Get_GroupTests_Output_Content')?['RestoreGroupTestOutputs']?['overallResult'], 'SKIPPED'), 'SKIPPED'), '', outputs('Compose_GroupTests_RunLink'))", @@ -750,6 +750,7 @@ "GroupTests_Workflow": "@outputs('Compose_GroupTests_RunLink')", "SCIMTests_Workflow": "@outputs('Compose_SCIMTests_RunLink')" }, + "authenticationModelResult": "@outputs('Evaluate_Test_Results')?['authenticationModelResult']", "overallResult": "@outputs('Evaluate_Test_Results')?['overallLogicAppResult']" } }, diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json index c4c9fbbd..1128c58f 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/SCIMTests_Workflow.json @@ -1063,7 +1063,7 @@ "flattenedGroupSchemaAttrCount": "@length(variables('flattenedGroupAttrNames'))", "missingGroupAttrCount": "@length(body('Filter_Missing_Group_Attrs'))", "missingGroupAttrs": "@body('Select_Missing_Group_Attr_Names')", - "overallResult": "@if(and(equals(outputs('SCIM_Get_Schemas')['statusCode'], 200), greater(length(coalesce(body('SCIM_Get_Schemas')?['Resources'], json('[]'))), 0), equals(length(body('Filter_Missing_User_Attrs')), 0), equals(length(body('Filter_Missing_Group_Attrs')), 0)), 'PASSED', 'FAILED')" + "overallResult": "@if(and(equals(outputs('SCIM_Get_Schemas')['statusCode'], 200), greater(length(coalesce(body('SCIM_Get_Schemas')?['Resources'], json('[]'))), 0), equals(length(body('Filter_Missing_User_Attrs')), 0), or(not(coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)), equals(length(body('Filter_Missing_Group_Attrs')), 0))), 'PASSED', 'FAILED')" } }, "Set_SchemaDiscoverabilityTestOutputs": { @@ -1077,11 +1077,11 @@ "name": "SchemaDiscoverabilityTestOutputs", "value": { "overallResult": "@coalesce(outputs('Compose_Schema_Discoverability_Summary')?['overallResult'], 'FAILED')", - "result": "@if(equals(coalesce(outputs('Compose_Schema_Discoverability_Summary')?['overallResult'], 'FAILED'), 'PASSED'), 'success', if(not(equals(outputs('SCIM_Get_Schemas')['statusCode'], 200)), concat('FAILED - Action: SCIM_Get_Schemas - HTTP ', string(outputs('SCIM_Get_Schemas')['statusCode'])), if(equals(length(coalesce(body('SCIM_Get_Schemas')?['Resources'], json('[]'))), 0), 'FAILED - Action: SCIM_Get_Schemas - endpoint returned no schemas', concat('FAILED - Action: Compose_Schema_Discoverability_Summary - Missing user attrs: ', string(body('Select_Missing_User_Attr_Names')), ' | Missing group attrs: ', string(body('Select_Missing_Group_Attr_Names'))))))", + "result": "@if(equals(coalesce(outputs('Compose_Schema_Discoverability_Summary')?['overallResult'], 'FAILED'), 'PASSED'), 'success', if(not(equals(outputs('SCIM_Get_Schemas')['statusCode'], 200)), concat('FAILED - Action: SCIM_Get_Schemas - HTTP ', string(outputs('SCIM_Get_Schemas')['statusCode'])), if(equals(length(coalesce(body('SCIM_Get_Schemas')?['Resources'], json('[]'))), 0), 'FAILED - Action: SCIM_Get_Schemas - endpoint returned no schemas', concat('FAILED - Action: Compose_Schema_Discoverability_Summary - Missing user attrs: ', string(body('Select_Missing_User_Attr_Names')), if(coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false), concat(' | Missing group attrs: ', string(body('Select_Missing_Group_Attr_Names'))), '')))))", "summary": "@outputs('Compose_Schema_Discoverability_Summary')", "detailedResults": [], "errorDetails": { - "summary": "@if(equals(coalesce(outputs('Compose_Schema_Discoverability_Summary')?['overallResult'], 'FAILED'), 'PASSED'), null, concat(if(greater(length(body('Filter_Missing_User_Attrs')), 0), concat('Missing user attributes (', string(length(body('Filter_Missing_User_Attrs'))), '): ', string(body('Select_Missing_User_Attr_Names')), '. '), ''), if(greater(length(body('Filter_Missing_Group_Attrs')), 0), concat('Missing group attributes (', string(length(body('Filter_Missing_Group_Attrs'))), '): ', string(body('Select_Missing_Group_Attr_Names')), '.'), '')))" + "summary": "@if(equals(coalesce(outputs('Compose_Schema_Discoverability_Summary')?['overallResult'], 'FAILED'), 'PASSED'), null, concat(if(greater(length(body('Filter_Missing_User_Attrs')), 0), concat('Missing user attributes (', string(length(body('Filter_Missing_User_Attrs'))), '): ', string(body('Select_Missing_User_Attr_Names')), '. '), ''), if(and(coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false), greater(length(body('Filter_Missing_Group_Attrs')), 0)), concat('Missing group attributes (', string(length(body('Filter_Missing_Group_Attrs'))), '): ', string(body('Select_Missing_Group_Attr_Names')), '.'), '')))" } } } @@ -2321,23 +2321,33 @@ "actions": {} }, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIMTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIM_Group_Create_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIMTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIM_Group_Create_Test" + ] + } ] } ] @@ -2982,23 +2992,33 @@ "actions": {} }, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIMTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIM_Group_Update_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIMTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIM_Group_Update_Test" + ] + } ] } ] @@ -4293,23 +4313,33 @@ "actions": {} }, "expression": { - "or": [ - { - "equals": [ - "@triggerBody()?['EnabledTests']", - "All" - ] - }, + "and": [ { "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIMTests" + "@coalesce(triggerBody()?['initializationData']?['isGroupSupported'], false)", + true ] }, { - "equals": [ - "@triggerBody()?['EnabledTests']", - "SCIM_Group_Pagination_Test" + "or": [ + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "All" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIMTests" + ] + }, + { + "equals": [ + "@triggerBody()?['EnabledTests']", + "SCIM_Group_Pagination_Test" + ] + } ] } ] @@ -4641,6 +4671,12 @@ }, "expression": { "and": [ + { + "equals": [ + "@coalesce(triggerBody()?['initializationData']?['isManagerAttributeSupported'], false)", + true + ] + }, { "equals": [ "@contains(string(coalesce(triggerBody()?['initializationData']?['targetDirectoryUserAttributes'], json('[]'))), 'manager')", @@ -4698,8 +4734,9 @@ "SCIMUserPaginationTestOutputs": "@variables('SCIMUserPaginationTestOutputs')", "SCIMGroupPaginationTestOutputs": "@variables('SCIMGroupPaginationTestOutputs')", "SCIMUpdateManagerTestOutputs": "@variables('SCIMUpdateManagerTestOutputs')", + "authenticationModelResult": "@if(or(equals(variables('ValidateCredentialsTestOutputs')['overallResult'], 'PASSED'), equals(variables('FederatedIdentityTestOutputs')['overallResult'], 'PASSED')), 'PASSED', 'FAILED')", "testSuiteName": "SCIMTests", - "status": "@if(or(or(or(equals(variables('SchemaDiscoverabilityTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMNullUpdateTestOutputs')['overallResult'], 'FAILED')), or(or(equals(variables('ValidateCredentialsTestOutputs')['overallResult'], 'FAILED'), equals(variables('FederatedIdentityTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMUserCreateTestOutputs')['overallResult'], 'FAILED'))), or(or(or(equals(variables('SCIMGroupCreateTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMUserUpdateTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMGroupUpdateTestOutputs')['overallResult'], 'FAILED')), and(contains(string(coalesce(triggerBody()?['initializationData']?['targetDirectoryUserAttributes'], json('[]'))), 'manager'), equals(variables('SCIMUpdateManagerTestOutputs')['overallResult'], 'FAILED')))), 'Failed', 'Passed')", + "status": "@if(or(or(or(equals(variables('SchemaDiscoverabilityTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMNullUpdateTestOutputs')['overallResult'], 'FAILED')), or(and(not(equals(variables('ValidateCredentialsTestOutputs')['overallResult'], 'PASSED')), not(equals(variables('FederatedIdentityTestOutputs')['overallResult'], 'PASSED'))), equals(variables('SCIMUserCreateTestOutputs')['overallResult'], 'FAILED'))), or(or(or(equals(variables('SCIMGroupCreateTestOutputs')['overallResult'], 'FAILED'), equals(variables('SCIMUserUpdateTestOutputs')['overallResult'], 'FAILED')), equals(variables('SCIMGroupUpdateTestOutputs')['overallResult'], 'FAILED')), and(contains(string(coalesce(triggerBody()?['initializationData']?['targetDirectoryUserAttributes'], json('[]'))), 'manager'), equals(variables('SCIMUpdateManagerTestOutputs')['overallResult'], 'FAILED')))), 'Failed', 'Passed')", "workflowRunId": "@workflow().run.name" } } diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json index 64df0424..5b165158 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/UserTests_Workflow.json @@ -4624,7 +4624,7 @@ "inputs": { "name": "RestoreUserTestOutputs", "value": { - "result": "@if(and(equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success')), concat('success (', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['restoreMode'], 'Unknown'), ')'), if(startsWith(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Reassign Phase] ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Reassign Phase] Provisioning: ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''))))", + "result": "@if(and(equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success')), 'success', if(startsWith(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'Failed Action:'), concat('FAILED - [Reassign Phase] ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], '')), concat('FAILED - [Reassign Phase] Provisioning: ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), ' | SCIM: ', coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''))))", "overallResult": "@outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['overallResult']", "provisioningLogsResult": "@if(and(contains(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'success'), not(contains(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['provisioningResult'], ''), 'failure'))), 'success', 'failure')", "scimCheckResult": "@if(equals(coalesce(outputs('RestoreUserTest_Analyze_Phase3_Provisioning_Results')?['scimCheckResult'], ''), 'success'), 'success', 'failure')", diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION index 2f52450b..2dbc24b3 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/VERSION @@ -1 +1 @@ -10.0 +11.0 diff --git a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/scim-onboarding.agent.md b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/scim-onboarding.agent.md index da369bf1..afc1475d 100644 --- a/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/scim-onboarding.agent.md +++ b/Microsoft.SCIM.LogicAppValidationTemplate/StandardLogicApp/scim-onboarding.agent.md @@ -115,16 +115,21 @@ Collect the ISV's SCIM endpoint and bearer token, validate their Azure environme $groups = Invoke-RestMethod -Uri "/Groups?count=1" -Headers $h $empty = Invoke-RestMethod -Uri "/Users?filter=userName%20eq%20%22nonexistent_xyz%22" -Headers $h $schema = Invoke-RestMethod -Uri "/Schemas" -Headers $h + $groupSchemaId = "urn:ietf:params:scim:schemas:core:2.0:Group" + $schemaSupportsGroups = @($schema.Resources).id -contains $groupSchemaId # Save schema as proper JSON $schema | ConvertTo-Json -Depth 20 | Set-Content .scim-schemas.json -NoNewline ``` From the schema response, detect: - `supportsUsers`: /Users returns 200 - - `supportsGroups`: /Groups returns 200 + - `supportsGroups`: /Groups returns 200 (runtime resource probe) + - `schemaSupportsGroups`: `/Schemas` contains a resource whose `id` is `urn:ietf:params:scim:schemas:core:2.0:Group` (schema-advertisement probe) - `supportsManager`: `manager` attribute in User schema - `supportsSoftDelete`: `active` attribute in User schema - `emptyFilterCompliant`: empty filter returns 200 with `totalResults: 0` + Keep `supportsGroups` and `schemaSupportsGroups` as separate facts. `/Groups` proves runtime resource availability; `/Schemas` proves whether the endpoint advertises the standard SCIM Group schema. Do not infer one result from the other. + 7. **Analyze bearer token** — if it's a JWT, decode the payload (base64) and check `exp` claim: ```bash echo "" | cut -d. -f2 | base64 -d 2>/dev/null | python3 -c "import sys,json; t=json.load(sys.stdin); print(t.get('exp','not a JWT'))" @@ -141,14 +146,15 @@ Present a summary to the ISV: ✅ SCIM endpoint — HTTP 200 ✅ /Users — Supported ✅ /Groups — +✅ /Schemas Group resource — ✅ Empty filter — -SCIM capabilities: Users ✓ Groups <✓|✗> Manager <✓|✗> Soft delete <✓|✗> +SCIM capabilities: Users ✓ Groups endpoint <✓|✗> Group schema <✓|✗> Manager <✓|✗> Soft delete <✓|✗> ``` -If `/Groups` is unsupported, warn the ISV: +If `/Groups` is unsupported or `/Schemas` does not advertise the Group schema, explain both observed facts to the ISV. If the endpoint is user-only and the Entra synchronization Group object mapping is disabled, Group tests are legitimate skips rather than failures: -> ⚠️ **Your SCIM endpoint does not support `/Groups`.** The validation suite includes Group tests (`Create_Group_Test`, `Update_Group_Test`, `Delete_Group_Test`, `SCIM_Group_Create_Test`, `SCIM_Group_Update_Test`, `SCIM_Group_Pagination_Test`, `POD_Group_Test`, `Restore_Group_Test`) that **will fail** because they call `/Groups` on your endpoint. These failures will block submission — the test suite requires all executed tests to pass. To pass Group tests, your SCIM server must implement the `/Groups` resource type and return HTTP 200 for `GET /Groups` (even if the response is an empty list). If you choose to proceed without Group support, the agent will apply Pattern #15 (disable Group sync mappings) to prevent Entra quarantine, but the Logic App Group tests will still fail and submission will not be possible until Groups are implemented. +> ℹ️ **This is a user-only SCIM endpoint.** The endpoint's `/Schemas` response does not advertise `urn:ietf:params:scim:schemas:core:2.0:Group`, and `/Groups` is not available. When the Entra synchronization Group object mapping is disabled, the validation suite legitimately skips Group tests. The final ISV summary must state this reason explicitly. If a Group mapping is enabled, apply Pattern #15 before testing. If Group tests execute and `/Groups` returns an error, apply blocking Pattern #16; do not relabel executed failures as skips. If empty filter is non-compliant, **STOP** and tell the ISV this is a mandatory requirement. They must fix their SCIM server before proceeding. @@ -372,7 +378,7 @@ For federated identity testing, also pass these Phase 4 parameters: |---|---|---| | Core SCIM tests | Use `scimBearerToken` ✓ | Use `scimBearerToken` ✓ | | `Validate_Credentials_Test` | **SKIPPED** (empty tokenEndpoint) | **RUNS** (exercises OAuth) | -| `Federated_Identity_Test` | **SKIPPED/FAILED based on missing federated inputs** | **RUNS** when federated inputs are populated | +| `Federated_Identity_Test` | **SKIPPED/FAILED based on missing federated inputs** | **RUNS** when federated inputs are populated; a non-passing result is acceptable when `Validate_Credentials_Test` succeeds | | POD / sync engine | Uses bearer from stored secrets | Uses OAuth from stored secrets | #### Step 2c: Create resource group (if needed) @@ -1203,17 +1209,44 @@ az rest --method GET \ Then fetch the output content from the `outputsLink.uri` in the response. +The sibling `Evaluate_Test_Results` action on the same run also exposes three top-level aggregation fields (fetch its `outputsLink.uri` the same way): + +| Field | Values | Meaning | +|---|---|---| +| `overallLogicAppResult` | `"Succeeded"` \| `"Failed"` | LA pass/fail verdict. `"Failed"` when any Strict test (User/SCIM/Group) is not `PASSED` — including illegitimate SKIP. Group Strict tests are legitimately excused when `isGroupSupported=false`; in the ISV summary, explain that `/Schemas` does not advertise the SCIM Group resource and the Entra Group mapping is disabled when those facts were verified. Manager tests are legitimately excused when `isManagerAttributeSupported=false`. | +| `optionalSuccessTestsResult` | `"PASSED"` \| `"WARNING"` | Signals WARNING when any of Delete_User, Delete_Group, Restore_Group, or SCIM_Group_Pagination is not `PASSED` (including illegitimate SKIP). Never causes `overallLogicAppResult="Failed"`. | +| `authenticationModelResult` | `"PASSED"` \| `"FAILED"` | `"PASSED"` when at least one of `Validate_Credentials_Test` or `Federated_Identity_Test` succeeded. `"FAILED"` when neither passed — also trips `overallLogicAppResult="Failed"`. | + ### Step 6b: Parse each test result -Each entry has: +Each entry in `Final_TestResults.testResults[]` has: ```json { "testName": "Create_User_Test", - "testResult": "success" | "", - "provisioningErrorDetails": { "errorCode": "...", "reason": "..." } + "testCategory": "mandatory" | "optional", + "testResult": "success" + | "FAILED - " + | "WARNING - " + | "SKIPPED" + | "SKIPPED - Group object mapping disabled in Entra sync schema" + | "SKIPPED - IsManagerAttributeSupported is false", + "provisioningErrorDetails": { "errorCode": "...", "reason": "..." }, + "recommendationUrl": "", + "runLink": "", + "message": "" } ``` +Test result semantics: +- **`"success"`** — the test ran and passed. +- **`"FAILED - "`** — a Strict test ran and failed. Contributes to `overallLogicAppResult="Failed"`. +- **`"WARNING - "`** — an OptionalSuccess test ran and failed. Contributes to `optionalSuccessTestsResult="WARNING"` only — does not affect `overallLogicAppResult`. +- **`"SKIPPED"`** — the test was excluded by the `EnabledTests` parameter. Under the mandated `EnabledTests: "All"` this should not appear for Strict tests; if it does, the Strict test is illegitimately skipped and `overallLogicAppResult` will be `"Failed"`. +- **`"SKIPPED - Group object mapping disabled in Entra sync schema"`** — legitimate skip when `isGroupSupported=false`. Before describing why, verify the Phase 1 `/Schemas` evidence and the current Entra mapping state. When `/Schemas` does not advertise `urn:ietf:params:scim:schemas:core:2.0:Group` and the Entra Group object mapping is disabled, tell the ISV exactly that. Overall run stays `"Succeeded"`. +- **`"SKIPPED - IsManagerAttributeSupported is false"`** — legitimate skip when `isManagerAttributeSupported=false`. Overall run stays `"Succeeded"`. + +**Authentication pair exception:** `Validate_Credentials_Test` and `Federated_Identity_Test` are `Mandatory/StrictOneSuccess`, not independently strict. Evaluate them as a pair using `authenticationModelResult`. When `authenticationModelResult == "PASSED"`, one model succeeded and the other model may be skipped or may contain a diagnostic non-success result such as `"Entra token acquisition failed"`. Do not classify that non-passing counterpart as a failed validation test, do not block submission, and do not include it in `Tests failed`. When `authenticationModelResult == "FAILED"`, authentication fails and submission is blocked. + ### Step 6c: Drill into child workflow actions to find the real error (BEFORE pattern matching) **The `Final_TestResults` summary is never enough to diagnose a failure.** It tells you *which* test failed and gives a high-level message, but the actual root cause — the HTTP status code, the Graph API error body, the SCIM server response — lives inside the child workflow's action inputs and outputs. You MUST drill down to that level before classifying any failure. @@ -1227,7 +1260,7 @@ Follow this process for **every** failed test in `Final_TestResults`: - `Create_Group_Test`, `Update_Group_Test`, `Delete_Group_Test`, `Group_Update_Add_Member_Test`, `Group_Update_Remove_Member_Test`, `POD_Group_Test`, `Restore_Group_Test` → **GroupTests_Workflow** - `Schema_Discoverability_Test`, `SCIM_Null_Update_Test`, `SCIM_User_Create_Test`, `SCIM_User_Update_Test`, `SCIM_Group_Create_Test`, `SCIM_Group_Update_Test`, `SCIM_User_Pagination_Test`, `SCIM_Group_Pagination_Test`, `Validate_Credentials_Test`, `Federated_Identity_Test`, `SCIM_Update_Manager_Test` → **SCIMTests_Workflow** -> **Note:** `Delete_User_Test` is **optional** — a failure produces WARNING (not FAIL) in the overall result. `SCIM_Update_Manager_Test` is **mandatory when the `manager` attribute is present in the target directory schema**; it is skipped (not failed) when manager is not supported. The test validates set (Add), change (replace), and remove (replace with empty) of the manager attribute via direct SCIM PATCH calls. +> **Note:** `Delete_User_Test` is **Mandatory / OptionalSuccess** — a failure produces WARNING (not FAIL) in the overall result. An illegitimate SKIP (e.g. `EnabledTests` narrowed to exclude it) also trips WARNING via `optionalSuccessTestsResult`. `SCIM_Update_Manager_Test` is **Skippable / Strict** — gated by `isManagerAttributeSupported`. When `isManagerAttributeSupported=false` the test is legitimately skipped (no penalty); otherwise it must pass. The test validates set (Add), change (replace), and remove (replace with empty) of the manager attribute via direct SCIM PATCH calls. #### 2. List all executed actions in the child workflow @@ -1332,17 +1365,18 @@ All 8 required permissions must be present: | 12 | `NO_LOGS` / `PROVISIONING_LOGS_MISSING` **after Step 6c confirms no permission error AND Pattern #14 is ruled out** | Entra sync cycle too slow | ⚠️ Maybe | Re-run once (sync service gets faster on subsequent cycles). If same failure repeats, escalate. | | 13 | `Authentication_MSGraphPermissionMissing` | MI missing Graph permission | ✅ Yes | Parse the missing permission name(s) from the error, find the appRoleId from the Graph SP, assign via `appRoleAssignments`. This is NOT a propagation delay — the permission was never assigned. **After assigning, you MUST `az webapp restart` the LA** to force a new MI token that carries the added appRole; without restart the cached token still lacks the permission and the next run will fail identically. Poll `/host/default/properties/status` until `state=Running` (~60s), then re-run. | | 14 | `NO_LOGS_FOUND` on **every** UserTests/GroupTests test AND/OR `POD_User_Test`/`POD_Group_Test` returns 401 from `provisionOnDemand` AND/OR `GET /synchronization/jobs/.status.code == Quarantine` | Entra sync job quarantined (connectivity parameters missing/rejected) OR LA MI is not an owner of the App + SP (synchronization owner required for `provisionOnDemand`) | ✅ Yes | **Before any re-run of the orchestrator**, GET `/synchronization/jobs/` and check `status.code`. If `Quarantine`: re-PATCH `https://graph.microsoft.com/beta/servicePrincipals//synchronization/connectivityParameters` with only the supported keys for the auth mode (bearer: `authenticationType` + `baseAddress` + `secretToken`; OAuth: `authenticationType` + `baseAddress` + `oauth2ClientId` + `oauth2ClientSecret` + `oauth2TokenExchangeUri` + `credentialLocationInRequest`). Then `POST /jobs//restart` with `{"criteria":{"resetScope":"Full"}}`, then `POST /jobs//start`, then re-verify `status.code` is `Active` and `lastExecution.error` is `null`. If `provisionOnDemand` still 401s after the job is healthy: add the LA MI's enterprise object id as owner of BOTH the application and the SP — `POST /applications//owners/$ref` and `POST /servicePrincipals//owners/$ref` with body `{"@odata.id":"https://graph.microsoft.com/v1.0/directoryObjects/"}` — then `az webapp restart` the LA and re-trigger the orchestrator. | -| 15 | Entra `/validateConnectivity` behavior (surfaced through Graph `validateCredentials`) returns `SystemForCrossDomainIdentityManagementServiceIncompatible`, `CredentialValidationUnavailable`, or inner HTTP `404` involving Group connectivity **and** Phase 1 found `/Groups` unsupported **and** the job schema has an enabled Group object mapping | Entra processes or probes Group because the synchronization schema enables its Group object mapping, but the SCIM endpoint is user-only | ✅ Yes | Follow the mandatory Pattern #15 procedure below: disable every Group object mapping with a full-schema `PUT`, verify, restart/start the job, and revalidate. | +| 15 | Entra `/validateConnectivity` behavior (surfaced through Graph `validateCredentials`) returns `SystemForCrossDomainIdentityManagementServiceIncompatible`, `CredentialValidationUnavailable`, or inner HTTP `404` involving Group connectivity **and** Phase 1 found `/Groups` unsupported, `/Schemas` does not advertise the standard Group schema, **and** the job schema has an enabled Group object mapping | Entra processes or probes Group because the synchronization schema enables its Group object mapping, but the SCIM endpoint is user-only | ✅ Yes | Follow the mandatory Pattern #15 procedure below: disable every Group object mapping with a full-schema `PUT`, verify, restart/start the job, and revalidate. | | 16 | Any Group test (`Create_Group_Test`, `Update_Group_Test`, `Delete_Group_Test`, `Group_Update_Add_Member_Test`, `Group_Update_Remove_Member_Test`, `SCIM_Group_Create_Test`, `SCIM_Group_Update_Test`, `SCIM_Group_Pagination_Test`, `POD_Group_Test`, `Restore_Group_Test`) fails with `404`, `Not Found`, or SCIM error **and** Phase 1 found `/Groups` unsupported | The Logic App test workflows call `/Groups` directly using the bearer token — Pattern #15 only disables the Entra sync-engine Group mapping, not the LA tests themselves | ❌ No | **Do NOT auto-fix or suppress.** Report to the ISV: *"Your SCIM endpoint does not implement the `/Groups` resource type. The following Group tests failed because your server returned 404 for `/Groups` requests: [list failed tests]. To pass validation and submit to the Entra app gallery, your SCIM server must support the `/Groups` endpoint and return HTTP 200 (even for an empty group list). These failures block submission."* Do NOT allow submission. Do NOT re-run — the same tests will fail identically. Wait for the ISV to confirm they have added `/Groups` support, then re-probe `/Groups` (Phase 1 Step 6) to confirm before re-triggering. | #### Pattern #15: Disable Group object mappings for a user-only endpoint This issue is commonly described as `/validateConnectivity` failing. The public Graph calls in this agent use the `validateCredentials` endpoints; the Group probe is part of Entra's underlying connectivity-validation behavior. -Apply this recovery only after all three conditions are confirmed: +Apply this recovery only after all four conditions are confirmed: 1. Phase 1 showed that `/Groups?count=1` is unsupported or returns `404`. -2. The actual inner connectivity error is `SystemForCrossDomainIdentityManagementServiceIncompatible`, `CredentialValidationUnavailable`, or an HTTP `404` involving Group. A generic `401`, `403`, rejected bearer token, or OAuth token-exchange failure does not match. -3. `GET /servicePrincipals//synchronization/jobs//schema` contains at least one object mapping where `sourceObjectName == "Group"` or `targetObjectName == "Group"` and `enabled == true`. +2. Phase 1 showed that `/Schemas` does not advertise `urn:ietf:params:scim:schemas:core:2.0:Group`. +3. The actual inner connectivity error is `SystemForCrossDomainIdentityManagementServiceIncompatible`, `CredentialValidationUnavailable`, or an HTTP `404` involving Group. A generic `401`, `403`, rejected bearer token, or OAuth token-exchange failure does not match. +4. `GET /servicePrincipals//synchronization/jobs//schema` contains at least one object mapping where `sourceObjectName == "Group"` or `targetObjectName == "Group"` and `enabled == true`. If no Group mapping exists or every Group mapping is already disabled, do not write the schema. Pattern #15 is not the root cause; continue diagnosis using the exact inner error. @@ -1363,6 +1397,8 @@ When all conditions match: 7. Re-run saved-credential connectivity validation where applicable, then poll the job until `status.code` is `Active` or `InProgress`, `status.quarantine` is `null`, and `status.lastExecution.error` is `null` (or `lastExecution.state == "Succeeded"`). 8. Before re-triggering tests, follow the existing Step 5a sync-job health gate and mandatory Step 5a2 Logic App restart. Do not ask the ISV for permission; this pattern is auto-fixable. +> **After Pattern #15 completes**, subsequent LA runs are expected to show every Group test's `testResult` as `"SKIPPED - Group object mapping disabled in Entra sync schema"`. This is the intended post-#15 state — not a failure. `overallLogicAppResult` will remain `"Succeeded"` provided every non-Group Strict test passes and `authenticationModelResult` is `"PASSED"`. In the final ISV summary, state: `Group tests skipped: (legitimate). Reason: the ISV endpoint /Schemas response does not advertise the SCIM Group resource, and the Entra Group object mapping is disabled.` + ### Step 6e: Extract canonical values from schema validation errors When the error contains `is not one of the canonical values: [val1, val2]`: @@ -1421,9 +1457,13 @@ Give the ISV a complete, copy-ready submission summary for the exact successful ### Steps -1. **Apply the success gate.** Continue only when all of the following are true: +1. **Apply the success gate.** Continue only when ALL of the following are true: - The exact captured orchestrator `` reached terminal status `Succeeded`. - - `Final_TestResults` for that same run has no blocking failures. + - `Evaluate_Test_Results.overallLogicAppResult == "Succeeded"` (fetched from the `Evaluate_Test_Results` action inputs on that run). + - `Evaluate_Test_Results.authenticationModelResult == "PASSED"` (at least one auth model succeeded — this is a hard requirement). + - Every **non-authentication** entry in `Final_TestResults.testResults[]` has `testResult` starting with `"success"`, `"SKIPPED"`, or `"WARNING"` — NEVER `"FAILED"`. + - Treat `Validate_Credentials_Test` and `Federated_Identity_Test` as one `Mandatory/StrictOneSuccess` authentication pair. Because `authenticationModelResult == "PASSED"` is already required, a skipped or non-passing counterpart (including a diagnostic result such as `"Entra token acquisition failed"`) is acceptable and does not block submission. Report which authentication model passed, but do not count the counterpart in `Tests failed`. + - `optionalSuccessTestsResult == "PASSED"` is preferred; `"WARNING"` is acceptable — call out each warning test explicitly in the summary. - No Phase 6 issue remains unresolved. Do not print submission details for a failed, cancelled, timed-out, running, or stale run. A workflow status of `Succeeded` and the test-result totals are separate facts; verify and print both. @@ -1459,8 +1499,10 @@ Workflow: Orchestrator_Workflow Run ID: Run status: Succeeded Tests passed: -Tests skipped: +Tests skipped (legitimate — feature not supported): +Tests warning: Tests failed: 0 + (legitimate). Reason: the ISV endpoint /Schemas response does not advertise the SCIM Group resource, and the Entra Group object mapping is disabled."> Entra application: Service principal object ID: @@ -1474,6 +1516,8 @@ Official submission guide: https://github.com/AzureAD/SCIMReferenceCode/blob/mas Submission request ID: Enter the request ID supplied separately by the Microsoft team; the Logic App does not generate it. ``` +The conditional Group explanation is mandatory when its two evidence gates hold. Count only the recognized Group-skip results in ``; do not use the total skipped count, and do not print this reason for unrelated skips. If the evidence gates do not hold, diagnose the Group outcome under Pattern #15 or Pattern #16 instead of claiming a legitimate schema-based skip. + 6. Tell the ISV to review the application details and attestations before submitting because the form cannot be edited after submission. If the app-specific link does not open, use the generic fallback, select the enterprise application matching both `` and ``, then go to **Provisioning > Submit validation results**. ---