Iiq Rule Reference Graph
Loads a Rule and object export from IdentityIQ and shows, for every BeanShell Rule, who references it, what it references, and what breaks if you edit it.
IIQ Rule Reference Graph
Loads a Rule and object export from IdentityIQ and shows, for every BeanShell Rule, who references it, what it references, and what breaks if you edit it. For the engineer who inherited 500 connectors and several hundred rules nobody dares delete.
Date: 2026-10-05 Theme: Identify + Observability Platform: SailPoint IdentityIQ Status: Prototype
What it is
A single-page console that reads a parsed object export (Rule, Application, Workflow, TaskDefinition, CertificationDefinition, Policy) and builds the reference graph IdentityIQ does not draw for you. It runs eight checks over that graph (orphans, dangling references, wrong-type wiring, library methods that will not load, nested libraries, copy-pasted bodies, high fan-out) and gives each rule a neighbourhood view, a blast radius, and its source. It also ships the illustrative Rule XML you would run to produce the export from a live system.
Who it serves
The IAM engineer who owns the IdentityIQ codebase and gets asked, before every change, "is anything still using this?" Secondary: the person doing the 8.4 to 8.5 upgrade, who needs to know which of the several hundred rules in spt_rule are load bearing before they start regression testing.
The IIQ pain it addresses
Rules are the customisation layer of IdentityIQ. Every Application's Rules tab has slots for Correlation, Creation, Manager Correlation, Customization, Managed Entitlement Customization, Before and After Provisioning, and connector-specific BuildMap and schema rules. Certifications have their own set (pre-delegation, exclusion, certifier, phase change, escalation, sign-off approver). Workflows call them from steps, TaskDefinitions name them, Policies reference an owner rule. At 500+ connectors, that works out to several hundred Rule objects, and the documentation is clear about the consequence of sharing one: "Changes made to the rule in one location will affect the functionality in all locations where it is used."
What the platform does not give you is the inverse index. The Rule Editor shows name, type, description, arguments and source. The type attribute filters which rules a dropdown offers, which is useful, but it says nothing about where the rule is already wired. When someone on the Developer Community asked in November 2023 how to find every place a rule is referenced, the answers were: grep your SSB tree, write a BeanShell rule that loops over objects and checks app.toXml().contains(ruleName), or query the database directly. Those are the right answers. They are also the kind of thing every shop rewrites from scratch, once, and loses.
There are four specific failure modes the sample data reproduces, each grounded in a documented behaviour or a community thread:
- Orphaned rules. A Box Customization rule outlives the Box application it served. A 7.3-era utility library survives two upgrades because nothing says it is unused.
- Dangling references. An Application's Customization slot names a rule that was renamed in a hotfix. A Workflow step points at a plan-builder rule that was deleted. Nothing complains until the aggregation or the lifecycle event runs.
- Transitive library calls. Rule A references library B, which references library C, and A calls a method from C. IdentityIQ loads direct
ReferencedRulesonly; the community statement is "it does NOT load the transitive references." The symptom isCommand not foundat run time, and the April 2026 thread on exactly that error shows people still hitting it. - Shadow copies. The Rule Editor's "Copy From Existing Rule" field is how a lab-forest Correlation rule ends up as a byte-for-byte clone of the corp one. Both now need patching for every fix, and no one remembers that the second exists.
The fifth, which no thread discusses but the type documentation implies, is wrong-type wiring: a rule imported by XML into a slot whose dropdown would never have offered it. It runs. It just does not do what the slot name suggests.
How it works
- Stat tiles across the top: rules in the export, live with no findings, orphaned, broken wiring, dangling references, shadow copies.
- Inventory table (left). One row per rule with a status dot, type, count of objects and rules that use it, count of libraries it uses, and finding flags. Filter by free text (rule name, description, or the name of a referencing object such as
Workday-HR), by type, or by status chip. - Detail panel (right). Click any row. The top is an SVG neighbourhood: things that reference the rule on the left, the rule in the centre, libraries it references on the right. A missing library draws in red with a dashed edge. Below that, the rule's findings ranked by severity, and the blast radius: every object affected if the rule is edited, including objects reached only through a dependent rule, each annotated with the path. The source follows, headed by the methods it defines (for a library) or calls (for everything else).
- All findings tab. Every check result, sortable by severity, filterable by kind, exportable to CSV for a change ticket. Click a row to jump to the rule.
- Collector rule tab. The Rule XML that would produce this JSON from a live IdentityIQ: iterate Rule objects for their metadata and
ReferencedRules, then iterate the five referencing classes and scan each object's XML forReferenceelements of class Rule. It states on the page that it is structurally illustrative and has not been validated against a deployment, and it lists the references it will miss.
The checks are plain functions at the top of script.js. Similarity is a token Jaccard over the normalised source. Method detection is a regular expression, not a BeanShell parser; it is good enough to catch the transitive-library case in the sample and will produce false positives on exotic code. The thresholds (0.85 for a shadow copy, 3 objects for fan-out, 3 years for a stale orphan) are this prototype's judgement, not anything IdentityIQ documents.
What's in this folder
README.md: this file.metadata.md: provenance (theme, model, sources, assumptions).cover-image.png: card cover art.requirements.md: functional and non-functional requirements, the eight checks, and the explicit assumptions behind the slot names and type strings.index.html: the page. Three tabs (inventory and detail, findings, collector). Carries an inline copy of the sample data so it works fromfile://in browsers that blockfetch.style.css: dark console styling shared with the other prototypes in this collection.script.js: graph construction, the eight checks, similarity and method extraction, blast radius, and the DOM rendering. Pure functions first, DOM last.sample-data.json: 25 fictional Rule objects (4 libraries, 21 typed rules) and 22 referencing objects across 14 Applications, 3 Workflows, 2 TaskDefinitions, 2 CertificationDefinitions and 1 Policy. Seeded with two orphans, three dangling references, one transitive-library call, one type mismatch, one exact and two near shadow copies, and one library used by 11 objects.
How to run / read it
Open index.html in any modern browser. No build, no server, no keys. To run the checks against a real export without the page, strip the DOM section from script.js and call buildGraph and analyse under Node with your own JSON in the same shape.
Estimated impact
The manual version of this is the BeanShell loop from the community thread, run once per question. In a shop with a few hundred rules, each "is this safe to change" question costs an engineer somewhere between twenty minutes (grep hits a clean SSB tree) and half a day (the rule is referenced by XML import in a slot nobody checked). The graph answers it in one click and, more usefully, answers it for every rule at once before an upgrade, so the regression plan is scoped to the rules that are actually wired rather than to the whole table. I do not have a measured number for the hours saved; the honest claim is that a four-hour investigation becomes a lookup, and that the transitive-library and dangling-reference checks catch two classes of production failure before a connector or lifecycle event trips them.
Why this fits an IIQ shop with 500+ connectors
Rule count scales with connector count. Each Application brings its own Correlation and Customization rule at minimum, delimited and JDBC sources add BuildMap rules, and the provisioning-capable ones add Before and After Provisioning. Shared libraries make this manageable and make the blast radius of a one-line change enormous: in the sample, one utility library is reachable from 11 objects through 12 rules, and the real number in a 500-connector shop is higher. The tool reads an export, so it costs the production system nothing beyond a console export -clean or a one-off collector run, and it does not need a lower environment that mirrors production to be useful.
Sources
- Official documentation (full URL):
https://documentation.sailpoint.com/identityiq_84/help/systemadmin/rulereuse.html— The caution that a rule reused in many places changes behaviour everywhere it is used; the basis for the blast radius and high fan-out check.https://documentation.sailpoint.com/identityiq_84/help/systemadmin/rulelibraries.html— Rule libraries as Rule objects, theReferencedRulesandReferenceelements, and invoking library methods from a rule's Source.https://documentation.sailpoint.com/identityiq_84/help/systemadmin/typeattributesinrules.html— Thetypeattribute, how it limits which rules a dropdown offers (the PolicyOwner example), and where the type is shown; the basis for the type mismatch check.https://documentation.sailpoint.com/identityiq_84/help/systemadmin/usingruleeditor.html— Rule Editor fields, including "Copy From Existing Rule"; the basis for the shadow copy check.https://documentation.sailpoint.com/identityiq_84/help/systemadmin/importrulexml.html— Rules imported via Global Settings > Import from File or the iiq console import command.https://documentation.sailpoint.com/identityiq_84/help/certification/rules_in_certifications.html— The certification rule types (CertificationExclusion, CertificationPreDelegation, Certifier, CertificationPhaseChange, WorkItemEscalationRule, CertificationSignOffApprover) used in the sample data.https://documentation.sailpoint.com/identityiq/help/application_configuration/configure/using_edit_application_page/rules_tab.html— The Application Rules tab (Correlation, Creation, Manager Correlation, Customization, Managed Entitlement Customization, Before and After Provisioning, schema and connector rules). This page is the 8.5 help set; the 8.4 equivalent was not reachable during this run.
- Community / current research (full URL):
https://developer.sailpoint.com/discuss/t/to-find-out-a-rule-referenced-at-what-all-places/20163— November 2023 thread asking how to find every place a rule is referenced; answers are grep over SSB, a BeanShelltoXml().contains()loop, a direct SQL query, and the Object Exporter plugin. The pain this prototype addresses.https://developer.sailpoint.com/discuss/t/rulelibrary-reference-in-another-rulelibrary/56164— May 2024 thread with the statement that IdentityIQ loads referenced rules but not their transitive references; the basis for the transitive method check.https://developer.sailpoint.com/discuss/t/issue-calling-method-from-referenced-rule-library/206047— April 2026 thread onCommand not foundwhen calling a library method, showing the failure mode is still current.https://developer.sailpoint.com/discuss/t/referencedrules-ignored-some-times/14717— July 2023 thread: "Referenced rules don't cascade. Each rule needs to reference all of the rule libraries it needs."https://developer.sailpoint.com/discuss/t/download-all-iiq-objects-in-the-system/79286— September 2024 thread with the consoleexport -clean rule.xml rulecommand and the Object Exporter plugin as ways to get the export this prototype reads.
Requirements
Requirements — IIQ Rule Reference Graph
Purpose
Give an IdentityIQ engineer one screen that answers "where is this Rule used, what does it depend on, and what breaks if I change it" for every Rule object in a deployment. The 8.4 documentation describes the Rule Editor (name, description, type, arguments, source), the type attribute that filters which rules a dropdown offers, ReferencedRules for rule libraries, and the caution that a rule reused in several places changes behaviour everywhere it is used. None of the fetched pages describe a view that lists a rule's references, and the community answer to "where is this rule referenced" is grep, a BeanShell scan with toXml().contains(ruleName), or a direct SQL query. This prototype is that scan, with the checks a reviewer would run on the result.
Functional requirements
- Load one export from
sample-data.json: arulesarray (name, type, language, description, modified date,referencedRules, BeanShell source) and anobjectsarray (class, name, and the rule references found in that object, each with the slot it was found in). The shape is what a parsediiq console export -cleanof Rule, Application, Workflow, TaskDefinition, CertificationDefinition and Policy objects would give you. - Build the reference graph client side: for every rule, the objects that reference it (with slot), the rules that reference it as a library, and the libraries it references. Record references to rule names that are not in the export as dangling.
- Run these checks and emit one finding per hit, each with a kind, a severity (high / medium / low), the rule, a detail sentence and a suggested action:
ORPHAN: no object and no rule references it. Severity rises to medium when the rule was last modified 3 or more years ago.DANGLING_REF: an object slot or aReferencedRulesentry names a rule that does not exist in the export.TYPE_MISMATCH: a rule sits in a slot whose expected type (see the table inscript.js) does not match the rule'stype. The UI dropdown would not have offered it, so it was wired by XML import.TRANSITIVE_METHOD: the rule's source calls a method that is defined only in a library reachable through another library, not referenced directly. IdentityIQ loads directReferencedRulesonly, so this fails at run time.UNREFERENCED_METHOD: the source calls a method defined in a library the rule does not reference at all.NESTED_LIBRARY: a library (a rule with no type) that itself hasReferencedRules. Informational; its consumers must reference the nested libraries themselves.SHADOW_COPY: two rules of the same type whose normalised source bodies have a token Jaccard at or above 0.85.HIGH_FANOUT: editing the rule touches 3 or more objects, counted through every rule that depends on it.
- Rule inventory table: one row per rule with a status dot (live / review / broken / orphan), type, inbound reference count, outbound library count, and finding flags. Free text filter across rule name, description and referencing object names. Type dropdown and status chips.
- Detail panel for the selected rule: an inline SVG neighbourhood (referencing objects on the left, the rule in the centre, libraries on the right, missing libraries drawn in red), the rule's findings ranked by severity, the blast radius (every object affected if the rule is edited, including those reached through dependent rules, each annotated with the path), and the source with the methods it defines or calls.
- Findings tab: every finding across the export, sortable by severity, filterable by kind, with CSV export generated in the browser. Clicking a finding opens the rule.
- Collector tab: an illustrative Rule XML that would produce the JSON from a live deployment by iterating the five object classes and scanning each object's XML for
Referenceelements of class Rule. It must carry a visible statement that it is structurally illustrative and has not been validated against a deployment, and must list its known gaps (string-form workflow references, dynamicgetObjectByName(Rule.class, ...)calls, Forms and EmailTemplates not scanned). - No network calls. The page reads the bundled JSON; if
fetchis blocked onfile://, it falls back to a copy of the same JSON inlined inindex.html.
Non-functional requirements
- Vanilla HTML, CSS and JS. No build step, no framework, no CDN.
- Opens from
file://or any static server with no console errors in current Chrome, Edge, Firefox and Safari. - Graph building, the checks, similarity, method extraction and blast radius are pure functions at the top of
script.jsthat take plain objects, so they can be run under Node against a real export without the DOM. - Thresholds (
SHADOW_SIMILARITY,HIGH_FANOUT,STALE_YEARS) and the slot-to-type table are constants at the top ofscript.js. - Visual style matches the other prototypes in this collection: dark console, navy and slate, blue, teal and amber accents.
Explicit design assumptions (not confirmed against a fetched page)
- The slot names in
sample-data.json(correlationRule,creationRule,customizationRule,managerCorrelationRule,beforeProvisioningRule,afterProvisioningRule,buildMapRule,preDelegationRule,exclusionRule,ownerRule) are readable labels modelled on the Application Rules tab and the certification rule list. They are not verified attribute names from an 8.4 export, and a real collector would need to map each object class's actual XML to them. - The
typestring values (Correlation,IdentityCreation,Customization,ManagerCorrelation,BeforeProvisioning,AfterProvisioning,BuildMap) are inferred from the rule names on the Application Rules tab. The documentation confirmsPolicyOwner,CertificationPreDelegationandCertificationExclusionas type strings; the rest are assumed. - Method extraction is a regular expression over BeanShell, not a parser. It will miss methods called through a variable and will flag a locally defined method as a library call if the definition does not sit at the start of a line.
- The 0.85 similarity cutoff, the 3-object fan-out line and the 3-year staleness line are this prototype's judgement.
Out of scope
- Writing anything back to IdentityIQ. The tool reads an export and suggests; a human deletes or merges.
- Scanning Rule source bodies for dynamic rule invocation or for references to Applications and other objects.
- Rules held in Forms, EmailTemplates, IdentityTriggers or Plugin configuration.
- Running the collector itself from the page.
More from IAM Ideas