@izara_project/izara-core-generate-service-code 1.0.78 → 1.0.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/package.json +2 -2
  2. package/src/compile/flowValidator.js +163 -0
  3. package/src/compile/loadSchemas.js +15 -5
  4. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +137 -7
  5. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +132 -17
  6. package/src/emit/crud/crudActionPlan.js +82 -0
  7. package/src/emit/crud/emitCrudApplicationArtifacts.js +162 -112
  8. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
  9. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +84 -512
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +536 -0
  12. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +87 -202
  13. package/src/emit/crud/templates/DeleteLogicalLib.ejs +213 -0
  14. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +217 -0
  15. package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
  16. package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +9 -2
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +87 -444
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +472 -0
  19. package/src/emit/custom/customFlows.js +27 -2
  20. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -2
  21. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +10 -3
  22. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  23. package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
  24. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +2 -2
  25. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +3 -9
  26. package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -16
  27. package/src/emit/rbac/rbacFlowTag.js +2 -7
  28. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +148 -21
  29. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +4 -2
  30. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +1 -1
  31. package/src/emit/relationship/templates/CreateRelationship_Main.ejs +1 -1
  32. package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +1 -1
  33. package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
  34. package/src/emit/relationship/templates/MoveRelationship_Main.ejs +1 -1
  35. package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +1 -1
  36. package/src/emit/resource/emitResourceArtifacts.js +83 -68
  37. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +31 -5
  38. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +21 -0
  39. package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
  40. package/src/emit/shared/templates/FlowHandler_HdrApi.ejs +1 -1
  41. package/src/emit/shared/templates/FlowHandler_HdrDsq.ejs +2 -2
  42. package/src/emit/shared/templates/FlowHandler_HdrInv.ejs +1 -1
  43. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +2 -2
  44. package/src/emit/systemText/emitSystemTextSchemas.js +246 -0
  45. package/src/emit/systemText/templates/SystemTextSchemas.ejs +10 -0
  46. package/src/generate.js +55 -8
  47. package/test/crudApplicationArtifacts.test.js +147 -19
  48. package/test/customFlowApplicationArtifacts.test.js +308 -16
  49. package/test/dynamicCrudFlowSchemas.test.js +150 -14
  50. package/test/dynamicRbacFlowSchemas.test.js +2 -2
  51. package/test/dynamicRelationshipFlowSchemas.test.js +1 -1
  52. package/test/graphDrivenFlowSchema.test.js +257 -0
  53. package/test/publicApi.test.js +14 -5
  54. package/test/resourceArtifacts.test.js +25 -19
  55. package/test/systemTextSchemas.test.js +154 -0
  56. package/src/emit/crud/templates/CreateComplete_HdrSqs.ejs +0 -99
  57. package/src/emit/crud/templates/DeleteComplete_HdrSqs.ejs +0 -99
  58. package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +0 -174
  59. package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +0 -187
  60. package/src/emit/crud/templates/UpdateComplete_HdrSqs.ejs +0 -99
  61. 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(hasRbacAddOn);
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
- sqsQueues.add(`${action}CompleteHdrSqs`);
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
- for (const object of objects.filter(hasRbacAddOn)) {
207
- const flowTag = upperFirst(object.objectType) + 'RbacFlow';
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 topicName = flow.outputTopic
289
- ? flow.outputTopic.startsWith('Out')
290
- ? flow.outputTopic
291
- : `Out${upperFirst(flow.outputTopic)}`
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', { hasS3: state.s3FlowTags.length > 0 }),
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') return [];
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
- ...CRUD_ACTIONS.map((action) => `${action}HdrSqs`),
618
- ...CRUD_ACTIONS.filter((action) => action !== 'Get').map(
619
- (action) => `${action}CompleteHdrSqs`
620
- ),
621
- ...state.beforeLogical
622
- .filter(({ action }) => CRUD_ACTIONS.includes(action))
623
- .map(({ action }) => `${action}BeforeLogicalHdrSqs`)
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.flatMap((action) => [
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') return [];
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')
@@ -836,11 +858,7 @@ function hasSelfRbacAddOn(object) {
836
858
  }
837
859
 
838
860
  function hasRbacAddOn(object) {
839
- const selfHasRbac = hasSelfRbacAddOn(object);
840
- const belongToHasRbac =
841
- Array.isArray(object?.belongToSchema?.addOnDataStructure) &&
842
- object.belongToSchema.addOnDataStructure.some((addOn) => addOn?.type === 'rbac');
843
- return selfHasRbac || belongToHasRbac;
861
+ return hasSelfRbacAddOn(object);
844
862
  }
845
863
 
846
864
  /**
@@ -849,15 +867,12 @@ function hasRbacAddOn(object) {
849
867
  * UserRbacFlow SQS functions emitted in emitRbacApplicationArtifacts.
850
868
  */
851
869
  function rbacFlowQueueNames(state) {
852
- return (state.objects ?? [])
853
- .filter(hasRbacAddOn)
854
- .map((object) => {
855
- const objectType = object?.objectType;
856
- if (typeof objectType !== 'string' || objectType.trim() === '') return null;
857
- const flowTag = `${objectType[0].toUpperCase()}${objectType.slice(1)}RbacFlow`;
858
- return `${flowTag}HdrSqs`;
859
- })
860
- .filter(Boolean);
870
+ const flowTags = [
871
+ ...new Set(
872
+ (state.objects ?? []).filter(hasRbacAddOn).map(rbacFlowTag)
873
+ )
874
+ ];
875
+ return flowTags.map((flowTag) => `${flowTag}HdrSqs`);
861
876
  }
862
877
  function includesEvent(flow, event) {
863
878
  return Array.isArray(flow?.event) && flow.event.includes(event);
@@ -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: 'FlowObjectsRoleTest2',
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, 'CreateNode_In', 'GraphHandler')}`
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: '<%- 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 ? ',' : '' %>
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: '<%- prop.type || 'string' %>'<% if (typeof prop.default !== 'undefined') { %>,
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: '<%- prop.type || 'string' %>' }
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: '<%- 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 ? ',' : '' %>
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: '<%- prop.type || 'string' %>'<% if (typeof prop.default !== 'undefined') { %>,
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: '<%- prop.type || 'string' %>' }
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 ? ',' : '' %>