@izara_project/izara-core-generate-service-code 1.0.84 → 1.0.86

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 (46) hide show
  1. package/package.json +1 -1
  2. package/src/compile/compileProject.js +1 -2
  3. package/src/compile/loadSchemas.js +29 -17
  4. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +6 -0
  5. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +26 -6
  6. package/src/emit/crud/crudActionPlan.js +3 -1
  7. package/src/emit/crud/emitCrudApplicationArtifacts.js +47 -8
  8. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +136 -25
  9. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +248 -181
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +1155 -293
  12. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  13. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +36 -4
  14. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  15. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +76 -14
  16. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +35 -3
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +754 -353
  19. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +5 -2
  20. package/src/emit/rbac/emitRbacApplicationArtifacts.js +102 -6
  21. package/src/emit/rbac/templates/CancelUsage_Main.ejs +82 -22
  22. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +130 -14
  23. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +61 -12
  24. package/src/emit/rbac/templates/DeleteTargetRole_Main.ejs +96 -0
  25. package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +106 -0
  26. package/src/emit/rbac/templates/GetTargetRole_Main.ejs +62 -0
  27. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +30 -11
  28. package/src/emit/rbac/templates/UpdateTargetRole_Main.ejs +107 -0
  29. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +40 -15
  30. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +22 -7
  31. package/src/emit/resource/emitResourceArtifacts.js +52 -2
  32. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +6 -2
  33. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +2 -0
  34. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  35. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +0 -1
  36. package/src/emit/systemText/emitSystemTextSchemas.js +5 -2
  37. package/src/generate.js +18 -12
  38. package/src/generateResources/IntTest/generateResources/generateResources.js +1 -1
  39. package/src/generateResources/IntTest/generateTests/generateTemplate.js +1 -1
  40. package/src/generateResources/IntTest/upload/uploadIntTest.js +8 -2
  41. package/test/createTargetRoleHandler.test.js +42 -1
  42. package/test/crudApplicationArtifacts.test.js +53 -0
  43. package/test/dynamicCrudFlowSchemas.test.js +16 -2
  44. package/test/dynamicRbacFlowSchemas.test.js +5 -2
  45. package/test/publicApi.test.js +18 -14
  46. package/test/resourceArtifacts.test.js +24 -0
@@ -56,7 +56,10 @@ export function generatedLambdaRole() {
56
56
  Effect: 'Allow',
57
57
  Action: ['sns:Publish'],
58
58
  Resource: [
59
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
59
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
60
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
61
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% if (rbac) { %>,
62
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
60
63
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
61
64
  ]
62
65
  }<% } %>
@@ -75,7 +78,8 @@ export function generatedLambdaRole() {
75
78
  Effect: 'Allow',
76
79
  Action: ['sns:Publish'],
77
80
  Resource: [
78
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
81
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
82
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
79
83
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
80
84
  ]
81
85
  }
@@ -271,6 +271,8 @@ Resources:
271
271
  TimeToLiveSpecification:
272
272
  AttributeName: ttlTimestamp
273
273
  Enabled: true
274
+ StreamSpecification:
275
+ StreamViewType: NEW_AND_OLD_IMAGES
274
276
  <% } %>
