@agiledigital/pingone-aic-script-tester 0.1.0
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.
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +274 -0
- package/dist/bin/fetch-jar.d.ts +2 -0
- package/dist/bin/fetch-jar.js +13 -0
- package/dist/bin/pull-profile.d.ts +2 -0
- package/dist/bin/pull-profile.js +40 -0
- package/dist/bin/show-log.d.ts +2 -0
- package/dist/bin/show-log.js +31 -0
- package/dist/classes/.complete +12 -0
- package/dist/classes/AmClassShutter.class +0 -0
- package/dist/classes/AmContextFactory$ObservedContext.class +0 -0
- package/dist/classes/AmContextFactory.class +0 -0
- package/dist/classes/AmScopes.class +0 -0
- package/dist/classes/HostOps.class +0 -0
- package/dist/classes/JsValues.class +0 -0
- package/dist/classes/Json$Parser.class +0 -0
- package/dist/classes/Json.class +0 -0
- package/dist/classes/LanguageVersions.class +0 -0
- package/dist/classes/Runner.class +0 -0
- package/dist/classes/ScriptContextScope.class +0 -0
- package/dist/src/aic/callbacks.d.ts +35 -0
- package/dist/src/aic/callbacks.js +130 -0
- package/dist/src/aic/conform.d.ts +90 -0
- package/dist/src/aic/conform.js +193 -0
- package/dist/src/aic/constants.d.ts +13 -0
- package/dist/src/aic/constants.js +13 -0
- package/dist/src/aic/diff.d.ts +25 -0
- package/dist/src/aic/diff.js +201 -0
- package/dist/src/aic/emit-journey.d.ts +64 -0
- package/dist/src/aic/emit-journey.js +254 -0
- package/dist/src/aic/emit-result.d.ts +10 -0
- package/dist/src/aic/emit-result.js +39 -0
- package/dist/src/aic/emit-session.d.ts +26 -0
- package/dist/src/aic/emit-session.js +132 -0
- package/dist/src/aic/emit-subject.d.ts +40 -0
- package/dist/src/aic/emit-subject.js +210 -0
- package/dist/src/aic/file-lease.d.ts +35 -0
- package/dist/src/aic/file-lease.js +543 -0
- package/dist/src/aic/http.d.ts +21 -0
- package/dist/src/aic/http.js +127 -0
- package/dist/src/aic/idm.d.ts +10 -0
- package/dist/src/aic/idm.js +112 -0
- package/dist/src/aic/index.d.ts +35 -0
- package/dist/src/aic/index.js +21 -0
- package/dist/src/aic/js.d.ts +8 -0
- package/dist/src/aic/js.js +11 -0
- package/dist/src/aic/lease-identity.d.ts +38 -0
- package/dist/src/aic/lease-identity.js +72 -0
- package/dist/src/aic/lease-lock.d.ts +45 -0
- package/dist/src/aic/lease-lock.js +173 -0
- package/dist/src/aic/managed.d.ts +28 -0
- package/dist/src/aic/managed.js +199 -0
- package/dist/src/aic/provider.d.ts +156 -0
- package/dist/src/aic/provider.js +416 -0
- package/dist/src/aic/record.d.ts +28 -0
- package/dist/src/aic/record.js +183 -0
- package/dist/src/aic/resource-snapshot.d.ts +12 -0
- package/dist/src/aic/resource-snapshot.js +116 -0
- package/dist/src/aic/run.d.ts +102 -0
- package/dist/src/aic/run.js +450 -0
- package/dist/src/aic/tenant.d.ts +107 -0
- package/dist/src/aic/tenant.js +307 -0
- package/dist/src/aic/trace.d.ts +25 -0
- package/dist/src/aic/trace.js +56 -0
- package/dist/src/aic/txid.d.ts +11 -0
- package/dist/src/aic/txid.js +25 -0
- package/dist/src/aic/unsupported.d.ts +15 -0
- package/dist/src/aic/unsupported.js +60 -0
- package/dist/src/bindings/allowlist.d.ts +42 -0
- package/dist/src/bindings/allowlist.js +62 -0
- package/dist/src/bindings/harvest.d.ts +7 -0
- package/dist/src/bindings/harvest.js +137 -0
- package/dist/src/bindings/index.d.ts +4 -0
- package/dist/src/bindings/index.js +3 -0
- package/dist/src/bindings/preamble.d.ts +23 -0
- package/dist/src/bindings/preamble.js +36 -0
- package/dist/src/bindings/run.d.ts +33 -0
- package/dist/src/bindings/run.js +55 -0
- package/dist/src/case/equal.d.ts +2 -0
- package/dist/src/case/equal.js +40 -0
- package/dist/src/case/index.d.ts +5 -0
- package/dist/src/case/index.js +4 -0
- package/dist/src/case/portable.d.ts +10 -0
- package/dist/src/case/portable.js +28 -0
- package/dist/src/case/session.d.ts +34 -0
- package/dist/src/case/session.js +66 -0
- package/dist/src/case/state.d.ts +4 -0
- package/dist/src/case/state.js +47 -0
- package/dist/src/case/types.d.ts +266 -0
- package/dist/src/case/types.js +106 -0
- package/dist/src/case/util.d.ts +7 -0
- package/dist/src/case/util.js +115 -0
- package/dist/src/case/validate.d.ts +8 -0
- package/dist/src/case/validate.js +463 -0
- package/dist/src/case/verdict.d.ts +6 -0
- package/dist/src/case/verdict.js +810 -0
- package/dist/src/diagnostics.d.ts +7 -0
- package/dist/src/diagnostics.js +5 -0
- package/dist/src/emit-dts.d.ts +2 -0
- package/dist/src/emit-dts.js +82 -0
- package/dist/src/emit-js.d.ts +3 -0
- package/dist/src/emit-js.js +149 -0
- package/dist/src/harness/failures.d.ts +26 -0
- package/dist/src/harness/failures.js +113 -0
- package/dist/src/harness/idm.d.ts +12 -0
- package/dist/src/harness/idm.js +44 -0
- package/dist/src/harness/index.d.ts +11 -0
- package/dist/src/harness/index.js +6 -0
- package/dist/src/harness/lease.d.ts +136 -0
- package/dist/src/harness/lease.js +286 -0
- package/dist/src/harness/residue.d.ts +23 -0
- package/dist/src/harness/residue.js +73 -0
- package/dist/src/harness/show-log.d.ts +43 -0
- package/dist/src/harness/show-log.js +253 -0
- package/dist/src/harness/spec.d.ts +67 -0
- package/dist/src/harness/spec.js +189 -0
- package/dist/src/harness/step.d.ts +80 -0
- package/dist/src/harness/step.js +97 -0
- package/dist/src/harness/types.d.ts +100 -0
- package/dist/src/harness/types.js +1 -0
- package/dist/src/harness/vitest.d.ts +52 -0
- package/dist/src/harness/vitest.js +155 -0
- package/dist/src/idents.d.ts +4 -0
- package/dist/src/idents.js +42 -0
- package/dist/src/jvm.d.ts +124 -0
- package/dist/src/jvm.js +432 -0
- package/dist/src/load.d.ts +2 -0
- package/dist/src/load.js +104 -0
- package/dist/src/paths.d.ts +36 -0
- package/dist/src/paths.js +50 -0
- package/dist/src/profile/index.d.ts +5 -0
- package/dist/src/profile/index.js +3 -0
- package/dist/src/profile/normalise.d.ts +16 -0
- package/dist/src/profile/normalise.js +106 -0
- package/dist/src/profile/pull.d.ts +22 -0
- package/dist/src/profile/pull.js +36 -0
- package/dist/src/profile/seed.d.ts +11 -0
- package/dist/src/profile/seed.js +28 -0
- package/dist/src/profile/store.d.ts +13 -0
- package/dist/src/profile/store.js +60 -0
- package/dist/src/profile/types.d.ts +45 -0
- package/dist/src/profile/types.js +1 -0
- package/dist/src/profile/validate.d.ts +38 -0
- package/dist/src/profile/validate.js +129 -0
- package/dist/src/project.d.ts +37 -0
- package/dist/src/project.js +93 -0
- package/dist/src/protocol.d.ts +62 -0
- package/dist/src/protocol.js +68 -0
- package/dist/src/provider-module.d.ts +11 -0
- package/dist/src/provider-module.js +46 -0
- package/dist/src/runner.d.ts +39 -0
- package/dist/src/runner.js +337 -0
- package/dist/src/schema.d.ts +48 -0
- package/dist/src/schema.js +93 -0
- package/generated/scripted-decision-mocks.cjs +722 -0
- package/generated/scripted-decision-mocks.d.ts +626 -0
- package/generated/scripted-decision-next.json +3640 -0
- package/java/AmClassShutter.java +98 -0
- package/java/AmContextFactory.java +69 -0
- package/java/AmScopes.java +49 -0
- package/java/HostOps.java +180 -0
- package/java/JsValues.java +39 -0
- package/java/Json.java +441 -0
- package/java/LanguageVersions.java +55 -0
- package/java/Runner.java +289 -0
- package/java/ScriptContextScope.java +147 -0
- package/package.json +88 -0
- package/src/bindings/rhino/runtime.cjs +3021 -0
package/java/Runner.java
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import java.io.BufferedReader;
|
|
2
|
+
import java.io.FileDescriptor;
|
|
3
|
+
import java.io.FileOutputStream;
|
|
4
|
+
import java.io.InputStreamReader;
|
|
5
|
+
import java.io.PrintStream;
|
|
6
|
+
import java.nio.charset.Charset;
|
|
7
|
+
import java.nio.charset.StandardCharsets;
|
|
8
|
+
import java.util.LinkedHashMap;
|
|
9
|
+
import java.util.List;
|
|
10
|
+
import java.util.Locale;
|
|
11
|
+
import java.util.Map;
|
|
12
|
+
import java.util.TimeZone;
|
|
13
|
+
import javax.script.ScriptContext;
|
|
14
|
+
import javax.script.SimpleScriptContext;
|
|
15
|
+
import org.mozilla.javascript.Context;
|
|
16
|
+
import org.mozilla.javascript.EvaluatorException;
|
|
17
|
+
import org.mozilla.javascript.RhinoException;
|
|
18
|
+
import org.mozilla.javascript.Script;
|
|
19
|
+
import org.mozilla.javascript.Scriptable;
|
|
20
|
+
import org.mozilla.javascript.ScriptableObject;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Long-lived JVM speaking line-delimited JSON on stdin/stdout. One process,
|
|
24
|
+
* many jobs, a fresh {@link ScriptContextScope} per job. Anything the runner
|
|
25
|
+
* itself needs to say goes to stderr.
|
|
26
|
+
*
|
|
27
|
+
* <pre>
|
|
28
|
+
* java -cp rhino.jar:classes Runner
|
|
29
|
+
* </pre>
|
|
30
|
+
*/
|
|
31
|
+
public final class Runner {
|
|
32
|
+
|
|
33
|
+
/** Harness default so a missing timeout cannot hang the process. AM's default is 0 (no timeout). */
|
|
34
|
+
static final long DEFAULT_TIMEOUT_MS = 10_000L;
|
|
35
|
+
|
|
36
|
+
static final PrintStream OUT =
|
|
37
|
+
new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8);
|
|
38
|
+
static final PrintStream ERR =
|
|
39
|
+
new PrintStream(new FileOutputStream(FileDescriptor.err), true, StandardCharsets.UTF_8);
|
|
40
|
+
|
|
41
|
+
public static void main(String[] args) throws Exception {
|
|
42
|
+
final AmContextFactory factory = new AmContextFactory();
|
|
43
|
+
ERR.println("rhino-local-runner ready " + Json.stringify(environment(factory)));
|
|
44
|
+
final BufferedReader in =
|
|
45
|
+
new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
|
|
46
|
+
String line;
|
|
47
|
+
while ((line = in.readLine()) != null) {
|
|
48
|
+
if (line.isEmpty()) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
handleLine(factory, line);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* What this JVM would make of a script that looked at its surroundings. The
|
|
57
|
+
* client refuses a JVM whose answers differ from the AM image's, because a
|
|
58
|
+
* host that defaulted to its own timezone or locale would pass a date-shaped
|
|
59
|
+
* test locally that fails on the tenant.
|
|
60
|
+
*/
|
|
61
|
+
static Map<String, Object> environment(AmContextFactory factory) {
|
|
62
|
+
final Map<String, Object> env = new LinkedHashMap<String, Object>();
|
|
63
|
+
env.put("javaFeature", Integer.valueOf(Runtime.version().feature()));
|
|
64
|
+
env.put("javaVersion", Runtime.version().toString());
|
|
65
|
+
env.put("javaVendorVersion", System.getProperty("java.vendor.version"));
|
|
66
|
+
env.put("timezone", TimeZone.getDefault().getID());
|
|
67
|
+
env.put("locale", Locale.getDefault().toLanguageTag());
|
|
68
|
+
env.put("charset", Charset.defaultCharset().name());
|
|
69
|
+
final Context cx = factory.enterContext();
|
|
70
|
+
try {
|
|
71
|
+
env.put("rhino", cx.getImplementationVersion());
|
|
72
|
+
} finally {
|
|
73
|
+
Context.exit();
|
|
74
|
+
}
|
|
75
|
+
return env;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static void handleLine(AmContextFactory factory, String line) {
|
|
79
|
+
final Object parsed;
|
|
80
|
+
try {
|
|
81
|
+
parsed = Json.parse(line);
|
|
82
|
+
} catch (RuntimeException e) {
|
|
83
|
+
ERR.println("rhino-local-runner: skipping unparseable line: " + e.getMessage());
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
final Map<String, Object> job;
|
|
87
|
+
try {
|
|
88
|
+
job = Json.asObject(parsed, "job");
|
|
89
|
+
} catch (RuntimeException e) {
|
|
90
|
+
ERR.println("rhino-local-runner: skipping non-object job: " + e.getMessage());
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
final Object idRaw = job.get("id");
|
|
94
|
+
if (!(idRaw instanceof String) || ((String) idRaw).isEmpty()) {
|
|
95
|
+
ERR.println("rhino-local-runner: skipping job with no string id");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
final String id = (String) idRaw;
|
|
99
|
+
try {
|
|
100
|
+
if (Json.optionalBoolean(job, "shutdown", false)
|
|
101
|
+
|| "shutdown".equals(Json.optionalString(job, "op"))) {
|
|
102
|
+
write(response(id, "ok", JsValues.of(Scriptable.NOT_FOUND), null));
|
|
103
|
+
OUT.flush();
|
|
104
|
+
System.exit(0);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
write(evalJob(factory, id, job));
|
|
108
|
+
} catch (Throwable t) {
|
|
109
|
+
write(errorResponse(id, "runtime_error", t, null, -1, -1, null));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static Map<String, Object> evalJob(
|
|
114
|
+
AmContextFactory factory, String id, Map<String, Object> job) {
|
|
115
|
+
final String source = Json.optionalString(job, "source");
|
|
116
|
+
if (source == null) {
|
|
117
|
+
return errorResponse(
|
|
118
|
+
id,
|
|
119
|
+
"protocol_error",
|
|
120
|
+
new IllegalArgumentException("job is missing source"),
|
|
121
|
+
null,
|
|
122
|
+
-1,
|
|
123
|
+
-1,
|
|
124
|
+
null);
|
|
125
|
+
}
|
|
126
|
+
final String sourceName;
|
|
127
|
+
final String requestedName = Json.optionalString(job, "sourceName");
|
|
128
|
+
if (requestedName != null && !requestedName.isEmpty()) {
|
|
129
|
+
sourceName = requestedName;
|
|
130
|
+
} else {
|
|
131
|
+
sourceName = id;
|
|
132
|
+
}
|
|
133
|
+
final int languageVersion;
|
|
134
|
+
try {
|
|
135
|
+
languageVersion = LanguageVersions.parse(job.get("languageVersion"));
|
|
136
|
+
} catch (RuntimeException e) {
|
|
137
|
+
return errorResponse(id, "protocol_error", e, sourceName, -1, -1, null);
|
|
138
|
+
}
|
|
139
|
+
final long timeoutMs = Json.optionalLong(job, "timeoutMs", DEFAULT_TIMEOUT_MS);
|
|
140
|
+
final String preamble = Json.optionalString(job, "preamble");
|
|
141
|
+
final String preambleName;
|
|
142
|
+
final String requestedPreamble = Json.optionalString(job, "preambleName");
|
|
143
|
+
if (requestedPreamble != null && !requestedPreamble.isEmpty()) {
|
|
144
|
+
preambleName = requestedPreamble;
|
|
145
|
+
} else {
|
|
146
|
+
preambleName = "<preamble>";
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
final List<String> classAllowList;
|
|
150
|
+
try {
|
|
151
|
+
classAllowList = Json.optionalStringList(job, "classAllowList");
|
|
152
|
+
} catch (RuntimeException e) {
|
|
153
|
+
return errorResponse(id, "protocol_error", e, sourceName, -1, -1, null);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
final Context cx = factory.enterContext();
|
|
157
|
+
try {
|
|
158
|
+
cx.setLanguageVersion(languageVersion);
|
|
159
|
+
// No list means no shutter, which is the pre-shutter behaviour: every
|
|
160
|
+
// Java name resolves. Callers that mean to reproduce a script context
|
|
161
|
+
// pass that context's allowLists.
|
|
162
|
+
if (classAllowList != null) {
|
|
163
|
+
cx.setClassShutter(AmClassShutter.of(classAllowList));
|
|
164
|
+
}
|
|
165
|
+
if (cx instanceof AmContextFactory.ObservedContext) {
|
|
166
|
+
((AmContextFactory.ObservedContext) cx).timeoutMs = timeoutMs;
|
|
167
|
+
}
|
|
168
|
+
final SimpleScriptContext scriptContext = AmScopes.newEngineContext(sourceName);
|
|
169
|
+
injectGlobals(scriptContext, job.get("globals"));
|
|
170
|
+
final Scriptable scope = AmScopes.makeScriptable(cx, scriptContext);
|
|
171
|
+
|
|
172
|
+
if (preamble != null && !preamble.isEmpty()) {
|
|
173
|
+
try {
|
|
174
|
+
final String hostOpName = "__rhinoLocalHostOp";
|
|
175
|
+
HostOps hostOps = new HostOps();
|
|
176
|
+
hostOps.setParentScope(scope);
|
|
177
|
+
hostOps.setPrototype(ScriptableObject.getFunctionPrototype(scope));
|
|
178
|
+
ScriptableObject.putProperty(scope, hostOpName, hostOps);
|
|
179
|
+
try {
|
|
180
|
+
Script preambleScript = cx.compileString(preamble, preambleName, 1, null);
|
|
181
|
+
preambleScript.exec(cx, scope);
|
|
182
|
+
} finally {
|
|
183
|
+
ScriptableObject.deleteProperty(scope, hostOpName);
|
|
184
|
+
}
|
|
185
|
+
} catch (EvaluatorException e) {
|
|
186
|
+
return errorFromRhino(id, "compile_error", e);
|
|
187
|
+
} catch (RhinoException e) {
|
|
188
|
+
return errorFromRhino(id, "runtime_error", e);
|
|
189
|
+
} catch (Error e) {
|
|
190
|
+
if (isInterrupt(e)) {
|
|
191
|
+
return timeoutResponse(id);
|
|
192
|
+
}
|
|
193
|
+
throw e;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
final Script script;
|
|
198
|
+
try {
|
|
199
|
+
script = cx.compileString(source, sourceName, 1, null);
|
|
200
|
+
} catch (EvaluatorException e) {
|
|
201
|
+
return errorFromRhino(id, "compile_error", e);
|
|
202
|
+
} catch (RhinoException e) {
|
|
203
|
+
return errorFromRhino(id, "compile_error", e);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
final Object completion;
|
|
207
|
+
try {
|
|
208
|
+
completion = script.exec(cx, scope);
|
|
209
|
+
} catch (RhinoException e) {
|
|
210
|
+
return errorFromRhino(id, "runtime_error", e);
|
|
211
|
+
} catch (Error e) {
|
|
212
|
+
if (isInterrupt(e)) {
|
|
213
|
+
return timeoutResponse(id);
|
|
214
|
+
}
|
|
215
|
+
throw e;
|
|
216
|
+
}
|
|
217
|
+
final String resultGlobal = Json.optionalString(job, "resultGlobal");
|
|
218
|
+
final Object result = resultGlobal == null
|
|
219
|
+
? completion
|
|
220
|
+
: ScriptableObject.getProperty(scope, resultGlobal);
|
|
221
|
+
return response(id, "ok", JsValues.of(result), null);
|
|
222
|
+
} finally {
|
|
223
|
+
Context.exit();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
static void injectGlobals(SimpleScriptContext scriptContext, Object globalsRaw) {
|
|
228
|
+
if (globalsRaw == null) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
Map<String, Object> globals = Json.asObject(globalsRaw, "globals");
|
|
232
|
+
for (Map.Entry<String, Object> e : globals.entrySet()) {
|
|
233
|
+
scriptContext.setAttribute(e.getKey(), e.getValue(), ScriptContext.ENGINE_SCOPE);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
static boolean isInterrupt(Error e) {
|
|
238
|
+
return "Interrupt.".equals(e.getMessage());
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
static Map<String, Object> errorFromRhino(String id, String outcome, RhinoException e) {
|
|
242
|
+
return errorResponse(
|
|
243
|
+
id, outcome, e, e.sourceName(), e.lineNumber(), e.columnNumber(), e.lineSource());
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static Map<String, Object> timeoutResponse(String id) {
|
|
247
|
+
Map<String, Object> err = new LinkedHashMap<String, Object>();
|
|
248
|
+
err.put("class", "java.lang.Error");
|
|
249
|
+
err.put("message", "Interrupt.");
|
|
250
|
+
err.put("sourceName", null);
|
|
251
|
+
err.put("line", Integer.valueOf(-1));
|
|
252
|
+
err.put("column", Integer.valueOf(-1));
|
|
253
|
+
err.put("lineSource", null);
|
|
254
|
+
return response(id, "timeout", JsValues.of(Scriptable.NOT_FOUND), err);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
static Map<String, Object> errorResponse(
|
|
258
|
+
String id,
|
|
259
|
+
String outcome,
|
|
260
|
+
Throwable t,
|
|
261
|
+
String sourceName,
|
|
262
|
+
int line,
|
|
263
|
+
int column,
|
|
264
|
+
String lineSource) {
|
|
265
|
+
Map<String, Object> err = new LinkedHashMap<String, Object>();
|
|
266
|
+
err.put("class", t.getClass().getName());
|
|
267
|
+
err.put("message", t.getMessage());
|
|
268
|
+
err.put("sourceName", sourceName);
|
|
269
|
+
err.put("line", Integer.valueOf(line));
|
|
270
|
+
err.put("column", Integer.valueOf(column));
|
|
271
|
+
err.put("lineSource", lineSource);
|
|
272
|
+
return response(id, outcome, JsValues.of(Scriptable.NOT_FOUND), err);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static Map<String, Object> response(
|
|
276
|
+
String id, String outcome, JsValues value, Map<String, Object> error) {
|
|
277
|
+
Map<String, Object> rec = new LinkedHashMap<String, Object>();
|
|
278
|
+
rec.put("id", id);
|
|
279
|
+
rec.put("outcome", outcome);
|
|
280
|
+
rec.put("valueKind", value.kind);
|
|
281
|
+
rec.put("value", value.json);
|
|
282
|
+
rec.put("error", error);
|
|
283
|
+
return rec;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
static void write(Map<String, Object> rec) {
|
|
287
|
+
OUT.println(Json.stringify(rec));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import java.util.ArrayList;
|
|
2
|
+
import java.util.List;
|
|
3
|
+
import javax.script.Bindings;
|
|
4
|
+
import javax.script.ScriptContext;
|
|
5
|
+
import org.mozilla.javascript.Context;
|
|
6
|
+
import org.mozilla.javascript.NativeObject;
|
|
7
|
+
import org.mozilla.javascript.Scriptable;
|
|
8
|
+
import org.mozilla.javascript.Wrapper;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Replica of AM 8.1.1 {@code
|
|
12
|
+
* org.forgerock.openam.scripting.factories.ScriptContextScope}, measured with
|
|
13
|
+
* {@code javap -p -c} on {@code openam-scripting-8.1.1.jar}.
|
|
14
|
+
*
|
|
15
|
+
* <p>Implements {@link Scriptable} only — not {@code ScriptableObject} and not
|
|
16
|
+
* {@code ConstProperties}. That is the lever for top-level {@code const}:
|
|
17
|
+
* Rhino's {@code putConstProperty} silently drops the initializer when the
|
|
18
|
+
* scope is not {@code ConstProperties}, after {@code defineConstProperty} has
|
|
19
|
+
* already {@code put} {@code Undefined}. Decision-node scripts therefore read
|
|
20
|
+
* top-level {@code const} back as {@code undefined}.
|
|
21
|
+
*
|
|
22
|
+
* <p>AM's class depends on {@code org.forgerock.util.Reject}; this replica does
|
|
23
|
+
* not, so we do not have to extract forgerock-util.
|
|
24
|
+
*/
|
|
25
|
+
final class ScriptContextScope implements Scriptable {
|
|
26
|
+
|
|
27
|
+
private final ScriptContext scriptContext;
|
|
28
|
+
private Scriptable prototype;
|
|
29
|
+
private Scriptable parentScope;
|
|
30
|
+
|
|
31
|
+
ScriptContextScope(ScriptContext scriptContext) {
|
|
32
|
+
if (scriptContext == null) {
|
|
33
|
+
throw new IllegalArgumentException("scriptContext");
|
|
34
|
+
}
|
|
35
|
+
this.scriptContext = scriptContext;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Override
|
|
39
|
+
public String getClassName() {
|
|
40
|
+
return "ScriptContextScope";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Override
|
|
44
|
+
public boolean has(String name, Scriptable start) {
|
|
45
|
+
return scriptContext.getAttributesScope(name) != -1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Override
|
|
49
|
+
public boolean has(int index, Scriptable start) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Override
|
|
54
|
+
public Object get(String name, Scriptable start) {
|
|
55
|
+
int scope = scriptContext.getAttributesScope(name);
|
|
56
|
+
if (scope != -1) {
|
|
57
|
+
Object value = scriptContext.getAttribute(name, scope);
|
|
58
|
+
return Context.javaToJS(value, this);
|
|
59
|
+
}
|
|
60
|
+
return Scriptable.NOT_FOUND;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Override
|
|
64
|
+
public Object get(int index, Scriptable start) {
|
|
65
|
+
return Scriptable.NOT_FOUND;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@Override
|
|
69
|
+
public void put(String name, Scriptable start, Object value) {
|
|
70
|
+
int scope = scriptContext.getAttributesScope(name);
|
|
71
|
+
if (scope == -1) {
|
|
72
|
+
scope = ScriptContext.ENGINE_SCOPE;
|
|
73
|
+
}
|
|
74
|
+
if (value instanceof Wrapper) {
|
|
75
|
+
value = ((Wrapper) value).unwrap();
|
|
76
|
+
}
|
|
77
|
+
scriptContext.setAttribute(name, value, scope);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@Override
|
|
81
|
+
public void put(int index, Scriptable start, Object value) {
|
|
82
|
+
// AM no-ops integer keys.
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@Override
|
|
86
|
+
public void delete(String name) {
|
|
87
|
+
int scope = scriptContext.getAttributesScope(name);
|
|
88
|
+
if (scope != -1) {
|
|
89
|
+
scriptContext.removeAttribute(name, scope);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@Override
|
|
94
|
+
public void delete(int index) {
|
|
95
|
+
// AM no-ops integer keys.
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@Override
|
|
99
|
+
public Scriptable getPrototype() {
|
|
100
|
+
return prototype;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@Override
|
|
104
|
+
public void setPrototype(Scriptable prototype) {
|
|
105
|
+
this.prototype = prototype;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@Override
|
|
109
|
+
public Scriptable getParentScope() {
|
|
110
|
+
return parentScope;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@Override
|
|
114
|
+
public void setParentScope(Scriptable parentScope) {
|
|
115
|
+
this.parentScope = parentScope;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@Override
|
|
119
|
+
public Object[] getIds() {
|
|
120
|
+
List<Object> ids = new ArrayList<Object>();
|
|
121
|
+
for (Integer scope : scriptContext.getScopes()) {
|
|
122
|
+
Bindings bindings = scriptContext.getBindings(scope.intValue());
|
|
123
|
+
// AM does not null-check; SimpleScriptContext's GLOBAL_SCOPE starts null.
|
|
124
|
+
if (bindings != null) {
|
|
125
|
+
ids.addAll(bindings.keySet());
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return ids.toArray();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
@Override
|
|
132
|
+
public Object getDefaultValue(Class<?> hint) {
|
|
133
|
+
return NativeObject.getDefaultValue(this, hint);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@Override
|
|
137
|
+
public boolean hasInstance(Scriptable instance) {
|
|
138
|
+
Scriptable proto = instance.getPrototype();
|
|
139
|
+
while (proto != null) {
|
|
140
|
+
if (proto.equals(this)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
proto = proto.getPrototype();
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agiledigital/pingone-aic-script-tester",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Local Rhino harness: mock-surface generator and typed client for the long-lived JVM runner.",
|
|
6
|
+
"license": "MIT OR Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/agiledigital-labs/pingone-aic-manager.git",
|
|
10
|
+
"directory": "packages/rhino-local"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/src/harness/index.d.ts",
|
|
18
|
+
"default": "./dist/src/harness/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./case": {
|
|
21
|
+
"types": "./dist/src/case/index.d.ts",
|
|
22
|
+
"default": "./dist/src/case/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./aic": {
|
|
25
|
+
"types": "./dist/src/aic/index.d.ts",
|
|
26
|
+
"default": "./dist/src/aic/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./bindings": {
|
|
29
|
+
"types": "./dist/src/bindings/index.d.ts",
|
|
30
|
+
"default": "./dist/src/bindings/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./runner": {
|
|
33
|
+
"types": "./dist/src/runner.d.ts",
|
|
34
|
+
"default": "./dist/src/runner.js"
|
|
35
|
+
},
|
|
36
|
+
"./profile": {
|
|
37
|
+
"types": "./dist/src/profile/index.d.ts",
|
|
38
|
+
"default": "./dist/src/profile/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./diagnostics": {
|
|
41
|
+
"types": "./dist/src/diagnostics.d.ts",
|
|
42
|
+
"default": "./dist/src/diagnostics.js"
|
|
43
|
+
},
|
|
44
|
+
"./package.json": "./package.json"
|
|
45
|
+
},
|
|
46
|
+
"bin": {
|
|
47
|
+
"aic-script-tester-show-log": "dist/bin/show-log.js",
|
|
48
|
+
"aic-script-tester-pull-profile": "dist/bin/pull-profile.js",
|
|
49
|
+
"aic-script-tester-fetch-jar": "dist/bin/fetch-jar.js"
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist/",
|
|
53
|
+
"generated/",
|
|
54
|
+
"java/*.java",
|
|
55
|
+
"LICENSE-APACHE",
|
|
56
|
+
"LICENSE-MIT",
|
|
57
|
+
"src/bindings/rhino/runtime.cjs"
|
|
58
|
+
],
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=24"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"generate": "node src/generate.ts",
|
|
64
|
+
"measure": "node src/measure.ts",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"lint": "eslint . --max-warnings 0",
|
|
68
|
+
"lint:am": "eslint --config eslint.am.config.js generated src/bindings cases --max-warnings 0",
|
|
69
|
+
"pull-profile": "node bin/pull-profile.ts",
|
|
70
|
+
"show-log": "node bin/show-log.ts",
|
|
71
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && node src/build-classes.ts",
|
|
72
|
+
"prepack": "npm run build",
|
|
73
|
+
"fetch-jar": "node bin/fetch-jar.ts"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@eslint/js": "10.0.1",
|
|
77
|
+
"@types/node": "24.19.0",
|
|
78
|
+
"eslint": "10.11.0",
|
|
79
|
+
"typescript": "5.9.3",
|
|
80
|
+
"typescript-eslint": "8.71.0",
|
|
81
|
+
"vitest": "5.0.2",
|
|
82
|
+
"zod": "^4.6.4"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"vitest": "^5.0.2",
|
|
86
|
+
"zod": "^4.6.4"
|
|
87
|
+
}
|
|
88
|
+
}
|