@reventlessdev/reventless-aws 3.0.0-alpha.394 → 3.0.0-alpha.396

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +8 -8
  3. package/scripts/DeployApp.res +7 -1
  4. package/scripts/DeployApp.res.mjs +1 -1
  5. package/scripts/ProvisionAccounts.res +89 -4
  6. package/scripts/ProvisionAccounts.res.mjs +101 -5
  7. package/scripts/ProvisionIdentity.res +42 -18
  8. package/scripts/ProvisionIdentity.res.mjs +40 -26
  9. package/src/Platform.res +47 -10
  10. package/src/Platform.res.mjs +44 -10
  11. package/src/Platform_Stack.res +17 -0
  12. package/src/Platform_Stack.res.mjs +7 -1
  13. package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +16 -7
  14. package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +16 -3
  15. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +59 -9
  16. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res.mjs +53 -6
  17. package/src/adapter/Auth/Auth_Cognito.res +13 -2
  18. package/src/adapter/Auth/Auth_Cognito.res.mjs +9 -2
  19. package/src/adapter/Auth/Auth_IdentityStore.res +52 -0
  20. package/src/adapter/Auth/Auth_IdentityStore.res.mjs +46 -0
  21. package/src/adapter/Auth/Auth_IdentityStore_Schema.res +39 -0
  22. package/src/adapter/Auth/Auth_IdentityStore_Schema.res.mjs +35 -0
  23. package/src/adapter/Identity/IdentityProvider_Cognito_Backend.res +251 -0
  24. package/src/adapter/Identity/IdentityProvider_Cognito_Backend.res.mjs +300 -0
  25. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res +7 -4
  26. package/src/adapter/Runtime/AutomationSliceEntryPoint_Ops.res.mjs +2 -2
  27. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res +80 -0
  28. package/src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs +53 -2
  29. package/src/components/AutomationSlice_Builder.res.mjs +1 -1
  30. package/src/components/OutboundTranslationSlice_Builder.res +2 -0
  31. package/src/components/OutboundTranslationSlice_Builder.res.mjs +1 -1
  32. package/src/plugin/runtime/PluginRuntime_Builder.res +23 -0
  33. package/src/plugin/runtime/PluginRuntime_Builder.res.mjs +29 -0
  34. package/tests/Auth_ActiveRoleTrigger_OpsTest.res +40 -0
  35. package/tests/Auth_ActiveRoleTrigger_OpsTest.res.mjs +59 -8
  36. package/tests/Auth_CognitoTest.res +62 -0
  37. package/tests/Auth_CognitoTest.res.mjs +98 -0
  38. package/tests/Auth_IdentityStore_SchemaTest.res +35 -0
  39. package/tests/Auth_IdentityStore_SchemaTest.res.mjs +43 -0
  40. package/tests/IdentityProvider_Cognito_BackendTest.res +314 -0
  41. package/tests/IdentityProvider_Cognito_BackendTest.res.mjs +442 -0
  42. package/tests/ProvisionAccountsTest.res.mjs +1 -1
  43. package/tests/Util_ShellConfigTest.res.mjs +1 -22
