First draft of your first rule, add rule ve validator

This commit is contained in:
tyler-mairose-sp
2023-06-09 10:39:41 -04:00
parent b082e68bfc
commit fab15ead51
10 changed files with 735 additions and 4 deletions

View File

@@ -3,7 +3,7 @@ id: cloud-executed-rules
title: Cloud Executed Rules
pagination_label: Cloud Executed Rules
sidebar_label: Cloud Executed Rules
sidebar_position: 1
sidebar_position: 2
sidebar_class_name: cloudExecutedRules
keywords: ['cloud', 'rules']
description: Overview of cloud-executed rules

View File

@@ -3,7 +3,7 @@ id: connector-executed-rules
title: Connector Executed Rules
pagination_label: Connector Executed Rules
sidebar_label: Connector Executed Rules
sidebar_position: 1
sidebar_position: 3
sidebar_class_name: cloudExecutedRules
keywords: ['connector', 'rules']
description: Overview of connector-executed rules.

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,21 @@
---
id: guides
title: Rule Guides
pagination_label: Guides
sidebar_label: Guides
sidebar_position: 1
sidebar_class_name: Rules
keywords: ['rules', 'guides']
description: Transform Guides
slug: /docs/rules/guides
tags: ['Rules', 'Guides']
---
Not sure how to use rules yet? Read these guides to see how you can use rules and learn how to get started!
```mdx-code-block
import DocCardList from '@theme/DocCardList';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
<DocCardList items={useCurrentSidebarCategory().items}/>
```

View File

