@izara_project/izara-core-generate-service-code 1.0.85 → 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.
- package/package.json +1 -1
- package/src/compile/compileProject.js +1 -2
- package/src/compile/loadSchemas.js +29 -17
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -0
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +15 -4
- package/src/emit/crud/emitCrudApplicationArtifacts.js +10 -4
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +10 -4
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +36 -4
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +35 -3
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +754 -353
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +5 -2
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +102 -6
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +34 -4
- package/src/emit/rbac/templates/DeleteTargetRole_Main.ejs +96 -0
- package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +106 -0
- package/src/emit/rbac/templates/GetTargetRole_Main.ejs +62 -0
- package/src/emit/rbac/templates/UpdateTargetRole_Main.ejs +107 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -12
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +12 -0
- package/src/emit/resource/emitResourceArtifacts.js +43 -2
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +4 -2
- package/src/emit/systemText/emitSystemTextSchemas.js +5 -2
- package/src/generate.js +18 -12
- package/src/generateResources/IntTest/generateResources/generateResources.js +1 -1
- package/src/generateResources/IntTest/generateTests/generateTemplate.js +1 -1
- package/src/generateResources/IntTest/upload/uploadIntTest.js +8 -2
- package/test/createTargetRoleHandler.test.js +42 -1
- package/test/crudApplicationArtifacts.test.js +53 -0
- package/test/dynamicRbacFlowSchemas.test.js +5 -2
- package/test/publicApi.test.js +18 -14
- package/test/resourceArtifacts.test.js +3 -0
|
@@ -52,7 +52,7 @@ async function _getL2Cache(_izContext, submittedByUserId, cacheSubKey) {
|
|
|
52
52
|
try {
|
|
53
53
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
54
54
|
const result = await dynamodbSharedLib.getItem(_izContext, tableName, {
|
|
55
|
-
submittedByUserId,
|
|
55
|
+
userId: submittedByUserId,
|
|
56
56
|
cacheKey: cacheSubKey
|
|
57
57
|
});
|
|
58
58
|
if (result && result.ttlTimestamp && result.ttlTimestamp > Math.floor(Date.now() / 1000)) {
|
|
@@ -77,7 +77,7 @@ async function _setL2Cache(_izContext, submittedByUserId, cacheSubKey, value) {
|
|
|
77
77
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
78
78
|
const ttlTimestamp = Math.floor(Date.now() / 1000) + L2_TTL_SECONDS;
|
|
79
79
|
await dynamodbSharedLib.putItem(_izContext, tableName, {
|
|
80
|
-
submittedByUserId,
|
|
80
|
+
userId: submittedByUserId,
|
|
81
81
|
cacheKey: cacheSubKey,
|
|
82
82
|
permission: value.returnValue ? value.returnValue.permission : value.permission,
|
|
83
83
|
roleIdKey: value.returnValue ? value.returnValue.roleIdKey : value.roleIdKey,
|
|
@@ -133,7 +133,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
133
133
|
throw new Error('Missing flowTypeConcat in requestParams');
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams
|
|
136
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:`, {
|
|
137
137
|
submittedByUserId,
|
|
138
138
|
targetId,
|
|
139
139
|
flowTypeConcat,
|
|
@@ -175,7 +175,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
175
175
|
// 1. Check L1 In-Memory Cache
|
|
176
176
|
const l1Hit = _getL1Cache(fullCacheKey);
|
|
177
177
|
if (l1Hit) {
|
|
178
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L1 Cache hit
|
|
178
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L1 Cache hit:`, l1Hit);
|
|
179
179
|
await _publicMessageOut(_izContext, { ...l1Hit, parentFlowId });
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
@@ -183,19 +183,19 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
183
183
|
// 2. Check L2 Shared DynamoDB Cache
|
|
184
184
|
const l2Hit = await _getL2Cache(_izContext, submittedByUserId, cacheSubKey);
|
|
185
185
|
if (l2Hit) {
|
|
186
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L2 Cache hit
|
|
186
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L2 Cache hit:`, l2Hit);
|
|
187
187
|
_setL1Cache(fullCacheKey, l2Hit);
|
|
188
188
|
await _publicMessageOut(_izContext, { ...l2Hit, parentFlowId });
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Cache miss — querying DynamoDB
|
|
192
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Cache miss — querying DynamoDB`);
|
|
193
193
|
|
|
194
194
|
// 3. Fallback to DB Query
|
|
195
195
|
const userRolesResult = await dynamodbSharedLib.query(
|
|
196
196
|
_izContext,
|
|
197
197
|
dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
198
|
-
{ submittedByUserId }
|
|
198
|
+
{ userId: submittedByUserId }
|
|
199
199
|
);
|
|
200
200
|
|
|
201
201
|
let userRoles = [];
|
|
@@ -205,7 +205,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
205
205
|
userRoles = userRolesResult.Items;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] userRoles fetched
|
|
208
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] userRoles fetched:`, { userRoles });
|
|
209
209
|
|
|
210
210
|
const targetIdPrefix = `${targetId}_`;
|
|
211
211
|
const targetRoles = [];
|
|
@@ -215,13 +215,13 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] targetRoles filtered
|
|
218
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] targetRoles filtered:`, {
|
|
219
219
|
targetIdPrefix,
|
|
220
220
|
targetRoles
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
if (targetRoles.length === 0) {
|
|
224
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] no targetRoles found, permission denied
|
|
224
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] no targetRoles found, permission denied`);
|
|
225
225
|
const result = {
|
|
226
226
|
returnValue: {
|
|
227
227
|
permission: false,
|
|
@@ -250,7 +250,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
250
250
|
})
|
|
251
251
|
);
|
|
252
252
|
|
|
253
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] rolePermissions fetched
|
|
253
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] rolePermissions fetched:`, {
|
|
254
254
|
rolePermissions
|
|
255
255
|
});
|
|
256
256
|
|
|
@@ -278,7 +278,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
278
278
|
status: 'Completed'
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] validation result
|
|
281
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] validation result:`, cacheResult);
|
|
282
282
|
|
|
283
283
|
// Store in L1 & L2 Cache
|
|
284
284
|
_setL1Cache(fullCacheKey, cacheResult);
|
|
@@ -26,6 +26,18 @@ import { sns } from '@izara_project/izara-core-library-external-request';
|
|
|
26
26
|
export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
27
27
|
try {
|
|
28
28
|
const { roleIdKey, userId } = requestParams;
|
|
29
|
+
<% if (operation === 'Delete') { -%>
|
|
30
|
+
if (roleIdKey && roleIdKey.endsWith('_owner')) {
|
|
31
|
+
const remainingUsers = await dynamodbSharedLib.query(
|
|
32
|
+
_izContext,
|
|
33
|
+
dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
|
|
34
|
+
{ roleIdKey }
|
|
35
|
+
);
|
|
36
|
+
if (remainingUsers?.Items?.length <= 1) {
|
|
37
|
+
throw new Error('Cannot remove the last remaining owner');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
<% } -%>
|
|
29
41
|
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
30
42
|
{
|
|
31
43
|
action: '<%- action %>',
|
|
@@ -31,14 +31,17 @@ const RELATIONSHIP_ACTIONS = [
|
|
|
31
31
|
];
|
|
32
32
|
const RBAC_ACTIONS = [
|
|
33
33
|
'CreateTargetRole',
|
|
34
|
-
'
|
|
34
|
+
'UpdateTargetRole',
|
|
35
35
|
'DeleteTargetRole',
|
|
36
|
+
'GetTargetRole',
|
|
37
|
+
'ListTargetRole',
|
|
36
38
|
'CreateRolePermissions',
|
|
37
39
|
'ListRolePermissions',
|
|
38
40
|
'DeleteRolePermissions',
|
|
39
41
|
'CreateUserRole',
|
|
40
42
|
'ListUserInRoles',
|
|
41
43
|
'DeleteUserFromRole',
|
|
44
|
+
'GetMyPermissions',
|
|
42
45
|
'ValidatorRbac',
|
|
43
46
|
'CreateRoleLimit',
|
|
44
47
|
'ListRoleLimits',
|
|
@@ -728,7 +731,10 @@ function roleStatements(state, roleName) {
|
|
|
728
731
|
addStatement(
|
|
729
732
|
statements,
|
|
730
733
|
['sns:Publish'],
|
|
731
|
-
|
|
734
|
+
[
|
|
735
|
+
...topicArns(roleTopicNames(state, roleName)),
|
|
736
|
+
...roleExternalTopicArns(state, roleName)
|
|
737
|
+
]
|
|
732
738
|
);
|
|
733
739
|
if (state.webSocketRoles.has(roleName)) {
|
|
734
740
|
statements.push({
|
|
@@ -766,6 +772,7 @@ function roleTableNames(state, roleName) {
|
|
|
766
772
|
...(state.rbac
|
|
767
773
|
? [
|
|
768
774
|
'TargetRoles',
|
|
775
|
+
'RolePermissions',
|
|
769
776
|
'RoleUsers',
|
|
770
777
|
'UserRoles',
|
|
771
778
|
'RoleLimit',
|
|
@@ -925,6 +932,9 @@ function roleTopicNames(state, roleName) {
|
|
|
925
932
|
topics.push(`${action}_In`, `${action}_Out`);
|
|
926
933
|
}
|
|
927
934
|
}
|
|
935
|
+
if (state.rbac) {
|
|
936
|
+
topics.push('ValidatorRbac_In');
|
|
937
|
+
}
|
|
928
938
|
return topics;
|
|
929
939
|
}
|
|
930
940
|
if (roleName === 'FlowRelationshipRole') {
|
|
@@ -937,6 +947,9 @@ function roleTopicNames(state, roleName) {
|
|
|
937
947
|
topics.push(`${action}_In`, `${action}_Out`);
|
|
938
948
|
}
|
|
939
949
|
}
|
|
950
|
+
if (state.rbac) {
|
|
951
|
+
topics.push('ValidatorRbac_In');
|
|
952
|
+
}
|
|
940
953
|
return topics;
|
|
941
954
|
}
|
|
942
955
|
if (roleName === 'FlowRbacRole') {
|
|
@@ -1023,6 +1036,34 @@ function roleExternalDynamoTables(state, roleName) {
|
|
|
1023
1036
|
return [];
|
|
1024
1037
|
}
|
|
1025
1038
|
|
|
1039
|
+
function roleExternalTopicArns(state, roleName) {
|
|
1040
|
+
if (!state.rbac) {
|
|
1041
|
+
return [];
|
|
1042
|
+
}
|
|
1043
|
+
const extraTags = getRbacValidatorServiceTags(state).filter(
|
|
1044
|
+
(tag) => tag && tag !== 'Rbac'
|
|
1045
|
+
);
|
|
1046
|
+
const extraTopics = extraTags.map(
|
|
1047
|
+
(tag) =>
|
|
1048
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ValidatorRbac_In`
|
|
1049
|
+
);
|
|
1050
|
+
if (roleName === 'FlowObjectsRole') {
|
|
1051
|
+
return [
|
|
1052
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
1053
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ConfirmUsage_In`,
|
|
1054
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_CancelUsage_In`,
|
|
1055
|
+
...extraTopics
|
|
1056
|
+
];
|
|
1057
|
+
}
|
|
1058
|
+
if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
|
|
1059
|
+
return [
|
|
1060
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
1061
|
+
...extraTopics
|
|
1062
|
+
];
|
|
1063
|
+
}
|
|
1064
|
+
return [];
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1026
1067
|
function queueArns(queueNames) {
|
|
1027
1068
|
return [...new Set(queueNames)]
|
|
1028
1069
|
.sort()
|
|
@@ -58,7 +58,8 @@ export function generatedLambdaRole() {
|
|
|
58
58
|
Resource: [
|
|
59
59
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
|
|
60
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')}`<%
|
|
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) { %>,
|
|
62
63
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
63
64
|
]
|
|
64
65
|
}<% } %>
|
|
@@ -77,7 +78,8 @@ export function generatedLambdaRole() {
|
|
|
77
78
|
Effect: 'Allow',
|
|
78
79
|
Action: ['sns:Publish'],
|
|
79
80
|
Resource: [
|
|
80
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}
|
|
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) { %>,
|
|
81
83
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
82
84
|
]
|
|
83
85
|
}
|
|
@@ -17,14 +17,17 @@ const RELATIONSHIP_ACTIONS = [
|
|
|
17
17
|
];
|
|
18
18
|
const RBAC_SHARED_FLOW_TAGS = [
|
|
19
19
|
'CreateTargetRole',
|
|
20
|
-
'
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
`[DEBUG] [Generate] STATUS=SCHEMAS_LOADED |
|
|
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
|
-
|
|
109
|
-
|
|
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
|
-
|
|
127
|
-
`[INFO] [Generate] STATUS=FINISHED |
|
|
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
|
-
|
|
133
|
-
`[ERROR] [Generate] STATUS=FAILED |
|
|
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
|
-
|
|
106
|
+
console.log(
|
|
107
107
|
'Error generating code with template propertyNode schema:',
|
|
108
108
|
error
|
|
109
109
|
);
|
|
@@ -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
|
-
|
|
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,
|
|
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(
|
|
@@ -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
|
-
'
|
|
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 = [
|
package/test/publicApi.test.js
CHANGED
|
@@ -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
|
|
60
|
+
test('generate logs its lifecycle through console.log', async () => {
|
|
61
61
|
const rootPath = await createCrudProject();
|
|
62
62
|
const messages = [];
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
])
|
|
68
|
-
);
|
|
63
|
+
const originalLog = console.log;
|
|
64
|
+
console.log = (...args) => {
|
|
65
|
+
messages.push(args.join(' '));
|
|
66
|
+
};
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
try {
|
|
69
|
+
await generate(rootPath);
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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 () => {
|
|
@@ -365,6 +365,9 @@ test('emits CreateNodeCallbackHdrSqs in FlowObjectsRole when object has graph an
|
|
|
365
365
|
const role = roleBlock(iam, 'FlowObjectsRole');
|
|
366
366
|
assert.match(role, /CreateNodeCallbackHdrSqs/);
|
|
367
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/);
|
|
368
371
|
});
|
|
369
372
|
|
|
370
373
|
function roleBlock(iam, roleName) {
|