@reventlessdev/reventless-aws 3.0.0-alpha.299 → 3.0.0-alpha.301
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 +9 -9
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +1 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +2 -1
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res +1 -0
- package/src/adapter/Api/Platform_ComponentDefinitions_Lambda_Ops.res.mjs +2 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore.res +10 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore.res.mjs +1 -1
- package/src/adapter/Auth/Auth_ActiveRoleStore_Ops.res +39 -4
- package/src/adapter/Auth/Auth_ActiveRoleStore_Ops.res.mjs +22 -3
- package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +1 -1
- package/src/components/Api/AppSync_Adapter.res +10 -7
- package/tests/Auth_ActiveRoleStoreTest.res +32 -0
- package/tests/Auth_ActiveRoleStoreTest.res.mjs +29 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.301 (2026-08-15)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **aws:** ask Cognito about a caller by the name it knows them by ([265f436](https://github.com/ReventlessDev/reventless-core/commit/265f4361f9695a12d1dcc055b256ec72174d428e))
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **core:** curate the pages a shell builds across a plugin's views ([589835a](https://github.com/ReventlessDev/reventless-core/commit/589835a1ad428c5e2dea8bf6e4c64e49d2f67e0d))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# 3.0.0-alpha.300 (2026-08-14)
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **core:** one contract for which refusal a platform gave ([7705c13](https://github.com/ReventlessDev/reventless-core/commit/7705c13ec63f41a3a659bc98cfb45b880fd5b222))
|
|
21
|
+
|
|
22
|
+
|
|
6
23
|
# 3.0.0-alpha.299 (2026-08-14)
|
|
7
24
|
|
|
8
25
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.301",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"dependencies": {
|
|
@@ -12,18 +12,18 @@
|
|
|
12
12
|
"@aws-sdk/s3-request-presigner": "3.970.0",
|
|
13
13
|
"sury": "11.0.0-alpha.4",
|
|
14
14
|
"uuid": "^13.0.0",
|
|
15
|
+
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.11",
|
|
15
16
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.32",
|
|
16
|
-
"@reventlessdev/rescript-
|
|
17
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.7",
|
|
17
18
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.10",
|
|
18
|
-
"@reventlessdev/rescript-
|
|
19
|
-
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.75",
|
|
20
|
-
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
19
|
+
"@reventlessdev/rescript-pulumi-aws": "2.4.0-alpha.76",
|
|
21
20
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
|
|
22
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
23
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.140",
|
|
21
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.235",
|
|
24
22
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.31",
|
|
25
|
-
"@reventlessdev/
|
|
26
|
-
"@reventlessdev/reventless-
|
|
23
|
+
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.19",
|
|
24
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.99",
|
|
25
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.114",
|
|
26
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.142"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"rescript": "12.3.0",
|
|
@@ -87,9 +87,10 @@ function make(api, pluginReadModelTableName, offloadBucketName, schemaReady, bak
|
|
|
87
87
|
});
|
|
88
88
|
strings("views", sel.views);
|
|
89
89
|
strings("commands", sel.commands);
|
|
90
|
+
strings("derived", sel.derived);
|
|
90
91
|
return entry;
|
|
91
92
|
})) : "";
|
|
92
|
-
let adminEntryJson = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry(Platform_Admin_Structure$ReventlessCore.pluginId, Platform_Admin_Structure$ReventlessCore.structure));
|
|
93
|
+
let adminEntryJson = JSON.stringify(Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry(Platform_Admin_Structure$ReventlessCore.pluginId, undefined, Platform_Admin_Structure$ReventlessCore.structure));
|
|
93
94
|
let packageDirs = Object.fromEntries([[
|
|
94
95
|
"@reventlessdev/reventless-aws",
|
|
95
96
|
Util_Bundle$ReventlessAws.resolvePackageRoot(undefined, "@reventlessdev/reventless-aws")
|
|
@@ -304,6 +304,7 @@ let bakeSelection = (json: JSON.t): option<ReventlessCore.Platform_BakedManifest
|
|
|
304
304
|
ReventlessCore.Platform_BakedManifest.plugin,
|
|
305
305
|
views: strings(o, "views"),
|
|
306
306
|
commands: strings(o, "commands"),
|
|
307
|
+
derived: strings(o, "derived"),
|
|
307
308
|
})
|
|
308
309
|
)
|
|
309
310
|
}
|
|
@@ -263,7 +263,8 @@ function bakeSelection(json) {
|
|
|
263
263
|
return Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(json), o => Stdlib_Option.map(Stdlib_Option.flatMap(o["plugin"], Stdlib_JSON.Decode.string), plugin => ({
|
|
264
264
|
plugin: plugin,
|
|
265
265
|
views: strings(o, "views"),
|
|
266
|
-
commands: strings(o, "commands")
|
|
266
|
+
commands: strings(o, "commands"),
|
|
267
|
+
derived: strings(o, "derived")
|
|
267
268
|
})));
|
|
268
269
|
}
|
|
269
270
|
|
|
@@ -40,6 +40,15 @@ type storeTable = {
|
|
|
40
40
|
// JS resolver code (APPSYNC_JS runtime): forward the caller's arguments and the
|
|
41
41
|
// authorizer-verified identity. `sub` is what keys the row, and it comes from
|
|
42
42
|
// here — the mutation has no `sub` argument for a client to supply.
|
|
43
|
+
//
|
|
44
|
+
// `username` travels with it because the two answer different questions. The row
|
|
45
|
+
// is keyed on `sub`, which is stable across a rename and is what the pre-token
|
|
46
|
+
// trigger looks the row up by; but Cognito's admin API addresses a user by
|
|
47
|
+
// *username*, and a pool with neither `UsernameAttributes` nor `AliasAttributes`
|
|
48
|
+
// does not accept a `sub` there — it answers `UserNotFoundException`, which is
|
|
49
|
+
// how the membership read used to fail for every caller on such a pool. Both
|
|
50
|
+
// fields come from the authorizer, so forwarding the second grants nothing the
|
|
51
|
+
// first did not.
|
|
43
52
|
let invokeCode: Pulumi.Input.t<string> = `import { util } from '@aws-appsync/utils';
|
|
44
53
|
export function request(ctx) {
|
|
45
54
|
const id = ctx.identity;
|
|
@@ -47,7 +56,7 @@ export function request(ctx) {
|
|
|
47
56
|
operation: 'Invoke',
|
|
48
57
|
payload: {
|
|
49
58
|
arguments: ctx.args,
|
|
50
|
-
identity: id != null && id.sub != null ? { sub: id.sub } : null
|
|
59
|
+
identity: id != null && id.sub != null ? { sub: id.sub, username: id.username ?? null } : null
|
|
51
60
|
}
|
|
52
61
|
};
|
|
53
62
|
}
|
|
@@ -22,7 +22,7 @@ export function request(ctx) {
|
|
|
22
22
|
operation: 'Invoke',
|
|
23
23
|
payload: {
|
|
24
24
|
arguments: ctx.args,
|
|
25
|
-
identity: id != null && id.sub != null ? { sub: id.sub } : null
|
|
25
|
+
identity: id != null && id.sub != null ? { sub: id.sub, username: id.username ?? null } : null
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
}
|
|
@@ -50,16 +50,25 @@ token they hold no longer mentions the role they are asking for. This is the sam
|
|
|
50
50
|
trap the local path documents on `LocalAuth.Login.reissue`, where membership is
|
|
51
51
|
re-read from the user store rather than from the token's own record of it.
|
|
52
52
|
|
|
53
|
+
🚨 **Addressed by username, not by `sub`.** `AdminListGroupsForUser` takes a
|
|
54
|
+
`Username`, and a `sub` is only accepted there when the pool makes it one — a
|
|
55
|
+
pool with `UsernameAttributes` (email or phone sign-in), where the generated
|
|
56
|
+
username *is* the subject. On a plain username pool the same call answers
|
|
57
|
+
`UserNotFoundException: User does not exist.`, which fails the whole mutation
|
|
58
|
+
before it reaches the subset check: not "you may not act as that role" but "you
|
|
59
|
+
do not exist", for a caller who is signed in and holds the role. The row is still
|
|
60
|
+
keyed on `sub` — this parameter names the user to Cognito, nothing else.
|
|
61
|
+
|
|
53
62
|
Paginated deliberately: `AdminListGroupsForUser` caps a page at 60 groups, and a
|
|
54
63
|
truncated read would silently refuse a role the caller genuinely holds.
|
|
55
64
|
*/
|
|
56
|
-
let membershipOf = async (~
|
|
65
|
+
let membershipOf = async (~username: string, ~poolId: string): array<string> => {
|
|
57
66
|
let collected = []
|
|
58
67
|
let nextToken = ref(None)
|
|
59
68
|
let more = ref(true)
|
|
60
69
|
while more.contents {
|
|
61
70
|
let page = await CognitoIdentityServiceProvider.AdminListGroupsForUserCommand.make({
|
|
62
|
-
username
|
|
71
|
+
username,
|
|
63
72
|
userPoolId: poolId,
|
|
64
73
|
nextToken: ?nextToken.contents,
|
|
65
74
|
})->CognitoIdentityServiceProvider.AdminListGroupsForUserCommand.send
|
|
@@ -89,13 +98,33 @@ let mayActAs = (~membership: array<string>, ~requested: string): bool =>
|
|
|
89
98
|
|
|
90
99
|
// ── AppSync resolver event / result shapes ──────────────────────────────────
|
|
91
100
|
|
|
92
|
-
type identity = {sub?: string}
|
|
101
|
+
type identity = {sub?: string, username?: Nullable.t<string>}
|
|
93
102
|
type activeRoleArgs = {activeRole?: Nullable.t<string>}
|
|
94
103
|
type appSyncEvent = {
|
|
95
104
|
arguments?: activeRoleArgs,
|
|
96
105
|
identity?: identity,
|
|
97
106
|
}
|
|
98
107
|
|
|
108
|
+
/**
|
|
109
|
+
The name to address this caller by when asking Cognito what groups they are in.
|
|
110
|
+
|
|
111
|
+
The username when the authorizer supplied one, the subject otherwise. The
|
|
112
|
+
fallback is not a guess at a username: it is the behaviour this handler had
|
|
113
|
+
before the username was forwarded, kept for the pool shapes where it is correct —
|
|
114
|
+
one whose username *is* the subject — rather than turning a working deployment
|
|
115
|
+
into a hard failure on an absent field. Pure so the choice can be tested without
|
|
116
|
+
a pool.
|
|
117
|
+
*/
|
|
118
|
+
let cognitoLookupName = (~identity: identity): option<string> =>
|
|
119
|
+
switch identity.username {
|
|
120
|
+
| Some(Value(name)) if name->String.trim != "" => Some(name)
|
|
121
|
+
| _ =>
|
|
122
|
+
switch identity.sub {
|
|
123
|
+
| Some("") | None => None
|
|
124
|
+
| Some(sub) => Some(sub)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
99
128
|
let result = (~activeRole: option<string>, ~availableRoles: array<string>): JSON.t =>
|
|
100
129
|
Dict.fromArray([
|
|
101
130
|
("activeRole", activeRole->Option.mapOr(JSON.Null, JSON.Encode.string)),
|
|
@@ -111,8 +140,14 @@ let handler = async (event: appSyncEvent): JSON.t => {
|
|
|
111
140
|
// unauthenticated path from ever writing a row keyed on the empty subject.
|
|
112
141
|
JsError.throwWithMessage("unauthenticated")
|
|
113
142
|
}
|
|
143
|
+
// Two names for one caller, and they are not interchangeable: `sub` keys the
|
|
144
|
+
// row, the lookup name addresses Cognito. See `membershipOf`.
|
|
145
|
+
let lookupName = switch event.identity->Option.flatMap(i => cognitoLookupName(~identity=i)) {
|
|
146
|
+
| Some(name) => name
|
|
147
|
+
| None => JsError.throwWithMessage("unauthenticated")
|
|
148
|
+
}
|
|
114
149
|
let table = tableName()
|
|
115
|
-
let membership = await membershipOf(~
|
|
150
|
+
let membership = await membershipOf(~username=lookupName, ~poolId=userPoolId())
|
|
116
151
|
|
|
117
152
|
// An absent argument and an explicit `null` mean the same thing — clear the
|
|
118
153
|
// preference and go back to full membership on the next refresh. That is not an
|
|
@@ -33,13 +33,13 @@ function userPoolId() {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async function membershipOf(
|
|
36
|
+
async function membershipOf(username, poolId) {
|
|
37
37
|
let collected = [];
|
|
38
38
|
let nextToken;
|
|
39
39
|
let more = true;
|
|
40
40
|
while (more) {
|
|
41
41
|
let page = await CognitoIdentityServiceProvider$AwsSdk.AdminListGroupsForUserCommand.send(new ClientCognitoIdentityProvider.AdminListGroupsForUserCommand({
|
|
42
|
-
Username:
|
|
42
|
+
Username: username,
|
|
43
43
|
UserPoolId: poolId,
|
|
44
44
|
NextToken: nextToken
|
|
45
45
|
}));
|
|
@@ -60,6 +60,22 @@ function mayActAs(membership, requested) {
|
|
|
60
60
|
return membership.includes(requested);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
function cognitoLookupName(identity) {
|
|
64
|
+
let match = identity.username;
|
|
65
|
+
if (match !== undefined) {
|
|
66
|
+
let name = Primitive_option.valFromOption(match);
|
|
67
|
+
if (name == null) {
|
|
68
|
+
name === null;
|
|
69
|
+
} else if (name.trim() !== "") {
|
|
70
|
+
return name;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
let sub = identity.sub;
|
|
74
|
+
if (sub !== undefined && sub !== "") {
|
|
75
|
+
return sub;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
63
79
|
function result(activeRole, availableRoles) {
|
|
64
80
|
return Object.fromEntries([
|
|
65
81
|
[
|
|
@@ -78,8 +94,10 @@ async function handler(event) {
|
|
|
78
94
|
if (sub === "") {
|
|
79
95
|
Stdlib_JsError.throwWithMessage("unauthenticated");
|
|
80
96
|
}
|
|
97
|
+
let name = Stdlib_Option.flatMap(event.identity, cognitoLookupName);
|
|
98
|
+
let lookupName = name !== undefined ? name : Stdlib_JsError.throwWithMessage("unauthenticated");
|
|
81
99
|
let table = tableName();
|
|
82
|
-
let membership = await membershipOf(
|
|
100
|
+
let membership = await membershipOf(lookupName, userPoolId());
|
|
83
101
|
let match = Stdlib_Option.flatMap(event.arguments, a => a.activeRole);
|
|
84
102
|
let requested;
|
|
85
103
|
if (match !== undefined) {
|
|
@@ -122,6 +140,7 @@ export {
|
|
|
122
140
|
userPoolId,
|
|
123
141
|
membershipOf,
|
|
124
142
|
mayActAs,
|
|
143
|
+
cognitoLookupName,
|
|
125
144
|
result,
|
|
126
145
|
handler,
|
|
127
146
|
}
|
|
@@ -68,7 +68,7 @@ let make: ReventlessCore.QueryDb_Adapter.resolversMaker<api, role> = (
|
|
|
68
68
|
~subIdField,
|
|
69
69
|
~idResolverConfigs: array<idResolverConfig>,
|
|
70
70
|
~idsResolverConfigs: array<idsResolverConfig>,
|
|
71
|
-
// AWS path enforces authorization via `@
|
|
71
|
+
// AWS path enforces authorization via `@aws_cognito_user_pools(cognito_groups: …)` on the
|
|
72
72
|
// SDL fields (see Stage E in docs/plans/host-ui-login-core.md). Accepted but
|
|
73
73
|
// ignored here so the in-memory and AWS resolver maker signatures stay aligned.
|
|
74
74
|
~authorization as _: Reventless.Authorization.permission,
|
|
@@ -185,10 +185,13 @@ let rec waitForMergeSuccess = async (
|
|
|
185
185
|
// When both are present on the same field, the spec-level permission wins
|
|
186
186
|
// (it is more specific). `AllowGroups([g1, g2, ...])` emits
|
|
187
187
|
// `@aws_cognito_user_pools(cognito_groups: ["g1", "g2", ...])`.
|
|
188
|
-
// `AllowAuthenticated` / `AllowAnonymous` emit
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
//
|
|
188
|
+
// `AllowAuthenticated` / `AllowAnonymous` emit the group-less
|
|
189
|
+
// `@aws_cognito_user_pools` — same reachability (with Cognito as primary auth
|
|
190
|
+
// any reaching request is already authenticated), but stated rather than left
|
|
191
|
+
// implicit, so `assertGateable` can tell "deliberately open" from "nobody
|
|
192
|
+
// stamped this". `AllowGroups([])` and `DenyAll` emit a sentinel `__deny_all__`
|
|
193
|
+
// group that no Cognito user can belong to — effectively blocking the field at
|
|
194
|
+
// the API layer.
|
|
192
195
|
//
|
|
193
196
|
// NOT `@aws_auth(...)`: that is the single-mode form, which AppSync ignores on a
|
|
194
197
|
// multi-auth API — which every API this adapter provisions is. See
|
|
@@ -422,14 +425,14 @@ let injectAwsAuth = (
|
|
|
422
425
|
})
|
|
423
426
|
}
|
|
424
427
|
|
|
425
|
-
// Injects
|
|
428
|
+
// Injects the Cognito group directive on ALL mutation, query, and subscription
|
|
426
429
|
// fields in a fragment. Used for the base fragment where all fields share the
|
|
427
430
|
// same authorization group.
|
|
428
431
|
//
|
|
429
432
|
// `~iamFieldNames` opts the named mutation/query fields into deploy-time IAM
|
|
430
433
|
// (dual-auth): those fields emit `@aws_cognito_user_pools(cognito_groups:
|
|
431
|
-
// ["<group>"]) @aws_iam
|
|
432
|
-
//
|
|
434
|
+
// ["<group>"]) @aws_iam`, keeping the same Cognito group gating while also
|
|
435
|
+
// admitting the SigV4 system caller.
|
|
433
436
|
// Subscriptions are never IAM-marked (the deploy caller does not subscribe).
|
|
434
437
|
// Canonical definition lives in the runtime-pure AppSync_SdlDecorate so the
|
|
435
438
|
// bundled AdminEventCollector Lambda's reactive push decorates the admin base
|
|
@@ -40,3 +40,35 @@ describe("Auth_ActiveRoleStore_Ops.mayActAs — narrowing only", () => {
|
|
|
40
40
|
expect(Ops.mayActAs(~membership=[], ~requested="Shopper"))->toBe(false)
|
|
41
41
|
)
|
|
42
42
|
})
|
|
43
|
+
|
|
44
|
+
// Which name goes to Cognito. `sub` keys the row and `AdminListGroupsForUser`
|
|
45
|
+
// takes a username, and a pool that makes neither an alias of the other answers
|
|
46
|
+
// `UserNotFoundException` when handed the wrong one — a signed-in caller holding
|
|
47
|
+
// the role they asked for, told they do not exist.
|
|
48
|
+
describe("Auth_ActiveRoleStore_Ops.cognitoLookupName", () => {
|
|
49
|
+
testSync("the username is what addresses Cognito when the authorizer sent one", () =>
|
|
50
|
+
expect(
|
|
51
|
+
Ops.cognitoLookupName(~identity={sub: "d265d464-2091-706a-e5f9-3afafe7be29c", username: Value("merch")}),
|
|
52
|
+
)->toEqual(Some("merch"))
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
testSync("an absent username falls back to the subject, as before it was forwarded", () =>
|
|
56
|
+
expect(Ops.cognitoLookupName(~identity={sub: "sub-1"}))->toEqual(Some("sub-1"))
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
// The resolver sends `id.username ?? null`, so null is the shape an authorizer
|
|
60
|
+
// that names no username actually produces — not a missing field.
|
|
61
|
+
testSync("an explicitly null username falls back too", () =>
|
|
62
|
+
expect(Ops.cognitoLookupName(~identity={sub: "sub-1", username: Null}))->toEqual(Some("sub-1"))
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
testSync("a blank username is not a name to look anyone up by", () =>
|
|
66
|
+
expect(Ops.cognitoLookupName(~identity={sub: "sub-1", username: Value(" ")}))->toEqual(
|
|
67
|
+
Some("sub-1"),
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
testSync("neither name means there is nobody to ask about", () =>
|
|
72
|
+
expect(Ops.cognitoLookupName(~identity={}))->toEqual(None)
|
|
73
|
+
)
|
|
74
|
+
})
|
|
@@ -30,6 +30,35 @@ globalThis.describe("Auth_ActiveRoleStore_Ops.mayActAs — narrowing only", () =
|
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
globalThis.describe("Auth_ActiveRoleStore_Ops.cognitoLookupName", () => {
|
|
34
|
+
globalThis.test("the username is what addresses Cognito when the authorizer sent one", () => {
|
|
35
|
+
globalThis.expect(Auth_ActiveRoleStore_Ops$ReventlessAws.cognitoLookupName({
|
|
36
|
+
sub: "d265d464-2091-706a-e5f9-3afafe7be29c",
|
|
37
|
+
username: "merch"
|
|
38
|
+
})).toEqual("merch");
|
|
39
|
+
});
|
|
40
|
+
globalThis.test("an absent username falls back to the subject, as before it was forwarded", () => {
|
|
41
|
+
globalThis.expect(Auth_ActiveRoleStore_Ops$ReventlessAws.cognitoLookupName({
|
|
42
|
+
sub: "sub-1"
|
|
43
|
+
})).toEqual("sub-1");
|
|
44
|
+
});
|
|
45
|
+
globalThis.test("an explicitly null username falls back too", () => {
|
|
46
|
+
globalThis.expect(Auth_ActiveRoleStore_Ops$ReventlessAws.cognitoLookupName({
|
|
47
|
+
sub: "sub-1",
|
|
48
|
+
username: null
|
|
49
|
+
})).toEqual("sub-1");
|
|
50
|
+
});
|
|
51
|
+
globalThis.test("a blank username is not a name to look anyone up by", () => {
|
|
52
|
+
globalThis.expect(Auth_ActiveRoleStore_Ops$ReventlessAws.cognitoLookupName({
|
|
53
|
+
sub: "sub-1",
|
|
54
|
+
username: " "
|
|
55
|
+
})).toEqual("sub-1");
|
|
56
|
+
});
|
|
57
|
+
globalThis.test("neither name means there is nobody to ask about", () => {
|
|
58
|
+
globalThis.expect(Auth_ActiveRoleStore_Ops$ReventlessAws.cognitoLookupName({})).toEqual(undefined);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
33
62
|
let Ops;
|
|
34
63
|
|
|
35
64
|
let Contract;
|