isc-transforms-mcp 1.0.17 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "sailpoint.isc.transforms.replace.schema.json",
|
|
4
4
|
"title": "SailPoint ISC Transform Schema - replace",
|
|
5
|
-
"description": "Strict schema
|
|
5
|
+
"description": "Strict schema for the SailPoint ISC replace transform. Finds all occurrences of a single Java regular expression pattern in the input string and replaces every match with the replacement string. Unlike replaceAll, this operates on a single regex+replacement pair. Key behaviors: (1) ALL occurrences are replaced, not just the first. (2) Use an empty replacement string to delete all matched text. (3) Capture groups in the regex can be referenced as $1, $2, etc. in the replacement. (4) Use bracket notation for literal special characters (e.g., '[.]' for a literal dot). (5) input is optional — if omitted the transform uses the source+attribute configured in the identity profile UI.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": [
|
|
@@ -12,16 +12,18 @@
|
|
|
12
12
|
],
|
|
13
13
|
"properties": {
|
|
14
14
|
"type": {
|
|
15
|
-
"const": "replace"
|
|
15
|
+
"const": "replace",
|
|
16
|
+
"description": "Transform operation type. Must be exactly 'replace'."
|
|
16
17
|
},
|
|
17
18
|
"name": {
|
|
18
19
|
"type": "string",
|
|
19
|
-
"minLength": 1
|
|
20
|
+
"minLength": 1,
|
|
21
|
+
"description": "Display name for this transform, shown in UI dropdowns and identity profile mappings."
|
|
20
22
|
},
|
|
21
23
|
"requiresPeriodicRefresh": {
|
|
22
24
|
"type": "boolean",
|
|
23
25
|
"default": false,
|
|
24
|
-
"description": "
|
|
26
|
+
"description": "If true, re-evaluates this transform during the nightly identity refresh cycle. Default is false."
|
|
25
27
|
},
|
|
26
28
|
"attributes": {
|
|
27
29
|
"type": "object",
|
|
@@ -30,19 +32,24 @@
|
|
|
30
32
|
"regex",
|
|
31
33
|
"replacement"
|
|
32
34
|
],
|
|
35
|
+
"description": "Required container for replace operation attributes.",
|
|
33
36
|
"properties": {
|
|
34
37
|
"regex": {
|
|
35
38
|
"type": "string",
|
|
36
39
|
"minLength": 1,
|
|
37
|
-
"description": "
|
|
40
|
+
"description": "Required. The Java regular expression pattern to search for. ALL occurrences of the pattern in the input are replaced — not just the first match. Pattern syntax notes: (1) Standard Java regex — character classes, quantifiers, anchors, and capture groups are all supported. (2) Use bracket notation to match literal special regex characters: '[.]' for a literal dot, '[+]' for a literal plus, '[-]' for a literal hyphen. (3) Capture groups with parentheses (e.g., '([A-Za-z]+)') can be back-referenced in the replacement field as $1, $2, etc. (4) The pattern is case-sensitive by default — use character classes (e.g., '[Aa]') or inline flag '(?i)' to match case-insensitively."
|
|
38
41
|
},
|
|
39
42
|
"replacement": {
|
|
40
43
|
"type": "string",
|
|
41
|
-
"description": "Replacement string."
|
|
44
|
+
"description": "Required. The string that replaces every occurrence of the matched pattern. Replacement notes: (1) Use an empty string \"\" to delete all matched text. (2) Use $0 to insert the entire matched text, $1 for the first capture group, $2 for the second, etc. (3) To include a literal dollar sign, use \\$."
|
|
42
45
|
},
|
|
43
46
|
"input": {
|
|
44
|
-
"description": "Optional explicit input
|
|
45
|
-
"
|
|
47
|
+
"description": "Optional explicit input providing the string to apply the regex replacement to. If omitted, the transform uses the source and attribute combination configured in the identity profile UI. When provided, must be a nested transform object or a static string.",
|
|
48
|
+
"anyOf": [
|
|
49
|
+
{
|
|
50
|
+
"type": "string",
|
|
51
|
+
"description": "Static string value to apply the regex replacement to."
|
|
52
|
+
},
|
|
46
53
|
{
|
|
47
54
|
"$ref": "#/$defs/NestedTransform"
|
|
48
55
|
}
|
|
@@ -54,7 +61,7 @@
|
|
|
54
61
|
"$defs": {
|
|
55
62
|
"NestedTransform": {
|
|
56
63
|
"type": "object",
|
|
57
|
-
"description": "
|
|
64
|
+
"description": "A nested transform object that provides the string input for the replace operation. Its output string is the value the regex replacement is applied to. The 'name' field is optional in nested transforms per SailPoint docs.",
|
|
58
65
|
"additionalProperties": false,
|
|
59
66
|
"required": [
|
|
60
67
|
"type",
|
|
@@ -62,18 +69,22 @@
|
|
|
62
69
|
],
|
|
63
70
|
"properties": {
|
|
64
71
|
"id": {
|
|
65
|
-
"type": "string"
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "Optional ID when referencing an existing saved transform."
|
|
66
74
|
},
|
|
67
75
|
"name": {
|
|
68
76
|
"type": "string",
|
|
69
|
-
"minLength": 1
|
|
77
|
+
"minLength": 1,
|
|
78
|
+
"description": "Optional display name for the nested transform."
|
|
70
79
|
},
|
|
71
80
|
"type": {
|
|
72
81
|
"type": "string",
|
|
73
|
-
"minLength": 1
|
|
82
|
+
"minLength": 1,
|
|
83
|
+
"description": "The operation type of the nested transform (e.g., 'accountAttribute', 'identityAttribute', 'trim')."
|
|
74
84
|
},
|
|
75
85
|
"requiresPeriodicRefresh": {
|
|
76
|
-
"type": "boolean"
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"description": "Whether this nested transform re-evaluates during nightly refresh."
|
|
77
88
|
},
|
|
78
89
|
"attributes": {
|
|
79
90
|
"type": "object",
|
|
@@ -85,12 +96,49 @@
|
|
|
85
96
|
},
|
|
86
97
|
"examples": [
|
|
87
98
|
{
|
|
99
|
+
"name": "Replace Whitespace with Underscore",
|
|
88
100
|
"type": "replace",
|
|
89
|
-
"name": "Replace Transform",
|
|
90
101
|
"attributes": {
|
|
91
102
|
"regex": "\\s+",
|
|
92
103
|
"replacement": "_"
|
|
93
104
|
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"name": "Remove Non-Alphanumeric Characters",
|
|
108
|
+
"type": "replace",
|
|
109
|
+
"attributes": {
|
|
110
|
+
"regex": "[^A-Za-z0-9]",
|
|
111
|
+
"replacement": ""
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"name": "Extract Domain from Email (Capture Group)",
|
|
116
|
+
"type": "replace",
|
|
117
|
+
"attributes": {
|
|
118
|
+
"regex": "^[^@]+@(.+)$",
|
|
119
|
+
"replacement": "$1",
|
|
120
|
+
"input": {
|
|
121
|
+
"type": "identityAttribute",
|
|
122
|
+
"attributes": {
|
|
123
|
+
"name": "email"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"name": "Replace Literal Dots with Hyphens",
|
|
130
|
+
"type": "replace",
|
|
131
|
+
"attributes": {
|
|
132
|
+
"regex": "[.]",
|
|
133
|
+
"replacement": "-",
|
|
134
|
+
"input": {
|
|
135
|
+
"type": "accountAttribute",
|
|
136
|
+
"attributes": {
|
|
137
|
+
"sourceName": "HR Source",
|
|
138
|
+
"attributeName": "displayName"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
94
142
|
}
|
|
95
143
|
]
|
|
96
144
|
}
|
package/dist/transforms/lint.js
CHANGED
|
@@ -428,29 +428,52 @@ function lintFirstValid(attrs) {
|
|
|
428
428
|
return msgs;
|
|
429
429
|
}
|
|
430
430
|
// ---------------------------------------------------------------------------
|
|
431
|
-
// 8. replace —
|
|
431
|
+
// 8. replace — regex compile, all-instances info, backreference hint
|
|
432
|
+
// Docs: https://developer.sailpoint.com/docs/extensibility/transforms/operations/replace
|
|
432
433
|
// ---------------------------------------------------------------------------
|
|
433
434
|
function lintReplace(attrs) {
|
|
434
435
|
const msgs = [];
|
|
436
|
+
// 1. regex: must be a non-empty string and a valid compilable regex
|
|
435
437
|
if (attrs?.regex !== undefined) {
|
|
436
438
|
if (typeof attrs.regex !== "string") {
|
|
437
439
|
push(msgs, "error", "regex must be a string.", "attributes.regex");
|
|
438
440
|
}
|
|
441
|
+
else if (attrs.regex.trim() === "") {
|
|
442
|
+
push(msgs, "error", "regex must not be empty.", "attributes.regex");
|
|
443
|
+
}
|
|
439
444
|
else {
|
|
440
|
-
//
|
|
445
|
+
// Compile check — surface syntax errors before ISC does
|
|
441
446
|
try {
|
|
442
447
|
new RegExp(attrs.regex);
|
|
443
448
|
}
|
|
444
449
|
catch (e) {
|
|
445
|
-
push(msgs, "error", `regex '${attrs.regex}' is not a valid regular expression: ${e?.message ?? e}
|
|
450
|
+
push(msgs, "error", `regex '${attrs.regex}' is not a valid regular expression: ${e?.message ?? String(e)}. ` +
|
|
451
|
+
"Use bracket notation for literal special characters (e.g., '[.]' for a literal dot, '[-]' for a literal hyphen).", "attributes.regex");
|
|
446
452
|
}
|
|
453
|
+
// All-instances info — users often expect first-match-only behaviour
|
|
454
|
+
push(msgs, "info", "replace replaces ALL occurrences of the pattern in the input string, not just the first match. " +
|
|
455
|
+
"To target only a specific occurrence, use a more precise regex that anchors to the position you want.", "attributes.regex");
|
|
447
456
|
}
|
|
448
457
|
}
|
|
449
|
-
|
|
450
|
-
|
|
458
|
+
// 2. replacement: must be a string; empty string is valid and deletes all matches
|
|
459
|
+
if (attrs?.replacement !== undefined) {
|
|
460
|
+
if (typeof attrs.replacement !== "string") {
|
|
461
|
+
push(msgs, "error", "replacement must be a string. Use an empty string \"\" to delete all text matched by the regex.", "attributes.replacement");
|
|
462
|
+
}
|
|
463
|
+
else if (/\$\d+/.test(attrs.replacement)) {
|
|
464
|
+
// Backreference detected — confirm the regex has the matching capture group
|
|
465
|
+
push(msgs, "info", "replacement contains a backreference (e.g., '$1'). Ensure the regex contains a matching capture group (e.g., '(.+)'). " +
|
|
466
|
+
"'$0' refers to the entire match; '$1' refers to the first capture group, '$2' to the second, etc.", "attributes.replacement");
|
|
467
|
+
}
|
|
451
468
|
}
|
|
452
|
-
|
|
453
|
-
|
|
469
|
+
// 3. input: optional per docs (omit to use UI-configured source+attribute).
|
|
470
|
+
// Validate type only when present.
|
|
471
|
+
if (attrs?.input !== undefined) {
|
|
472
|
+
const inp = attrs.input;
|
|
473
|
+
if (!(typeof inp === "string" || (isPlainObject(inp) && typeof inp.type === "string"))) {
|
|
474
|
+
push(msgs, "warn", "input must be a nested transform object {type, attributes} providing the string to apply the regex to, or a static string. " +
|
|
475
|
+
"If omitted, the transform uses the source+attribute combination configured in the identity profile UI.", "attributes.input");
|
|
476
|
+
}
|
|
454
477
|
}
|
|
455
478
|
return msgs;
|
|
456
479
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "isc-transforms-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for SailPoint Identity Security Cloud (ISC) Transform authoring — scaffold, strict lint, catalog, and safe upsert to live tenants.",
|
|
6
6
|
"author": {
|