---
title: Violation workflow example
description: Example workflow for handling segregation of duties violations through remediation and exceptions
component: pingoneaic
page_id: pingoneaic:identity-governance:administration/example-violation-workflow
canonical_url: https://docs.pingidentity.com/pingoneaic/identity-governance/administration/example-violation-workflow.html
keywords: ["workflows", "use cases", "examples", "SoD", "violation"]
section_ids:
  assumptions: Assumptions
  example: Example
---

# Violation workflow example

In this example, an administrator creates a workflow that:

* Processes a single violation task.

* If the violation outcome is `Remediate`, it remediates the violation, validates the result, and removes the entitlements.

* If the violation outcome is `Allow`, it creates an exception.

* If the violation outcome is `expiration`, it goes to a manual decision using the fulfillment node.

* If the end user tasked with the manual fulfillment approves of the various outcomes, the workflow is complete.

* If the end user tasked with the manual fulfillment denies the resulting outcomes, the workflow calls a reject requests script, and loops back for another manual confirmation.

## Assumptions

* Each violation has an owner.

* Make sure to catch any error/failure conditions.

## Example

![An example of a violation handling workflow.](../_images/governance-workflow-example-violation.png)

* 1 The Violation node routes the violation to the appropriate outcome. Options are: `Remediate`, `Allow`, and `Expiration`.

* 2 The Remediate Violation Script node gets the context information for the violation and sets the `remediationResponse`.

  > **Collapse: Click to display Remediate Violation script**
  >
  > ```js
  > logger.info("Remediating violation");
  >
  > var content = execution.getVariables();
  > var violationId = content.get('id');
  > var remediation = content.get('remediation');
  > logger.info("Remediating violation - violationId: " + violationId + ', remediation payload: ' + remediation);
  >
  > var remediationContent = null;
  >
  > var remediationResponse = openidm.action('iga/governance/violation/' + violationId + '/remediate', 'POST', remediation);
  > logger.info("Remediating response: " + remediationResponse);
  >
  > remediationContent = remediationResponse.decision.remediation;
  > execution.setVariable("remediation", remediationContent);
  > ```

* 3 The Remediate Violation IF/ELSE node routes successful validations to an auto remove script node and validation failures to a failure handling node.

* 4 The Remove Grants Auto script node removes the entitlement grants that caused the violation.

  > **Collapse: Click to display Auto Remove Entitlement Grants script**
  >
  > ```js
  > logger.info("Removing grants automatically");
  >
  > var content = execution.getVariables();
  > var violationId = content.get('id');
  > var failureReason = null;
  > var phaseName = content.get('phaseName');
  > var violationObj;
  >
  > logger.info("Removing entitlement grants for violation " + violationId + " with phase name " + phaseName);
  >
  > try {
  >   violationObj = openidm.action('iga/governance/violation/lookup/' + violationId, 'GET', {}, {});
  > }
  > catch (e) {
  >   failureReason = "Removing entitlement grants failed: Error reading violation with id " + violationId + ". Error message: " + e.message;
  > }
  >
  > if (!failureReason) {
  >   var remediation = violationObj.decision.remediation;
  >   var failedDeprovisioning = false;
  >   var deprovisionedIds = [];
  >   for(var grant of violationObj.violatingAccess) {
  >     if (!remediation.grantIds.includes(grant.compositeId)) {
  >       continue;
  >     }
  >
  >     var userId = violationObj.user.id;
  >     logger.info("Removing entitlement grant: " + grant.compositeId + ", user: " + userId + ", violation: " + violationId);
  >
  >     try {
  >       var payload = {
  >         entitlementId: grant.assignment.id
  >       };
  >       logger.info('Payload to remove grant: ' + JSON.stringify(payload));
  >
  >       var queryParams = {
  >         "_action": "remove"
  >       }
  >
  >       var result = openidm.action('iga/governance/user/' + userId + '/entitlements', 'POST', payload,queryParams);
  >       execution.setVariables(result);
  >
  >       logger.info("Deprovisioned " + grant.assignment.id + " successfully, user " + userId + + ", violation: " + violationId);
  >       deprovisionedIds.push(grant.compositeId);
  >     }
  >     catch (e) {
  >       failureReason = failureReason + ". Removing grants failed: Error deprovisioning entitlement" + grant.assignment.id + " from user. Error message: " + e.message + ".";
  >       failedDeprovisioning = true;
  >     }
  >   }
  >
  >   if (!failedDeprovisioning) {
  >     openidm.action('iga/governance/violation/' + violationId + '/remediation/status/complete', 'POST', {});
  >   } else {
  >     failureReason = failureReason + ". Grants removed: " + deprovisionedIds;
  >   }
  > }
  >
  > if (failureReason) {
  >   var update = { 'comment': failureReason };
  >   openidm.action('iga/governance/violation/' + violationId + '/comment', 'POST', update, {});
  > }
  > ```

* 5 The Allow Violation script node logs the information. If a failure arises, Identity Governance posts the failure with the reason.

  > **Collapse: Click to display Allow Violation script node**
  >
  > ```js
  > logger.info("Allowing violation");
  > var content = execution.getVariables();
  > var violationId = content.get('id');
  > var phaseName = content.get('phaseName');
  > logger.info("Violation to be allowed: " + violationId + " with phase name " + phaseName);
  >
  > var failureReason = null;
  > try {
  >     var allowResponse = openidm.action('iga/governance/violation/' + violationId + '/allow', 'POST', {});
  > logger.info("Violation " + violationId + " was allowed successfully.");} catch (e) {
  >     failureReason = "Failed allowing violation with id " + violationId + ". Error message: " + e.message;
  > }
  >
  > if (failureReason) {
  >     var update = { "comment": failureReason };
  >     try {
  >         openidm.action('iga/governance/violation/' + violationId + '/phases/' + phaseName + '/comment', 'POST', update, {});
  >     } catch (e) {
  >         openidm.action('iga/governance/violation/' + violationId + '/comment', 'POST', update, {});
  >     }
  > }
  > ```

* 6 The Fulfillment node requests a manual completion of the task by an authorized end user, typically during review time. If successful, the task is fulfilled, and the workflow is complete.

* 7 The Reject Request script node retrieves the `requestID`, logs the rejection, and sends a reject request.

  > **Collapse: Click to display Reject Request script**
  >
  > ```js
  > logger.info("Rejecting request");
  >
  > var content = execution.getVariables();
  > var requestId = content.get('id');
  >
  > logger.info("Execution Content: " + content);
  > var requestIndex = openidm.action('iga/governance/requests/' + requestId, 'GET', {}, {});
  > var decision = {'outcome': 'denied', 'status': 'complete', 'decision': 'rejected'};
  > var queryParams = { '_action': 'update'};
  > openidm.action('iga/governance/requests/' + requestId, 'POST', decision, queryParams);
  > ```

|   |                                                                                                                                                                                                                                                   |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Download the JSON file for this workflow [here](../_attachments/workflows/workflowUIViolationProcessWorkflowExample.json).Learn more about how to import or export workflows in [workflow editor canvas](workflow-configure.html#orch-ui-canvas). |
