@reventlessdev/reventless-aws 3.0.0-alpha.293 → 3.0.0-alpha.295
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/CHANGELOG.md +17 -0
- package/package.json +8 -8
- package/src/Platform.res +38 -25
- package/src/Platform.res.mjs +6 -4
- package/src/Platform_Stack.res +4 -0
- package/src/Platform_Stack.res.mjs +2 -1
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res +211 -3
- package/src/adapter/Auth/Auth_ActiveRolePoolAttachment.res.mjs +115 -4
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res +6 -1
- package/src/adapter/Auth/Auth_ActiveRoleTrigger.res.mjs +4 -2
- package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +8 -1
- package/src/components/Api/AppSync_Adapter.res +19 -23
- package/src/components/Api/AppSync_Adapter.res.mjs +8 -20
- package/src/components/Api/AppSync_SdlDecorate.res +30 -14
- package/src/components/Api/AppSync_SdlDecorate.res.mjs +11 -10
- package/tests/AppSync_AdapterTest.res +35 -20
- package/tests/AppSync_AdapterTest.res.mjs +23 -16
- package/tests/AppSync_SdlDecorateTest.res +4 -4
- package/tests/AppSync_SdlDecorateTest.res.mjs +4 -4
- package/tests/Auth_ActiveRolePoolAttachmentTest.res +74 -0
- package/tests/Auth_ActiveRolePoolAttachmentTest.res.mjs +31 -0
|
@@ -31,7 +31,7 @@ type Mutation {
|
|
|
31
31
|
type Subscription {
|
|
32
32
|
onCatalog_AddProduct(id: ID): CommandResult
|
|
33
33
|
onUIFragmentChange: UIFragmentChangeEvent
|
|
34
|
-
@
|
|
34
|
+
@aws_cognito_user_pools(cognito_groups: ["Admin"])
|
|
35
35
|
onCatalogEventLog_eventAppended: CatalogEventLogEvent
|
|
36
36
|
}`
|
|
37
37
|
|
|
@@ -43,13 +43,13 @@ describe("AppSync_SdlDecorate.injectAwsSubscribe", () => {
|
|
|
43
43
|
)
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
-
testSync("appends the many-mutations fan-in on a no-arg field, keeping
|
|
46
|
+
testSync("appends the many-mutations fan-in on a no-arg field, keeping the group directive", () => {
|
|
47
47
|
let sdl = AppSync_SdlDecorate.injectAwsSubscribe(stitchedSdl, ~sources)
|
|
48
48
|
expect(sdl)->toContain(
|
|
49
49
|
`onUIFragmentChange: UIFragmentChangeEvent\n @aws_subscribe(mutations: ["Platform_UIFragmentRegistered", "Platform_UIFragmentUpdated", "Platform_UIFragmentDeregistered"])`,
|
|
50
50
|
)
|
|
51
51
|
// The auth directive line appended by injectAwsAuthAll survives.
|
|
52
|
-
expect(sdl)->toContain(`@
|
|
52
|
+
expect(sdl)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
testSync("leaves unmapped fields (Source A) and non-Subscription blocks untouched", () => {
|
|
@@ -113,7 +113,7 @@ describe("AppSync_SdlDecorate.injectAwsAuthAll", () => {
|
|
|
113
113
|
expect(parts.mutations->Array.getUnsafe(0))->toContain("@aws_iam")
|
|
114
114
|
// A query NOT in iamFieldNames stays Cognito-only.
|
|
115
115
|
let other = queryField("Other_Query")
|
|
116
|
-
expect(other)->toContain(`@
|
|
116
|
+
expect(other)->toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`)
|
|
117
117
|
expect(other->String.includes("@aws_iam"))->toBe(false)
|
|
118
118
|
})
|
|
119
119
|
})
|
|
@@ -35,7 +35,7 @@ type Mutation {
|
|
|
35
35
|
type Subscription {
|
|
36
36
|
onCatalog_AddProduct(id: ID): CommandResult
|
|
37
37
|
onUIFragmentChange: UIFragmentChangeEvent
|
|
38
|
-
@
|
|
38
|
+
@aws_cognito_user_pools(cognito_groups: ["Admin"])
|
|
39
39
|
onCatalogEventLog_eventAppended: CatalogEventLogEvent
|
|
40
40
|
}`;
|
|
41
41
|
|
|
@@ -44,10 +44,10 @@ globalThis.describe("AppSync_SdlDecorate.injectAwsSubscribe", () => {
|
|
|
44
44
|
let sdl = AppSync_SdlDecorate$ReventlessAws.injectAwsSubscribe(stitchedSdl, sources);
|
|
45
45
|
globalThis.expect(sdl).toContain(`onCatalog_AddProduct(id: ID): CommandResult\n @aws_subscribe(mutations: ["Catalog_AddProduct"])`);
|
|
46
46
|
});
|
|
47
|
-
globalThis.test("appends the many-mutations fan-in on a no-arg field, keeping
|
|
47
|
+
globalThis.test("appends the many-mutations fan-in on a no-arg field, keeping the group directive", () => {
|
|
48
48
|
let sdl = AppSync_SdlDecorate$ReventlessAws.injectAwsSubscribe(stitchedSdl, sources);
|
|
49
49
|
globalThis.expect(sdl).toContain(`onUIFragmentChange: UIFragmentChangeEvent\n @aws_subscribe(mutations: ["Platform_UIFragmentRegistered", "Platform_UIFragmentUpdated", "Platform_UIFragmentDeregistered"])`);
|
|
50
|
-
globalThis.expect(sdl).toContain(`@
|
|
50
|
+
globalThis.expect(sdl).toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`);
|
|
51
51
|
});
|
|
52
52
|
globalThis.test("leaves unmapped fields (Source A) and non-Subscription blocks untouched", () => {
|
|
53
53
|
let sdl = AppSync_SdlDecorate$ReventlessAws.injectAwsSubscribe(stitchedSdl, sources);
|
|
@@ -100,7 +100,7 @@ globalThis.describe("AppSync_SdlDecorate.injectAwsAuthAll", () => {
|
|
|
100
100
|
globalThis.expect(queryField("Platform_ApiFragments")).toContain("@aws_iam");
|
|
101
101
|
globalThis.expect(parts.mutations[0]).toContain("@aws_iam");
|
|
102
102
|
let other = queryField("Other_Query");
|
|
103
|
-
globalThis.expect(other).toContain(`@
|
|
103
|
+
globalThis.expect(other).toContain(`@aws_cognito_user_pools(cognito_groups: ["Admin"])`);
|
|
104
104
|
globalThis.expect(other.includes("@aws_iam")).toBe(false);
|
|
105
105
|
});
|
|
106
106
|
});
|
|
@@ -209,3 +209,77 @@ describe("Auth_ActiveRolePoolAttachment.attachedTrigger", () => {
|
|
|
209
209
|
)
|
|
210
210
|
)
|
|
211
211
|
})
|
|
212
|
+
|
|
213
|
+
// The pre-attach check. Its whole job is to keep a trigger that cannot run off a
|
|
214
|
+
// live pool, because a pre-token-generation trigger that throws does not degrade
|
|
215
|
+
// the feature — it fails every sign-in for every user of that pool.
|
|
216
|
+
describe("Auth_ActiveRolePoolAttachment.probeVerdict", () => {
|
|
217
|
+
// The real payload from the outage this check exists to prevent: the function
|
|
218
|
+
// could not resolve a package at module load, so it died during init and never
|
|
219
|
+
// reached its handler. Nothing inside the handler could have caught this.
|
|
220
|
+
let initFailurePayload = `{"errorType":"Error","errorMessage":"Cannot find package '@reventlessdev/reventless-core' imported from /var/task/node_modules/@reventlessdev/reventless-aws/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res.mjs","code":"ERR_MODULE_NOT_FOUND"}`
|
|
221
|
+
|
|
222
|
+
testSync("refuses a function that died before reaching its handler", () =>
|
|
223
|
+
expect(
|
|
224
|
+
Attachment.probeVerdict(~functionError=Some("Unhandled"), ~payload=initFailurePayload),
|
|
225
|
+
)->toEqual(Attachment.Crashed("Unhandled"))
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
testSync("accepts a function that hands the event back", () =>
|
|
229
|
+
expect(
|
|
230
|
+
Attachment.probeVerdict(
|
|
231
|
+
~functionError=None,
|
|
232
|
+
~payload=`{"request":{"groupConfiguration":{"groupsToOverride":[]}},"response":{}}`,
|
|
233
|
+
),
|
|
234
|
+
)->toEqual(Attachment.Healthy)
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
// A 200 carrying the wrong shape is as fatal to sign-in as a throw, and far
|
|
238
|
+
// easier to mistake for success.
|
|
239
|
+
testSync("refuses a successful call that returns something else", () =>
|
|
240
|
+
expect(Attachment.probeVerdict(~functionError=None, ~payload=`{"ok":true}`))->toEqual(
|
|
241
|
+
Attachment.NotAnEvent,
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
// Produces a verdict rather than escaping: a parse error here would fail the
|
|
246
|
+
// deploy with a message about JSON instead of about the trigger.
|
|
247
|
+
testSync("treats an unparseable payload as not an event", () =>
|
|
248
|
+
expect(Attachment.probeVerdict(~functionError=None, ~payload="<html>502</html>"))->toEqual(
|
|
249
|
+
Attachment.NotAnEvent,
|
|
250
|
+
)
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
testSync("treats an empty payload as not an event", () =>
|
|
254
|
+
expect(Attachment.probeVerdict(~functionError=None, ~payload=""))->toEqual(
|
|
255
|
+
Attachment.NotAnEvent,
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
describe("Auth_ActiveRolePoolAttachment.probeEvent", () => {
|
|
261
|
+
let event = Attachment.probeEvent(~userPoolId="eu-west-1_Example")->JSON.Decode.object
|
|
262
|
+
|
|
263
|
+
testSync("is shaped like the V1_0 event Cognito sends", () =>
|
|
264
|
+
expect(
|
|
265
|
+
event
|
|
266
|
+
->Option.flatMap(o => o->Dict.get("request"))
|
|
267
|
+
->Option.flatMap(JSON.Decode.object)
|
|
268
|
+
->Option.isSome,
|
|
269
|
+
)->toBe(true)
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
// Empty membership and a subject that cannot exist: the probe checks that the
|
|
273
|
+
// function runs, not what it decides, and must not collide with a real row.
|
|
274
|
+
testSync("presents no groups to narrow", () =>
|
|
275
|
+
expect(
|
|
276
|
+
event
|
|
277
|
+
->Option.flatMap(o => o->Dict.get("request"))
|
|
278
|
+
->Option.flatMap(JSON.Decode.object)
|
|
279
|
+
->Option.flatMap(r => r->Dict.get("groupConfiguration"))
|
|
280
|
+
->Option.flatMap(JSON.Decode.object)
|
|
281
|
+
->Option.flatMap(g => g->Dict.get("groupsToOverride"))
|
|
282
|
+
->Option.flatMap(JSON.Decode.array),
|
|
283
|
+
)->toEqual(Some([]))
|
|
284
|
+
)
|
|
285
|
+
})
|
|
@@ -219,6 +219,37 @@ globalThis.describe("Auth_ActiveRolePoolAttachment.attachedTrigger", () => {
|
|
|
219
219
|
});
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
+
globalThis.describe("Auth_ActiveRolePoolAttachment.probeVerdict", () => {
|
|
223
|
+
globalThis.test("refuses a function that died before reaching its handler", () => {
|
|
224
|
+
globalThis.expect(Auth_ActiveRolePoolAttachment$ReventlessAws.probeVerdict("Unhandled", `{"errorType":"Error","errorMessage":"Cannot find package '@reventlessdev/reventless-core' imported from /var/task/node_modules/@reventlessdev/reventless-aws/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res.mjs","code":"ERR_MODULE_NOT_FOUND"}`)).toEqual({
|
|
225
|
+
TAG: "Crashed",
|
|
226
|
+
_0: "Unhandled"
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
globalThis.test("accepts a function that hands the event back", () => {
|
|
230
|
+
globalThis.expect(Auth_ActiveRolePoolAttachment$ReventlessAws.probeVerdict(undefined, `{"request":{"groupConfiguration":{"groupsToOverride":[]}},"response":{}}`)).toEqual("Healthy");
|
|
231
|
+
});
|
|
232
|
+
globalThis.test("refuses a successful call that returns something else", () => {
|
|
233
|
+
globalThis.expect(Auth_ActiveRolePoolAttachment$ReventlessAws.probeVerdict(undefined, `{"ok":true}`)).toEqual("NotAnEvent");
|
|
234
|
+
});
|
|
235
|
+
globalThis.test("treats an unparseable payload as not an event", () => {
|
|
236
|
+
globalThis.expect(Auth_ActiveRolePoolAttachment$ReventlessAws.probeVerdict(undefined, "<html>502</html>")).toEqual("NotAnEvent");
|
|
237
|
+
});
|
|
238
|
+
globalThis.test("treats an empty payload as not an event", () => {
|
|
239
|
+
globalThis.expect(Auth_ActiveRolePoolAttachment$ReventlessAws.probeVerdict(undefined, "")).toEqual("NotAnEvent");
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
globalThis.describe("Auth_ActiveRolePoolAttachment.probeEvent", () => {
|
|
244
|
+
let event = Stdlib_JSON.Decode.object(Auth_ActiveRolePoolAttachment$ReventlessAws.probeEvent("eu-west-1_Example"));
|
|
245
|
+
globalThis.test("is shaped like the V1_0 event Cognito sends", () => {
|
|
246
|
+
globalThis.expect(Stdlib_Option.isSome(Stdlib_Option.flatMap(Stdlib_Option.flatMap(event, o => o["request"]), Stdlib_JSON.Decode.object))).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
globalThis.test("presents no groups to narrow", () => {
|
|
249
|
+
globalThis.expect(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_Option.flatMap(event, o => o["request"]), Stdlib_JSON.Decode.object), r => r["groupConfiguration"]), Stdlib_JSON.Decode.object), g => g["groupsToOverride"]), Stdlib_JSON.Decode.array)).toEqual([]);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
222
253
|
let Attachment;
|
|
223
254
|
|
|
224
255
|
export {
|