@izara_project/izara-core-generate-service-code 1.0.55 → 1.0.56

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/codeGenerators/app/initial_setup/InitialSetupGenerator.js +223 -123
  3. package/src/codeGenerators/app/initial_setup/templates/InitialSetup_LambdaRole.ejs +6 -6
  4. package/src/codeGenerators/app/sls_yaml/FindDataYamlGenerator.js +1 -1
  5. package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +299 -197
  6. package/src/codeGenerators/app/sls_yaml/RoleNameConfigGenerator.js +84 -60
  7. package/src/codeGenerators/app/sls_yaml/SharedResourceYamlGenerator.js +304 -271
  8. package/src/codeGenerators/app/sls_yaml/__tests__/SharedResourceYamlGenerator.test.js +91 -32
  9. package/src/codeGenerators/app/sls_yaml/templates/SharedResource_Yaml.ejs +2 -2
  10. package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/EndpointsGenerator.js +1 -1
  11. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/templates/rbac/FlowRbac_Main.ejs +252 -0
  12. package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/RelationshipFlowGenerator.js +1 -1
  13. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowClassifier.js +3 -2
  14. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js +12 -5
  15. package/src/codeGenerators/app/src/generatedCode/libs/templates/Consts.ejs +23 -23
  16. package/src/codeGenerators/resource/sls_yaml/DynamoDBGenerator.js +1 -1
  17. package/src/codeGenerators/resource/sls_yaml/FlowOutGenerator.js +4 -6
  18. package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +26 -10
  19. package/src/codeGenerators/resource/sls_yaml/templates/SystemDynamoDB_Yaml.ejs +64 -0
  20. package/src/generate.js +1 -1
  21. package/src/generateCode.js +7 -7
  22. package/src/generateSchema.js +1 -1
  23. package/src/schemaGenerators/app/src/schemas/FlowSchemas/FlowSchemaGenerator.js +0 -1
  24. package/src/schemaGenerators/app/src/schemas/FlowSchemas/RbacFlowSchemaGenerator.js +16 -2
  25. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs +12 -12
  26. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicRbacFlowSchemaTemplate.ejs +1 -0
  27. package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/UserRbacFlowSchemaTemplate.ejs +22 -0
  28. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/.gitkeep +0 -0
  29. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/templates/FlowEndpointBeforeLogical_Main.ejs +0 -0
  30. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/templates/crud/CreateEndpoint_Main.ejs +0 -0
  31. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/templates/crud/DeleteEndpoint_Main.ejs +0 -0
  32. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/templates/crud/GetEndpoint_Main.ejs +0 -0
  33. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowEndpoints → FlowObjects}/templates/crud/UpdateEndpoint_Main.ejs +0 -0
  34. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessChangeRelationshipComplete_Main.ejs +0 -0
  35. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessChangeRelationship_Main.ejs +0 -0
  36. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessCreateRelationshipComplete_Main.ejs +0 -0
  37. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessCreateRelationship_Main.ejs +0 -0
  38. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessDeleteRelationshipComplete_Main.ejs +0 -0
  39. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessDeleteRelationship_Main.ejs +0 -0
  40. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessGetRelationshipComplete_Main.ejs +0 -0
  41. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessGetRelationship_Main.ejs +0 -0
  42. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessMoveRelationshipComplete_Main.ejs +0 -0
  43. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessMoveRelationship_Main.ejs +0 -0
  44. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessUpdateRelationshipComplete_Main.ejs +0 -0
  45. /package/src/codeGenerators/app/src/generatedCode/Flow/{FlowRelationshipEndpoints → FlowRelationships}/templates/relationship/ProcessUpdateRelationship_Main.ejs +0 -0
@@ -34,7 +34,10 @@ describe('generateSharedResourceYaml', () => {
34
34
  'Resources:',
35
35
  ' AwaitingStepTable:',
36
36
  ' Properties:',
37
- ' TableName: ${self:custom.iz_resourcePrefix}AwaitingStep'
37
+ ' TableName: ${self:custom.iz_resourcePrefix}AwaitingStep',
38
+ ' WebSocketTaskTable:',
39
+ ' Properties:',
40
+ ' TableName: ${self:custom.iz_resourcePrefix}WebSocketTask'
38
41
  ].join('\n'),
39
42
  'utf8'
40
43
  );
