# Introducing the Rule Development Kit

**URL:** <https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851>\
**Category:** Community Updates\
**Tags:** rules, sailpoint-identity-security\
**Created:** [October 11, 2023, 3:31pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851 "2023-10-11T15:31:09Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![tyler\_mairose](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/tyler_mairose/32/30112_2.png) [@tyler\_mairose](https://developer.sailpoint.com/discuss/u/tyler_mairose)\
**Post date:** [October 11, 2023, 3:31pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/1 "2023-10-11T15:31:09Z")

</div>

You have been asking for a way to write and test [cloud rules](https://developer.sailpoint.com/idn/docs/rules/cloud-rules/) locally before handing them off to Professional Services for validation and installation. We are incredibly excited to announce a new tool available to the SailPoint Developer Community: **The Rule Development Kit.**

Utilizing the Rule Development Kit will save you both time and money when it comes to submitting rules for review, by ensuring that your rule logic is sound—and so much more!

We will be doing a live stream today, at 1PM Central Time, to give an introduction and overview of the Rule Development Kit and show you how to get started (_and don’t worry, the recording will be available right at this same link!_):

> [@Dev Live Stream, October - Introducing the Rule Development Kit](https://developer.sailpoint.com/discuss/t/dev-live-stream-october-introducing-the-rule-development-kit/14114):
>
> This month, we’ll be hearing from @tyler_mairose as he teaches us what SailPoint’s new Rule Development Kit is and how to use it to develop rules faster, and with less effort. This will save you time and money by reducing the time spent developing and debugging rules, leading to less PS time evaluating and implementing them!

# The Rule Development Kit

 ![intellisense](https://global.discourse-cdn.com/sailpoint/original/2X/d/d6515c9b191e69cb37f85af06471330ab7e08886.jpeg)

## Overview

The SailPoint Rule Development Kit (RDK) is a project you can use to develop rules quickly and easily. The RDK provides you with the classes and methods available to you when you’re developing a rule. You can mock out these classes and run your rule locally to test your logic before submitting it for review. The RDK ships with a few [example rules](https://github.com/sailpoint-oss/rule-development-kit/tree/main/src/test/java/sailpoint) to demonstrate its functionality and to help you get started.

Refer to the following guide to get started with the RDK:  
[https://developer.sailpoint.com/idn/tools/rule-development-kit/](https://developer.sailpoint.com/idn/tools/rule-development-kit/)

## Requirements

> ‼ The Rule Development Kit is only for IdentityNow [Cloud Executed Rules](https://developer.sailpoint.com/idn/docs/rules/cloud-rules).

Java and Maven are needed for this tool to run, for more information and installation steps refer to [requirements](https://developer.sailpoint.com/idn/tools/rule-development-kit#requirements).

You can use any IDE that supports Maven and Java, but our team will always recommend VS Code as this is the IDEs we are most familiar with.

## Next Steps

As always, we’d love to hear your feedback! If you notice that this tool could be expanded to better fit your needs or notice that something is incorrect please let us know right here in the announcement, create an [issue](https://github.com/sailpoint-oss/rule-development-kit/issues) in Github, or you can [send us a message directly](https://developer.sailpoint.com/discuss/new-message?groupname=developer_relations&title=Rules%20Docs%20Issue&body=What%20is%20your%20issue%3F).

---

<div class="post-metadata">

**Author:** ![drosenbauer](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/drosenbauer/32/3381_2.png) [@drosenbauer](https://developer.sailpoint.com/discuss/u/drosenbauer)\
**Post date:** [October 11, 2023, 4:55pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/2 "2023-10-11T16:55:48Z")

</div>

> The Rule Development Kit is only for IdentityNow [Cloud Executed Rules](https://developer.sailpoint.com/idn/docs/rules/cloud-rules).

It’ll work for most IIQ rules too! I plan to do so.

---

<div class="post-metadata">

**Author:** ![jsr749](https://avatars.discourse-cdn.com/v4/letter/j/eb8c5e/32.png) [@jsr749](https://developer.sailpoint.com/discuss/u/jsr749)\
**Post date:** [October 17, 2023, 2:41pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/3 "2023-10-17T14:41:05Z")

</div>

Hi, I am seeing this error when attempting to clone the kit repo:

git clone [git@github.com](mailto:git@github.com):sailpoint-oss/rule-development-kit.git  
Cloning into ‘rule-development-kit’…  
Connection reset by 140.82.113.3 port 22  
fatal: Could not read from remote repository.

Please make sure you have the correct access rights  
and the repository exists.

---

<div class="post-metadata">

**Author:** ![tyler\_mairose](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/tyler_mairose/32/30112_2.png) [@tyler\_mairose](https://developer.sailpoint.com/discuss/u/tyler_mairose)\
**Post date:** [October 18, 2023, 2:52pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/7 "2023-10-18T14:52:22Z")

</div>

A post was split to a new topic: [Rule Development Kit Installation issue when running mvn clean install](https://developer.sailpoint.com/discuss/t/rule-development-kit-installation-issue-when-running-mvn-clean-install/19307)

---

<div class="post-metadata">

**Author:** ![adunker](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/adunker/32/2664_2.png) [@adunker](https://developer.sailpoint.com/discuss/u/adunker)\
**Post date:** [October 25, 2023, 6:42pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/8 "2023-10-25T18:42:28Z")

</div>

This is a great tool! Thank you!

---

<div class="post-metadata">

**Author:** ![colin\_mckibben](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/colin_mckibben/32/37182_2.png) [@colin\_mckibben](https://developer.sailpoint.com/discuss/u/colin_mckibben)\
**Post date:** [October 25, 2023, 7:09pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/9 "2023-10-25T19:09:15Z")

</div>

Excited to hear what you think!

---

<div class="post-metadata">

**Author:** ![Michael\_Tai](https://avatars.discourse-cdn.com/v4/letter/m/c6cbf5/32.png) [@Michael\_Tai](https://developer.sailpoint.com/discuss/u/Michael_Tai)\
**Post date:** [November 9, 2023, 12:37pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/10 "2023-11-09T12:37:17Z")

</div>

We had tried it for Connector Executed Rules, it also worked, however need to some changes to make it.

---

<div class="post-metadata">

**Author:** ![colin\_mckibben](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/colin_mckibben/32/37182_2.png) [@colin\_mckibben](https://developer.sailpoint.com/discuss/u/colin_mckibben)\
**Post date:** [November 9, 2023, 12:38pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/11 "2023-11-09T12:38:05Z")

</div>

What changes did you have in mind, Ping? @tyler_mairose would love to hear them!

---

<div class="post-metadata">

**Author:** ![adamian](https://avatars.discourse-cdn.com/v4/letter/a/a183cd/32.png) [@adamian](https://developer.sailpoint.com/discuss/u/adamian)\
**Post date:** [April 26, 2024, 8:28am UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/12 "2024-04-26T08:28:40Z")

</div>

I was watching this presentation ( [Getting started with the SailPoint Rule Development Kit](https://developer.sailpoint.com/discuss/t/getting-started-with-the-sailpoint-rule-development-kit/37625) ) and thought I would share some changes that I’ve made to the RDK to make my life easier.

Two things bothered me that I could solve:

- I don’t like having duplicated code, e.g. [rule-development-kit/src/main/java/UsernameGenerator.java at a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a · sailpoint-oss/rule-development-kit · GitHub](https://github.com/sailpoint-oss/rule-development-kit/blob/a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a/src/main/java/UsernameGenerator.java) and [rule-development-kit/src/main/resources/rules/Rule - AttributeGenerator - UsernameGenerator.xml at a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a · sailpoint-oss/rule-development-kit · GitHub](https://github.com/sailpoint-oss/rule-development-kit/blob/a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a/src/main/resources/rules/Rule%20-%20AttributeGenerator%20-%20UsernameGenerator.xml) . They are mostly the same, but not quite.  
We have to manually copy Java code into the XML file, remove some imports, but not all, add some code outside of the Java functions (the BSH entry), and do some other small changes (e.g. remove objects that are in context already). This has to be done over and over to keep the files in sync and it is very error prone.
- You could just edit only the XML files, without having any Java code, but this doesn’t offer the same flexibility. You can see that that the IDE support is not that good, so typos are not caught automatically by the IDE. JUnit test for the helper functions are also easier to understand if they don’t have any beanshell loading, so you need to have Java code and XML code.

My solution was to use a plugin to generate the XML code from the Java classes at compile time.  
Using the plugin `com.igormaznitsa:jcp` in `pom.xml`:

```xml
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.2.5</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>com.igormaznitsa</groupId>
                <artifactId>jcp</artifactId>
                <version>7.1.1</version>
                <executions>
                    <execution>
                        <id>preprocessSources</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>preprocess</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>${basedir}/src/main/java/rules</source>
                            </sources>
                            <target>${project.basedir}/src/main/resources/rules</target>
                            <!-- <keepComments>REMOVE_JCP_ONLY</keepComments> -->
                            <keepComments>false</keepComments>
                            <keepLines>false</keepLines>
                            <dontOverwriteSameContent>true</dontOverwriteSameContent>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

```

and creating the Java class like this:

```java
//#outname "Rule - AttributeGenerator - UserPrincipalNameGenerator.xml"
//$$<?xml version='1.0' encoding='UTF-8'?>
//$$<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
//$$<Rule name="UserPrincipalNameGenerator" type="AttributeGenerator">
//$$ <Description>Generate a unique UserPrincipalName for Active Directory.</Description>
//$$ <Source><![CDATA[
//#//
package rules;

import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
//#//
import org.apache.log4j.LogManager;
//#//
import org.apache.log4j.Logger;
import sailpoint.object.Application;
import sailpoint.object.Identity;
import sailpoint.server.IdnRuleUtil;

//#if false

/**
 * ...
 */
@SuppressWarnings({"rawtypes", "FieldMayBeFinal"}) // BeanShell doesn't support generics
public class UserPrincipalNameGenerator {

    Logger log = LogManager.getLogger(rules.UserPrincipalNameGenerator.class);
    Identity identity = new Identity();
    Application application = new Application();
    IdnRuleUtil idn;
//#endif

    private static String RULE_CONFIG_ATTRIBUTE = "userPrincipalNameGeneratorConfig";
    private static int MAX_USERNAME_LENGTH = 64;

    public void loadConfiguration() {
        ...
    }

    public String generateUserPrincipalName(String firstName, String lastName, String domain) {
        ...
    }

    String generateUserPrincipalName(String firstName, String lastName, String domain, int maxUsernameLength) {
        ...
    }

    String getCanonicalFirstName(String firstName) {
        ...
    }

    String getCanonicalLastName(String lastName) {
        ...
    }

    private static String capitalize(String lastName) {
        ...
    }

    private static String replaceUnsupportedCharsWithSpace(String firstName) {
        ...
    }

    private Map ASCII_REPLACEMENTS = Map.of(
            ...
    );

    private String normalizeDiacritics(String text) {
        ...
    }

    public boolean isUpnUnique(String upn) {
        ...
    }

    String getDomain(Identity identity) {
        ...
    }

    //#//
    String beanshellEntry() {
        loadConfiguration();
        String domain = getDomain(identity);
        if (domain == null) {
            return null;
        }
        return generateUserPrincipalName(identity.getFirstname(), identity.getLastname(), domain);
        //#//
    }
//#//
}
//$$ ]]></Source>
//$$</Rule>

```

This allows to exclude some lines from XML (e.g. importing of org.apache.log4j.\* classes, the beanshell entry function declaration), or blocks of code (documentation, class declaration and objects already present in context - log, identity, idn, application).  
This code can be than broken in individual functions which can be easily tested independently, without having to set up identities or the BeanShell environment.

* * *

For my personal taste I would also try to reduce the duplicate code in the tests, I find such tests easier to read than [rule-development-kit/src/test/java/sailpoint/UsernameGeneratorTest.java at a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a · sailpoint-oss/rule-development-kit · GitHub](https://github.com/sailpoint-oss/rule-development-kit/blob/a4fdf22221b1d5a0cd8f4f4f9db414c511c4b84a/src/test/java/sailpoint/UsernameGeneratorTest.java#L26-L53)

```auto
    @Test
    public void testRule_uniqueLogic() {
        mockIdentity("John", "Doe");

        mockAccountExists("John.Doe@example.com");
        mockAccountExists("John.Doe2@example.com");

        assertEquals("John.Doe3@example.com", evalRule());
    }

```

Next step would be to use [AssertJ](https://assertj.github.io/doc/) as testing library instead of the plain JUnit.

---

<div class="post-metadata">

**Author:** ![AdamVentum](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/adamventum/32/10508_2.png) [@AdamVentum](https://developer.sailpoint.com/discuss/u/AdamVentum)\
**Post date:** [May 13, 2024, 12:57pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/13 "2024-05-13T12:57:59Z")

</div>

Thank you @tyler_mairose, this is what I need!  
Regards,  
Adam

---

<div class="post-metadata">

**Author:** ![liamkokeeffe](https://sea1.discourse-cdn.com/sailpoint/discuss/user_avatar/developer.sailpoint.com/liamkokeeffe/32/29279_2.png) [@liamkokeeffe](https://developer.sailpoint.com/discuss/u/liamkokeeffe)\
**Post date:** [December 3, 2024, 9:07pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/14 "2024-12-03T21:07:43Z")

</div>

Hello @adamian,

Neat idea! Would love to set this up in our environment as well so that we can better debug and actually step into the Java classes we are testing.

Have you found a way to generate the XML version of the Java class without formatting the class like that?

Thanks,

Liam

---

<div class="post-metadata">

**Author:** ![adamian](https://avatars.discourse-cdn.com/v4/letter/a/a183cd/32.png) [@adamian](https://developer.sailpoint.com/discuss/u/adamian)\
**Post date:** [December 4, 2024, 7:45am UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/15 "2024-12-04T07:45:56Z")

</div>

Hi @liamkokeeffe,

> [@liamkokeeffe](#):
>
> Have you found a way to generate the XML version of the Java class without formatting the class like that?

I haven’t tried to improve this solution further, as I think it would need a custom plugin/processor for this, as it needs to know which XML header to add, which imports and which class fields to selectively remove, and which method to remove (the beanshellEntry method definition, but not its body).

I am pretty happy with the solution, as I can do everything in Java and only minimally worry about the XML, and I don’t have to manually do all these operations every time I need to generate the XML and test it.

---

<div class="post-metadata">

**Author:** ![LuisCab](https://avatars.discourse-cdn.com/v4/letter/l/d6d6ee/32.png) [@LuisCab](https://developer.sailpoint.com/discuss/u/LuisCab)\
**Post date:** [February 28, 2025, 4:41pm UTC](https://developer.sailpoint.com/discuss/t/introducing-the-rule-development-kit/18851/16 "2025-02-28T16:41:40Z")

</div>

Has anyone tried making this working with IIQ?