@@ -0,0 +1,442 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Pulumi from "@pulumi/pulumi";
6
+ import * as Auth_UserId$ReventlessCore from "@reventlessdev/reventless-core/src/adapter/Auth/Auth_UserId.res.mjs";
7
+ import * as IdentityProvider_Cognito_Backend$ReventlessAws from "../src/adapter/Identity/IdentityProvider_Cognito_Backend.res.mjs";
8
+ import * as AutomationSliceRuntime_Builder_Single$ReventlessAws from "../src/adapter/Runtime/AutomationSliceRuntime_Builder_Single.res.mjs";
9
+
10
+ function awsError(code) {
11
+ let e = new Error(code + `: from the fake pool`);
12
+ e.name = code;
13
+ return e;
14
+ }
15
+
16
+ function fakeOps(pool, failOn) {
17
+ let record = step => {
18
+ pool.calls.push(step);
19
+ if (failOn === undefined) {
20
+ return;
21
+ }
22
+ if (failOn[0] !== step) {
23
+ return;
24
+ }
25
+ throw awsError(failOn[1]);
26
+ };
27
+ return {
28
+ createUser: async (username, param) => {
29
+ record("createUser");
30
+ if (username in pool.users) {
31
+ throw awsError("UsernameExistsException");
32
+ }
33
+ let sub = `sub-` + username;
34
+ pool.users[username] = [
35
+ sub,
36
+ []
37
+ ];
38
+ return sub;
39
+ },
40
+ subOf: async username => {
41
+ record("subOf");
42
+ let match = pool.users[username];
43
+ if (match !== undefined) {
44
+ return match[0];
45
+ }
46
+ throw awsError("UserNotFoundException");
47
+ },
48
+ setPassword: async (param, param$1) => record("setPassword"),
49
+ addToGroup: async (username, group) => {
50
+ record("addToGroup");
51
+ let match = pool.users[username];
52
+ if (match !== undefined) {
53
+ pool.users[username] = [
54
+ match[0],
55
+ match[1].concat([group])
56
+ ];
57
+ return;
58
+ }
59
+ throw awsError("UserNotFoundException");
60
+ },
61
+ removeFromGroup: async (username, group) => {
62
+ record("removeFromGroup");
63
+ let match = pool.users[username];
64
+ if (match !== undefined) {
65
+ pool.users[username] = [
66
+ match[0],
67
+ match[1].filter(g => g !== group)
68
+ ];
69
+ return;
70
+ }
71
+ throw awsError("UserNotFoundException");
72
+ },
73
+ deleteUser: async username => {
74
+ record("deleteUser");
75
+ if (!(username in pool.users)) {
76
+ throw awsError("UserNotFoundException");
77
+ }
78
+ return Stdlib_Dict.$$delete(pool.users, username);
79
+ },
80
+ putUserId: async (sub, userId) => {
81
+ record("putUserId");
82
+ pool.rows[sub] = userId;
83
+ },
84
+ deleteUserId: async sub => {
85
+ record("deleteUserId");
86
+ return Stdlib_Dict.$$delete(pool.rows, sub);
87
+ }
88
+ };
89
+ }
90
+
91
+ function emptyPool() {
92
+ return {
93
+ users: {},
94
+ rows: {},
95
+ calls: []
96
+ };
97
+ }
98
+
99
+ function email(address) {
100
+ return {
101
+ TAG: "ToEmail",
102
+ _0: address
103
+ };
104
+ }
105
+
106
+ globalThis.describe("IdentityProvider_Cognito_Backend", () => {
107
+ globalThis.test("creates the principal, sets its password and groups, and mints its id", async () => {
108
+ let pool_users = {};
109
+ let pool_rows = {};
110
+ let pool_calls = [];
111
+ let pool = {
112
+ users: pool_users,
113
+ rows: pool_rows,
114
+ calls: pool_calls
115
+ };
116
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
117
+ let answer = await provider.createPrincipal({
118
+ TAG: "ToEmail",
119
+ _0: "new@example.com"
120
+ }, {
121
+ TAG: "Password",
122
+ _0: "pw"
123
+ }, ["Shopper"]);
124
+ globalThis.expect(answer).toEqual({
125
+ TAG: "Ok",
126
+ _0: {
127
+ providerId: "new@example.com"
128
+ }
129
+ });
130
+ globalThis.expect(pool_users["new@example.com"]).toEqual([
131
+ "sub-new@example.com",
132
+ ["Shopper"]
133
+ ]);
134
+ globalThis.expect(Stdlib_Option.map(pool_rows["sub-new@example.com"], Auth_UserId$ReventlessCore.isMinted)).toEqual(true);
135
+ });
136
+ globalThis.test("an existing account is a Conflict, not an outage", async () => {
137
+ let pool_users = {};
138
+ let pool_rows = {};
139
+ let pool_calls = [];
140
+ let pool = {
141
+ users: pool_users,
142
+ rows: pool_rows,
143
+ calls: pool_calls
144
+ };
145
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
146
+ let create = () => provider.createPrincipal({
147
+ TAG: "ToEmail",
148
+ _0: "twice@example.com"
149
+ }, "NoCredential", []);
150
+ await create();
151
+ globalThis.expect(await create()).toEqual({
152
+ TAG: "Error",
153
+ _0: "Conflict"
154
+ });
155
+ });
156
+ globalThis.test("a later step failing undoes the account, so a retry starts clean", async () => {
157
+ let pool_users = {};
158
+ let pool_rows = {};
159
+ let pool_calls = [];
160
+ let pool = {
161
+ users: pool_users,
162
+ rows: pool_rows,
163
+ calls: pool_calls
164
+ };
165
+ let failing = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, [
166
+ "addToGroup",
167
+ "TooManyRequestsException"
168
+ ]), true);
169
+ let first = await failing.createPrincipal({
170
+ TAG: "ToEmail",
171
+ _0: "retry@example.com"
172
+ }, {
173
+ TAG: "Password",
174
+ _0: "pw"
175
+ }, ["Shopper"]);
176
+ let tmp;
177
+ if (first.TAG === "Ok") {
178
+ tmp = false;
179
+ } else {
180
+ let tmp$1 = first._0;
181
+ tmp = typeof tmp$1 !== "object" ? false : tmp$1.TAG === "Unavailable";
182
+ }
183
+ globalThis.expect(tmp).toBe(true);
184
+ globalThis.expect("retry@example.com" in pool_users).toBe(false);
185
+ globalThis.expect(Object.keys(pool_rows)).toEqual([]);
186
+ let healthy = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
187
+ let second = await healthy.createPrincipal({
188
+ TAG: "ToEmail",
189
+ _0: "retry@example.com"
190
+ }, {
191
+ TAG: "Password",
192
+ _0: "pw"
193
+ }, ["Shopper"]);
194
+ globalThis.expect(second).toEqual({
195
+ TAG: "Ok",
196
+ _0: {
197
+ providerId: "retry@example.com"
198
+ }
199
+ });
200
+ });
201
+ globalThis.test("a password the pool's policy rejects is Refused, and undone", async () => {
202
+ let pool_users = {};
203
+ let pool_rows = {};
204
+ let pool_calls = [];
205
+ let pool = {
206
+ users: pool_users,
207
+ rows: pool_rows,
208
+ calls: pool_calls
209
+ };
210
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, [
211
+ "setPassword",
212
+ "InvalidPasswordException"
213
+ ]), true);
214
+ let answer = await provider.createPrincipal({
215
+ TAG: "ToEmail",
216
+ _0: "weak@example.com"
217
+ }, {
218
+ TAG: "Password",
219
+ _0: "1"
220
+ }, []);
221
+ let tmp;
222
+ if (answer.TAG === "Ok") {
223
+ tmp = false;
224
+ } else {
225
+ let tmp$1 = answer._0;
226
+ tmp = typeof tmp$1 !== "object" ? false : tmp$1.TAG !== "Unavailable";
227
+ }
228
+ globalThis.expect(tmp).toBe(true);
229
+ globalThis.expect("weak@example.com" in pool_users).toBe(false);
230
+ });
231
+ globalThis.test("NoCredential sets no password", async () => {
232
+ let pool_users = {};
233
+ let pool_rows = {};
234
+ let pool_calls = [];
235
+ let pool = {
236
+ users: pool_users,
237
+ rows: pool_rows,
238
+ calls: pool_calls
239
+ };
240
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
241
+ await provider.createPrincipal({
242
+ TAG: "ToEmail",
243
+ _0: "later@example.com"
244
+ }, "NoCredential", []);
245
+ globalThis.expect(pool_calls.includes("setPassword")).toBe(false);
246
+ });
247
+ globalThis.test("without a store, no id is minted", async () => {
248
+ let pool_users = {};
249
+ let pool_rows = {};
250
+ let pool_calls = [];
251
+ let pool = {
252
+ users: pool_users,
253
+ rows: pool_rows,
254
+ calls: pool_calls
255
+ };
256
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), false);
257
+ await provider.createPrincipal({
258
+ TAG: "ToEmail",
259
+ _0: "old@example.com"
260
+ }, "NoCredential", []);
261
+ globalThis.expect(pool_calls.includes("putUserId")).toBe(false);
262
+ globalThis.expect("old@example.com" in pool_users).toBe(true);
263
+ });
264
+ globalThis.test("a push address is refused before the pool is asked", async () => {
265
+ let pool_users = {};
266
+ let pool_rows = {};
267
+ let pool_calls = [];
268
+ let pool = {
269
+ users: pool_users,
270
+ rows: pool_rows,
271
+ calls: pool_calls
272
+ };
273
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
274
+ let answer = await provider.createPrincipal({
275
+ TAG: "ToPush",
276
+ _0: {
277
+ TAG: "Fcm",
278
+ registrationToken: "tok"
279
+ }
280
+ }, "NoCredential", []);
281
+ let tmp;
282
+ if (answer.TAG === "Ok") {
283
+ tmp = false;
284
+ } else {
285
+ let tmp$1 = answer._0;
286
+ tmp = typeof tmp$1 !== "object" ? false : tmp$1.TAG !== "Unavailable";
287
+ }
288
+ globalThis.expect(tmp).toBe(true);
289
+ globalThis.expect(pool_calls).toEqual([]);
290
+ });
291
+ globalThis.test("groups change on the pool, and an unknown principal is Refused", async () => {
292
+ let pool_users = {};
293
+ let pool_rows = {};
294
+ let pool_calls = [];
295
+ let pool = {
296
+ users: pool_users,
297
+ rows: pool_rows,
298
+ calls: pool_calls
299
+ };
300
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
301
+ let principal = {
302
+ providerId: "grp@example.com"
303
+ };
304
+ await provider.createPrincipal({
305
+ TAG: "ToEmail",
306
+ _0: "grp@example.com"
307
+ }, "NoCredential", ["Shopper"]);
308
+ globalThis.expect(await provider.addToGroup(principal, "Reviewer")).toEqual({
309
+ TAG: "Ok",
310
+ _0: undefined
311
+ });
312
+ globalThis.expect(await provider.removeFromGroup(principal, "Shopper")).toEqual({
313
+ TAG: "Ok",
314
+ _0: undefined
315
+ });
316
+ globalThis.expect(pool_users["grp@example.com"]).toEqual([
317
+ "sub-grp@example.com",
318
+ ["Reviewer"]
319
+ ]);
320
+ let match = await provider.addToGroup({
321
+ providerId: "ghost"
322
+ }, "Shopper");
323
+ let tmp;
324
+ if (match.TAG === "Ok") {
325
+ tmp = false;
326
+ } else {
327
+ let tmp$1 = match._0;
328
+ tmp = typeof tmp$1 !== "object" ? false : tmp$1.TAG !== "Unavailable";
329
+ }
330
+ globalThis.expect(tmp).toBe(true);
331
+ });
332
+ globalThis.test("deleting removes the account and its row, and a second delete is Ok", async () => {
333
+ let pool_users = {};
334
+ let pool_rows = {};
335
+ let pool_calls = [];
336
+ let pool = {
337
+ users: pool_users,
338
+ rows: pool_rows,
339
+ calls: pool_calls
340
+ };
341
+ let provider = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true);
342
+ let principal = {
343
+ providerId: "gone@example.com"
344
+ };
345
+ await provider.createPrincipal({
346
+ TAG: "ToEmail",
347
+ _0: "gone@example.com"
348
+ }, "NoCredential", []);
349
+ globalThis.expect(await provider.deletePrincipal(principal)).toEqual({
350
+ TAG: "Ok",
351
+ _0: undefined
352
+ });
353
+ globalThis.expect("gone@example.com" in pool_users).toBe(false);
354
+ globalThis.expect("sub-gone@example.com" in pool_rows).toBe(false);
355
+ globalThis.expect(await provider.deletePrincipal(principal)).toEqual({
356
+ TAG: "Ok",
357
+ _0: undefined
358
+ });
359
+ });
360
+ globalThis.test("an outage while deleting is retried, not reported as done", async () => {
361
+ let pool_users = {};
362
+ let pool_rows = {};
363
+ let pool_calls = [];
364
+ let pool = {
365
+ users: pool_users,
366
+ rows: pool_rows,
367
+ calls: pool_calls
368
+ };
369
+ await IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, undefined), true).createPrincipal({
370
+ TAG: "ToEmail",
371
+ _0: "busy@example.com"
372
+ }, "NoCredential", []);
373
+ let failing = IdentityProvider_Cognito_Backend$ReventlessAws.withOps(fakeOps(pool, [
374
+ "deleteUser",
375
+ "TooManyRequestsException"
376
+ ]), true);
377
+ let match = await failing.deletePrincipal({
378
+ providerId: "busy@example.com"
379
+ });
380
+ let tmp;
381
+ if (match.TAG === "Ok") {
382
+ tmp = false;
383
+ } else {
384
+ let tmp$1 = match._0;
385
+ tmp = typeof tmp$1 !== "object" ? false : tmp$1.TAG === "Unavailable";
386
+ }
387
+ globalThis.expect(tmp).toBe(true);
388
+ globalThis.expect("busy@example.com" in pool_users).toBe(true);
389
+ });
390
+ globalThis.test("no pool configured answers Unavailable with no operations", () => {
391
+ globalThis.expect(IdentityProvider_Cognito_Backend$ReventlessAws.provider("", "").operations).toEqual([]);
392
+ });
393
+ globalThis.test("a configured pool publishes all four operations", () => {
394
+ globalThis.expect(IdentityProvider_Cognito_Backend$ReventlessAws.provider("eu-west-1_X", "t").operations).toEqual([
395
+ "CreatePrincipal",
396
+ "AddToGroup",
397
+ "RemoveFromGroup",
398
+ "DeletePrincipal"
399
+ ]);
400
+ });
401
+ });
402
+
403
+ globalThis.describe("AutomationSliceRuntime_Builder_Single.declaresIdentityProvider", () => {
404
+ let info = needs => ({
405
+ specModulePath: "",
406
+ bodyModulePath: "",
407
+ callbackType: "outbound",
408
+ queryDbTableName: Pulumi.output(""),
409
+ queryDbResources: [],
410
+ context: undefined,
411
+ sourceTopics: {},
412
+ consumesDcbLog: true,
413
+ commandTargetName: undefined,
414
+ schedule: undefined,
415
+ schedulesResources: [],
416
+ capabilityNeeds: needs
417
+ });
418
+ globalThis.test("only a slice declaring the need earns the grant", () => {
419
+ globalThis.expect(AutomationSliceRuntime_Builder_Single$ReventlessAws.declaresIdentityProvider([
420
+ info(["Messaging"]),
421
+ info([])
422
+ ])).toBe(false);
423
+ globalThis.expect(AutomationSliceRuntime_Builder_Single$ReventlessAws.declaresIdentityProvider([
424
+ info(["Messaging"]),
425
+ info(["IdentityProvider"])
426
+ ])).toBe(true);
427
+ });
428
+ });
429
+
430
+ let Backend;
431
+
432
+ let IP;
433
+
434
+ export {
435
+ Backend,
436
+ IP,
437
+ awsError,
438
+ fakeOps,
439
+ emptyPool,
440
+ email,
441
+ }
442
+ /* Not a pure module */
@@ -162,7 +162,7 @@ globalThis.describe("ProvisionAccounts.provision", () => {
162
162
  TAG: "Error",
163
163
  _0: "pool signs in on email"
164
164
  });