@@ -58,7 +61,13 @@ describe('generateSharedResourceYaml', () => {
58
61
  ' QueueName: ${self:custom.iz_resourcePrefix}ReservationsSqsDLQ',
59
62
  ' InReservations:',
60
63
  ' Properties:',
61
- ' TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_Reservations_In'
64
+ ' TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_ReservationsComplete_In',
65
+ ' InReservationsMain:',
66
+ ' Properties:',
67
+ ' TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_Reservations_In',
68
+ ' InCreateRolePermissions:',
69
+ ' Properties:',
70
+ ' TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_CreateRolePermissions_In'
62
71
  ].join('\n'),
63
72
  'utf8'
64
73
  );
@@ -92,85 +101,135 @@ describe('generateSharedResourceYaml', () => {
92
101
  ),
93
102
  [
94
103
  'ReservationsCompleteSqs:',
104
+ ' role: WebSocketMainRole',
95
105
  ' events:',
96
106
  ' - sqs:',
97
107
  ' arn: arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}ReservationsCompleteSqs'
98
108
  ].join('\n'),
99
109
  'utf8'
100
110
  );
111
+
112
+ await fs.writeFile(
113
+ path.join(
114
+ tmpDir,
115
+ 'app',
116
+ 'sls_yaml',
117
+ 'generatedCode',
118
+ 'source',
119
+ 'role-name-config.yml'
120
+ ),
121
+ [
122
+ '# for createIamRole',
123
+ '- arn:aws:iam::${self:custom.iz_accountId}:role/${self:custom.iz_resourcePrefix}FlowObjectsRole',
124
+ '- arn:aws:iam::${self:custom.iz_accountId}:role/${self:custom.iz_resourcePrefix}ProcFindDataRole',
125
+ '- arn:aws:iam::${self:custom.iz_accountId}:role/${self:custom.iz_resourcePrefix}RegisterRole',
126
+ '- arn:aws:iam::${self:custom.iz_accountId}:role/${self:custom.iz_resourcePrefix}ReservationsRole',
127
+ '- arn:aws:iam::${self:custom.iz_accountId}:role/${self:custom.iz_resourcePrefix}WebSocketMainRole'
128
+ ].join('\n'),
129
+ 'utf8'
130
+ );
101
131
  });
102
132
 
