@izara_project/izara-core-generate-service-code 1.0.86 → 1.0.87
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/package.json +1 -1
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +22 -15
- package/src/emit/crud/crudActionPlan.js +1 -1
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +6 -4
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +12 -3
- package/src/emit/crud/templates/CreateLogicalLib.ejs +85 -20
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +12 -3
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +12 -3
- package/src/emit/function/functionYamlArtifact.js +4 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +0 -3
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +1 -116
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +14 -10
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +14 -10
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +22 -12
- package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +14 -10
- package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +76 -34
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -9
- package/src/emit/resource/emitResourceArtifacts.js +32 -6
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +14 -18
- package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +4 -2
- package/test/createTargetRoleHandler.test.js +1 -15
- package/test/crudApplicationArtifacts.test.js +9 -3
- package/test/customFlowApplicationArtifacts.test.js +3 -5
- package/test/dynamicCrudFlowSchemas.test.js +5 -17
- package/test/dynamicRbacFlowSchemas.test.js +0 -3
- package/test/functionYamlArtifact.test.js +4 -2
- package/test/resourceArtifacts.test.js +4 -3
|
@@ -28,21 +28,25 @@ export default async function CreateTargetRole(_izContext, requestParams) {
|
|
|
28
28
|
_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
|
|
29
29
|
|
|
30
30
|
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
31
|
-
let identifiersConcat =
|
|
31
|
+
let identifiersConcat =
|
|
32
|
+
requestParams.identifiersConcat || requestParams.identifierConcat;
|
|
32
33
|
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
33
|
-
if (targetIdentifiers.identifierConcat) {
|
|
34
|
-
identifiersConcat =
|
|
34
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
35
|
+
identifiersConcat =
|
|
36
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
35
37
|
} else {
|
|
36
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
38
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
39
|
+
.filter(
|
|
40
|
+
(k) =>
|
|
41
|
+
k !== 'submittedByUserId' &&
|
|
42
|
+
k !== 'identifierConcat' &&
|
|
43
|
+
k !== 'identifiersConcat'
|
|
44
|
+
)
|
|
45
|
+
.sort();
|
|
37
46
|
const parts = [];
|
|
38
47
|
for (const key of sortedKeys) {
|
|
39
48
|
const value = targetIdentifiers[key];
|
|
40
|
-
if (
|
|
41
|
-
key !== 'submittedByUserId' &&
|
|
42
|
-
key !== 'identifierConcat' &&
|
|
43
|
-
value !== undefined &&
|
|
44
|
-
value !== null
|
|
45
|
-
) {
|
|
49
|
+
if (value !== undefined && value !== null) {
|
|
46
50
|
parts.push(`${key}#${value}`);
|
|
47
51
|
}
|
|
48
52
|
}
|
|
@@ -61,7 +65,11 @@ export default async function CreateTargetRole(_izContext, requestParams) {
|
|
|
61
65
|
permissions = [],
|
|
62
66
|
assignUserIds = []
|
|
63
67
|
} = requestParams;
|
|
64
|
-
|
|
68
|
+
let defaultRoleId = identifierUuid();
|
|
69
|
+
if (roleName === 'owner') {
|
|
70
|
+
defaultRoleId = 'owner';
|
|
71
|
+
}
|
|
72
|
+
const roleId = inputRoleId || defaultRoleId;
|
|
65
73
|
const roleIdKey = `${identifiersConcat}_${roleId}`;
|
|
66
74
|
|
|
67
75
|
await dynamodbSharedLib.putItem(
|
|
@@ -70,8 +78,10 @@ export default async function CreateTargetRole(_izContext, requestParams) {
|
|
|
70
78
|
{
|
|
71
79
|
identifiersConcat,
|
|
72
80
|
roleIdKey,
|
|
81
|
+
roleType: 'tenant_role',
|
|
73
82
|
roleName,
|
|
74
|
-
submittedByUserId
|
|
83
|
+
submittedByUserId,
|
|
84
|
+
createdAt: new Date().toISOString()
|
|
75
85
|
}
|
|
76
86
|
);
|
|
77
87
|
|
|
@@ -31,21 +31,25 @@ export default async function GetMyPermissions(_izContext, requestParams) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
34
|
-
let identifiersConcat =
|
|
34
|
+
let identifiersConcat =
|
|
35
|
+
requestParams.identifiersConcat || requestParams.identifierConcat;
|
|
35
36
|
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
36
|
-
if (targetIdentifiers.identifierConcat) {
|
|
37
|
-
identifiersConcat =
|
|
37
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
38
|
+
identifiersConcat =
|
|
39
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
38
40
|
} else {
|
|
39
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
41
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
42
|
+
.filter(
|
|
43
|
+
(k) =>
|
|
44
|
+
k !== 'submittedByUserId' &&
|
|
45
|
+
k !== 'identifierConcat' &&
|
|
46
|
+
k !== 'identifiersConcat'
|
|
47
|
+
)
|
|
48
|
+
.sort();
|
|
40
49
|
const parts = [];
|
|
41
50
|
for (const key of sortedKeys) {
|
|
42
51
|
const value = targetIdentifiers[key];
|
|
43
|
-
if (
|
|
44
|
-
key !== 'submittedByUserId' &&
|
|
45
|
-
key !== 'identifierConcat' &&
|
|
46
|
-
value !== undefined &&
|
|
47
|
-
value !== null
|
|
48
|
-
) {
|
|
52
|
+
if (value !== undefined && value !== null) {
|
|
49
53
|
parts.push(`${key}#${value}`);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
@@ -35,21 +35,25 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
|
|
|
35
35
|
} = requestParams;
|
|
36
36
|
|
|
37
37
|
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
38
|
-
let identifiersConcat =
|
|
38
|
+
let identifiersConcat =
|
|
39
|
+
requestParams.identifiersConcat || requestParams.identifierConcat;
|
|
39
40
|
if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
|
|
40
|
-
if (targetIdentifiers.identifierConcat) {
|
|
41
|
-
identifiersConcat =
|
|
41
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
42
|
+
identifiersConcat =
|
|
43
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
42
44
|
} else {
|
|
43
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
45
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
46
|
+
.filter(
|
|
47
|
+
(k) =>
|
|
48
|
+
k !== 'submittedByUserId' &&
|
|
49
|
+
k !== 'identifierConcat' &&
|
|
50
|
+
k !== 'identifiersConcat'
|
|
51
|
+
)
|
|
52
|
+
.sort();
|
|
44
53
|
const parts = [];
|
|
45
54
|
for (const key of sortedKeys) {
|
|
46
55
|
const value = targetIdentifiers[key];
|
|
47
|
-
if (
|
|
48
|
-
key !== 'submittedByUserId' &&
|
|
49
|
-
key !== 'identifierConcat' &&
|
|
50
|
-
value !== undefined &&
|
|
51
|
-
value !== null
|
|
52
|
-
) {
|
|
56
|
+
if (value !== undefined && value !== null) {
|
|
53
57
|
parts.push(`${key}#${value}`);
|
|
54
58
|
}
|
|
55
59
|
}
|
|
@@ -70,41 +74,79 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
const uniqueIdentify = `${usedTimestamp}_${_izContext.uniqueRequestId || Date.now()}`;
|
|
73
|
-
const roleLimitKeys = Array.isArray(requestParams.roleLimitIds)
|
|
74
|
-
? requestParams.roleLimitIds
|
|
75
|
-
: [roleLimitId || `${identifiersConcat}_${flowTypeConcat}`];
|
|
76
77
|
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for (const key of roleLimitKeys) {
|
|
81
|
-
const record = await dynamodbSharedLib.getItem(
|
|
78
|
+
let targetPlanTier = requestParams.planTier || null;
|
|
79
|
+
if (!targetPlanTier && identifiersConcat) {
|
|
80
|
+
const targetRolesResult = await dynamodbSharedLib.query(
|
|
82
81
|
_izContext,
|
|
83
|
-
dynamodbSharedLib.tableName(_izContext, '
|
|
84
|
-
{
|
|
82
|
+
dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
|
|
83
|
+
{ identifiersConcat }
|
|
85
84
|
);
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
let targetRoleItems = [];
|
|
86
|
+
if (Array.isArray(targetRolesResult)) {
|
|
87
|
+
targetRoleItems = targetRolesResult;
|
|
88
|
+
} else if (targetRolesResult && targetRolesResult.Items) {
|
|
89
|
+
targetRoleItems = targetRolesResult.Items;
|
|
90
|
+
}
|
|
91
|
+
for (const roleItem of targetRoleItems) {
|
|
92
|
+
if (roleItem.roleType === 'plan_tier') {
|
|
93
|
+
targetPlanTier = roleItem.roleIdKey;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!targetPlanTier) {
|
|
99
|
+
targetPlanTier = 'tier-free';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const limitRecords = [];
|
|
103
|
+
const tierPermission = await dynamodbSharedLib.getItem(
|
|
104
|
+
_izContext,
|
|
105
|
+
dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
|
|
106
|
+
{ roleIdKey: targetPlanTier, flowTypeConcat }
|
|
107
|
+
);
|
|
108
|
+
if (tierPermission && typeof tierPermission.limitValue === 'number') {
|
|
109
|
+
limitRecords.push(tierPermission);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (Array.isArray(requestParams.roleIdKeys)) {
|
|
113
|
+
for (const rKey of requestParams.roleIdKeys) {
|
|
114
|
+
const perm = await dynamodbSharedLib.getItem(
|
|
115
|
+
_izContext,
|
|
116
|
+
dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
|
|
117
|
+
{ roleIdKey: rKey, flowTypeConcat }
|
|
118
|
+
);
|
|
119
|
+
if (perm && typeof perm.limitValue === 'number') {
|
|
120
|
+
limitRecords.push(perm);
|
|
121
|
+
}
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
|
|
125
|
+
let maxLimit = Infinity;
|
|
91
126
|
if (limitRecords.length > 0) {
|
|
92
|
-
const isDecrease = (rec)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
const isDecrease = function (rec) {
|
|
128
|
+
if (
|
|
129
|
+
rec.effect === 'decrease' ||
|
|
130
|
+
rec.actionType === 'decrease' ||
|
|
131
|
+
rec.action === 'decrease'
|
|
132
|
+
) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
};
|
|
96
137
|
|
|
97
138
|
const increaseLimits = limitRecords.filter((rec) => !isDecrease(rec));
|
|
98
139
|
const decreaseLimits = limitRecords.filter((rec) => isDecrease(rec));
|
|
99
140
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
let maxIncrease = Infinity;
|
|
142
|
+
if (increaseLimits.length > 0) {
|
|
143
|
+
maxIncrease = Math.max(...increaseLimits.map((r) => r.limitValue));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let minDecrease = Infinity;
|
|
147
|
+
if (decreaseLimits.length > 0) {
|
|
148
|
+
minDecrease = Math.min(...decreaseLimits.map((r) => r.limitValue));
|
|
149
|
+
}
|
|
108
150
|
|
|
109
151
|
maxLimit = Math.min(maxIncrease, minDecrease);
|
|
110
152
|
}
|
|
@@ -101,19 +101,22 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
101
101
|
if (typeof targetIdentifiers === 'string') {
|
|
102
102
|
targetId = targetIdentifiers;
|
|
103
103
|
} else if (typeof targetIdentifiers === 'object') {
|
|
104
|
-
if (targetIdentifiers.identifierConcat) {
|
|
105
|
-
targetId =
|
|
104
|
+
if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
|
|
105
|
+
targetId =
|
|
106
|
+
targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
|
|
106
107
|
} else {
|
|
107
|
-
const sortedKeys = Object.keys(targetIdentifiers)
|
|
108
|
+
const sortedKeys = Object.keys(targetIdentifiers)
|
|
109
|
+
.filter(
|
|
110
|
+
(k) =>
|
|
111
|
+
k !== 'submittedByUserId' &&
|
|
112
|
+
k !== 'identifierConcat' &&
|
|
113
|
+
k !== 'identifiersConcat'
|
|
114
|
+
)
|
|
115
|
+
.sort();
|
|
108
116
|
const parts = [];
|
|
109
117
|
for (const key of sortedKeys) {
|
|
110
118
|
const value = targetIdentifiers[key];
|
|
111
|
-
if (
|
|
112
|
-
key !== 'submittedByUserId' &&
|
|
113
|
-
key !== 'identifierConcat' &&
|
|
114
|
-
value !== undefined &&
|
|
115
|
-
value !== null
|
|
116
|
-
) {
|
|
119
|
+
if (value !== undefined && value !== null) {
|
|
117
120
|
parts.push(`${key}#${value}`);
|
|
118
121
|
}
|
|
119
122
|
}
|
|
@@ -43,9 +43,6 @@ const RBAC_ACTIONS = [
|
|
|
43
43
|
'DeleteUserFromRole',
|
|
44
44
|
'GetMyPermissions',
|
|
45
45
|
'ValidatorRbac',
|
|
46
|
-
'CreateRoleLimit',
|
|
47
|
-
'ListRoleLimits',
|
|
48
|
-
'DeleteRoleLimit',
|
|
49
46
|
'ReservedDynamicUsage',
|
|
50
47
|
'ConfirmUsage',
|
|
51
48
|
'CancelUsage'
|
|
@@ -62,12 +59,12 @@ const SYSTEM_TABLES = [
|
|
|
62
59
|
'AwaitingStep'
|
|
63
60
|
];
|
|
64
61
|
const RBAC_TABLES = [
|
|
62
|
+
'Roles',
|
|
65
63
|
'TargetRoles',
|
|
66
64
|
'RolePermissions',
|
|
67
65
|
'RoleUsers',
|
|
68
66
|
'UserRoles',
|
|
69
67
|
'RbacPermissionCaches',
|
|
70
|
-
'RoleLimit',
|
|
71
68
|
'RunningTotalUsage',
|
|
72
69
|
'RunningTotalReservedUsage',
|
|
73
70
|
'WebSocketTask'
|
|
@@ -417,12 +414,12 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
417
414
|
const systemTables = [...SYSTEM_TABLES];
|
|
418
415
|
if (rbac) {
|
|
419
416
|
systemTables.push(
|
|
417
|
+
'Roles',
|
|
420
418
|
'TargetRoles',
|
|
421
419
|
'RolePermissions',
|
|
422
420
|
'RoleUsers',
|
|
423
421
|
'UserRoles',
|
|
424
422
|
'RbacPermissionCaches',
|
|
425
|
-
'RoleLimit',
|
|
426
423
|
'RunningTotalUsage',
|
|
427
424
|
'RunningTotalReservedUsage'
|
|
428
425
|
);
|
|
@@ -736,6 +733,11 @@ function roleStatements(state, roleName) {
|
|
|
736
733
|
...roleExternalTopicArns(state, roleName)
|
|
737
734
|
]
|
|
738
735
|
);
|
|
736
|
+
addStatement(
|
|
737
|
+
statements,
|
|
738
|
+
['lambda:InvokeFunction'],
|
|
739
|
+
roleExternalLambdaArns(state, roleName)
|
|
740
|
+
);
|
|
739
741
|
if (state.webSocketRoles.has(roleName)) {
|
|
740
742
|
statements.push({
|
|
741
743
|
action: ['execute-api:ManageConnections'],
|
|
@@ -771,11 +773,11 @@ function roleTableNames(state, roleName) {
|
|
|
771
773
|
'WebSocketTask',
|
|
772
774
|
...(state.rbac
|
|
773
775
|
? [
|
|
776
|
+
'Roles',
|
|
774
777
|
'TargetRoles',
|
|
775
778
|
'RolePermissions',
|
|
776
779
|
'RoleUsers',
|
|
777
780
|
'UserRoles',
|
|
778
|
-
'RoleLimit',
|
|
779
781
|
'RunningTotalUsage',
|
|
780
782
|
'RunningTotalReservedUsage'
|
|
781
783
|
]
|
|
@@ -1064,6 +1066,30 @@ function roleExternalTopicArns(state, roleName) {
|
|
|
1064
1066
|
return [];
|
|
1065
1067
|
}
|
|
1066
1068
|
|
|
1069
|
+
function roleExternalLambdaArns(state, roleName) {
|
|
1070
|
+
if (!state.rbac) {
|
|
1071
|
+
return [];
|
|
1072
|
+
}
|
|
1073
|
+
const extraTags = getRbacValidatorServiceTags(state).filter(
|
|
1074
|
+
(tag) => tag && tag !== 'Rbac'
|
|
1075
|
+
);
|
|
1076
|
+
const extraLambdas = extraTags.map(
|
|
1077
|
+
(tag) =>
|
|
1078
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`
|
|
1079
|
+
);
|
|
1080
|
+
if (
|
|
1081
|
+
roleName === 'FlowObjectsRole' ||
|
|
1082
|
+
roleName === 'FlowRbacRole' ||
|
|
1083
|
+
roleName === 'FlowRelationshipRole'
|
|
1084
|
+
) {
|
|
1085
|
+
return [
|
|
1086
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
|
|
1087
|
+
...extraLambdas
|
|
1088
|
+
];
|
|
1089
|
+
}
|
|
1090
|
+
return [];
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1067
1093
|
function queueArns(queueNames) {
|
|
1068
1094
|
return [...new Set(queueNames)]
|
|
1069
1095
|
.sort()
|
|
@@ -138,6 +138,18 @@ Resources:
|
|
|
138
138
|
KeyType: RANGE
|
|
139
139
|
|
|
140
140
|
<% if (hasRbac) { %>
|
|
141
|
+
RolesTable:
|
|
142
|
+
Type: 'AWS::DynamoDB::Table'
|
|
143
|
+
Properties:
|
|
144
|
+
TableName: ${self:custom.iz_resourcePrefix}Roles
|
|
145
|
+
BillingMode: PAY_PER_REQUEST
|
|
146
|
+
AttributeDefinitions:
|
|
147
|
+
- AttributeName: roleIdKey
|
|
148
|
+
AttributeType: S
|
|
149
|
+
KeySchema:
|
|
150
|
+
- AttributeName: roleIdKey
|
|
151
|
+
KeyType: HASH
|
|
152
|
+
|
|
141
153
|
TargetRolesTable:
|
|
142
154
|
Type: 'AWS::DynamoDB::Table'
|
|
143
155
|
Properties:
|
|
@@ -221,22 +233,6 @@ Resources:
|
|
|
221
233
|
AttributeName: ttlTimestamp
|
|
222
234
|
Enabled: true
|
|
223
235
|
|
|
224
|
-
RoleLimitTable:
|
|
225
|
-
Type: 'AWS::DynamoDB::Table'
|
|
226
|
-
Properties:
|
|
227
|
-
TableName: ${self:custom.iz_resourcePrefix}RoleLimit
|
|
228
|
-
BillingMode: PAY_PER_REQUEST
|
|
229
|
-
AttributeDefinitions:
|
|
230
|
-
- AttributeName: roleLimitId
|
|
231
|
-
AttributeType: S
|
|
232
|
-
- AttributeName: limitType
|
|
233
|
-
AttributeType: S
|
|
234
|
-
KeySchema:
|
|
235
|
-
- AttributeName: roleLimitId
|
|
236
|
-
KeyType: HASH
|
|
237
|
-
- AttributeName: limitType
|
|
238
|
-
KeyType: RANGE
|
|
239
|
-
|
|
240
236
|
RunningTotalUsageTable:
|
|
241
237
|
Type: 'AWS::DynamoDB::Table'
|
|
242
238
|
Properties:
|
|
@@ -245,12 +241,12 @@ Resources:
|
|
|
245
241
|
AttributeDefinitions:
|
|
246
242
|
- AttributeName: identifiersConcat
|
|
247
243
|
AttributeType: S
|
|
248
|
-
- AttributeName:
|
|
244
|
+
- AttributeName: flowTypeConcat
|
|
249
245
|
AttributeType: S
|
|
250
246
|
KeySchema:
|
|
251
247
|
- AttributeName: identifiersConcat
|
|
252
248
|
KeyType: HASH
|
|
253
|
-
- AttributeName:
|
|
249
|
+
- AttributeName: flowTypeConcat
|
|
254
250
|
KeyType: RANGE
|
|
255
251
|
|
|
256
252
|
RunningTotalReservedUsageTable:
|
|
@@ -15,16 +15,12 @@ const OWN_TOPIC_FLOWS = [
|
|
|
15
15
|
'DeleteTargetRole',
|
|
16
16
|
'CreateUserRole',
|
|
17
17
|
'DeleteUserFromRole',
|
|
18
|
-
'CreateRoleLimit',
|
|
19
|
-
'DeleteRoleLimit',
|
|
20
18
|
'ReservedDynamicUsage',
|
|
21
19
|
'ConfirmUsage',
|
|
22
20
|
'CancelUsage'
|
|
23
21
|
];
|
|
24
22
|
|
|
25
23
|
const LIMIT_FLOWS = [
|
|
26
|
-
'CreateRoleLimit',
|
|
27
|
-
'DeleteRoleLimit',
|
|
28
24
|
'ReservedDynamicUsage',
|
|
29
25
|
'ConfirmUsage',
|
|
30
26
|
'CancelUsage'
|
|
@@ -40,7 +36,7 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
40
36
|
const rootPath = await createProject(true);
|
|
41
37
|
const result = await generateCreateTargetRoleHandler(rootPath);
|
|
42
38
|
|
|
43
|
-
assert.equal(result.files.length,
|
|
39
|
+
assert.equal(result.files.length, 59);
|
|
44
40
|
assert.match(
|
|
45
41
|
await readFile(join(rootPath, result.files[0].path), 'utf8'),
|
|
46
42
|
/CreateTargetRole/
|
|
@@ -130,16 +126,6 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
130
126
|
),
|
|
131
127
|
/Math\.min\(maxIncrease, minDecrease\)/
|
|
132
128
|
);
|
|
133
|
-
assert.match(
|
|
134
|
-
await readFile(
|
|
135
|
-
join(
|
|
136
|
-
rootPath,
|
|
137
|
-
'app/src/generatedCode/FlowLimit/CreateRoleLimit/source/CreateRoleLimit_Main.js'
|
|
138
|
-
),
|
|
139
|
-
'utf8'
|
|
140
|
-
),
|
|
141
|
-
/actionType/
|
|
142
|
-
);
|
|
143
129
|
const rbacYaml = await readFile(
|
|
144
130
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-rbac.yml'),
|
|
145
131
|
'utf8'
|
|
@@ -239,7 +239,7 @@ test('emits a single Complete RBAC handler for Update without Graph', async () =
|
|
|
239
239
|
);
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
-
test('emits
|
|
242
|
+
test('emits Complete handlers and inlines sync RBAC for Update with Graph', async () => {
|
|
243
243
|
const rootPath = await createRbacProject(false, true);
|
|
244
244
|
const result = await generateCrudApplicationArtifacts(rootPath, {
|
|
245
245
|
serviceTag: 'orders'
|
|
@@ -248,19 +248,25 @@ test('emits RbacCallback and Complete handlers for Update with Graph', async ()
|
|
|
248
248
|
.map((file) => file.path)
|
|
249
249
|
.filter((path) => path.includes('/FlowObjects/Update/source/'));
|
|
250
250
|
|
|
251
|
-
assert.ok(updatePaths.includes(
|
|
251
|
+
assert.ok(!updatePaths.includes(
|
|
252
252
|
'app/src/generatedCode/FlowObjects/Update/source/UpdateRbacCallback_Main.js'
|
|
253
253
|
));
|
|
254
254
|
assert.ok(updatePaths.includes(
|
|
255
255
|
'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
|
|
256
256
|
));
|
|
257
|
+
const updateMainContent = await readFile(
|
|
258
|
+
join(rootPath, 'app/src/generatedCode/FlowObjects/Update/source/Update_Main.js'),
|
|
259
|
+
'utf8'
|
|
260
|
+
);
|
|
261
|
+
assert.match(updateMainContent, /checkRbacPermission/);
|
|
262
|
+
assert.match(updateMainContent, /sync: true/);
|
|
257
263
|
execFileSync(
|
|
258
264
|
process.execPath,
|
|
259
265
|
[
|
|
260
266
|
'--check',
|
|
261
267
|
join(
|
|
262
268
|
rootPath,
|
|
263
|
-
'app/src/generatedCode/FlowObjects/Update/source/
|
|
269
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
|
|
264
270
|
)
|
|
265
271
|
],
|
|
266
272
|
{ stdio: 'inherit' }
|
|
@@ -895,7 +895,7 @@ test('registers SQS queue, SNS subscription, and SNS out topic for custom flowSc
|
|
|
895
895
|
);
|
|
896
896
|
});
|
|
897
897
|
|
|
898
|
-
test('
|
|
898
|
+
test('uses synchronous RBAC without obsolete callback SQS subscriptions in InitialSetupConfig', async () => {
|
|
899
899
|
const rootPath = await createProject();
|
|
900
900
|
await writeFile(
|
|
901
901
|
join(rootPath, 'app/src/schemas/ObjectSchemas/Member.js'),
|
|
@@ -920,10 +920,8 @@ test('renders RBAC Validator subscriptions in InitialSetupConfig when object has
|
|
|
920
920
|
),
|
|
921
921
|
'utf8'
|
|
922
922
|
);
|
|
923
|
-
assert.
|
|
924
|
-
assert.
|
|
925
|
-
assert.match(initialSetupConfigContent, /sqsEndpoint: 'UpdateRbacCallbackHdrSqs'/);
|
|
926
|
-
assert.match(initialSetupConfigContent, /sqsEndpoint: 'DeleteRbacCallbackHdrSqs'/);
|
|
923
|
+
assert.doesNotMatch(initialSetupConfigContent, /sqsEndpoint: 'UpdateRbacCallbackHdrSqs'/);
|
|
924
|
+
assert.doesNotMatch(initialSetupConfigContent, /sqsEndpoint: 'DeleteRbacCallbackHdrSqs'/);
|
|
927
925
|
});
|
|
928
926
|
|
|
929
927
|
test('deduplicates duplicate nextSteps topics across flowSteps in InitialSetupConfig', async () => {
|
|
@@ -142,7 +142,7 @@ test('generates a direct Complete step for RBAC-only Update flows', async () =>
|
|
|
142
142
|
assert.equal(update.flowSteps[1].properties.length, 0);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
test('generates
|
|
145
|
+
test('generates CreateNodeCallback and Complete for Create when RBAC and Graph are present', async () => {
|
|
146
146
|
const rootPath = await createProject({
|
|
147
147
|
generatedBy: 'user',
|
|
148
148
|
});
|
|
@@ -160,13 +160,12 @@ test('generates RbacCallback and Complete for Create when RBAC and Graph are pre
|
|
|
160
160
|
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
161
161
|
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
162
162
|
'Start',
|
|
163
|
-
'RbacCallback',
|
|
164
163
|
'CreateNodeCallback',
|
|
165
164
|
'Complete'
|
|
166
165
|
]);
|
|
167
166
|
});
|
|
168
167
|
|
|
169
|
-
test('uses
|
|
168
|
+
test('uses CreateNodeCallback step when Graph storage is present with sync RBAC', async () => {
|
|
170
169
|
const rootPath = await mkdtemp(
|
|
171
170
|
join(tmpdir(), 'generate-service-code-v2-crud-rbac-graph-')
|
|
172
171
|
);
|
|
@@ -186,11 +185,10 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
|
|
|
186
185
|
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
187
186
|
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
188
187
|
'Start',
|
|
189
|
-
'RbacCallback',
|
|
190
188
|
'CreateNodeCallback',
|
|
191
189
|
'Complete'
|
|
192
190
|
]);
|
|
193
|
-
assert.deepEqual(create.flowSteps[
|
|
191
|
+
assert.deepEqual(create.flowSteps[1].properties, [
|
|
194
192
|
'returnValue',
|
|
195
193
|
'parentFlowId',
|
|
196
194
|
'status',
|
|
@@ -199,7 +197,7 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
|
|
|
199
197
|
]);
|
|
200
198
|
});
|
|
201
199
|
|
|
202
|
-
test('chains
|
|
200
|
+
test('chains Start and Complete for Update with RBAC and Graph', async () => {
|
|
203
201
|
const rootPath = await mkdtemp(
|
|
204
202
|
join(tmpdir(), 'generate-service-code-v2-crud-update-rbac-graph-')
|
|
205
203
|
);
|
|
@@ -219,19 +217,9 @@ test('chains RbacCallback and Complete for Update with RBAC and Graph', async ()
|
|
|
219
217
|
const update = await readGeneratedFlow(rootPath, 'Update');
|
|
220
218
|
assert.deepEqual(update.flowSteps.map((step) => step.stepName), [
|
|
221
219
|
'Start',
|
|
222
|
-
'RbacCallback',
|
|
223
220
|
'Complete'
|
|
224
221
|
]);
|
|
225
222
|
assert.deepEqual(update.flowSteps[0].nextSteps, [
|
|
226
|
-
{ targetType: 'ownTopic', stepName: 'RbacCallback' },
|
|
227
|
-
{
|
|
228
|
-
targetType: 'extTopic',
|
|
229
|
-
serviceTag: 'Rbac',
|
|
230
|
-
topicName: 'ValidatorRbac_In',
|
|
231
|
-
toStepNames: ['RbacCallback']
|
|
232
|
-
}
|
|
233
|
-
]);
|
|
234
|
-
assert.deepEqual(update.flowSteps[1].nextSteps, [
|
|
235
223
|
{ targetType: 'ownTopic', stepName: 'Complete' },
|
|
236
224
|
{
|
|
237
225
|
targetType: 'extTopic',
|
|
@@ -240,7 +228,7 @@ test('chains RbacCallback and Complete for Update with RBAC and Graph', async ()
|
|
|
240
228
|
toStepNames: ['Complete']
|
|
241
229
|
}
|
|
242
230
|
]);
|
|
243
|
-
assert.deepEqual(update.flowSteps[
|
|
231
|
+
assert.deepEqual(update.flowSteps[1].properties, [
|
|
244
232
|
'returnValue',
|
|
245
233
|
'parentFlowId',
|
|
246
234
|
'status',
|
|
@@ -83,12 +83,14 @@ test('filters all SQS functions by their calling flow', () => {
|
|
|
83
83
|
/#<#CreateCompleteHdrSqsFilterPatterns#>[\s\S]*filterPatterns:[\s\S]*\$\{self:custom\.iz_resourcePrefix\}CreateCompleteHdrSqs/
|
|
84
84
|
);
|
|
85
85
|
assert.match(completion, /#<#\/CreateCompleteHdrSqsFilterPatterns#>/);
|
|
86
|
-
assert.match(completion, /exists: false/);
|
|
86
|
+
assert.match(completion, /callingFlow:\s*\n\s*- exists: false/);
|
|
87
|
+
assert.match(completion, /MessageAttributes:\s*\n\s*- exists: false/);
|
|
87
88
|
assert.match(
|
|
88
89
|
ordinary,
|
|
89
90
|
/#<#CreateHdrSqsFilterPatterns#>[\s\S]*filterPatterns:[\s\S]*\$\{self:custom\.iz_resourcePrefix\}CreateHdrSqs/
|
|
90
91
|
);
|
|
91
92
|
assert.match(ordinary, /#<#\/CreateHdrSqsFilterPatterns#>/);
|
|
92
|
-
assert.match(ordinary, /exists: false/);
|
|
93
|
+
assert.match(ordinary, /callingFlow:\s*\n\s*- exists: false/);
|
|
94
|
+
assert.match(ordinary, /MessageAttributes:\s*\n\s*- exists: false/);
|
|
93
95
|
});
|
|
94
96
|
|
|
@@ -76,8 +76,9 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
|
|
|
76
76
|
assert.match(dynamoYaml, /OrdersTable:/);
|
|
77
77
|
assert.match(dynamoYaml, /#<#OrdersTableSetting#>/);
|
|
78
78
|
assert.match(dynamoYaml, /#<#\/OrdersTableSetting#>/);
|
|
79
|
+
assert.match(dynamoYaml, /RolesTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}Roles/);
|
|
79
80
|
assert.match(dynamoYaml, /TargetRolesTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+AttributeName: identifiersConcat/);
|
|
80
|
-
assert.
|
|
81
|
+
assert.doesNotMatch(dynamoYaml, /RoleLimitTable:/);
|
|
81
82
|
assert.match(dynamoYaml, /RunningTotalUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalUsage/);
|
|
82
83
|
assert.match(dynamoYaml, /RunningTotalReservedUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalReservedUsage/);
|
|
83
84
|
const iam = await readFile(
|
|
@@ -108,9 +109,9 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
|
|
|
108
109
|
roleBlock(iam, 'FlowRbacRole'),
|
|
109
110
|
/RolePermissions|ProcessCreateTargetRoleHdrSqs/
|
|
110
111
|
);
|
|
111
|
-
assert.
|
|
112
|
+
assert.doesNotMatch(roleBlock(iam, 'FlowRbacRole'), /RoleLimit/);
|
|
112
113
|
assert.match(roleBlock(iam, 'FlowRbacRole'), /RunningTotalUsage/);
|
|
113
|
-
assert.
|
|
114
|
+
assert.doesNotMatch(roleBlock(iam, 'FlowObjectsRole'), /RoleLimit/);
|
|
114
115
|
// Per-object RBAC flow queue (e.g. ValidatorRbacHdrSqs from Order with rbac add-on)
|
|
115
116
|
assert.match(roleBlock(iam, 'FlowRbacRole'), /ValidatorRbacHdrSqs/);
|
|
116
117
|
|