275
277
  <% if (hasS3) { %>
276
278
  ReservedDataMainTable:
@@ -88,7 +88,7 @@ export const main = middleware.wrap(async (event, context) => {
88
88
 
89
89
  // add argument (to invoke lambda) to passOnProperties[]
90
90
  passOnProperties.push(record.body.Message);
91
- <% if (typeof usePassBack === 'undefined' ? functionName.endsWith('Complete') : usePassBack) { %>
91
+ <% if (typeof usePassBack === 'undefined' ? (functionName.endsWith('Complete') || functionName.endsWith('CompleteMain') || functionName.includes('Callback')) : usePassBack) { %>
92
92
  passOnProperties.push(
93
93
  callingFlowSharedLib.addPassBackPropertiesToPassOnProperties(
94
94
  record.body.Message
@@ -9,7 +9,6 @@ WebSocketConnect:
9
9
  authorizer:
10
10
  arn: arn:aws:lambda:${self:custom.iz_region}:${self:custom.iz_accountId}:function:UserAccount${self:custom.iz_stage}UserIdentityAuthorizer
11
11
  identitySource:
12
- - 'route.request.header.Authorization'
13
12
  - 'route.request.querystring.access_token'
14
13
  #<#/WebSocketConnectAuthorizer#>
15
14
  - websocket:
@@ -17,14 +17,17 @@ const RELATIONSHIP_ACTIONS = [
17
17
  ];
18
18
  const RBAC_SHARED_FLOW_TAGS = [
19
19
  'CreateTargetRole',
20
- 'ListTargetRole',
20
+ 'UpdateTargetRole',
21
21
  'DeleteTargetRole',
22
+ 'GetTargetRole',
23
+ 'ListTargetRole',
22
24
  'CreateRolePermissions',
23
25
  'ListRolePermissions',
24
26
  'DeleteRolePermissions',
25
27
  'CreateUserRole',
26
28
  'ListUserInRoles',
27
- 'DeleteUserFromRole'
29
+ 'DeleteUserFromRole',
30
+ 'GetMyPermissions'
28
31
  ];
29
32
 
30
33
  export function systemTextSchemaManagedPaths() {
package/src/generate.js CHANGED
@@ -64,12 +64,10 @@ import {
64
64
 
65
65
  export async function generate(rootPath, options = {}) {
66
66
  const startedAt = Date.now();
67
- const logger = options.logger;
68
- logger?.info?.(`[INFO] [Generate] STATUS=STARTED | rootPath=${rootPath}`);
67
+ console.log(`[INFO] [Generate] STATUS=STARTED | rootPath=${rootPath}`);
69
68
  try {
70
69
  const project = compileProject({ ...options, rootPath });
71
70
  const schemaLoadOptions = {
72
- logger,
73
71
  skipValidation: options.skipValidation
74
72
  };
75
73
  const [rawObjects, relationships, flows, notifications] = await Promise.all([
@@ -92,8 +90,10 @@ export async function generate(rootPath, options = {}) {
92
90
  relationships,
93
91
  schemaBucketName
94
92
  );
95
- logger?.debug?.(
96
- `[DEBUG] [Generate] STATUS=SCHEMAS_LOADED | objects=${objects.length} relationships=${relationships.length} flows=${flows.length}`
93
+ console.log(
94
+ `[DEBUG] [Generate] STATUS=SCHEMAS_LOADED | ` +
95
+ `objects=${objects.length} ` +
96
+ `relationships=${relationships.length} flows=${flows.length}`
97
97
  );
98
98
  const groups = await _emitGroups({
99
99
  project,
@@ -103,10 +103,14 @@ export async function generate(rootPath, options = {}) {
103
103
  notifications,
104
104
  objectGraphServiceTags,
105
105
  relationshipGraphServiceTags,
106
- logger
106
+ logger: options.logger
107
+ });
108
+ const scopeCounts = groups.map((group) => {
109
+ return `${group.scope}=${group.artifacts.length}`;
107
110
  });
108
- logger?.debug?.(
109
- `[DEBUG] [Generate] STATUS=ARTIFACTS_EMITTED | ${groups.map((group) => `${group.scope}=${group.artifacts.length}`).join(' ')}`
111
+ const emittedScopeSummary = scopeCounts.join(' ');
112
+ console.log(
113
+ `[DEBUG] [Generate] STATUS=ARTIFACTS_EMITTED | ${emittedScopeSummary}`
110
114
  );
111
115
  let files = [];
112
116
  if (groups.length > 0) {
@@ -123,14 +127,16 @@ export async function generate(rootPath, options = {}) {
123
127
  );
124
128
  }
125
129
  const durationMs = Date.now() - startedAt;
126
- logger?.info?.(
127
- `[INFO] [Generate] STATUS=FINISHED | files=${files.length} durationMs=${durationMs}`
130
+ console.log(
131
+ `[INFO] [Generate] STATUS=FINISHED | ` +
132
+ `files=${files.length} durationMs=${durationMs}`
128
133
  );
129
134
 
130
135
  return { project, durationMs, files };
131
136
  } catch (error) {
132
- logger?.error?.(
133
- `[ERROR] [Generate] STATUS=FAILED | durationMs=${Date.now() - startedAt}`,
137
+ console.log(
138
+ `[ERROR] [Generate] STATUS=FAILED | ` +
139
+ `durationMs=${Date.now() - startedAt}`,
134
140
  error
135
141
  );
136
142
  throw error;
@@ -103,7 +103,7 @@ async function generateCodeWithTemplate(_izContext, savePath, settings) {
103
103
 
104
104
  return allCreateSource;
105
105
  } catch (error) {
106
- _izContext.logger.error(
106
+ console.log(
107
107
  'Error generating code with template propertyNode schema:',
108
108
  error
109
109
  );
@@ -71,7 +71,7 @@ async function generateCodeWithTemplate(_izContext, savePath, settings) {
71
71
 
72
72
  return allCreateSource;
73
73
  } catch (error) {
74
- _izContext.logger.error(
74
+ console.log(
75
75
  'Error generating code with template propertyNode schema:',
76
76
  error
77
77
  );
@@ -17,10 +17,16 @@ import fs from 'fs';
17
17
  import path from 'path';
18
18
 
19
19
  import { s3 } from '@izara_project/izara-core-library-s3';
20
- import Logger from '@izara_project/izara-core-library-logger';
20
+
21
+ const consoleLogger = {
22
+ debug: console.log,
23
+ info: console.log,
24
+ warn: console.log,
25
+ error: console.error
26
+ };
21
27
 
22
28
  const DEFAULT_BUCKET = 'integrationtest-config-us-east-2';
23
- const _izContext = { Logger };
29
+ const _izContext = { logger: consoleLogger, Logger: consoleLogger };
24
30
 
25
31
  function _getAllFiles(dirPath, filePaths = []) {
26
32
  if (!fs.existsSync(dirPath)) {
@@ -9,6 +9,7 @@ import { generateCreateTargetRoleHandler } from '../src/emit/rbac/generateCreate
9
9
  const roots = new Set();
10
10
  const OWN_TOPIC_FLOWS = [
11
11
  'CreateTargetRole',
12
+ 'UpdateTargetRole',
12
13
  'CreateRolePermissions',
13
14
  'DeleteRolePermissions',
14
15
  'DeleteTargetRole',
@@ -39,7 +40,7 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
39
40
  const rootPath = await createProject(true);
40
41
  const result = await generateCreateTargetRoleHandler(rootPath);
41
42
 
42
- assert.equal(result.files.length, 60);
43
+ assert.equal(result.files.length, 70);
43
44
  assert.match(
44
45
  await readFile(join(rootPath, result.files[0].path), 'utf8'),
45
46
  /CreateTargetRole/
@@ -48,6 +49,46 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
48
49
  await readFile(join(rootPath, result.files[0].path), 'utf8'),
49
50
  /roleName = 'owner'/
50
51
  );
52
+ assert.match(
53
+ await readFile(
54
+ join(
55
+ rootPath,
56
+ 'app/src/generatedCode/FlowRbac/UpdateTargetRole/source/UpdateTargetRole_Main.js'
57
+ ),
58
+ 'utf8'
59
+ ),
60
+ /Cannot modify system owner role/
61
+ );
62
+ assert.match(
63
+ await readFile(
64
+ join(
65
+ rootPath,
66
+ 'app/src/generatedCode/FlowRbac/DeleteTargetRole/source/DeleteTargetRole_Main.js'
67
+ ),
68
+ 'utf8'
69
+ ),
70
+ /Cannot delete system owner role/
71
+ );
72
+ assert.match(
73
+ await readFile(
74
+ join(
75
+ rootPath,
76
+ 'app/src/generatedCode/FlowRbac/GetTargetRole/source/GetTargetRole_Main.js'
77
+ ),
78
+ 'utf8'
79
+ ),
80
+ /GetTargetRole/
81
+ );
82
+ assert.match(
83
+ await readFile(
84
+ join(
85
+ rootPath,
86
+ 'app/src/generatedCode/FlowRbac/GetMyPermissions/source/GetMyPermissions_Main.js'
87
+ ),
88
+ 'utf8'
89
+ ),
90
+ /GetMyPermissions/
91
+ );
51
92
  assert.match(
52
93
  await readFile(join(rootPath, result.files[1].path), 'utf8'),
53
94
  /CreateTargetRoleHdrSqs/
@@ -357,6 +357,59 @@ test('logs warning when ObjectSchema has invalid or non-CRUD generatedBy in crud
357
357
  );
358
358
  });
359
359
 
360
+ test('emits targetIdentifiers consistency check and fallback in Update_Main.js and Delete_Main.js', async () => {
361
+ const rootPath = await createProject(true);
362
+ await generateCrudApplicationArtifacts(rootPath, {
363
+ serviceTag: 'orders'
364
+ });
365
+
366
+ const updateMain = await readFile(
367
+ join(
368
+ rootPath,
369
+ 'app/src/generatedCode/FlowObjects/Update/source/Update_Main.js'
370
+ ),
371
+ 'utf8'
372
+ );
373
+ assert.match(updateMain, /targetIdentifiers\.\$\{key\} must match objInstanceFull\.identifiers\.\$\{key\}/);
374
+ assert.match(updateMain, /if \(!objectSchema\.hasOwnProperty\('belongTo'\)\)/);
375
+ assert.doesNotMatch(updateMain, /requestParams\.targetIdentifiers\s*=/);
376
+
377
+ const deleteMain = await readFile(
378
+ join(
379
+ rootPath,
380
+ 'app/src/generatedCode/FlowObjects/Delete/source/Delete_Main.js'
381
+ ),
382
+ 'utf8'
383
+ );
384
+ assert.match(deleteMain, /targetIdentifiers\.\$\{key\} must match identifiers\.\$\{key\}/);
385
+ assert.match(deleteMain, /if \(!objectSchema\.hasOwnProperty\('belongTo'\)\)/);
386
+ assert.doesNotMatch(deleteMain, /requestParams\.targetIdentifiers\s*=/);
387
+ });
388
+
389
+ test('emits targetIdentifiers passed directly to checkRbacPermission options in RBAC project', async () => {
390
+ const rootPath = await createRbacProject();
391
+ await generateCrudApplicationArtifacts(rootPath, {
392
+ serviceTag: 'orders'
393
+ });
394
+
395
+ const updateMain = await readFile(
396
+ join(
397
+ rootPath,
398
+ 'app/src/generatedCode/FlowObjects/Update/source/Update_Main.js'
399
+ ),
400
+ 'utf8'
401
+ );
402
+ assert.match(updateMain, /checkRbacPermission\([\s\S]*targetIdentifiers,[\s\S]*rbacObjType/);
403
+
404
+ const deleteMain = await readFile(
405
+ join(
406
+ rootPath,
407
+ 'app/src/generatedCode/FlowObjects/Delete/source/Delete_Main.js'
408
+ ),
409
+ 'utf8'
410
+ );
411
+ assert.match(deleteMain, /checkRbacPermission\([\s\S]*targetIdentifiers,[\s\S]*rbacObjType/);
412
+ });
360
413
 
361
414
  async function createProject(withCrudObject) {
362
415
  const rootPath = await mkdtemp(
@@ -161,6 +161,7 @@ test('generates RbacCallback and Complete for Create when RBAC and Graph are pre
161
161
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
162
162
  'Start',
163
163
  'RbacCallback',
164
+ 'CreateNodeCallback',
164
165
  'Complete'
165
166
  ]);
166
167
  });
@@ -186,6 +187,7 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
186
187
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
187
188
  'Start',
188
189
  'RbacCallback',
190
+ 'CreateNodeCallback',
189
191
  'Complete'
190
192
  ]);
191
193
  assert.deepEqual(create.flowSteps[2].properties, [
@@ -221,10 +223,22 @@ test('chains RbacCallback and Complete for Update with RBAC and Graph', async ()
221
223
  'Complete'
222
224
  ]);
223
225
  assert.deepEqual(update.flowSteps[0].nextSteps, [
224
- { targetType: 'ownTopic', stepName: 'RbacCallback' }
226
+ { targetType: 'ownTopic', stepName: 'RbacCallback' },
227
+ {
228
+ targetType: 'extTopic',
229
+ serviceTag: 'Rbac',
230
+ topicName: 'ValidatorRbac_In',
231
+ toStepNames: ['RbacCallback']
232
+ }
225
233
  ]);
226
234
  assert.deepEqual(update.flowSteps[1].nextSteps, [
227
- { targetType: 'ownTopic', stepName: 'Complete' }
235
+ { targetType: 'ownTopic', stepName: 'Complete' },
236
+ {
237
+ targetType: 'extTopic',
238
+ serviceTag: 'GraphHandler',
239
+ topicName: 'UpdateNode_In',
240
+ toStepNames: ['Complete']
241
+ }
228
242
  ]);
229
243
  assert.deepEqual(update.flowSteps[2].properties, [
230
244
  'returnValue',
@@ -10,14 +10,17 @@ import { generateDynamicRbacFlowSchemas } from '../src/emit/rbac/generateDynamic
10
10
  const projectRoots = new Set();
11
11
  const STATIC_RBAC_ACTIONS = [
12
12
  'CreateTargetRole',
13
- 'ListTargetRole',
13
+ 'UpdateTargetRole',
14
14
  'DeleteTargetRole',
15
+ 'GetTargetRole',
16
+ 'ListTargetRole',
15
17
  'CreateRolePermissions',
16
18
  'ListRolePermissions',
17
19
  'DeleteRolePermissions',
18
20
  'CreateUserRole',
19
21
  'ListUserInRoles',
20
- 'DeleteUserFromRole'
22
+ 'DeleteUserFromRole',
23
+ 'GetMyPermissions'
21
24
  ];
22
25
 
23
26
  const STATIC_LIMIT_ACTIONS = [
@@ -57,24 +57,28 @@ test('generate commits schemas, application artifacts, and resources in one publ
57
57
  );
58
58
  });
59
59
 
60
- test('generate logs its lifecycle through the supplied logger', async () => {
60
+ test('generate logs its lifecycle through console.log', async () => {
61
61
  const rootPath = await createCrudProject();
62
62
  const messages = [];
63
- const logger = Object.fromEntries(
64
- ['info', 'debug', 'error'].map((level) => [
65
- level,
66
- (message) => messages.push(message)
67
- ])
68
- );
63
+ const originalLog = console.log;
64
+ console.log = (...args) => {
65
+ messages.push(args.join(' '));
66
+ };
69
67
 
70
- await generate(rootPath, { logger });
68
+ try {
69
+ await generate(rootPath);
71
70
 
72
- assert.match(messages[0], /STATUS=STARTED/);
73
- assert.ok(messages.some((message) => /STATUS=SCHEMAS_LOADED/.test(message)));
74
- assert.ok(
75
- messages.some((message) => /STATUS=ARTIFACTS_EMITTED/.test(message))
76
- );
77
- assert.match(messages.at(-1), /STATUS=FINISHED/);
71
+ assert.match(messages[0], /STATUS=STARTED/);
72
+ assert.ok(messages.some((message) => {
73
+ return /STATUS=SCHEMAS_LOADED/.test(message);
74
+ }));
75
+ assert.ok(messages.some((message) => {
76
+ return /STATUS=ARTIFACTS_EMITTED/.test(message);
77
+ }));
78
+ assert.match(messages.at(-1), /STATUS=FINISHED/);
79
+ } finally {
80
+ console.log = originalLog;
81
+ }
78
82
  });
79
83
 
80
84
  test('generate commits RBAC WebSocket entries for own-topic mutation flows', async () => {
@@ -346,6 +346,30 @@ test('emits IAM role for generated DSQ flows in generate-shared-resource.yml', a
346
346
  assert.match(role, /GeneratedDsqHdrDsq/);
347
347
  });
348
348
 
349
+ test('emits CreateNodeCallbackHdrSqs in FlowObjectsRole when object has graph and rbac', async () => {
350
+ const rootPath = await createProject();
351
+ const schemas = join(rootPath, 'app/src/schemas');
352
+ await writeFile(
353
+ join(schemas, 'ObjectSchemas/Node.js'),
354
+ "export default { objectType: 'node', generatedBy: 'user', addOnDataStructure: [{ type: 'rbac' }], identifiers: [{ type: 'partitionKey', fieldName: 'nodeId' }], storageResources: { main: { storageType: 'graph', tableName: 'Nodes' } } };\n"
355
+ );
356
+ await generateResourceArtifacts(rootPath);
357
+
358
+ const iam = await readFile(
359
+ join(
360
+ rootPath,
361
+ 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
362
+ ),
363
+ 'utf8'
364
+ );
365
+ const role = roleBlock(iam, 'FlowObjectsRole');
366
+ assert.match(role, /CreateNodeCallbackHdrSqs/);
367
+ assert.match(role, /CreateNodeCallbackHdrSqsDLQ/);
368
+ assert.match(role, /RolePermissions/);
369
+ assert.match(role, /ValidatorRbac_In/);
370
+ assert.match(role, /Rbac_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
371
+ });
372
+
349
373
  function roleBlock(iam, roleName) {
350
374
  const match = iam.match(
351
375
  new RegExp(