@@ -0,0 +1,495 @@
---
id: your-first-rule
title: Your First Rule
pagination_label: Your First Rule
sidebar_label: Your First Rule
sidebar_class_name: yourFirstRule
keywords: ['rules', 'guides', 'first']
description: Learn to build your first rule!
sidebar_position: 1
slug: /docs/rules/guides/your-first-rule
tags: ['Rules', 'Guides', 'First']
---
## Overview
In this guide you'll learn the end to end process of writing a cloud rule to generate a username to be used during account creation.
- [Attribute generator rule overview](#attribute-generator-rule)
- [Username requirements](#username-requirements)
- [Writing the rule](#writing-the-rule)
- [Validating the rule](#validate-the-rule)
- [Submitting for rule review](#submitting-for-rule-review)
## Attribute Generator rule
This rule generates complex account attribute values during provisioning, e.g. when creating an account. You would typically use this rule when you are creating an account to generate attributes like usernames.
This rule executes in the IdentityNow cloud, and it has read-only access to IdentityNow data models, but it does not have access to on-premise sources or connectors.
Refer to [Attribute Generator Rule](../cloud-rules/account_profile_attribute_generator.md) to learn more about the inputs available to you during the rule execution.
## Username requirements
With this rule you will be able to generate a unique username and check for uniqueness for an Active Directory source.
The unique username will be generated as follows.
- Retrieve the first name, last name and other name of the user.
- If other name is not available then we will use the first name.
- First, check the length of (othername | firstname).lastname, if it is greater than 12 then use the first 12 letters of the first name, add a period `.` and append the first character of the last name. Convert to lowercase. Check for uniqueness.
- If it is not unique then use the first 12 characters of the first name and add a period `.` and append the second character of the last name. Convert to lowercase. Check for uniqueness.
- Follow this pattern until a unique username is found. If all characters of the last name are exhausted return null.
### Example Outputs
The following example shows the output if the other name is not null, the othername.lastname is less than 12 characters and the username `james.doe` after being lowercased is unique.
<div style={{textAlign: 'center'}}>
```mermaid
flowchart TD
A[first name]
B[last name]
C[other name]
A --> | John| E
B --> | Doe | E
C --> | James| E
E[othername.lastname]
F[Length greater than 12?]
E --> |James.Doe|F
F --> |No| G
G[lowercase username]
G --> |james.doe| H
H[Check Uniqueness]
H --> |Unique| I
I[Final Result: \n james.doe]
```
</div>
The next example shows the case where the other name if null, the firstname.lastname is greater than 12 characters and the firstname.firstCharacterOfLastName lowercased `alexander.s` is not unique. The rule will then use the firstname.secondCharacterOfLastName lowercased `alexander.m`.
<div style={{textAlign: 'center'}}>
```mermaid
flowchart TD
A[first name]
B[last name]
C[other name]
A --> | Alexander| E
B --> | Smith | E
C --> | null| E
E[firstname.lastname]
F[Length greater than 12?]
E --> |Alexander.Smith|F
F --> |Yes| H
H[firstname.firstCharacterOfLastName]
I[lowercase username]
H--> I
I--> |alexander.s| J
J[Check Uniqueness]
J--> |Unique| K
K[Final Result:\nalexander.s]
L[firstname.secondCharacterOfLastName]
J--> |Not Unique| L
M[lowercase username]
L-->M
N[Check Uniqueness]
M--> |alexander.m| N
N --> |Unique| P
P[Final Result:\n alexander.m]
```
</div>
## Writing the rule
Create a new xml file with the following naming scheme [rule file naming](/idn/docs/rules/cloud-rules#review-guidelines).
Open that file in your preferred editor.
For the attribute generator rule you can begin with the following template.
```xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule name="Example Rule" type="AttributeGenerator">
<Description>Describe your rule here.</Description>
<Source><![CDATA[
// Add your logic here.
]]></Source>
</Rule>
```
### Add imports and generateUsername function
Add a description and the necessary imports for your rule. This rule will need `Identity` and `Application` from `sailpoint.object` and a few other classes for working with Strings. Also added is the global constant `MAX_USERNAME_LENGTH` in the example below this rule will use the value of 12.
```java
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule name="ADUserNameGenerator" type="AttributeGenerator">
<Description>This will generate a unique username for active directory</Description>
<Source><![CDATA[
import sailpoint.tools.GeneralException;
import sailpoint.object.*;
import java.util.ArrayList;
import sailpoint.api.*;
import java.util.List;
import org.apache.commons.lang.StringUtils;
//Global constant
int MAX_USERNAME_LENGTH = 12;
public String generateUsername(String firstName, String lastName) {
}
]]></Source>
</Rule>
```
### Get the firstName, lastName, and otherName attributes and sanitize input
```java
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule name="Example Rule" type="AttributeGenerator">
<Description>This will generate a unique username for active directory</Description>
<Source><![CDATA[
import sailpoint.tools.GeneralException;
import sailpoint.object.*;
import java.util.ArrayList;
import sailpoint.api.*;
import java.util.List;
import org.apache.commons.lang.StringUtils;
//Global constant
int MAX_USERNAME_LENGTH = 12;
public String generateUsername(String firstName, String lastName) {
firstName = StringUtils.trimToNull( firstName );
lastName = StringUtils.trimToNull( lastName );
otherName = identity.getStringAttribute("otherName");
if(firstName != null){
firstName = firstName.replaceAll("[^a-zA-Z0-9]", "");
}
if(lastName != null){
lastName = lastName.replaceAll("[^a-zA-Z0-9]", "");
}
if(otherName != null){
otherName = otherName.replaceAll("[^a-zA-Z0-9]", "");
}
if ( ( firstName == null ) || ( lastName == null ) ){
log.debug( "AD Create User Name | Exit from generateADUsername method. No last name and other name for user" );
return null;
}
// If other name is available then we are using firstname as other name
if( !StringUtils.isEmpty(otherName) )
firstName = otherName;
// This will hold the final username;
String username = null;
log.debug( "AD Create User Name | Final first name and last name for user: " +firstName + " " +lastName );
// This will hold the final username;
String finalUserName = null;
String fullName = firstName + "." + lastName;
String newUsername = lastName;
}
]]></Source>
</Rule>
```
### Logic when the proposed username is greater than the max length
If the full name is greater than the `MAX_USERNAME_LENGTH` the rule will check if the length of the first name is greater than the MAX_USERNAME_LENGTH minus 2 (in the case below 10) characters of the first name to allow for the period `.` and the first character of the last name to take up the remaining two characters. If the first name is less than the `MAX_USERNAME_LENGTH` the rule will use the full first name for the username with the period `.` and the first character of the last name appended. After the username is determined, a call to `isUnique( username )` is made. This uses the IDNRuleUtil class to check active directory if the username exists. We will add in that function shortly.
```java
if(fullName.length() > MAX_USERNAME_LENGTH) {
int firstNameLength = firstName.length();
//Checking if the firstname length is more than the MAX minus 2 chars.
//If firstname is more then the MAX minus 2 we are picking MAX minus 2 characters from the firstname.
if(firstNameLength > (MAX_USERNAME_LENGTH - 2)){
//lastNameLength represents the current pointer of lastlength.
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName.substring(0,(MAX_USERNAME_LENGTH-2)) + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username )) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
//If firstname is less than or equal to the MAX minus 2 chars then we are considering full firstname for username generation.
else{
//lastNameLength represents the current pointer of lastlength.
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username )) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
}
```
### Logic when the proposed user name is within the max length
If the username firstname.lastname is less than or equal to the `MAX_USERNAME_LENGTH` check it for uniqueness against active directory. If it is not unique, check uniqueness with firstname.firstLetterOfLastName, firstname.secondLetterOfLastName, etc...
```java
//The full name is less than MAX_USERNAME_LENGTH minus 2 chars directly assign username to full name.
username = fullName;
username = username.toLowerCase();
if( isUnique( username ) ) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
else{
//If the username was not unique with firstname.last name we then check uniqueness
// with firstname.firstLetterOfLastName, firstname.secondLetterOfLastName e.t.c...
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username ) ) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
```
### Add function `isUnique()` to check active directory for username
The `isUnique()` function takes the username as a string and uses the `accountExistsByDisplayName()` function from the IDNRuleUtil class to search active directory and return a true or false result depending if the username is already taken. The function takes an application name and username to test against. The variables `idn` and `application` are included as inputs to the attribute generator rule and are already initialized. Refer to [inputs](../cloud-rules/account_profile_attribute_generator.md#input) to see all inputs available to attribute generator rules.
```java
public boolean isUnique ( String username ) throws GeneralException {
return !idn.accountExistsByDisplayName(application.getName(), username);
}
```
### Invoke `generateUsername()` with the identities first and last name
This is the final part of the rule. We call our `generateUsername()` function, passing in the identities first and last name.
The `identity` variable is already initialized and included as input to our attribute generator rule.
```java
return generateUsername( identity.getFirstname(), identity.getLastname() );
```
## The complete rule
```java
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule name="ADUserNameGenerator" type="AttributeGenerator">
<Description>This will generate a unique username for active directory</Description>
<Source><![CDATA[
import sailpoint.tools.GeneralException;
import sailpoint.object.*;
import java.util.ArrayList;
import sailpoint.api.*;
import java.util.List;
import org.apache.commons.lang.StringUtils;
//Global constant
int MAX_USERNAME_LENGTH = 12;
public String generateUsername(String firstName, String lastName) {
firstName = StringUtils.trimToNull( firstName );
lastName = StringUtils.trimToNull( lastName );
String otherName = identity.getStringAttribute("otherName");
if(firstName != null){
firstName = firstName.replaceAll("[^a-zA-Z0-9]", "");
}
if(lastName != null){
lastName = lastName.replaceAll("[^a-zA-Z0-9]", "");
}
if(otherName != null){
otherName = otherName.replaceAll("[^a-zA-Z0-9]", "");
}
if ( ( firstName == null ) || ( lastName == null ) ){
log.debug( "AD Create User Name | Exit from generateADUsername method. No last name and other name for user" );
return null;
}
// If other name is available then we are using firstname as other name
if( !StringUtils.isEmpty(otherName) )
firstName = otherName;
// This will hold the final username;
String username = null;
log.debug( "AD Create User Name | Final first name and last name for user: " +firstName + " " +lastName );
// This will hold the final username;
String finalUserName = null;
String fullName = firstName + "." + lastName;
String newUsername = lastName;
if(fullName.length() > MAX_USERNAME_LENGTH) {
int firstNameLength = firstName.length();
//Checking if the firstname length is more than the MAX minus 2 chars.
//If firstname is more then the MAX minus 2 we are picking MAX minus 2 characters from the firstname.
if(firstNameLength > (MAX_USERNAME_LENGTH - 2)){
//lastNameLength represents the current pointer of lastlength.
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName.substring(0,(MAX_USERNAME_LENGTH-2)) + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username )) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
//If firstname is less than or equal to the MAX minus 2 chars then we are considering full firstname for username generation.
else{
//lastNameLength represents the current pointer of lastlength.
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username )) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
} else {
//The full name is less than MAX_USERNAME_LENGTH minus 2 chars directly assign username to full name.
username = fullName;
username = username.toLowerCase();
if( isUnique( username ) ) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
else{
//If the username was not unique with firstname.last name we then check uniqueness
// with firstname.firstLetterOfLastName, firstname.secondLetterOfLastName e.t.c...
for(int lastNameLength = 0 ; lastNameLength < lastName.length() ; lastNameLength++){
username = firstName + "." + lastName.charAt(lastNameLength);
username = username.toLowerCase();
if( isUnique( username ) ) {
log.debug( "AD Create User Name | Unique username generated: " +username);
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
finalUserName = username;
return username;
}
}
}
}
if( finalUserName == null ) {
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method without generating username" );return null;
}
log.debug( "AD Create User Name | Exit from the GenerateADUsername Method" );
}
public boolean isUnique ( String username ) throws GeneralException {
return !idn.accountExistsByDisplayName(application.getName(), username);
}
return generateUsername( identity.getFirstname(), identity.getLastname() );
]]></Source>
</Rule>
```
## Validate the rule
Before you send the rule off to the professional services team to upload your rule to your tenant for use you can send it through the rule validator to check for any errors.
Refer to [Rule Validator](../rule-validator) for installation.
Run the rule validator against your newly written rule.
```bash
sp-rv --file ~/rules/Rule - AttributeGenerator - ADUserNameGenerator.xml
________________________________________________________________________________
SailPoint SaaS Rule Validator v3.0.26
By the SaaS Acceleration Team
(c)2022-23 SailPoint Technologies Inc
Command line arguments:
--file {-f} = "/Users/tyler.mairose/development/identitynow-services-config/devrel/devrel.identitynow.com/rules/Rule - AttributeGenerator - ADUserNameGenerator.xml"
Executed from: /Users/tyler.mairose/Downloads/sailpoint-saas-rule-validator-3.0.26
Jar location : /Users/tyler.mairose/Downloads/sailpoint-saas-rule-validator-3.0.26
________________________________________________________________________________
File name : /Users/tyler.mairose/development/identitynow-services-config/devrel/devrel.identitynow.com/rules/Rule - AttributeGenerator - ADUserNameGenerator.xml
Rule name : ADUserNameGenerator
Process date : Thu Jun 08 17:22:53 EDT 2023
________________________________________________________________________________
No errors found.
Warnings: (3)
Line 55 - [LintValidatorForStatement(31)] For statement detected: for ( int lastNameLength = 0 ; . . "For Loops" can cause issues when looping with incorrect exit conditions. Ensure Looping exit conditions are correct.
55: for ( int lastNameLength = 0 ; lastNameLength < lastName .length ( ) ; lastNameLength ++ ) {
Line 70 - [LintValidatorForStatement(31)] For statement detected: for ( int lastNameLength = 0 ; . . "For Loops" can cause issues when looping with incorrect exit conditions. Ensure Looping exit conditions are correct.
70: for ( int lastNameLength = 0 ; lastNameLength < lastName .length ( ) ; lastNameLength ++ ) {
Line 95 - [LintValidatorForStatement(31)] For statement detected: for ( int lastNameLength = 0 ; . . "For Loops" can cause issues when looping with incorrect exit conditions. Ensure Looping exit conditions are correct.
95: for ( int lastNameLength = 0 ; lastNameLength < lastName .length ( ) ; lastNameLength ++ ) {
________________________________________________________________________________
Runtime stats:
Started validation at Thu Jun 08 17:22:53 EDT 2023
1 Rules Analyzed
0 Errors
3 Warnings
Finished validation at: Thu Jun 08 17:22:53 EDT 2023
Process completed in 1 second.
________________________________________________________________________________
Validation status: SUCCESS
________________________________________________________________________________
```
## Submitting for rule review
In order to submit your Cloud Rule for review, approval, and inclusion in the SailPoint platform, they should be submitted via [SailPoint Expert Services](https://www.sailpoint.com/services/professional/#contact-form). If you need assistance writing and testing rules, they can be sure to assist in that process as well. Please make sure your contact information is up to date, in case the review team needs to contact you.
## Add Rule to account creation
Log into your IdentityNow tenant and navigate to **Admin** -> **Connections** -> **Sources** -> **{Source Name}** -> **Accounts** -> **Create Account**. Scroll to the attribute you wish to use the rule for generating the username. Check the generator radio button and pick your new rule from the drop down.
![Account Create](./img/account-create.png)
Now you can trigger an account creation and the attribute chosen will have its value generated by your rule.

View File

@@ -3,7 +3,7 @@ id: rule-utility
title: Using IDNRuleUtil as a Wrapper for Common Rule Operations
pagination_label: IdentityNow Rule Utility
sidebar_label: IdentityNow Rule Utility
sidebar_position: 2
sidebar_position: 4
sidebar_class_name: ruleUtility
keywords: ['rule', 'utility']
description: Using IDNRuleUtil as a Wrapper for Common Rule Operations

View File

@@ -42,6 +42,40 @@ Though IdentityNow shares some common functionality with other SailPoint product
From a SailPoint support perspective, rules are considered configurations. SailPoint supports the underlying platform but not the rule configurations themselves. Any problems with the way rules are implemented or run over time are the responsibilities the customer or implementer must manage. SailPoint's IdentityNow Expert Services need hours to cover any rule configuration work (e.g., creating rules, best practices reviews, application to your IdentityNow environment, and promotion between sandbox & prod environments). Contact your Customer Success Manager with any questions. While rules allow some advanced flexibility, you must consider these support implications when you are deciding whether to implement rules. Consider rule usage a last resort, and use IdentityNow features instead whenever you can.
## Best Practices for Rule deployments
SailPoint Identity Now deployments often require the deployment of rules to the clients IdentityNow tenants. Because IdentityNow is a multi-tenant solution, rules that are poorly written can have negative performance implications on other tenants in the same cloud. As such, SailPoint requires all rules to be reviewed prior to deployment. The time to complete these reviews requires an expert services contract to leverage billable hours.
This article covers common topics around this process including best practices, rule review expectations, and more.
### SLAs for Rule Review
SailPoint has a 24 hour SLA on rule deployments for rules submitted over weekdays and next business day for rules submitted over the weekend.
However, around 65% of rule reviews are completed in less 4 business hours, with the average turnaround time of 3-6 hours after ticket has been assigned. If a specific deployment window is required, SailPoint must be alerted at least 48 hours in advance so that the time for the reviewer and deployment expert may be reserved.
### Go Live expectations
SailPoint rule review team members work from 9am-5pm Monday-Friday in their local time zones, excluding holidays. For clients planning to go live on a weekend, we recommend having rules deployed in the sandbox environment prior to go live so that they can be promoted to production without SailPoint involvement. See the section below entitled [Promoting Rules from Sandbox to Production](#promoting-rules-from-sandbox-to-production).
Note that even for clients who purchase Weekend Go-Live Support, rule deploys are not covered in the Weekend Go Live service as there are multiple teams involved in the rule deploy process.
### Rule Deployments
SailPoint recommends only submitting one rule at a time or only rules that should be deployed together.
Typical rule reviews are billed 15-30 minutes per rule. However, this can vary based on the complexity of the rule or if the rule is rejected and must be resubmitted for review.
In the case of rejection, we recommend submitting a new ticket to avoid a scenario where a case owner is out of the office.
## Promoting Rules from Sandbox to Production
A rule that has been approved in a sandbox tenant through the SailPoint rule review process, for example an IdentityAttribute, Correlation or ManagerCorrelation rule or any other rule type, can be migrated to the production IdentityNow tenant.
This applies to all rule types, as the signature has been approved/verified during the SailPoint rule review process, the sp-config API allows you to import ANY approved tenant rules. (this includes cloud rules!)
For more details on the sp-config API see [sp-config](/idn/api/beta/export-sp-config)
## Rule Guidelines
- **Supported Rules**

View File

@@ -3,7 +3,7 @@ id: java-docs
title: Java Docs
pagination_label: Java Docs
sidebar_label: Java Docs
sidebar_position: 2
sidebar_position: 6
sidebar_class_name: ruleJavaDocs
keywords: ['rules', 'java', 'docs']
description: Documentation for rule development in IdentityNow.

View File

@@ -0,0 +1,181 @@
---
id: rule-validator
title: IdentityNow Rule Validator
pagination_label: IdentityNow Rule Validator
sidebar_label: IdentityNow Rule Validator
sidebar_position: 5
sidebar_class_name: ruleValidator
keywords: ['rule', 'validator']
description: IdentityNow Rule Validator
slug: /docs/rules/rule-validator
tags: ['Rules']
---
## Overview
The IdentityNow Rule Validator is a simple tool to validate IdentityNow rules for malformed or incorrect code fragments, and help make sure they conform to the SailPoint [IdentityNow Rule Guide](/idn/docs/rules#rule-guidelines) before rule submission. While this does check code fragments, it is not a code parser or linter; it does not check the code for syntax or completeness. This is not designed to replace any sort of unit testing you might do outside of IdentityNow. Running the IdentityNow Rule Validator against your rules before submission helps look for problems early on. It is designed to help catch common items that often trip up rule reviews, and provide immediate feedback during the rule writing process. This however is not a guarantee that the rule will be approved or doesn't have other flaws.
## Changelog
### Version 3.0
- BeanShell linter will now validate syntax and usage to help discover issues in your code before you deploy
- A watch option which continually monitors and validate/lint your code while you develop.
### Version 2.0
- Migrated to a Java-based runtime
- Enhanced results reporting
- Ability to toggle warnings on/off as part of the results report
- File naming convention checks
- Handling for connector-executed rules
### Version 1.0.1
- Initial release!
## Requirements
This utility is a Java based application and requires **Java SE Development Kit (JDK) 11** or higher to run.
:::info
Please note that the previous version used JDK 8 (1.8), if you do not have the JDK 11 or above then this must be downloaded and installed first
:::
## Support / Features
This utility is developed by SailPoint Technology Services, and its usage is covered via SailPoint Expert Services. If you have any issues, bugs, or feature requests, please submit them to SailPoint Expert Services.
## Installation and Updates
To use the Rule Validator locally, decompress the `sailpoint-saas-rule-validator-{3.0.xx}-distribution.zip` package into a folder on your workstation. The sp-rv command executes the java package, and has been designed to be run from a path so can be executed anywhere from your file system.
### Linux and MacOS considerations
Under Linux and MacOS ensure the `sp-rv` script has execute privileges, by executing the `chmod` command on the `sp-rv` script:
```bash
chmod +x sp-rv
```
## Running the Rule Validator
To run the validator with standard reporting, simply invoke the following command.
```bash
sp-rv --file {path or file name}
```
This will automatically validate all XML files in the path or a specific file name. To automatically include all nested sub-directories in the validation, include the `--recursive` flag.
```bash
sp-rv --file "~/path-to-rules" --recursive
```
:::info
If you provide a specific file name, then the `--recursive` flag parameter is ignored; the recursive evaluation will only be conducted if the filePath parameter is null or a directory.
:::
### Watch Option
The new rule validator contains a watch feature to monitor a folder for changes.
```bash
sp-rv --watch {path}
```
This will automatically validate all XML files within the specified path. The path must always be a directory and not a file.
To automatically include all nested sub-directories in the validation, include the `--recursive` flag.
```bash
sp-rv --watch "~/path-to-rules" --recursive
```
:::info
In order to exit watch mode press `CTRL+C`
:::
## Example Output
### Rule with no errors but one warning
```bash
________________________________________________________________________________
SailPoint SaaS Rule Validator v3.0.9-beta
By the SaaS Acceleration Team
(c)2022-23 SailPoint Technologies Inc
________________________________________________________________________________
Executed from: /Users/sailpoint/Documents/test rules
Jar location : /Users/sailpoint/Documents/tools
File name : /Users/sailpoint/Documents/test rules/Rule - AttributeGenerator - Generate userPrincipalName.xml
Script name : Generate userPrincipalName
Date : Wed Mar 08 18:13:12 GMT 2023
________________________________________________________________________________
No errors found.
Warnings:
Line 126 - [LintBSHAmbiguousName] Could not find variable name 'calculatedUpnDomain '
________________________________________________________________________________
Runtime stats:
Started validation at 2023-03-08 06:13:12.558
1 Rules Analyzed
0 Errors
1 Warnings
Finished validation at: 2023-03-08 06:13:13.009
Process completed in 0 seconds.
________________________________________________________________________________
```
### Failure with warnings
```bash
SailPoint SaaS Rule Validator v3.0.9-beta
By the SaaS Acceleration Team
(c)2022-23 SailPoint Technologies Inc
________________________________________________________________________________
Executed from: /Users/sailpoint/Documents/test rules
Jar location : /Users/sailpoint/Documents/tools
File name : /Users/sailpoint/Documents/test rules/Rule - Generic - WS_OGE_ID_Generation.xml
Script name : WS_OGE_ID_Generation
Date : Wed Mar 08 18:15:58 GMT 2023
________________________________________________________________________________
Errors: (2)
Line 72 - [IDNLintProcessor] While statement detected: while ( ! isIDUnique && Util .isNotNullOrEmpty ( APPLICATION_ID ) && count <= 9 ) { . . While loops are disallowed due to infinite loop risks; use a 'for' loop with explicit exit conditions instead
Line 121 - [IDNLintProcessor] While statement detected: while ( ! isUnique && ( attempt <= MAX_ATTEMPTS ) ) { . . While loops are disallowed due to infinite loop risks; use a 'for' loop with explicit exit conditions instead
Warnings:
Line 36 - [LintBSHMethodInvocation] No type was assigned or resolved for variable name: idn
Line 49 - [LintBSHTypedVariableDeclaration] Variable name 'ogeId' is shadowing an earlier variable declaration
Line 73 - [LintBSHTypedVariableDeclaration] Variable name 'sourceId' is shadowing an earlier variable declaration
Line 105 - [LintBSHTypedVariableDeclaration] Variable name 'ogeId' is shadowing an earlier variable declaration
Line 125 - [LintBSHTypedVariableDeclaration] Variable name 'sourceId' is shadowing an earlier variable declaration
Line 147 - [LintBSHAmbiguousName] Could not find variable name 'e_firstname '
Line 160 - [LintBSHAmbiguousName] Could not find variable name 'e_firstname '
Line 160 - [LintBSHAmbiguousName] Could not find variable name 'e_middleName '
Line 160 - [LintBSHAmbiguousName] Could not find variable name 'e_lastname '
Line 162 - [LintBSHAmbiguousName] Could not find variable name 'c_firstname '
Line 162 - [LintBSHAmbiguousName] Could not find variable name 'c_middleName '
Line 162 - [LintBSHAmbiguousName] Could not find variable name 'c_lastname '
________________________________________________________________________________
Runtime stats:
Started validation at 2023-03-08 06:15:57.946
1 Rules Analyzed
2 Errors
12 Warnings
Finished validation at: 2023-03-08 06:15:58.261
Process completed in 0 seconds.
________________________________________________________________________________
```
## Resources
<a target="\_blank" href={require('/static/sailpoint-saas-rule-validator-3.0.26.zip').default}> Identity Now Rule Validator </a>

Binary file not shown.