isc-transforms-mcp 1.0.13 → 1.0.14

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.static.schema.json",
4
4
  "title": "SailPoint ISC Transform Schema - static",
5
- "description": "Strict schema derived from SailPoint official Static operation documentation. Returns a fixed string value. Docs also allow Velocity Template Language (VTL) in the value, and allow dynamic variables in attributes to be referenced within the VTL.",
5
+ "description": "Strict schema for the SailPoint ISC Static transform. Returns a fixed string value or evaluates a Velocity Template Language (VTL) expression. The 'value' attribute holds either a literal string (e.g. 'Contractor') or a VTL template (e.g. \"#if($workerType=='Employee')Full-Time#{else}Contingent#end\"). Additional sibling keys in the attributes object are dynamic VTL variables each can be a static string or a nested transform whose output feeds the VTL expression. IMPORTANT: Attribute ordering matters — all dynamic variable attributes must be evaluated before the value expression runs. Reference variables using $varName or ${varName} (formal reference) or $!varName / $!{varName} (quiet reference, suppresses null output).",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": [
@@ -12,34 +12,37 @@
12
12
  ],
13
13
  "properties": {
14
14
  "type": {
15
- "const": "static"
15
+ "const": "static",
16
+ "description": "Transform operation type. Must be exactly 'static'."
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": "Whether the transform should be reevaluated nightly as part of identity refresh. Default false."
26
+ "description": "If true, re-evaluates this transform during the nightly identity refresh cycle. Set to true if the VTL expression uses dynamic variables that may change over time. Default is false."
25
27
  },
26
28
  "attributes": {
27
29
  "type": "object",
28
- "description": "Static value plus optional dynamic variables (per docs).",
30
+ "description": "Required container. Must include 'value' (the fixed string or VTL expression). Any additional keys are dynamic VTL variables each key name maps to a static string or a nested transform. Use $keyName or ${keyName} in value to reference them. Attribute ordering in the identity profile matters: all variable attributes must be placed before the static transform.",
29
31
  "required": [
30
32
  "value"
31
33
  ],
32
34
  "properties": {
33
35
  "value": {
34
36
  "type": "string",
35
- "description": "Static string value or Velocity template."
37
+ "description": "The output of this transform. Either a fixed string literal (e.g. 'Contractor') or a VTL expression referencing dynamic variables defined as sibling keys in attributes (e.g. \"#if($workerType=='Employee')Full-Time#{else}Contingent#end\" or \"$first.$last@example.com\"). Supports: $varName (simple), ${varName} (formal), $!varName (quiet — outputs empty string if null), $!{varName} (quiet formal). VTL conditionals: #if($var=='value')result#{else}alternative#end."
36
38
  }
37
39
  },
38
40
  "additionalProperties": {
39
- "description": "Dynamic variables referenced in Velocity template. Can be string literals or nested transforms.",
41
+ "description": "Dynamic VTL variable. The key becomes the variable name referenced as $keyName in value. The value can be a static string (e.g. 'HR') or a nested transform object (e.g. accountAttribute, identityAttribute) whose output feeds the VTL expression.",
40
42
  "anyOf": [
41
43
  {
42
- "type": "string"
44
+ "type": "string",
45
+ "description": "Static string value for this VTL variable."
43
46
  },
44
47
  {
45
48
  "$ref": "#/$defs/NestedTransform"
@@ -51,50 +54,52 @@
51
54
  "$defs": {
52
55
  "NestedTransform": {
53
56
  "type": "object",
54
- "description": "Nested transform object used as a dynamic variable. Docs examples often omit 'name'.",
57
+ "description": "A nested transform object used as a dynamic VTL variable value. The output of this nested transform is substituted for the variable reference in value. Common types: accountAttribute, identityAttribute, getReferenceIdentityAttribute. The 'name' field is optional in nested transforms per SailPoint docs.",
55
58
  "additionalProperties": false,
56
59
  "required": [
57
- "type"
60
+ "type",
61
+ "attributes"
58
62
  ],
59
63
  "properties": {
60
64
  "id": {
61
- "type": "string"
65
+ "type": "string",
66
+ "description": "Optional ID when referencing an existing saved transform."
62
67
  },
63
68
  "name": {
64
69
  "type": "string",
65
- "minLength": 1
70
+ "minLength": 1,
71
+ "description": "Optional display name for the nested transform."
66
72
  },
67
73
  "type": {
68
74
  "type": "string",
69
- "minLength": 1
75
+ "minLength": 1,
76
+ "description": "The operation type of the nested transform (e.g., 'accountAttribute', 'identityAttribute', 'getReferenceIdentityAttribute')."
70
77
  },
71
78
  "requiresPeriodicRefresh": {
72
- "type": "boolean"
79
+ "type": "boolean",
80
+ "description": "Whether this nested transform re-evaluates during nightly refresh."
73
81
  },
74
82
  "attributes": {
75
- "type": [
76
- "object",
77
- "null"
78
- ],
83
+ "type": "object",
79
84
  "additionalProperties": true,
80
- "description": "Operation-specific attributes for the nested transform (may be omitted for operations without attributes)."
85
+ "description": "Operation-specific attributes for the nested transform."
81
86
  }
82
87
  }
83
88
  }
84
89
  },
85
90
  "examples": [
86
91
  {
92
+ "name": "Fixed String",
87
93
  "type": "static",
88
- "name": "Static Transform",
89
94
  "attributes": {
90
95
  "value": "Contractor"
91
96
  }
92
97
  },
93
98
  {
99
+ "name": "Email From Identity Attributes",
94
100
  "type": "static",
95
- "name": "Static Transform (Template)",
96
101
  "attributes": {
97
- "value": "${first}.${last}@example.com",
102
+ "value": "$first.$last@example.com",
98
103
  "first": {
99
104
  "type": "identityAttribute",
100
105
  "attributes": {
@@ -108,6 +113,36 @@
108
113
  }
109
114
  }
110
115
  }
116
+ },
117
+ {
118
+ "name": "Worker Type Conditional",
119
+ "type": "static",
120
+ "attributes": {
121
+ "value": "#if($workerType=='Employee')Full-Time#{else}Contingent#end",
122
+ "workerType": {
123
+ "type": "accountAttribute",
124
+ "attributes": {
125
+ "sourceName": "HR Source",
126
+ "attributeName": "workerType"
127
+ }
128
+ }
129
+ }
130
+ },
131
+ {
132
+ "name": "Manager Email Quiet Reference",
133
+ "type": "static",
134
+ "attributes": {
135
+ "value": "$!{managerEmail}",
136
+ "managerEmail": {
137
+ "type": "getReferenceIdentityAttribute",
138
+ "attributes": {
139
+ "name": "Cloud Services Deployment Utility",
140
+ "operation": "getReferenceIdentityAttribute",
141
+ "uid": "manager",
142
+ "attributeName": "email"
143
+ }
144
+ }
145
+ }
111
146
  }
112
147
  ]
113
148
  }
@@ -1021,16 +1021,55 @@ function lintSubstring(attrs) {
1021
1021
  return msgs;
1022
1022
  }
1023
1023
  // ---------------------------------------------------------------------------
1024
- // 24. static — value must be a string
1024
+ // 24. static — value (fixed string or VTL), dynamic VTL variable cross-check
1025
+ // Docs: https://developer.sailpoint.com/docs/extensibility/transforms/operations/static
1025
1026
  // ---------------------------------------------------------------------------
1026
1027
  function lintStatic(attrs) {
1027
1028
  const msgs = [];
1028
- // Presence check is handled by checkRequired (spec.requiredAttributes).
1029
- // Here we only validate the type when value is present.
1029
+ // 1. value type check must be a string (fixed literal or VTL expression)
1030
1030
  if (attrs?.value !== undefined && attrs?.value !== null && typeof attrs.value !== "string") {
1031
- push(msgs, "error", "value must be a string.", "attributes.value");
1031
+ push(msgs, "error", "value must be a string — either a fixed literal (e.g. 'Contractor') or a VTL expression " +
1032
+ "(e.g. \"#if($workerType=='Employee')Full-Time#{else}Contingent#end\").", "attributes.value");
1033
+ return msgs; // cannot do VTL analysis without a string value
1034
+ }
1035
+ const value = attrs?.value;
1036
+ // 2. Empty value warning
1037
+ if (typeof value === "string" && value.trim() === "") {
1038
+ push(msgs, "warn", "value is an empty string — this will produce an empty (null-equivalent) attribute. " +
1039
+ "Provide a non-empty fixed string or VTL expression.", "attributes.value");
1040
+ }
1041
+ if (typeof value === "string" && value.length > 0) {
1042
+ // 3. Extract VTL variable references ($varName, ${varName}, $!varName, $!{varName})
1043
+ const vtlRefs = new Set();
1044
+ const refPattern = /\$!?\{?([A-Za-z_][A-Za-z0-9_]*)\}?/g;
1045
+ let m;
1046
+ while ((m = refPattern.exec(value)) !== null) {
1047
+ vtlRefs.add(m[1]);
1048
+ }
1049
+ if (vtlRefs.size > 0) {
1050
+ // 4. Warn for each VTL reference that has no matching dynamic variable in attributes
1051
+ for (const varName of vtlRefs) {
1052
+ if (!Object.prototype.hasOwnProperty.call(attrs, varName)) {
1053
+ push(msgs, "warn", `VTL references $${varName} in value but no dynamic variable '${varName}' is defined in attributes. ` +
1054
+ `Add a '${varName}' key to attributes with a static string or nested transform that supplies the value.`, `attributes.${varName}`);
1055
+ }
1056
+ }
1057
+ // 5. Ordering hint — VTL variables must be positioned before the value attribute in the identity profile
1058
+ push(msgs, "info", "VTL variables detected in value. Attribute ordering matters in identity profiles: " +
1059
+ "all dynamic variable attributes must be mapped and evaluated before the static transform's value expression runs. " +
1060
+ "Review the attribute mapping order in your identity profile.", "attributes.value");
1061
+ }
1062
+ // 6. Warn for dynamic variables defined in attributes but never referenced in value (likely a typo or leftover)
1063
+ const reservedKeys = new Set(["value"]);
1064
+ for (const key of Object.keys(attrs ?? {})) {
1065
+ if (reservedKeys.has(key))
1066
+ continue;
1067
+ if (!vtlRefs.has(key)) {
1068
+ push(msgs, "warn", `Dynamic variable '${key}' is defined in attributes but not referenced as $${key} in value. ` +
1069
+ `If intentional, remove it to keep the transform clean; otherwise check for a typo.`, `attributes.${key}`);
1070
+ }
1071
+ }
1032
1072
  }
1033
- // Any other keys in attributes are valid dynamic VTL variable definitions — no unknown-attribute errors.
1034
1073
  return msgs;
1035
1074
  }
1036
1075
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isc-transforms-mcp",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
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": {