103
- it('registers baseline IAM statements with explicit resources', async () => {
133
+ it('registers scoped IAM statements and avoids broad defaults', async () => {
104
134
  await generateSharedResourceYaml(
105
135
  { objects: [{ objectType: 'Foo' }], flows: [] },
106
136
  { outputPath: tmpDir }
107
137
  );
108
138
 
109
139
  const grouped = policyRegistry.toGroupedByRole();
140
+ const resources = grouped.FlowObjectsRole.statements.flatMap(
141
+ statement => statement.resource
142
+ );
143
+ const actions = grouped.FlowObjectsRole.statements.flatMap(
144
+ statement => statement.action
145
+ );
146
+
110
147
  expect(Object.keys(grouped).sort()).toEqual(
111
148
  expect.arrayContaining([
112
- 'PerActionEndpointRole',
149
+ 'FlowObjectsRole',
113
150
  'ProcFindDataRole',
114
- 'RegisterRole'
151
+ 'RegisterRole',
152
+ 'ReservationsRole',
153
+ 'WebSocketMainRole'
115
154
  ])
116
155
  );
117
-
118
- const resources = grouped.PerActionEndpointRole.statements.flatMap(
119
- statement => statement.resource
120
- );
121
-
122
156
  expect(resources).toContain(
123
157
  'arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}/perServiceSchemas/*'
124
158
  );
125
159
  expect(resources).toContain(
126
160
  'arn:aws:dynamodb:${self:custom.iz_region}:${self:custom.iz_accountId}:table/${self:custom.iz_resourcePrefix}AwaitingStep'
127
161
  );
128
- expect(resources).toContain(
129
- 'arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}ReservationsSqs'
162
+ const reservationResources = grouped.ReservationsRole.statements.flatMap(
163
+ statement => statement.resource
130
164
  );
131
- expect(resources).toContain(
132
- 'arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}ReservationsCompleteSqs'
165
+ const reservationActions = grouped.ReservationsRole.statements.flatMap(
166
+ statement => statement.action
133
167
  );
134
- expect(resources).toContain(
168
+
169
+ expect(reservationResources).toContain(
135
170
  'arn:aws:sns:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_serviceTag}_${self:custom.iz_stage}_Reservations_Out'
136
171
  );
172
+ expect(reservationResources).not.toContain(
173
+ 'arn:aws:sns:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_serviceTag}_${self:custom.iz_stage}_ReservationsComplete_In'
174
+ );
137
175
  expect(resources).not.toContain(
138
- 'arn:aws:dynamodb:${self:custom.iz_region}:${self:custom.iz_accountId}:table/${self:custom.iz_resourcePrefix}*'
176
+ 'arn:aws:sns:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_serviceTag}_${self:custom.iz_stage}_CreateRolePermissions_In'
139
177
  );
178
+ expect(reservationActions).toContain('sns:Publish');
179
+ expect(reservationActions).not.toContain('sns:Subscribe');
140
180
  expect(resources).not.toContain(
141
- 'arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}*'
181
+ 'arn:aws:dynamodb:${self:custom.iz_region}:${self:custom.iz_accountId}:table/${self:custom.iz_resourcePrefix}*'
142
182
  );
143
183
  });
144
184
 
145
- it('adds WebSocket permissions only for WebSocketMainRole when ownTopic flow exists', async () => {
185
+ it('adds WebSocket permissions only for WebSocketMainRole', async () => {
146
186
  await generateSharedResourceYaml(
147
187
  { flows: [{ flowTag: 'dummy', event: ['ownTopic'] }] },
148
188
  { outputPath: tmpDir }
149
189
  );
150
190
 
151
191
  const grouped = policyRegistry.toGroupedByRole();
152
- expect(Object.keys(grouped)).toContain('WebSocketMainRole');
153
192
  const wsActions = grouped.WebSocketMainRole.statements.flatMap(
154
193
  statement => statement.action
155
194
  );
156
- expect(wsActions).toEqual(
157
- expect.arrayContaining(['execute-api:ManageConnections'])
158
- );
195
+
196
+ expect(wsActions).toContain('execute-api:ManageConnections');
197
+ expect(wsActions).not.toContain('execute-api:Invoke');
198
+
199
+ for (const [roleName, roleData] of Object.entries(grouped)) {
200
+ if (roleName === 'WebSocketMainRole') continue;
201
+ const actions = roleData.statements.flatMap(statement => statement.action);
202
+ expect(actions).not.toContain('execute-api:ManageConnections');
203
+ expect(actions).not.toContain('execute-api:Invoke');
204
+ }
159
205
  });
160
206
 
161
- it('does not add WebSocket permissions for roles other than WebSocketMainRole', async () => {
207
+ it('only emits roles present in role-name-config', async () => {
208
+ policyRegistry.add(
209
+ 'UnexpectedRole',
210
+ 'sns:Publish',
211
+ 'arn:aws:sns:${self:custom.iz_region}:${self:custom.iz_accountId}:unexpected'
212
+ );
213
+
162
214
  await generateSharedResourceYaml(
163
- { flows: [{ flowTag: 'dummy', event: ['ownTopic'] }] },
215
+ { objects: [{ objectType: 'Foo' }], flows: [] },
164
216
  { outputPath: tmpDir }
165
217
  );
166
218
 
167
- const grouped = policyRegistry.toGroupedByRole();
168
- for (const roleName of Object.keys(grouped)) {
169
- if (roleName === 'WebSocketMainRole') continue;
170
- const actions = grouped[roleName].statements.flatMap(
171
- statement => statement.action
172
- );
173
- expect(actions).not.toContain('execute-api:ManageConnections');
174
- }
219
+ const content = await fs.readFile(
220
+ path.join(
221
+ tmpDir,
222
+ 'app',
223
+ 'sls_yaml',
224
+ 'generatedCode',
225
+ 'source',
226
+ 'generate-shared-resource.yml'
227
+ ),
228
+ 'utf8'
229
+ );
230
+
231
+ expect(content).toContain('FlowObjectsRole:');
232
+ expect(content).toContain('WebSocketMainRole:');
233
+ expect(content).not.toContain('UnexpectedRole:');
175
234
  });
176
235
  });
@@ -33,7 +33,7 @@ Resources:
33
33
  - "<%- r %>"
34
34
  <% }) %>
35
35
  <% }) %>
36
- #<#<%- roleName %>StatementHookCode#>
37
- #<#/<%- roleName %>StatementHookCode#>
36
+ #<#<%- roleName %>StatementHookCode#>
37
+ #<#/<%- roleName %>StatementHookCode#>
38
38
 
39
39
  <% }) %>
@@ -40,7 +40,7 @@ export async function generateEndpointsFlow(allSchemas, options) {
40
40
  for (const action of CRUD_ACTIONS) {
41
41
  const isAsync = CRUD_ASYNC_ACTIONS.includes(action);
42
42
  const upperAction = upperFirst(action);
43
- const flowOutputDir = path.join(baseOutputDir, 'FlowEndpoints', upperAction, 'source');
43
+ const flowOutputDir = path.join(baseOutputDir, 'FlowObjects', upperAction, 'source');
44
44
  await fs.mkdir(flowOutputDir, { recursive: true });
45
45
 
46
46
  const mainFileName = processMainFileName(action);
@@ -0,0 +1,252 @@
1
+ /*
2
+ Copyright (C) 2020 Sven Mason <http: //izara.io>
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Affero General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Affero General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see
16
+ <http: //www.gnu.org/licenses />.
17
+ */
18
+
19
+ import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
20
+ import snsSharedLib from '@izara_project/izara-core-library-sns';
21
+ import sqsSharedLib from '@izara_project/izara-core-library-sqs';
22
+ import asyncFlowSharedLib from '@izara_project/izara-core-library-asynchronous-flow';
23
+ import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
24
+ import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
25
+
26
+ //(<optionalImport>)
27
+ import { coreConsts } from '@izara_project/izara-core-library-core';
28
+ import { getObjectSchema } from '@izara_project/izara-core-library-service-schemas';
29
+ import {
30
+ lambda,
31
+ sns,
32
+ sqs
33
+ } from '@izara_project/izara-core-library-external-request';
34
+ import { NoRetryError } from '@izara_project/izara-core-library-core';
35
+ import { utils } from '@izara_project/izara-core-library-service-schemas';
36
+
37
+ const { createFlowTypeConcat } = utils;
38
+ //(</optionalImport>)
39
+
40
+ /**
41
+ *
42
+ *
43
+ * description of function.
44
+ * @param {Object} _izContext
45
+ * @param {CorrelationIds} _izContext.correlationIds - property of _izContext
46
+ * @param {Logger} _izContext.logger - property of _izContext
47
+ * @param {Object} requestParams - request params
48
+ * @param {Object} requestParams.identifiers - identifiers for get data
49
+ * @param {Object} requestParams.additionalRequest - additionalRequest
50
+ *
51
+ *
52
+ * @returns {object} description of return value
53
+ */
54
+
55
+ export default async function ProcessUserRbacFlow(
56
+ _izContext,
57
+ requestParams,
58
+ callingFlowConfig = {}
59
+ //(<additionalParams>)
60
+ //(</additionalParams>)
61
+ ) {
62
+ try {
63
+ _izContext.logger.debug('ProcessUserRbacFlow _izContext', _izContext);
64
+ _izContext.logger.debug('ProcessUserRbacFlow requestParams', requestParams);
65
+ _izContext.logger.debug(
66
+ 'ProcessUserRbacFlow callingFlowConfig',
67
+ callingFlowConfig
68
+ );
69
+
70
+ const userId = _izContext.correlationIds.get(coreConsts.BASE_USER_ID);
71
+ const targetId = _izContext.correlationIds.get(coreConsts.TARGET_ID);
72
+
73
+ if (!userId && !targetId) {
74
+ throw new Error(
75
+ 'Missing required request parameters: userId or targetId'
76
+ );
77
+ }
78
+
79
+ const { flowTypeConcat, inputParameterGroups } = requestParams;
80
+ if (!flowTypeConcat) {
81
+ throw new Error('Missing flowTypeConcat in requestParams');
82
+ }
83
+
84
+ _izContext.logger.debug('userId', userId);
85
+ _izContext.logger.debug('targetId', targetId);
86
+ _izContext.logger.debug('flowTypeConcat', flowTypeConcat);
87
+
88
+ const tableUserRoles = dynamodbSharedLib.tableName(_izContext, 'UserRoles');
89
+
90
+ const resultUserRoles = await dynamodbSharedLib.query(
91
+ _izContext,
92
+ tableUserRoles,
93
+ {
94
+ userId
95
+ }
96
+ );
97
+
98
+ if (!resultUserRoles.Items) {
99
+ resultUserRoles.Items = [];
100
+ }
101
+
102
+ let targetUserRoles = resultUserRoles.Items;
103
+
104
+ targetUserRoles = targetUserRoles.filter(
105
+ r => r.roleIdKey && r.roleIdKey.startsWith(targetId + '_')
106
+ );
107
+
108
+ const tableRolePermission = dynamodbSharedLib.tableName(
109
+ _izContext,
110
+ 'RolePermissions'
111
+ );
112
+
113
+ const chunkSize = 10;
114
+ const rbacRolePermissions = [];
115
+
116
+ for (let i = 0; i < targetUserRoles.length; i += chunkSize) {
117
+ const chunk = targetUserRoles.slice(i, i + chunkSize);
118
+ const promises = chunk.map(userRole =>
119
+ dynamodbSharedLib
120
+ .getItem(_izContext, tableRolePermission, {
121
+ roleIdKey: userRole.roleIdKey,
122
+ flowTypeConcat: flowTypeConcat
123
+ })
124
+ .catch(err => {
125
+ _izContext.logger.error(
126
+ `Error fetching permission for role ${userRole.roleIdKey}:`,
127
+ err
128
+ );
129
+ return null;
130
+ })
131
+ );
132
+
133
+ const results = await Promise.all(promises);
134
+ rbacRolePermissions.push(...results);
135
+ }
136
+
137
+ let isPermission = false;
138
+ let roleIdKey = '';
139
+
140
+ for (let i = 0; i < rbacRolePermissions.length; i++) {
141
+ const rbacRolePermission = rbacRolePermissions[i];
142
+ const userRole = targetUserRoles[i];
143
+
144
+ if (rbacRolePermission && rbacRolePermission.permission === true) {
145
+ const dbParameterGroups = rbacRolePermission.parameterGroups;
146
+ let isParamValid = true;
147
+
148
+ if (
149
+ dbParameterGroups &&
150
+ typeof dbParameterGroups === 'object' &&
151
+ !Array.isArray(dbParameterGroups)
152
+ ) {
153
+ const entries = Object.entries(dbParameterGroups);
154
+ if (entries.length > 0) {
155
+ let any_parameterGroup_match = false;
156
+
157
+ for (const [groupName, parameterGroup] of entries) {
158
+ if (!Array.isArray(parameterGroup)) {
159
+ _izContext.logger.debug(
160
+ `Skipping non-array parameterGroup: ${groupName}`
161
+ );
162
+ continue;
163
+ }
164
+
165
+ _izContext.logger.debug(
166
+ `Checking parameterGroup [${groupName}]:`,
167
+ parameterGroup
168
+ );
169
+ let parameterGroupMatch = true;
170
+
171
+ for (const check_parameter of parameterGroup) {
172
+ let tempRequestParams = inputParameterGroups || {};
173
+
174
+ if (
175
+ !check_parameter.parameterNames ||
176
+ !Array.isArray(check_parameter.parameterNames)
177
+ ) {
178
+ parameterGroupMatch = false;
179
+ break;
180
+ }
181
+
182
+ for (const parameterName of check_parameter.parameterNames) {
183
+ if (
184
+ !tempRequestParams ||
185
+ typeof tempRequestParams !== 'object' ||
186
+ !(parameterName in tempRequestParams)
187
+ ) {
188
+ parameterGroupMatch = false;
189
+ break;
190
+ }
191
+ tempRequestParams = tempRequestParams[parameterName];
192
+ }
193
+
194
+ if (!parameterGroupMatch) break;
195
+
196
+ if (
197
+ !check_parameter.parameterValues ||
198
+ !Array.isArray(check_parameter.parameterValues)
199
+ ) {
200
+ parameterGroupMatch = false;
201
+ break;
202
+ }
203
+
204
+ const valueMatched =
205
+ check_parameter.parameterValues.includes(tempRequestParams);
206
+
207
+ if (!valueMatched) {
208
+ parameterGroupMatch = false;
209
+ break;
210
+ }
211
+ }
212
+
213
+ if (parameterGroupMatch) {
214
+ _izContext.logger.debug(
215
+ `✅ parameterGroup [${groupName}] matched`
216
+ );
217
+ any_parameterGroup_match = true;
218
+ break;
219
+ } else {
220
+ _izContext.logger.debug(
221
+ `❌ parameterGroup [${groupName}] did not match`
222
+ );
223
+ }
224
+ }
225
+
226
+ isParamValid = any_parameterGroup_match;
227
+ }
228
+ }
229
+
230
+ if (isParamValid) {
231
+ isPermission = true;
232
+ roleIdKey = rbacRolePermission.roleIdKey;
233
+ _izContext.logger.debug(
234
+ '### matched rbacRolePermission ###',
235
+ rbacRolePermission
236
+ );
237
+ break;
238
+ } else {
239
+ _izContext.logger.debug(
240
+ '### rbacRolePermission parameterGroups check failed ###',
241
+ { roleIdKey: userRole.roleIdKey }
242
+ );
243
+ }
244
+ }
245
+ }
246
+
247
+ return { permission: isPermission, roleIdKey };
248
+ } catch (err) {
249
+ _izContext.logger.error('error ProcessUserRbacFlow: ', err);
250
+ throw err;
251
+ }
252
+ }
@@ -37,7 +37,7 @@ export async function generateRelationshipFlows(allSchemas, options) {
37
37
  const upperFlowTag = upperFirst(flowTag);
38
38
  const processFunction = processFunctionName(flowTag);
39
39
 
40
- const flowOutputDir = path.join(baseOutputDir, 'FlowRelationshipEndpoints', upperFlowTag, 'source');
40
+ const flowOutputDir = path.join(baseOutputDir, 'FlowRelationships', upperFlowTag, 'source');
41
41
  await fs.mkdir(flowOutputDir, { recursive: true });
42
42
 
43
43
  // 1. Generate Action Step (In) Main Function
@@ -42,8 +42,9 @@ export function isRelationshipFlow(flowTag) {
42
42
  }
43
43
 
44
44
  export function getFlowOutputSubDir(flowTag) {
45
- if (isCrudFlow(flowTag)) return 'FlowEndpoints';
45
+ if (isCrudFlow(flowTag)) return 'FlowObjects';
46
46
  if (isRbacFlow(flowTag)) return 'FlowRbac';
47
- if (isRelationshipFlow(flowTag)) return 'FlowRelationshipEndpoints';
47
+ if (isRelationshipFlow(flowTag)) return 'FlowRelationships';
48
+ if (String(flowTag || '').toLowerCase().endsWith('rbacflow')) return 'FlowRbac';
48
49
  return 'FlowSchemas';
49
50
  }
@@ -53,16 +53,23 @@ export async function generateFlowMainFunction(allSchemas, options) {
53
53
  let templateName = 'FlowEndpoint_Main.ejs';
54
54
  if (['Create', 'Update', 'Delete', 'Get'].includes(flowTag)) {
55
55
  templateName = `${flowTag}Endpoint_Main.ejs`;
56
+ } else if (String(flowTag || '').toLowerCase().endsWith('rbacflow')) {
57
+ templateName = 'FlowRbac_Main.ejs';
56
58
  } else if (isOwnTopic) {
57
59
  // Non-CRUD flow with ownTopic: WebSocket entry that fetches flowSchema and publishes to SNS In topic
58
60
  templateName = 'FlowMain_Wbs.ejs';
59
61
  }
60
62
 
61
- // crud templates live under FlowEndpoints (the only output child that uses them);
63
+ // crud templates live under FlowObjects (the only output child that uses them);
62
64
  // shared endpoint templates (FlowEndpoint_Main, FlowMain_Wbs) live under _internal/_shared/endpoint
63
- const templateBaseDir = templateName.startsWith('crud/') || ['CreateEndpoint_Main.ejs', 'UpdateEndpoint_Main.ejs', 'DeleteEndpoint_Main.ejs', 'GetEndpoint_Main.ejs'].includes(templateName)
64
- ? path.join(__dirname, '..', '..', 'FlowEndpoints', 'templates', 'crud')
65
- : path.join(__dirname, '..', '..', 'FlowSchemas', 'templates', 'endpoint');
65
+ let templateBaseDir;
66
+ if (templateName === 'FlowRbac_Main.ejs') {
67
+ templateBaseDir = path.join(__dirname, '..', '..', 'FlowRbac', 'templates', 'rbac');
68
+ } else if (templateName.startsWith('crud/') || ['CreateEndpoint_Main.ejs', 'UpdateEndpoint_Main.ejs', 'DeleteEndpoint_Main.ejs', 'GetEndpoint_Main.ejs'].includes(templateName)) {
69
+ templateBaseDir = path.join(__dirname, '..', '..', 'FlowObjects', 'templates', 'crud');
70
+ } else {
71
+ templateBaseDir = path.join(__dirname, '..', '..', 'FlowSchemas', 'templates', 'endpoint');
72
+ }
66
73
  const mainTemplateStr = await fs.readFile(
67
74
  path.join(templateBaseDir, templateName),
68
75
  'utf-8'
@@ -130,7 +137,7 @@ export async function generateFlowMainFunction(allSchemas, options) {
130
137
  const beforeLogicalConfigs = generateCode.filter(c => c.codeHookTag === 'beforeLogical');
131
138
  if (isCrud && beforeLogicalConfigs.length > 0) {
132
139
  const beforeLogicalTemplateStr = await fs.readFile(
133
- path.join(__dirname, '..', '..', 'FlowEndpoints', 'templates', 'FlowEndpointBeforeLogical_Main.ejs'),
140
+ path.join(__dirname, '..', '..', 'FlowObjects', 'templates', 'FlowEndpointBeforeLogical_Main.ejs'),
134
141
  'utf-8'
135
142
  );
136
143
 
@@ -166,12 +166,12 @@ const FUNCTION_NAME = {
166
166
  outTranslateIds: 'processTranslateIdsComplete',
167
167
  findData: 'findData',
168
168
  processLogical: 'processLogical',
169
- updateNodeComplete: 'updateNodeComplete',
170
- createObjectComplete: 'createObjectComplete',
171
- getNodeComplete: 'getNodeComplete',
169
+ updateNodeComplete: 'updateComplete',
170
+ createObjectComplete: 'createComplete',
171
+ getNodeComplete: 'getComplete',
172
172
  paginateProcessLogical: 'paginateProcessLogical',
173
173
  deleteNode: 'deleteNode',
174
- deleteNodeComplete: 'deleteNodeComplete',
174
+ deleteNodeComplete: 'deleteComplete',
175
175
  createObjectS3: 'createObjectS3',
176
176
  createObjectS3Complete: 'webSocketTaskComplete',
177
177
  processAfterUploadS3: 'processAfterUploadS3',
@@ -203,12 +203,12 @@ const SHORT_FUNCTION_NAME = functionName => {
203
203
  [FUNCTION_NAME.deleteRelComplete]: 'deleteRelComp',
204
204
  [FUNCTION_NAME.findData]: 'findData',
205
205
  [FUNCTION_NAME.processLogical]: 'processLogical',
206
- [FUNCTION_NAME.updateNodeComplete]: 'updateNodeComp',
207
- [FUNCTION_NAME.createObjectComplete]: 'createObjectComp',
208
- [FUNCTION_NAME.getNodeComplete]: 'getNodeComp',
206
+ [FUNCTION_NAME.updateNodeComplete]: 'updateComp',
207
+ [FUNCTION_NAME.createObjectComplete]: 'createComp',
208
+ [FUNCTION_NAME.getNodeComplete]: 'getComp',
209
209
  [FUNCTION_NAME.paginateProcessLogical]: 'paginateProLogical',
210
210
  [FUNCTION_NAME.deleteNode]: 'deleteNode',
211
- [FUNCTION_NAME.deleteNodeComplete]: 'deleteNodeComp',
211
+ [FUNCTION_NAME.deleteNodeComplete]: 'deleteComp',
212
212
  [FUNCTION_NAME.createObjectS3Complete]: 'webSocketTaskComp',
213
213
  [FUNCTION_NAME.getRel]: 'getRel',
214
214
  [FUNCTION_NAME.getRelComplete]: 'getRelComp',
@@ -238,7 +238,7 @@ const SOURCE_GENERATE_IAM_ROLE = {
238
238
  ProcessFindDataRole: 'ProcFindData',
239
239
  ObjectCompleteRole: 'ObjectCom',
240
240
  NodeCompleteRole: 'NodeCom',
241
- RelationshipRole: 'Relationship',
241
+ FlowRelationshipRole: 'Relationship',
242
242
  RelationshipCompleteRole: 'RelationshipCom',
243
243
  FlowSchemaUploadS3Role: 'FlowSchemaUploadS3',
244
244
  FlowSchemaOwnTopic: 'FlowSchemaOwnTopic',
@@ -320,27 +320,27 @@ const TOPIC_NAME_GENERATE_CODE = {
320
320
  createRelComplete: 'CreateRelationshipComplete',
321
321
  deleteRelComplete: 'DeleteRelationshipComplete',
322
322
  getRelComplete: 'GetRelationshipComplete',
323
- outUpdateRelComplete: 'UpdateRelationshipComplete_Out',
324
- outCreateRelComplete: 'CreateRelationshipComplete_Out',
325
- outDeleteRelComplete: 'DeleteRelationshipComplete_Out',
326
- outGetRelComplete: 'GetRelationshipComplete_Out',
327
- updateNodeComplete: 'UpdateNodeComplete',
328
- outUpdateNodeComplete: 'UpdateNodeComplete_Out',
329
- createNodeComplete: 'CreateObjectComplete',
330
- outCreateNodeComplete: 'CreateObjectComplete_Out',
331
- deleteNodeComplete: 'DeleteNodeComplete',
332
- outDeleteNodeComplete: 'DeleteNodeComplete_Out',
333
- getNodeComplete: 'GetNodeComplete',
334
- outGetNodeComplete: 'GetNodeComplete_Out',
323
+ outUpdateRelComplete: 'UpdateRelationship_Out',
324
+ outCreateRelComplete: 'CreateRelationship_Out',
325
+ outDeleteRelComplete: 'DeleteRelationship_Out',
326
+ outGetRelComplete: 'GetRelationship_Out',
327
+ updateNodeComplete: 'UpdateComplete',
328
+ outUpdateNodeComplete: 'Update_Out',
329
+ createNodeComplete: 'CreateComplete',
330
+ outCreateNodeComplete: 'Create_Out',
331
+ deleteNodeComplete: 'DeleteComplete',
332
+ outDeleteNodeComplete: 'Delete_Out',
333
+ getNodeComplete: 'GetComplete',
334
+ outGetNodeComplete: 'Get_Out',
335
335
  reservedLimitComplete: 'ReservedLimitComplete',
336
336
  createPreSignUrl: 'CreatePreSignUrl',
337
337
  flowSchemaOwnTopicComplete: 'FlowSchemaOwnTopicComplete',
338
338
  flowSchemaOwnTopicEndpointComplete: 'FlowSchemaOwnTopicEndpointComplete',
339
339
  createRecordComplete: 'CreateRecordComplete',
340
340
  changeRelationshipComplete: 'ChangeRelationshipComplete',
341
- outChangeRelationshipComplete: 'ChangeRelationshipComplete_Out',
341
+ outChangeRelationshipComplete: 'ChangeRelationship_Out',
342
342
  moveRelationshipComplete: 'MoveRelationshipComplete',
343
- outMoveRelationshipComplete: 'MoveRelationshipComplete_Out'
343
+ outMoveRelationshipComplete: 'MoveRelationship_Out'
344
344
  };
345
345
 
346
346
  const GRAPH_HANDLER_SERVICE_NAME = {
@@ -80,7 +80,7 @@ export async function generateDynamoDBTables(allSchemas, options) {
80
80
  const systemYamlTpl = await fs.readFile(systemYamlTplPath, 'utf-8');
81
81
  const systemYamlContent = ejs.render(systemYamlTpl, {});
82
82
  await fs.writeFile(yamlOutputPath, `${systemYamlContent}\n`, 'utf-8');
83
- generatedCount += 8; // 8 system tables
83
+ generatedCount += 12; // 12 system tables
84
84
 
85
85
  for (const [tableName, keys] of tables.entries()) {
86
86
  const yamlContent = ejs.render(yamlTpl, {
@@ -28,7 +28,7 @@ export async function generateFlowOut(allSchemas, options) {
28
28
 
29
29
  let generatedCount = 0;
30
30
  const yamlOutputPath = path.join(resourceYamlDir, 'generated-sns-out.yml');
31
- await fs.writeFile(yamlOutputPath, '', 'utf-8');
31
+ await fs.writeFile(yamlOutputPath, 'Resources:\n', 'utf-8'); // ponytail: simplest one-line fix
32
32
 
33
33
  const generatedTopics = new Set();
34
34
 
@@ -48,11 +48,9 @@ export async function generateFlowOut(allSchemas, options) {
48
48
  }
49
49
 
50
50
  const systemTopics = [
51
- 'CreateObjectComplete',
52
- 'DeleteNodeComplete',
53
- 'UpdateNodeComplete',
54
- 'ProcessLogicalComplete',
55
- 'FindDataComplete',
51
+ 'ProcessLogical',
52
+ 'PaginateProcessLogical',
53
+ 'FindData',
56
54
  'Create',
57
55
  'Update',
58
56
  'Delete',