@izara_project/izara-core-generate-service-code 1.0.78 → 1.0.80
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 +2 -2
- package/src/compile/flowValidator.js +163 -0
- package/src/compile/loadSchemas.js +15 -5
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +137 -7
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +137 -17
- package/src/emit/crud/crudActionPlan.js +82 -0
- package/src/emit/crud/emitCrudApplicationArtifacts.js +169 -112
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
- package/src/emit/crud/templates/CreateComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +90 -513
- package/src/emit/crud/templates/CreateLogicalLib.ejs +541 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +93 -203
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +213 -0
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +217 -0
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
- package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +118 -37
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +92 -444
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +477 -0
- package/src/emit/custom/customFlows.js +27 -2
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -2
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +10 -3
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
- package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +2 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +3 -9
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -16
- package/src/emit/rbac/rbacFlowTag.js +2 -7
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +148 -21
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +4 -2
- package/src/emit/relationship/templates/ChangeRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +6 -2
- package/src/emit/resource/emitResourceArtifacts.js +149 -79
- package/src/emit/resource/templates/DynamoDBTable_Yaml.ejs +4 -4
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +31 -5
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +21 -0
- package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
- package/src/emit/shared/templates/FlowHandler_HdrApi.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrDsq.ejs +2 -2
- package/src/emit/shared/templates/FlowHandler_HdrInv.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +2 -2
- package/src/emit/systemText/emitSystemTextSchemas.js +246 -0
- package/src/emit/systemText/templates/SystemTextSchemas.ejs +10 -0
- package/src/generate.js +55 -8
- package/test/crudApplicationArtifacts.test.js +158 -19
- package/test/customFlowApplicationArtifacts.test.js +307 -16
- package/test/dynamicCrudFlowSchemas.test.js +150 -14
- package/test/dynamicRbacFlowSchemas.test.js +2 -2
- package/test/dynamicRelationshipFlowSchemas.test.js +1 -1
- package/test/graphDrivenFlowSchema.test.js +257 -0
- package/test/publicApi.test.js +14 -5
- package/test/resourceArtifacts.test.js +66 -19
- package/test/systemTextSchemas.test.js +154 -0
- package/src/emit/crud/templates/CreateComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/DeleteComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +0 -174
- package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +0 -187
- package/src/emit/crud/templates/UpdateComplete_HdrSqs.ejs +0 -99
- package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +0 -47
|
@@ -10,12 +10,16 @@ import {
|
|
|
10
10
|
supportedCustomFlows
|
|
11
11
|
} from '../custom/customFlows.js';
|
|
12
12
|
import { hasSystemWebSocket } from '../system/emitSystemWebSocketArtifacts.js';
|
|
13
|
+
import { rbacFlowTag } from '../rbac/rbacFlowTag.js';
|
|
14
|
+
import {
|
|
15
|
+
CRUD_ACTIONS,
|
|
16
|
+
createCrudActionPlans
|
|
17
|
+
} from '../crud/crudActionPlan.js';
|
|
13
18
|
|
|
14
19
|
const TEMPLATE_URL = new URL('./templates/', import.meta.url);
|
|
15
20
|
const RESOURCE_ROOT = 'resource/sls_yaml/generatedCode/source';
|
|
16
21
|
const APP_ROOT = 'app/sls_yaml/generatedCode/source';
|
|
17
22
|
const INITIAL_SETUP_ROOT = 'app/initial_setup/generatedCode/source';
|
|
18
|
-
const CRUD_ACTIONS = ['Create', 'Update', 'Delete', 'Get'];
|
|
19
23
|
const RELATIONSHIP_ACTIONS = [
|
|
20
24
|
'CreateRelationship',
|
|
21
25
|
'UpdateRelationship',
|
|
@@ -33,7 +37,8 @@ const RBAC_ACTIONS = [
|
|
|
33
37
|
'DeleteRolePermissions',
|
|
34
38
|
'CreateUserRole',
|
|
35
39
|
'ListUserInRoles',
|
|
36
|
-
'DeleteUserFromRole'
|
|
40
|
+
'DeleteUserFromRole',
|
|
41
|
+
'ValidatorRbac'
|
|
37
42
|
];
|
|
38
43
|
const SYSTEM_TABLES = [
|
|
39
44
|
'WebSocketTask',
|
|
@@ -44,17 +49,14 @@ const SYSTEM_TABLES = [
|
|
|
44
49
|
'FindDataMain',
|
|
45
50
|
'LogicalResultsMain',
|
|
46
51
|
'LogicalResultsData',
|
|
47
|
-
'AwaitingStep'
|
|
48
|
-
'TargetRoles',
|
|
49
|
-
'RolePermissions',
|
|
50
|
-
'RoleUsers',
|
|
51
|
-
'UserRoles'
|
|
52
|
+
'AwaitingStep'
|
|
52
53
|
];
|
|
53
54
|
const RBAC_TABLES = [
|
|
54
55
|
'TargetRoles',
|
|
55
56
|
'RolePermissions',
|
|
56
57
|
'RoleUsers',
|
|
57
58
|
'UserRoles',
|
|
59
|
+
'RbacPermissionCaches',
|
|
58
60
|
'WebSocketTask'
|
|
59
61
|
];
|
|
60
62
|
const LEGACY_PROCESS_QUEUES = [
|
|
@@ -149,7 +151,8 @@ export const resourceArtifactPaths = [
|
|
|
149
151
|
function createResourceState({ objects, relationships, flows }) {
|
|
150
152
|
const crud = objects.some(isCrudObject);
|
|
151
153
|
const selfRbac = objects.some(hasSelfRbacAddOn);
|
|
152
|
-
const rbac = objects.some(
|
|
154
|
+
const rbac = objects.some(hasSelfRbacAddOn);
|
|
155
|
+
const crudActionPlans = createCrudActionPlans(objects);
|
|
153
156
|
const ownTopics = new Set([
|
|
154
157
|
'ProcessLogical',
|
|
155
158
|
'FindData',
|
|
@@ -162,7 +165,10 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
162
165
|
'PaginateProcessLogicalHdrSqs',
|
|
163
166
|
...flows
|
|
164
167
|
.filter((flow) => includesEvent(flow, 'extTopic'))
|
|
165
|
-
.map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`)
|
|
168
|
+
.map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`),
|
|
169
|
+
...flows
|
|
170
|
+
.filter((flow) => flow?.outputTopic && !flow?.generatedCodeConfig && upperFirst(flow.flowTag))
|
|
171
|
+
.map((flow) => `${upperFirst(flow.flowTag)}CompleteHdrSqs`)
|
|
166
172
|
]);
|
|
167
173
|
for (const { flowTag, stepName } of flowExtTopicSteps(flows)) {
|
|
168
174
|
sqsQueues.add(`${flowTag}${stepName}HdrSqs`);
|
|
@@ -186,7 +192,13 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
186
192
|
ownTopics.add(action);
|
|
187
193
|
}
|
|
188
194
|
for (const action of ['Create', 'Update', 'Delete']) {
|
|
189
|
-
|
|
195
|
+
const plan = crudActionPlans[action];
|
|
196
|
+
if (plan.hasComplete) {
|
|
197
|
+
sqsQueues.add(`${action}CompleteHdrSqs`);
|
|
198
|
+
}
|
|
199
|
+
if (plan.hasRbacCallback) {
|
|
200
|
+
sqsQueues.add(`${action}RbacCallbackHdrSqs`);
|
|
201
|
+
}
|
|
190
202
|
}
|
|
191
203
|
}
|
|
192
204
|
if (relationships.length > 0) {
|
|
@@ -203,24 +215,13 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
203
215
|
}
|
|
204
216
|
}
|
|
205
217
|
if (rbac) {
|
|
206
|
-
|
|
207
|
-
|
|
218
|
+
const flowTags = [
|
|
219
|
+
...new Set(objects.filter(hasRbacAddOn).map(rbacFlowTag))
|
|
220
|
+
];
|
|
221
|
+
for (const flowTag of flowTags) {
|
|
208
222
|
ownTopics.add(flowTag);
|
|
209
223
|
}
|
|
210
224
|
}
|
|
211
|
-
const beforeLogicalByAction = new Map();
|
|
212
|
-
for (const flow of flows.filter(
|
|
213
|
-
(flow) => flow?.generatedCodeConfig?.codeHookTag === 'beforeLogical'
|
|
214
|
-
)) {
|
|
215
|
-
const action = upperFirst(flow.generatedCodeConfig.generatedCodeTag);
|
|
216
|
-
if (!action || !flow.flowTag) continue;
|
|
217
|
-
const flowTags = beforeLogicalByAction.get(action) ?? new Set();
|
|
218
|
-
flowTags.add(flow.flowTag);
|
|
219
|
-
beforeLogicalByAction.set(action, flowTags);
|
|
220
|
-
}
|
|
221
|
-
const beforeLogical = [...beforeLogicalByAction].map(
|
|
222
|
-
([action, flowTags]) => ({ action, flowTags: [...flowTags].sort() })
|
|
223
|
-
);
|
|
224
225
|
const customRoles = [
|
|
225
226
|
...new Set([
|
|
226
227
|
...supportedCustomFlows(flows).map((flow) =>
|
|
@@ -244,6 +245,7 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
244
245
|
const webSocketRoles = new Set();
|
|
245
246
|
if (websocket) {
|
|
246
247
|
webSocketRoles.add('WebSocketMainRole');
|
|
248
|
+
webSocketRoles.add('RegisterRole');
|
|
247
249
|
}
|
|
248
250
|
if (crud) webSocketRoles.add('FlowObjectsRole');
|
|
249
251
|
if (relationships.length > 0) webSocketRoles.add('FlowRelationshipRole');
|
|
@@ -259,7 +261,6 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
259
261
|
}
|
|
260
262
|
const outTopics = new Set([
|
|
261
263
|
...ownTopics,
|
|
262
|
-
...beforeLogical.map(({ action }) => action),
|
|
263
264
|
...flows
|
|
264
265
|
.filter((flow) => flow?.outputTopic && upperFirst(flow.flowTag))
|
|
265
266
|
.map((flow) => upperFirst(flow.flowTag))
|
|
@@ -285,10 +286,11 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
285
286
|
.filter((flow) => includesEvent(flow, 's3'))
|
|
286
287
|
.map((flow) => {
|
|
287
288
|
const tag = upperFirst(flow.flowTag);
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
const outputTopicStr = typeof flow.outputTopic === 'string' ? flow.outputTopic : null;
|
|
290
|
+
const topicName = outputTopicStr
|
|
291
|
+
? (outputTopicStr.startsWith('Out')
|
|
292
|
+
? outputTopicStr
|
|
293
|
+
: `Out${upperFirst(outputTopicStr)}`)
|
|
292
294
|
: flow.s3Subscription?.topicName || 'OutCreate';
|
|
293
295
|
const queueName =
|
|
294
296
|
flow.s3Subscription?.queueName || `${tag}ReservedLimitHdrSqs`;
|
|
@@ -298,6 +300,9 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
298
300
|
return { subscriptionName, topicName, queueName };
|
|
299
301
|
});
|
|
300
302
|
const systemTables = [...SYSTEM_TABLES];
|
|
303
|
+
if (rbac) {
|
|
304
|
+
systemTables.push('TargetRoles', 'RolePermissions', 'RoleUsers', 'UserRoles', 'RbacPermissionCaches');
|
|
305
|
+
}
|
|
301
306
|
if (s3FlowTags.length > 0) {
|
|
302
307
|
systemTables.push('ReservedDataMain');
|
|
303
308
|
}
|
|
@@ -309,6 +314,7 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
309
314
|
return {
|
|
310
315
|
crud,
|
|
311
316
|
rbac,
|
|
317
|
+
crudActionPlans,
|
|
312
318
|
s3Subscriptions,
|
|
313
319
|
s3FlowTags,
|
|
314
320
|
hasHttpApi,
|
|
@@ -316,7 +322,6 @@ function createResourceState({ objects, relationships, flows }) {
|
|
|
316
322
|
ownTopics: [...ownTopics].filter(Boolean).sort(),
|
|
317
323
|
sqsQueues: [...sqsQueues].filter(Boolean).sort(),
|
|
318
324
|
dsqQueues: [...dsqQueues].filter(Boolean).sort(),
|
|
319
|
-
beforeLogical,
|
|
320
325
|
customRoles,
|
|
321
326
|
websocket,
|
|
322
327
|
webSocketRoles,
|
|
@@ -401,12 +406,6 @@ async function renderInSqs(state) {
|
|
|
401
406
|
...state.dsqQueues.map((queueName) =>
|
|
402
407
|
render('ResourceSqsYaml.ejs', { queueName })
|
|
403
408
|
),
|
|
404
|
-
...state.beforeLogical.map(({ action, flowTags }) =>
|
|
405
|
-
render('ResourceBeforeLogicalYaml.ejs', {
|
|
406
|
-
queueName: `${action}BeforeLogical`,
|
|
407
|
-
flowTags
|
|
408
|
-
})
|
|
409
|
-
),
|
|
410
409
|
...(state.websocket
|
|
411
410
|
? [
|
|
412
411
|
render('ResourceSqsYaml.ejs', {
|
|
@@ -455,7 +454,10 @@ async function renderOut(state) {
|
|
|
455
454
|
|
|
456
455
|
async function renderDynamo(state) {
|
|
457
456
|
const [system, ...tables] = await Promise.all([
|
|
458
|
-
render('SystemDynamoDB_Yaml.ejs', {
|
|
457
|
+
render('SystemDynamoDB_Yaml.ejs', {
|
|
458
|
+
hasS3: state.s3FlowTags.length > 0,
|
|
459
|
+
hasRbac: state.rbac
|
|
460
|
+
}),
|
|
459
461
|
...state.tables.map((table) => render('DynamoDBTable_Yaml.ejs', table))
|
|
460
462
|
]);
|
|
461
463
|
const indentedTables = tables.map((t) => indentYaml(t, 2)).join('\n');
|
|
@@ -481,15 +483,29 @@ async function renderIam(state) {
|
|
|
481
483
|
};
|
|
482
484
|
}
|
|
483
485
|
|
|
486
|
+
function getRbacValidatorServiceTags(state) {
|
|
487
|
+
const tags = new Set();
|
|
488
|
+
for (const obj of state.objects || []) {
|
|
489
|
+
if (obj.belongTo?.serviceTag && obj.belongTo.serviceTag !== 'Rbac') {
|
|
490
|
+
tags.add(obj.belongTo.serviceTag);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return Array.from(tags).sort();
|
|
494
|
+
}
|
|
495
|
+
|
|
484
496
|
async function renderLambdaRoleConfig(state) {
|
|
485
497
|
const s3Flows = state.flows
|
|
486
498
|
.filter((flow) => includesEvent(flow, 's3'))
|
|
487
499
|
.map((flow) => ({
|
|
488
500
|
roleName: upperFirst(flow.flowTag)
|
|
489
501
|
}));
|
|
502
|
+
const rbacValidatorServiceTags = getRbacValidatorServiceTags(state);
|
|
490
503
|
return render('GeneratedLambdaRoleServiceConfig.ejs', {
|
|
491
504
|
crud: state.crud,
|
|
492
505
|
relationships: state.relationships,
|
|
506
|
+
rbac: state.rbac,
|
|
507
|
+
rbacValidatorServiceTags,
|
|
508
|
+
objectGraphServiceTags: state.objectGraphServiceTags,
|
|
493
509
|
s3Flows
|
|
494
510
|
});
|
|
495
511
|
}
|
|
@@ -544,7 +560,10 @@ function roleNeedsSchemaRead(state, roleName) {
|
|
|
544
560
|
}
|
|
545
561
|
|
|
546
562
|
function roleTableNames(state, roleName) {
|
|
547
|
-
if (roleName === 'RegisterRole')
|
|
563
|
+
if (roleName === 'RegisterRole') {
|
|
564
|
+
if (state.websocket) return ['WebSocketTask', 'RegisterRecords'];
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
548
567
|
if (roleName === 'WebSocketMainRole')
|
|
549
568
|
return ['UserUploadRecords', 'WebSocketTask'];
|
|
550
569
|
if (roleName === 'FlowObjectsRole')
|
|
@@ -588,7 +607,7 @@ function roleTableNames(state, roleName) {
|
|
|
588
607
|
|
|
589
608
|
function dynamoActionsForRole(roleName) {
|
|
590
609
|
if (roleName === 'ProcFindDataRole')
|
|
591
|
-
return ['dynamodb:GetItem', 'dynamodb:Query'];
|
|
610
|
+
return ['dynamodb:GetItem', 'dynamodb:Query', 'dynamodb:UpdateItem'];
|
|
592
611
|
if (roleName === 'WebSocketMainRole')
|
|
593
612
|
return ['dynamodb:DeleteItem', 'dynamodb:PutItem', 'dynamodb:Query'];
|
|
594
613
|
if (roleName === 'FlowRbacRole')
|
|
@@ -613,15 +632,17 @@ function roleQueueNames(state, roleName) {
|
|
|
613
632
|
return [];
|
|
614
633
|
}
|
|
615
634
|
if (roleName === 'FlowObjectsRole') {
|
|
616
|
-
return
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
635
|
+
return CRUD_ACTIONS.flatMap((action) => {
|
|
636
|
+
const plan = state.crudActionPlans[action];
|
|
637
|
+
if (!plan.outputTopic) return [];
|
|
638
|
+
return [
|
|
639
|
+
`${action}HdrSqs`,
|
|
640
|
+
...(plan.hasRbacCallback
|
|
641
|
+
? [`${action}RbacCallbackHdrSqs`]
|
|
642
|
+
: []),
|
|
643
|
+
...(plan.hasComplete ? [`${action}CompleteHdrSqs`] : [])
|
|
644
|
+
];
|
|
645
|
+
});
|
|
625
646
|
}
|
|
626
647
|
if (roleName === 'FlowRelationshipRole') {
|
|
627
648
|
return [
|
|
@@ -634,10 +655,7 @@ function roleQueueNames(state, roleName) {
|
|
|
634
655
|
}
|
|
635
656
|
if (roleName === 'FlowRbacRole') {
|
|
636
657
|
return [
|
|
637
|
-
...RBAC_ACTIONS.
|
|
638
|
-
`${action}HdrSqs`,
|
|
639
|
-
`Process${action}HdrSqs`
|
|
640
|
-
]),
|
|
658
|
+
...RBAC_ACTIONS.map((action) => `${action}HdrSqs`),
|
|
641
659
|
...rbacFlowQueueNames(state)
|
|
642
660
|
];
|
|
643
661
|
}
|
|
@@ -673,6 +691,9 @@ function roleQueueNames(state, roleName) {
|
|
|
673
691
|
(queueName) => includesEvent(flow, 's3') && queueName.startsWith(tag)
|
|
674
692
|
)
|
|
675
693
|
);
|
|
694
|
+
if (flow.outputTopic) {
|
|
695
|
+
queueList.push(`${tag}CompleteHdrSqs`);
|
|
696
|
+
}
|
|
676
697
|
return queueList;
|
|
677
698
|
}
|
|
678
699
|
|
|
@@ -685,7 +706,8 @@ function roleDlqQueueNames(state, roleName) {
|
|
|
685
706
|
}
|
|
686
707
|
|
|
687
708
|
function roleTopicNames(state, roleName) {
|
|
688
|
-
if (roleName === 'ProcFindDataRole')
|
|
709
|
+
if (roleName === 'ProcFindDataRole')
|
|
710
|
+
return state.outTopics.filter((topic) => topic === 'FindData');
|
|
689
711
|
if (roleName === 'FlowObjectsRole')
|
|
690
712
|
return state.outTopics.filter((topic) => CRUD_ACTIONS.includes(topic));
|
|
691
713
|
if (roleName === 'FlowRelationshipRole')
|
|
@@ -786,17 +808,18 @@ function collectTables(schemas) {
|
|
|
786
808
|
const identifiers = Array.isArray(schema.identifiers)
|
|
787
809
|
? schema.identifiers
|
|
788
810
|
: [];
|
|
789
|
-
const
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
identifier.type === 'partitionKey' ||
|
|
794
|
-
identifier.type === 'identifier'
|
|
795
|
-
)
|
|
796
|
-
) ?? 'PK';
|
|
797
|
-
const sk = keyName(
|
|
798
|
-
identifiers.find((identifier) => identifier.type === 'sortKey')
|
|
811
|
+
const pkIdentifier = identifiers.find(
|
|
812
|
+
(identifier) =>
|
|
813
|
+
identifier.type === 'partitionKey' ||
|
|
814
|
+
identifier.type === 'identifier'
|
|
799
815
|
);
|
|
816
|
+
const skIdentifier = identifiers.find(
|
|
817
|
+
(identifier) => identifier.type === 'sortKey'
|
|
818
|
+
);
|
|
819
|
+
const pk = keyName(pkIdentifier) ?? 'PK';
|
|
820
|
+
const sk = keyName(skIdentifier);
|
|
821
|
+
const pkType = keyAttributeType(pkIdentifier, schema);
|
|
822
|
+
const skType = keyAttributeType(skIdentifier, schema);
|
|
800
823
|
for (const resource of Object.values(schema.storageResources)) {
|
|
801
824
|
if (
|
|
802
825
|
(resource?.storageType === 'dynamo' ||
|
|
@@ -805,12 +828,66 @@ function collectTables(schemas) {
|
|
|
805
828
|
resource.tableName &&
|
|
806
829
|
!tables.has(resource.tableName)
|
|
807
830
|
)
|
|
808
|
-
tables.set(resource.tableName, { pk, sk });
|
|
831
|
+
tables.set(resource.tableName, { pk, sk, pkType, skType });
|
|
809
832
|
}
|
|
810
833
|
}
|
|
811
834
|
return tables;
|
|
812
835
|
}
|
|
813
836
|
|
|
837
|
+
function keyAttributeType(identifier, schema) {
|
|
838
|
+
if (!identifier) return 'S';
|
|
839
|
+
if (identifier.attributeType) {
|
|
840
|
+
return identifier.attributeType;
|
|
841
|
+
}
|
|
842
|
+
if (identifier.dataType) {
|
|
843
|
+
return mapTypeToAttributeType(identifier.dataType);
|
|
844
|
+
}
|
|
845
|
+
if (identifier.fieldType) {
|
|
846
|
+
return mapTypeToAttributeType(identifier.fieldType);
|
|
847
|
+
}
|
|
848
|
+
const fieldName = identifier.fieldName ?? identifier.name;
|
|
849
|
+
if (fieldName && schema) {
|
|
850
|
+
let fieldDef =
|
|
851
|
+
schema.fieldNames?.[fieldName] ?? schema.properties?.[fieldName];
|
|
852
|
+
if (!fieldDef && Array.isArray(schema.addOnDataStructure)) {
|
|
853
|
+
for (const addOn of schema.addOnDataStructure) {
|
|
854
|
+
if (addOn?.fieldNames?.[fieldName]) {
|
|
855
|
+
fieldDef = addOn.fieldNames[fieldName];
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
if (fieldDef?.attributeType) {
|
|
861
|
+
return fieldDef.attributeType;
|
|
862
|
+
}
|
|
863
|
+
const type = fieldDef?.type ?? fieldDef?.dataType;
|
|
864
|
+
if (type) {
|
|
865
|
+
return mapTypeToAttributeType(type);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return 'S';
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
function mapTypeToAttributeType(type) {
|
|
872
|
+
if (typeof type !== 'string') return 'S';
|
|
873
|
+
const lower = type.toLowerCase();
|
|
874
|
+
if (
|
|
875
|
+
lower === 'number' ||
|
|
876
|
+
lower === 'numeric' ||
|
|
877
|
+
lower === 'integer' ||
|
|
878
|
+
lower === 'float' ||
|
|
879
|
+
lower === 'int' ||
|
|
880
|
+
lower === 'double' ||
|
|
881
|
+
lower === 'n'
|
|
882
|
+
) {
|
|
883
|
+
return 'N';
|
|
884
|
+
}
|
|
885
|
+
if (lower === 'binary' || lower === 'b') {
|
|
886
|
+
return 'B';
|
|
887
|
+
}
|
|
888
|
+
return 'S';
|
|
889
|
+
}
|
|
890
|
+
|
|
814
891
|
function keyName(identifier) {
|
|
815
892
|
if (!identifier) return null;
|
|
816
893
|
return (
|
|
@@ -836,11 +913,7 @@ function hasSelfRbacAddOn(object) {
|
|
|
836
913
|
}
|
|
837
914
|
|
|
838
915
|
function hasRbacAddOn(object) {
|
|
839
|
-
|
|
840
|
-
const belongToHasRbac =
|
|
841
|
-
Array.isArray(object?.belongToSchema?.addOnDataStructure) &&
|
|
842
|
-
object.belongToSchema.addOnDataStructure.some((addOn) => addOn?.type === 'rbac');
|
|
843
|
-
return selfHasRbac || belongToHasRbac;
|
|
916
|
+
return hasSelfRbacAddOn(object);
|
|
844
917
|
}
|
|
845
918
|
|
|
846
919
|
/**
|
|
@@ -849,15 +922,12 @@ function hasRbacAddOn(object) {
|
|
|
849
922
|
* UserRbacFlow SQS functions emitted in emitRbacApplicationArtifacts.
|
|
850
923
|
*/
|
|
851
924
|
function rbacFlowQueueNames(state) {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
return `${flowTag}HdrSqs`;
|
|
859
|
-
})
|
|
860
|
-
.filter(Boolean);
|
|
925
|
+
const flowTags = [
|
|
926
|
+
...new Set(
|
|
927
|
+
(state.objects ?? []).filter(hasRbacAddOn).map(rbacFlowTag)
|
|
928
|
+
)
|
|
929
|
+
];
|
|
930
|
+
return flowTags.map((flowTag) => `${flowTag}HdrSqs`);
|
|
861
931
|
}
|
|
862
932
|
function includesEvent(flow, event) {
|
|
863
933
|
return Array.isArray(flow?.event) && flow.event.includes(event);
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
BillingMode: PAY_PER_REQUEST
|
|
7
7
|
AttributeDefinitions:
|
|
8
8
|
- AttributeName: '<%- pk %>'
|
|
9
|
-
AttributeType: 'S'
|
|
9
|
+
AttributeType: '<%- pkType || 'S' %>'
|
|
10
10
|
<% if (sk) { %>
|
|
11
11
|
- AttributeName: '<%- sk %>'
|
|
12
|
-
AttributeType: 'S'
|
|
12
|
+
AttributeType: '<%- skType || 'S' %>'
|
|
13
13
|
<% } %>
|
|
14
14
|
KeySchema:
|
|
15
15
|
- AttributeName: '<%- pk %>'
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
- AttributeName: '<%- sk %>'
|
|
19
19
|
KeyType: 'RANGE'
|
|
20
20
|
<% } %>
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
#<#<%- tableName %>TableSetting#>
|
|
22
|
+
#<#/<%- tableName %>TableSetting#>
|
|
23
23
|
|
|
@@ -29,6 +29,7 @@ export function generatedLambdaRole() {
|
|
|
29
29
|
{
|
|
30
30
|
roleName: 'FlowObjects',
|
|
31
31
|
statement: [
|
|
32
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
32
33
|
{
|
|
33
34
|
Sid: 'FlowObjectsRoleTest0',
|
|
34
35
|
Effect: 'Allow',
|
|
@@ -43,27 +44,51 @@ export function generatedLambdaRole() {
|
|
|
43
44
|
Effect: 'Allow',
|
|
44
45
|
Action: ['sns:Publish'],
|
|
45
46
|
Resource: [
|
|
46
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'UpdateNode_In', 'GraphHandler')}
|
|
47
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'UpdateNode_In', 'GraphHandler')}`,
|
|
48
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CreateNode_In', 'GraphHandler')}`
|
|
47
49
|
]
|
|
48
|
-
}
|
|
50
|
+
}<% if (rbac || (rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0)) { %>,<% } -%>
|
|
51
|
+
<% } -%>
|
|
49
52
|
|
|
53
|
+
<% if (rbac || (rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0)) { -%>
|
|
50
54
|
{
|
|
51
|
-
Sid: '
|
|
55
|
+
Sid: 'FlowObjectsPublishValidatorRbacTopics',
|
|
52
56
|
Effect: 'Allow',
|
|
53
57
|
Action: ['sns:Publish'],
|
|
54
58
|
Resource: [
|
|
55
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, '
|
|
59
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
60
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
56
61
|
]
|
|
57
|
-
}
|
|
62
|
+
}<% } %>
|
|
58
63
|
//(<createFlowObjectsRole>)
|
|
59
64
|
//(</createFlowObjectsRole>)
|
|
60
65
|
]
|
|
61
66
|
},
|
|
62
67
|
<% } -%>
|
|
63
68
|
|
|
69
|
+
<% if (rbac) { -%>
|
|
70
|
+
{
|
|
71
|
+
roleName: 'FlowRbac',
|
|
72
|
+
statement: [
|
|
73
|
+
{
|
|
74
|
+
Sid: 'FlowRbacPublishValidatorRbacTopics',
|
|
75
|
+
Effect: 'Allow',
|
|
76
|
+
Action: ['sns:Publish'],
|
|
77
|
+
Resource: [
|
|
78
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
79
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
//(<createFlowRbacRole>)
|
|
83
|
+
//(</createFlowRbacRole>)
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
<% } -%>
|
|
87
|
+
|
|
64
88
|
{
|
|
65
89
|
roleName: 'ProcFindData',
|
|
66
90
|
statement: [
|
|
91
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
67
92
|
{
|
|
68
93
|
Sid: 'ProcFindDataRoleTest0',
|
|
69
94
|
Effect: 'Allow',
|
|
@@ -72,6 +97,7 @@ export function generatedLambdaRole() {
|
|
|
72
97
|
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'GetNodeHdrInv', 'GraphHandler')}`
|
|
73
98
|
]
|
|
74
99
|
}
|
|
100
|
+
<% } -%>
|
|
75
101
|
//(<createProcFindDataRole>)
|
|
76
102
|
//(</createProcFindDataRole>)
|
|
77
103
|
]
|
|
@@ -137,6 +137,7 @@ Resources:
|
|
|
137
137
|
- AttributeName: pendingStepId
|
|
138
138
|
KeyType: RANGE
|
|
139
139
|
|
|
140
|
+
<% if (hasRbac) { %>
|
|
140
141
|
TargetRolesTable:
|
|
141
142
|
Type: 'AWS::DynamoDB::Table'
|
|
142
143
|
Properties:
|
|
@@ -200,6 +201,26 @@ Resources:
|
|
|
200
201
|
KeyType: HASH
|
|
201
202
|
- AttributeName: roleIdKey
|
|
202
203
|
KeyType: RANGE
|
|
204
|
+
|
|
205
|
+
RbacPermissionCachesTable:
|
|
206
|
+
Type: 'AWS::DynamoDB::Table'
|
|
207
|
+
Properties:
|
|
208
|
+
TableName: ${self:custom.iz_resourcePrefix}RbacPermissionCaches
|
|
209
|
+
BillingMode: PAY_PER_REQUEST
|
|
210
|
+
AttributeDefinitions:
|
|
211
|
+
- AttributeName: userId
|
|
212
|
+
AttributeType: S
|
|
213
|
+
- AttributeName: cacheKey
|
|
214
|
+
AttributeType: S
|
|
215
|
+
KeySchema:
|
|
216
|
+
- AttributeName: userId
|
|
217
|
+
KeyType: HASH
|
|
218
|
+
- AttributeName: cacheKey
|
|
219
|
+
KeyType: RANGE
|
|
220
|
+
TimeToLiveSpecification:
|
|
221
|
+
AttributeName: ttlTimestamp
|
|
222
|
+
Enabled: true
|
|
223
|
+
<% } %>
|
|
203
224
|
<% if (hasS3) { %>
|
|
204
225
|
ReservedDataMainTable:
|
|
205
226
|
Type: 'AWS::DynamoDB::Table'
|
|
@@ -5,3 +5,10 @@ SubscriptionToOut<%= topicName %>WebSocketComplete:
|
|
|
5
5
|
TopicArn: !Ref Out<%= topicName %>
|
|
6
6
|
Endpoint: 'arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}WebSocketCompleteHdrSqs'
|
|
7
7
|
Protocol: 'sqs'
|
|
8
|
+
|
|
9
|
+
SubscriptionToOut<%= topicName %>RegisterComplete:
|
|
10
|
+
Type: AWS::SNS::Subscription
|
|
11
|
+
Properties:
|
|
12
|
+
TopicArn: !Ref Out<%= topicName %>
|
|
13
|
+
Endpoint: 'arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}RegisterCompleteHdrSqs'
|
|
14
|
+
Protocol: 'sqs'
|
|
@@ -13,7 +13,7 @@ const validatorSchema = {
|
|
|
13
13
|
type: 'object',
|
|
14
14
|
properties: {
|
|
15
15
|
<%_ startConfig.properties.forEach((prop, index) => { _%>
|
|
16
|
-
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: { type:
|
|
16
|
+
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: { type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %><% if (typeof prop.default !== 'undefined') { %>, default: <%- typeof prop.default === 'string' ? `'${prop.default.replace(/'/g, "\\'")}'` : JSON.stringify(prop.default) %><% } %> }<%- index < startConfig.properties.length - 1 ? ',' : '' %>
|
|
17
17
|
<%_ }) _%>
|
|
18
18
|
},
|
|
19
19
|
required: [<%- startConfig.properties.filter(p => p.required === true).map(p => `'${p.propertyName}'`).join(', ') %>]
|
|
@@ -31,7 +31,7 @@ let perRecordsValidatorSchema = {
|
|
|
31
31
|
properties: {
|
|
32
32
|
<%_ startConfig.properties.forEach((prop, index) => { _%>
|
|
33
33
|
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: {
|
|
34
|
-
type:
|
|
34
|
+
type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %><% if (typeof prop.default !== 'undefined') { %>,
|
|
35
35
|
default: <%- typeof prop.default === 'string' ? `'${prop.default.replace(/'/g, "\\'")}'` : JSON.stringify(prop.default) %><% } %>
|
|
36
36
|
}<%- index < startConfig.properties.length - 1 ? ',' : '' %>
|
|
37
37
|
<%_ }) _%>
|
|
@@ -51,7 +51,7 @@ let messageAttributeValidatorSchema = {
|
|
|
51
51
|
type: 'object',
|
|
52
52
|
properties: {
|
|
53
53
|
Type: { type: 'string' },
|
|
54
|
-
Value: { type:
|
|
54
|
+
Value: { type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %> }
|
|
55
55
|
},
|
|
56
56
|
required: ['Type', 'Value']
|
|
57
57
|
}<%- index < startConfig.messageAttributes.length - 1 ? ',' : '' %>
|
|
@@ -10,7 +10,7 @@ const validatorSchema = {
|
|
|
10
10
|
type: 'object',
|
|
11
11
|
properties: {
|
|
12
12
|
<%_ startConfig.properties.forEach((prop, index) => { _%>
|
|
13
|
-
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: { type:
|
|
13
|
+
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: { type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %><% if (typeof prop.default !== 'undefined') { %>, default: <%- typeof prop.default === 'string' ? `'${prop.default.replace(/'/g, "\\'")}'` : JSON.stringify(prop.default) %><% } %> }<%- index < startConfig.properties.length - 1 ? ',' : '' %>
|
|
14
14
|
<%_ }) _%>
|
|
15
15
|
},
|
|
16
16
|
required: [<%- startConfig.properties.filter(p => p.required === true).map(p => `'${p.propertyName}'`).join(', ') %>]
|
|
@@ -31,7 +31,7 @@ let perRecordsValidatorSchema = {
|
|
|
31
31
|
properties: {
|
|
32
32
|
<%_ startConfig.properties.forEach((prop, index) => { _%>
|
|
33
33
|
<%- /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(prop.propertyName) ? prop.propertyName : `'${prop.propertyName}'` %>: {
|
|
34
|
-
type:
|
|
34
|
+
type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %><% if (typeof prop.default !== 'undefined') { %>,
|
|
35
35
|
default: <%- typeof prop.default === 'string' ? `'${prop.default.replace(/'/g, "\\'")}'` : JSON.stringify(prop.default) %><% } %>
|
|
36
36
|
}<%- index < startConfig.properties.length - 1 ? ',' : '' %>
|
|
37
37
|
<%_ }) _%>
|
|
@@ -51,7 +51,7 @@ let messageAttributeValidatorSchema = {
|
|
|
51
51
|
type: 'object',
|
|
52
52
|
properties: {
|
|
53
53
|
Type: { type: 'string' },
|
|
54
|
-
Value: { type:
|
|
54
|
+
Value: { type: <%- prop.type === 'mixed' ? "['string', 'number', 'integer', 'boolean', 'null', 'object', 'array']" : `'${prop.type || 'string'}'` %> }
|
|
55
55
|
},
|
|
56
56
|
required: ['Type', 'Value']
|
|
57
57
|
}<%- index < startConfig.messageAttributes.length - 1 ? ',' : '' %>
|