@izara_project/izara-core-generate-service-code 1.0.89 → 1.0.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +2 -2
- package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +6 -6
- package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/CreateComplete_Main.ejs +153 -28
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +18 -18
- package/src/emit/crud/templates/CreateLogicalLib.ejs +83 -54
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +32 -25
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +5 -5
- package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +23 -23
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +15 -15
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +20 -22
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +5 -5
- package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +22 -22
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +15 -15
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +33 -36
- package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +7 -7
- package/src/emit/custom/templates/s3/ConfirmReserved_HdrSqs.ejs +3 -3
- package/src/emit/custom/templates/s3/ConfirmReserved_Main.ejs +3 -3
- package/src/emit/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +3 -3
- package/src/emit/custom/templates/s3/CreatePreSignUrl_Main.ejs +4 -4
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +26 -6
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +40 -13
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +33 -20
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/templates/ChangeRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/ChangeRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +17 -17
- package/src/emit/relationship/templates/CreateRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +14 -14
- package/src/emit/relationship/templates/DeleteRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +10 -10
- package/src/emit/relationship/templates/GetRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/GetRelationshipComplete_Main.ejs +5 -5
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +9 -9
- package/src/emit/relationship/templates/MoveRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +15 -15
- package/src/emit/relationship/templates/UpdateRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +11 -11
- package/src/emit/resource/emitResourceArtifacts.js +48 -18
- package/src/emit/shared/templates/FindData_Main.ejs +19 -19
- package/src/emit/shared/templates/PaginateProcessLogical_Main.ejs +3 -3
- package/src/emit/shared/templates/ProcessLogical_Main.ejs +15 -15
- package/test/createTargetRoleHandler.test.js +70 -9
- package/test/crudApplicationArtifacts.test.js +98 -3
- package/test/dynamicCrudFlowSchemas.test.js +2 -2
- package/test/dynamicRbacFlowSchemas.test.js +32 -4
- package/test/relationshipApplicationArtifacts.test.js +1 -1
- package/test/resourceArtifacts.test.js +42 -0
|
@@ -87,7 +87,7 @@ export default async function findData(
|
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
let
|
|
90
|
+
let foundErrors = [];
|
|
91
91
|
|
|
92
92
|
let standardErrorParams = [
|
|
93
93
|
_izContext,
|
|
@@ -139,8 +139,8 @@ export default async function findData(
|
|
|
139
139
|
_izContext.logger.debug('objInstanceBase: ', objInstanceBase)
|
|
140
140
|
|
|
141
141
|
if (!objInstanceBase) {
|
|
142
|
-
|
|
143
|
-
standardErrorParams.push(
|
|
142
|
+
foundErrors.push(`can't get data in dynamo by ${identifiersBase}`)
|
|
143
|
+
standardErrorParams.push(foundErrors)
|
|
144
144
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
145
145
|
return {
|
|
146
146
|
returnResponse: 'FindData cannot get data in dynamo'
|
|
@@ -148,8 +148,8 @@ export default async function findData(
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
if (!objInstanceBase.hasOwnProperty(fieldName.fieldName)) {
|
|
151
|
-
|
|
152
|
-
standardErrorParams.push(
|
|
151
|
+
foundErrors.push(`data in dynamoDB have no ${fieldName.fieldName}`)
|
|
152
|
+
standardErrorParams.push(foundErrors)
|
|
153
153
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
154
154
|
return {
|
|
155
155
|
returnResponse: 'Data have no fieldName'
|
|
@@ -195,8 +195,8 @@ export default async function findData(
|
|
|
195
195
|
_izContext.logger.debug('objInstanceBase: ', objInstanceBase)
|
|
196
196
|
|
|
197
197
|
if (!objInstanceBase) {
|
|
198
|
-
|
|
199
|
-
standardErrorParams.push(
|
|
198
|
+
foundErrors.push(`can't get data in dynamo by ${identifiersBase}`)
|
|
199
|
+
standardErrorParams.push(foundErrors)
|
|
200
200
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
201
201
|
return {
|
|
202
202
|
returnResponse: 'FindData cannot get data in dynamo'
|
|
@@ -204,8 +204,8 @@ export default async function findData(
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
if (!objInstanceBase.hasOwnProperty(fieldName.fieldName)) {
|
|
207
|
-
|
|
208
|
-
standardErrorParams.push(
|
|
207
|
+
foundErrors.push(`data in dynamoDB have no ${fieldName.fieldName}`)
|
|
208
|
+
standardErrorParams.push(foundErrors)
|
|
209
209
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
210
210
|
return {
|
|
211
211
|
returnResponse: 'Data have no fieldName'
|
|
@@ -255,8 +255,8 @@ export default async function findData(
|
|
|
255
255
|
_izContext.logger.debug('getDataByGraph: ', getDataByGraph)
|
|
256
256
|
|
|
257
257
|
if (!getDataByGraph) {
|
|
258
|
-
|
|
259
|
-
standardErrorParams.push(
|
|
258
|
+
foundErrors.push(`can't get data of ${objType.objectType} in graph`)
|
|
259
|
+
standardErrorParams.push(foundErrors)
|
|
260
260
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
261
261
|
return {
|
|
262
262
|
returnResponse: 'FindData cannot get data in graph'
|
|
@@ -271,8 +271,8 @@ export default async function findData(
|
|
|
271
271
|
|
|
272
272
|
<% if (graphDetail.getInIdentifiers) { %>
|
|
273
273
|
if (!objInstanceFull.identifiers.hasOwnProperty(fieldName.fieldName)) {
|
|
274
|
-
|
|
275
|
-
standardErrorParams.push(
|
|
274
|
+
foundErrors.push(`nodeProperties have no this ${fieldName.fieldName}`)
|
|
275
|
+
standardErrorParams.push(foundErrors)
|
|
276
276
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
277
277
|
return {
|
|
278
278
|
returnResponse: 'Data have no fieldName'
|
|
@@ -283,8 +283,8 @@ export default async function findData(
|
|
|
283
283
|
_izContext.logger.debug('this fieldName is identifier, get dataValue in identifiers: ', dataValue)
|
|
284
284
|
<% } else { %>
|
|
285
285
|
if (!objInstanceFull.fields.hasOwnProperty(fieldName.fieldName)) {
|
|
286
|
-
|
|
287
|
-
standardErrorParams.push(
|
|
286
|
+
foundErrors.push(`nodeProperties have no this ${fieldName.fieldName}`)
|
|
287
|
+
standardErrorParams.push(foundErrors)
|
|
288
288
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
289
289
|
return {
|
|
290
290
|
returnResponse: 'Data have no fieldName'
|
|
@@ -314,8 +314,8 @@ export default async function findData(
|
|
|
314
314
|
else
|
|
315
315
|
|
|
316
316
|
<% } %> {
|
|
317
|
-
|
|
318
|
-
standardErrorParams.push(
|
|
317
|
+
foundErrors.push('unrecognized fieldName')
|
|
318
|
+
standardErrorParams.push(foundErrors)
|
|
319
319
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
@@ -326,8 +326,8 @@ export default async function findData(
|
|
|
326
326
|
else
|
|
327
327
|
|
|
328
328
|
<% } %> {
|
|
329
|
-
|
|
330
|
-
standardErrorParams.push(
|
|
329
|
+
foundErrors.push('unrecognized objectType')
|
|
330
|
+
standardErrorParams.push(foundErrors)
|
|
331
331
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
332
332
|
return {
|
|
333
333
|
returnResponse: 'Function FindData Error'
|
|
@@ -98,7 +98,7 @@ export default async function paginateProcessLogical(
|
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
let
|
|
101
|
+
let foundErrors = [];
|
|
102
102
|
let standardErrorParams = [
|
|
103
103
|
_izContext,
|
|
104
104
|
logicalResultId,
|
|
@@ -153,8 +153,8 @@ export default async function paginateProcessLogical(
|
|
|
153
153
|
|
|
154
154
|
if (!startKey && queryDatas.Items.length == 0) {
|
|
155
155
|
_izContext.logger.debug(`can't find data in table ${tableName}`);
|
|
156
|
-
|
|
157
|
-
standardErrorParams.push(
|
|
156
|
+
foundErrors.push(`can't find data in table ${tableName}`);
|
|
157
|
+
standardErrorParams.push(foundErrors);
|
|
158
158
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
159
159
|
...standardErrorParams
|
|
160
160
|
);
|
|
@@ -96,7 +96,7 @@ export default async function processLogical(
|
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
let
|
|
99
|
+
let foundErrors = [];
|
|
100
100
|
|
|
101
101
|
let standardErrorParams = [
|
|
102
102
|
_izContext,
|
|
@@ -114,16 +114,16 @@ export default async function processLogical(
|
|
|
114
114
|
element.comparison
|
|
115
115
|
)
|
|
116
116
|
) {
|
|
117
|
-
|
|
117
|
+
foundErrors.push('comparison is not possible comparison');
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// validate partitionKeyValues
|
|
121
121
|
if (!element.hasOwnProperty('partitionKeyValues')) {
|
|
122
122
|
_izContext.logger.debug('element not have partitionKeyValues');
|
|
123
|
-
|
|
123
|
+
foundErrors.push('element not have partitionKeyValues');
|
|
124
124
|
} else if (Object.keys(element.partitionKeyValues).length === 0) {
|
|
125
125
|
_izContext.logger.debug('partitionKeyValues is empty');
|
|
126
|
-
|
|
126
|
+
foundErrors.push('partitionKeyValues is empty');
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
const objectSchemas = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
@@ -186,7 +186,7 @@ export default async function processLogical(
|
|
|
186
186
|
if (element.hasOwnProperty('sortKeyValues')) {
|
|
187
187
|
continue;
|
|
188
188
|
} else {
|
|
189
|
-
|
|
189
|
+
foundErrors.push(
|
|
190
190
|
'schema error: dynamo storageResource set to groupByPartitionKeyField but no sortKey'
|
|
191
191
|
);
|
|
192
192
|
break;
|
|
@@ -219,7 +219,7 @@ export default async function processLogical(
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
if (!tableName) {
|
|
222
|
-
|
|
222
|
+
foundErrors.push('no valid dynamo storageResource found');
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
if (
|
|
@@ -230,19 +230,19 @@ export default async function processLogical(
|
|
|
230
230
|
_izContext.logger.debug(
|
|
231
231
|
'element have sortKeyValues but cannot find sortKey in object schemas'
|
|
232
232
|
);
|
|
233
|
-
|
|
233
|
+
foundErrors.push(
|
|
234
234
|
'element have sortKeyValues but cannot find sortKey in object schemas'
|
|
235
235
|
);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
if (
|
|
239
|
-
_izContext.logger.debug('Have
|
|
240
|
-
standardErrorParams.push(
|
|
238
|
+
if (foundErrors.length > 0) {
|
|
239
|
+
_izContext.logger.debug('Have foundErrors: ', foundErrors);
|
|
240
|
+
standardErrorParams.push(foundErrors);
|
|
241
241
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
242
242
|
...standardErrorParams
|
|
243
243
|
);
|
|
244
244
|
return {
|
|
245
|
-
returnResponse: 'Have
|
|
245
|
+
returnResponse: 'Have foundErrors'
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
|
|
@@ -332,8 +332,8 @@ export default async function processLogical(
|
|
|
332
332
|
|
|
333
333
|
if (queryDatas.Items.length == 0) {
|
|
334
334
|
_izContext.logger.debug(`can't find data in ${tableName}`);
|
|
335
|
-
|
|
336
|
-
standardErrorParams.push(
|
|
335
|
+
foundErrors.push(`can't find data in ${tableName}`);
|
|
336
|
+
standardErrorParams.push(foundErrors);
|
|
337
337
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
338
338
|
...standardErrorParams
|
|
339
339
|
);
|
|
@@ -411,8 +411,8 @@ export default async function processLogical(
|
|
|
411
411
|
);
|
|
412
412
|
} else {
|
|
413
413
|
_izContext.logger.debug(`can't find data in ${tableName}`);
|
|
414
|
-
|
|
415
|
-
standardErrorParams.push(
|
|
414
|
+
foundErrors.push(`can't find data in ${tableName}`);
|
|
415
|
+
standardErrorParams.push(foundErrors);
|
|
416
416
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
417
417
|
...standardErrorParams
|
|
418
418
|
);
|
|
@@ -36,7 +36,7 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
36
36
|
const rootPath = await createProject(true);
|
|
37
37
|
const result = await generateCreateTargetRoleHandler(rootPath);
|
|
38
38
|
|
|
39
|
-
assert.equal(result.files.length,
|
|
39
|
+
assert.equal(result.files.length, 60);
|
|
40
40
|
assert.match(
|
|
41
41
|
await readFile(join(rootPath, result.files[0].path), 'utf8'),
|
|
42
42
|
/CreateTargetRole/
|
|
@@ -106,16 +106,67 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
106
106
|
),
|
|
107
107
|
/ListTargetRole/
|
|
108
108
|
);
|
|
109
|
+
const validatorRbac = await readFile(
|
|
110
|
+
join(
|
|
111
|
+
rootPath,
|
|
112
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_Main.js'
|
|
113
|
+
),
|
|
114
|
+
'utf8'
|
|
115
|
+
);
|
|
116
|
+
assert.match(validatorRbac, /Fast-path triggered: user self-action/);
|
|
117
|
+
assert.match(validatorRbac, /return l1Hit;/);
|
|
118
|
+
assert.match(validatorRbac, /return l2Hit;/);
|
|
119
|
+
assert.match(validatorRbac, /return cacheResult;/);
|
|
120
|
+
assert.doesNotMatch(validatorRbac, /L1 Cache hit:[^;]+;\s*return;/);
|
|
121
|
+
const validatorHdrInv = await readFile(
|
|
122
|
+
join(
|
|
123
|
+
rootPath,
|
|
124
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrInv.js'
|
|
125
|
+
),
|
|
126
|
+
'utf8'
|
|
127
|
+
);
|
|
109
128
|
assert.match(
|
|
110
|
-
|
|
129
|
+
validatorHdrInv,
|
|
130
|
+
/import ValidatorRbac from '\.\/ValidatorRbac_Main\.js';/
|
|
131
|
+
);
|
|
132
|
+
assert.match(
|
|
133
|
+
validatorHdrInv,
|
|
134
|
+
/middleware\.setValidatorSchema\(validatorSchema\);/
|
|
135
|
+
);
|
|
136
|
+
assert.match(
|
|
137
|
+
validatorHdrInv,
|
|
138
|
+
/await ValidatorRbac\(event\._izContext, \.\.\.passOnProperties\);/
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const validatorHdrApi = await readFile(
|
|
142
|
+
join(
|
|
143
|
+
rootPath,
|
|
144
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrApi.js'
|
|
145
|
+
),
|
|
146
|
+
'utf8'
|
|
147
|
+
);
|
|
148
|
+
assert.match(
|
|
149
|
+
validatorHdrApi,
|
|
150
|
+
/import ValidatorRbac from '\.\/ValidatorRbac_Main\.js';/
|
|
151
|
+
);
|
|
152
|
+
assert.match(
|
|
153
|
+
validatorHdrApi,
|
|
154
|
+
/middleware\.setValidatorSchema\(validatorSchema, { noAuthorizer: true }\);/
|
|
155
|
+
);
|
|
156
|
+
assert.match(
|
|
157
|
+
validatorHdrApi,
|
|
158
|
+
/await ValidatorRbac\(\s*event\._izContext,\s*\.\.\.passOnProperties\s*\);/
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
await assert.rejects(
|
|
162
|
+
readFile(
|
|
111
163
|
join(
|
|
112
164
|
rootPath,
|
|
113
|
-
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
),
|
|
117
|
-
/Fast-path triggered: user self-action/
|
|
165
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrSqs.js'
|
|
166
|
+
)
|
|
167
|
+
)
|
|
118
168
|
);
|
|
169
|
+
|
|
119
170
|
assert.match(
|
|
120
171
|
await readFile(
|
|
121
172
|
join(
|
|
@@ -130,6 +181,16 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
130
181
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-rbac.yml'),
|
|
131
182
|
'utf8'
|
|
132
183
|
);
|
|
184
|
+
assert.match(
|
|
185
|
+
rbacYaml,
|
|
186
|
+
/ValidatorRbacHdrInv:\n\s+handler: src\/generatedCode\/FlowRbac\/ValidatorRbac\/source\/ValidatorRbac_HdrInv\.main/
|
|
187
|
+
);
|
|
188
|
+
assert.match(
|
|
189
|
+
rbacYaml,
|
|
190
|
+
/ValidatorRbacHdrApi:\n\s+handler: src\/generatedCode\/FlowRbac\/ValidatorRbac\/source\/ValidatorRbac_HdrApi\.main/
|
|
191
|
+
);
|
|
192
|
+
assert.doesNotMatch(rbacYaml, /ValidatorRbacHdrSqs:/);
|
|
193
|
+
|
|
133
194
|
const limitYaml = await readFile(
|
|
134
195
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-limits.yml'),
|
|
135
196
|
'utf8'
|
|
@@ -158,7 +219,7 @@ test('removes CreateTargetRole handler when RBAC is removed', async () => {
|
|
|
158
219
|
await generateCreateTargetRoleHandler(rootPath);
|
|
159
220
|
await writeFile(
|
|
160
221
|
objectPath,
|
|
161
|
-
"export default { objectType: 'user', addOnDataStructure: [] };\n"
|
|
222
|
+
"export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: [] };\n"
|
|
162
223
|
);
|
|
163
224
|
|
|
164
225
|
assert.deepEqual((await generateCreateTargetRoleHandler(rootPath)).files, []);
|
|
@@ -193,7 +254,7 @@ async function createProject(hasRbac) {
|
|
|
193
254
|
await mkdir(directory, { recursive: true });
|
|
194
255
|
await writeFile(
|
|
195
256
|
join(directory, 'User.js'),
|
|
196
|
-
`export default { objectType: 'user', fieldNames: [], identifiers: [], addOnDataStructure: ${addOns} };\n`
|
|
257
|
+
`export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: ${addOns} };\n`
|
|
197
258
|
);
|
|
198
259
|
return rootPath;
|
|
199
260
|
}
|
|
@@ -44,7 +44,7 @@ test('emits CRUD handlers and function YAML from schema data without reading gen
|
|
|
44
44
|
assert.match(createMain, /CreateLogicalLib/);
|
|
45
45
|
assert.match(
|
|
46
46
|
createMain,
|
|
47
|
-
/validateFieldNames\(_izContext, requestParams, objectSchemas,
|
|
47
|
+
/validateFieldNames\(_izContext, requestParams, objectSchemas, foundErrors\)/
|
|
48
48
|
);
|
|
49
49
|
assert.doesNotMatch(
|
|
50
50
|
createMain,
|
|
@@ -59,12 +59,16 @@ test('emits CRUD handlers and function YAML from schema data without reading gen
|
|
|
59
59
|
);
|
|
60
60
|
assert.match(
|
|
61
61
|
createLogicalLib,
|
|
62
|
-
/export async function resolveAndGenerateIdentifiers\(\s*_izContext,\s*requestParams,\s*objectSchema,\s*
|
|
62
|
+
/export async function resolveAndGenerateIdentifiers\(\s*_izContext,\s*requestParams,\s*objectSchema,\s*foundErrors\s*\)/
|
|
63
63
|
);
|
|
64
64
|
assert.match(createLogicalLib, /return \{\s*objectSchemas\s*\};/);
|
|
65
65
|
assert.match(
|
|
66
66
|
createLogicalLib,
|
|
67
|
-
/export function validateFieldNames\(\s*_izContext,\s*requestParams,\s*objectSchemas,\s*
|
|
67
|
+
/export function validateFieldNames\(\s*_izContext,\s*requestParams,\s*objectSchemas,\s*foundErrors\s*\)/
|
|
68
|
+
);
|
|
69
|
+
assert.doesNotMatch(
|
|
70
|
+
createLogicalLib,
|
|
71
|
+
/targetIdentifiers\.submittedByUserId\s*=/
|
|
68
72
|
);
|
|
69
73
|
assert.doesNotMatch(createMain, /FlowHook|beforeLogical|codeHookTag/);
|
|
70
74
|
const yaml = await readFile(
|
|
@@ -637,6 +641,31 @@ test('emits async after-hook callback and SNS publish in CreateLogicalLib and fl
|
|
|
637
641
|
{ stdio: 'inherit' }
|
|
638
642
|
);
|
|
639
643
|
|
|
644
|
+
const createCompleteMain = await readFile(
|
|
645
|
+
join(
|
|
646
|
+
rootPath,
|
|
647
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_Main.js'
|
|
648
|
+
),
|
|
649
|
+
'utf8'
|
|
650
|
+
);
|
|
651
|
+
assert.match(
|
|
652
|
+
createCompleteMain,
|
|
653
|
+
/snsTopicArnByFlowSchema\(\s*_izContext,\s*'notifyAfterCreate_In'\s*\)/
|
|
654
|
+
);
|
|
655
|
+
assert.match(createCompleteMain, /CreateAfterHookCallbackHdrSqs/);
|
|
656
|
+
|
|
657
|
+
execFileSync(
|
|
658
|
+
process.execPath,
|
|
659
|
+
[
|
|
660
|
+
'--check',
|
|
661
|
+
join(
|
|
662
|
+
rootPath,
|
|
663
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_Main.js'
|
|
664
|
+
)
|
|
665
|
+
],
|
|
666
|
+
{ stdio: 'inherit' }
|
|
667
|
+
);
|
|
668
|
+
|
|
640
669
|
const yaml = await readFile(
|
|
641
670
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-objects.yml'),
|
|
642
671
|
'utf8'
|
|
@@ -1293,6 +1322,72 @@ test('supports objType in generatedCodeConfig with string, array, and global hoo
|
|
|
1293
1322
|
assert.match(deleteMain, /hookPayload_globalDeleteHook/);
|
|
1294
1323
|
});
|
|
1295
1324
|
|
|
1325
|
+
test('omits autoProvisionOwnerTargetRole in CreateNodeCallback when service only has child RBAC objects', async () => {
|
|
1326
|
+
const rootPath = await createRbacProject(false, true);
|
|
1327
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1328
|
+
serviceTag: 'orders'
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
const callbackMain = await readFile(
|
|
1332
|
+
join(
|
|
1333
|
+
rootPath,
|
|
1334
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateNodeCallback_Main.js'
|
|
1335
|
+
),
|
|
1336
|
+
'utf8'
|
|
1337
|
+
);
|
|
1338
|
+
assert.doesNotMatch(callbackMain, /autoProvisionOwnerTargetRole\(_izContext/);
|
|
1339
|
+
|
|
1340
|
+
const logicalLib = await readFile(
|
|
1341
|
+
join(
|
|
1342
|
+
rootPath,
|
|
1343
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
1344
|
+
),
|
|
1345
|
+
'utf8'
|
|
1346
|
+
);
|
|
1347
|
+
assert.match(logicalLib, /const ROOT_RBAC_OBJECT_TYPES = new Set\(\[\s*\]\);/);
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
test('emits autoProvisionOwnerTargetRole in CreateNodeCallback when service has root RBAC object', async () => {
|
|
1351
|
+
const rootPath = await mkdtemp(
|
|
1352
|
+
join(tmpdir(), 'generate-service-code-v2-crud-root-rbac-')
|
|
1353
|
+
);
|
|
1354
|
+
roots.add(rootPath);
|
|
1355
|
+
const schemaRoot = join(rootPath, 'app/src/schemas');
|
|
1356
|
+
await mkdir(join(schemaRoot, 'ObjectSchemas'), { recursive: true });
|
|
1357
|
+
await mkdir(join(schemaRoot, 'FlowSchemas'), { recursive: true });
|
|
1358
|
+
await writeFile(
|
|
1359
|
+
join(schemaRoot, 'ObjectSchemas/Workspace.js'),
|
|
1360
|
+
"export default { objectType: 'workspace', generatedBy: 'user', addOnDataStructure: [{ type: 'rbac' }], storageResources: { graph: { storageType: 'graph' } } };\n"
|
|
1361
|
+
);
|
|
1362
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1363
|
+
serviceTag: 'workspaces'
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
const callbackMain = await readFile(
|
|
1367
|
+
join(
|
|
1368
|
+
rootPath,
|
|
1369
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateNodeCallback_Main.js'
|
|
1370
|
+
),
|
|
1371
|
+
'utf8'
|
|
1372
|
+
);
|
|
1373
|
+
assert.match(
|
|
1374
|
+
callbackMain,
|
|
1375
|
+
/await autoProvisionOwnerTargetRole\(_izContext,\s*\{\s*node,\s*submittedByUserId,\s*objType: returnValue\?\.requestParams\?\.objType\s*\}\);/
|
|
1376
|
+
);
|
|
1377
|
+
|
|
1378
|
+
const logicalLib = await readFile(
|
|
1379
|
+
join(
|
|
1380
|
+
rootPath,
|
|
1381
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
1382
|
+
),
|
|
1383
|
+
'utf8'
|
|
1384
|
+
);
|
|
1385
|
+
assert.match(
|
|
1386
|
+
logicalLib,
|
|
1387
|
+
/const ROOT_RBAC_OBJECT_TYPES = new Set\(\[\s*'workspace',\s*\]\);/
|
|
1388
|
+
);
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1296
1391
|
async function createProject(withCrudObject) {
|
|
1297
1392
|
const rootPath = await mkdtemp(
|
|
1298
1393
|
join(tmpdir(), 'generate-service-code-v2-crud-application-')
|
|
@@ -197,7 +197,7 @@ test('uses CreateNodeCallback step when Graph storage is present with sync RBAC'
|
|
|
197
197
|
'returnValue',
|
|
198
198
|
'parentFlowId',
|
|
199
199
|
'status',
|
|
200
|
-
'
|
|
200
|
+
'foundErrors',
|
|
201
201
|
'graphServiceTag'
|
|
202
202
|
]);
|
|
203
203
|
});
|
|
@@ -237,7 +237,7 @@ test('chains Start and Complete for Update with RBAC and Graph', async () => {
|
|
|
237
237
|
'returnValue',
|
|
238
238
|
'parentFlowId',
|
|
239
239
|
'status',
|
|
240
|
-
'
|
|
240
|
+
'foundErrors',
|
|
241
241
|
'graphServiceTag'
|
|
242
242
|
]);
|
|
243
243
|
});
|
|
@@ -67,8 +67,36 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
|
|
|
67
67
|
properties: ['returnResult'],
|
|
68
68
|
messageAttributes: []
|
|
69
69
|
});
|
|
70
|
-
assert.deepEqual(user.event, ['
|
|
71
|
-
assert.equal(user.
|
|
70
|
+
assert.deepEqual(user.event, ['lambdaSyncInv', 'lambdaSyncApi']);
|
|
71
|
+
assert.equal(user.initiateBy, 'systemWithUser');
|
|
72
|
+
assert.deepEqual(user.stepProperties, {
|
|
73
|
+
parentFlowId: {
|
|
74
|
+
propertyName: 'parentFlowId',
|
|
75
|
+
type: 'string'
|
|
76
|
+
},
|
|
77
|
+
flowTypeConcat: {
|
|
78
|
+
propertyName: 'flowTypeConcat',
|
|
79
|
+
type: 'string'
|
|
80
|
+
},
|
|
81
|
+
parameterGroups: {
|
|
82
|
+
propertyName: 'parameterGroups',
|
|
83
|
+
type: 'object'
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
assert.deepEqual(user.stepMessageAttributes, {
|
|
87
|
+
submittedByUserId: {
|
|
88
|
+
propertyName: 'x-correlation-submitted-by-user-id',
|
|
89
|
+
type: 'string'
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
assert.deepEqual(user.flowSteps[0].properties, [
|
|
93
|
+
{ key: 'parentFlowId', required: false },
|
|
94
|
+
{ key: 'flowTypeConcat', required: true },
|
|
95
|
+
{ key: 'parameterGroups', default: {} }
|
|
96
|
+
]);
|
|
97
|
+
assert.deepEqual(user.flowSteps[0].messageAttributes, [
|
|
98
|
+
{ key: 'submittedByUserId', required: false }
|
|
99
|
+
]);
|
|
72
100
|
|
|
73
101
|
const confirmUsage = await readGeneratedFlow(
|
|
74
102
|
rootPath,
|
|
@@ -98,7 +126,7 @@ test('removes RBAC schemas when the last RBAC object is removed', async () => {
|
|
|
98
126
|
await generateDynamicRbacFlowSchemas(rootPath, { serviceTag: 'UserAccount' });
|
|
99
127
|
await writeFile(
|
|
100
128
|
objectPath,
|
|
101
|
-
"export default { objectType: 'user', addOnDataStructure: [] };\n"
|
|
129
|
+
"export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: [] };\n"
|
|
102
130
|
);
|
|
103
131
|
|
|
104
132
|
const result = await generateDynamicRbacFlowSchemas(rootPath);
|
|
@@ -160,7 +188,7 @@ async function createProject({ hasRbac = false } = {}) {
|
|
|
160
188
|
await mkdir(objectDirectory, { recursive: true });
|
|
161
189
|
await writeFile(
|
|
162
190
|
join(objectDirectory, 'User.js'),
|
|
163
|
-
`export default { objectType: 'user', fieldNames: [], identifiers: [], addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
|
|
191
|
+
`export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
|
|
164
192
|
);
|
|
165
193
|
return rootPath;
|
|
166
194
|
}
|
|
@@ -115,7 +115,7 @@ test('emits relationship action and complete handlers with data-first function Y
|
|
|
115
115
|
);
|
|
116
116
|
assert.match(
|
|
117
117
|
createCompleteContent,
|
|
118
|
-
/const {\s*returnValue,\s*parentFlowId,\s*status,\s*
|
|
118
|
+
/const {\s*returnValue,\s*parentFlowId,\s*status,\s*foundErrors,\s*graphServiceTag\s*} = requestParams;/
|
|
119
119
|
);
|
|
120
120
|
assert.doesNotMatch(
|
|
121
121
|
createCompleteContent,
|
|
@@ -418,6 +418,48 @@ test('emits CreateNodeCallbackHdrSqs in FlowObjectsRole when object has graph an
|
|
|
418
418
|
assert.match(role, /CancelUsageHdrInv/);
|
|
419
419
|
});
|
|
420
420
|
|
|
421
|
+
test('emits correct permissions in FlowObjectsRole when object is child RBAC node with graph', async () => {
|
|
422
|
+
const rootPath = await createProject();
|
|
423
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
424
|
+
await rm(join(schemas, 'ObjectSchemas/Order.js'));
|
|
425
|
+
await writeFile(
|
|
426
|
+
join(schemas, 'ObjectSchemas/ChildNode.js'),
|
|
427
|
+
"export default { objectType: 'childNode', generatedBy: 'user', belongTo: [{ serviceTag: 'UserAccount', objectType: 'user' }], identifiers: [{ type: 'partitionKey', fieldName: 'childId' }], storageResources: { main: { storageType: 'graph', tableName: 'ChildNodes' } } };\n"
|
|
428
|
+
);
|
|
429
|
+
await generateResourceArtifacts(rootPath);
|
|
430
|
+
|
|
431
|
+
const iam = await readFile(
|
|
432
|
+
join(
|
|
433
|
+
rootPath,
|
|
434
|
+
'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
|
|
435
|
+
),
|
|
436
|
+
'utf8'
|
|
437
|
+
);
|
|
438
|
+
const role = roleBlock(iam, 'FlowObjectsRole');
|
|
439
|
+
assert.match(role, /CreateNodeCallbackHdrSqs/);
|
|
440
|
+
assert.match(role, /CreateNodeCallbackHdrSqsDLQ/);
|
|
441
|
+
assert.match(role, /ValidatorRbac_In/);
|
|
442
|
+
assert.match(role, /Rbac_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
|
|
443
|
+
assert.match(role, /UserAccount_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
|
|
444
|
+
assert.match(role, /ConfirmUsageHdrInv/);
|
|
445
|
+
assert.match(role, /CancelUsageHdrInv/);
|
|
446
|
+
assert.match(role, /UserAccount\$\{self:custom\.iz_stage\}ValidatorRbacHdrInv/);
|
|
447
|
+
// Child node service is not RBAC provider: no TargetRoles or Roles table in DynamoDB permissions
|
|
448
|
+
assert.doesNotMatch(role, /TargetRoles/);
|
|
449
|
+
assert.doesNotMatch(role, /RolePermissions/);
|
|
450
|
+
assert.doesNotMatch(iam, /FlowRbacRole:/);
|
|
451
|
+
|
|
452
|
+
const dynamo = await readFile(
|
|
453
|
+
join(
|
|
454
|
+
rootPath,
|
|
455
|
+
'resource/sls_yaml/generatedCode/source/generated-dynamoDB-table.yml'
|
|
456
|
+
),
|
|
457
|
+
'utf8'
|
|
458
|
+
);
|
|
459
|
+
assert.doesNotMatch(dynamo, /TargetRolesTable:/);
|
|
460
|
+
assert.doesNotMatch(dynamo, /RolesTable:/);
|
|
461
|
+
});
|
|
462
|
+
|
|
421
463
|
test('emits CreateAfterHookCallbackHdrSqs in SQS resources and FlowObjectsRole when flow has after hook with ownTopic', async () => {
|
|
422
464
|
const rootPath = await createProject();
|
|
423
465
|
const schemas = join(rootPath, 'app/src/schemas');
|