165
- let outcome = await ProvisionAccounts$ReventlessAws.provision(file, "eu-west-1_Refuses", refuse);
165
+ let outcome = await ProvisionAccounts$ReventlessAws.provision(file, "eu-west-1_Refuses", undefined, refuse);
166
166
  let after = Nodefs.readFileSync(file, "utf8");
167
167
  Nodefs.rmSync(dir, {
168
168
  recursive: true,
@@ -5,7 +5,6 @@ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
5
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
7
  import * as Role$Reventless from "@reventlessdev/reventless-spec/src/types/Role.res.mjs";
8
- import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
8
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
10
9
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
11
10
  import * as Util_ShellConfig$ReventlessAws from "../src/util/Util_ShellConfig.res.mjs";
@@ -351,7 +350,7 @@ globalThis.describe("Util_ShellConfig.fields — shellConfig passthrough", () =>
351
350
  globalThis.describe("Util_ShellConfig.identityFields", () => {
352
351
  let fields = Util_ShellConfig$ReventlessAws.identityFields("eu-west-1_x", "7cl13nt");
353
352
  let get = key => Stdlib_Option.map(fields.find(param => param[0] === key), param => param[1]);
354
- globalThis.test("the new spelling is present", () => {
353
+ globalThis.test("the identity keys carry the pool and the client", () => {
355
354
  globalThis.expect([
356
355
  get("identityProviderId"),
357
356
  get("identityProviderClientId")
@@ -360,28 +359,8 @@ globalThis.describe("Util_ShellConfig.identityFields", () => {
360
359
  "7cl13nt"
361
360
  ]);
362
361
  });
363
- globalThis.test("the deprecated spelling is present too", () => {
364
- globalThis.expect([
365
- get("cognitoUserPoolId"),
366
- get("cognitoClientId")
367
- ]).toEqual([
368
- "eu-west-1_x",
369
- "7cl13nt"
370
- ]);
371
- });
372
- globalThis.test("both spellings carry identical values", () => {
373
- globalThis.expect([
374
- Primitive_object.equal(get("identityProviderId"), get("cognitoUserPoolId")),
375
- Primitive_object.equal(get("identityProviderClientId"), get("cognitoClientId"))
376
- ]).toEqual([
377
- true,
378
- true
379
- ]);
380
- });
381
362
  globalThis.test("nothing else sneaks into the identity field set", () => {
382
363
  globalThis.expect(fields.map(param => param[0]).toSorted(Primitive_string.compare)).toEqual([
383
- "cognitoClientId",
384
- "cognitoUserPoolId",
385
364
  "identityProviderClientId",
386
365
  "identityProviderId"
387
366
  ]);