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

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 (28) hide show
  1. package/package.json +1 -1
  2. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -1
  3. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +22 -15
  4. package/src/emit/crud/crudActionPlan.js +1 -1
  5. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +6 -4
  6. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +12 -3
  7. package/src/emit/crud/templates/CreateLogicalLib.ejs +85 -20
  8. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +12 -3
  9. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +12 -3
  10. package/src/emit/function/functionYamlArtifact.js +4 -2
  11. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +0 -3
  12. package/src/emit/rbac/emitRbacApplicationArtifacts.js +1 -116
  13. package/src/emit/rbac/templates/CancelUsage_Main.ejs +14 -10
  14. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +14 -10
  15. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +22 -12
  16. package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +14 -10
  17. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +76 -34
  18. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -9
  19. package/src/emit/resource/emitResourceArtifacts.js +32 -6
  20. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +14 -18
  21. package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +4 -2
  22. package/test/createTargetRoleHandler.test.js +1 -15
  23. package/test/crudApplicationArtifacts.test.js +9 -3
  24. package/test/customFlowApplicationArtifacts.test.js +3 -5
  25. package/test/dynamicCrudFlowSchemas.test.js +5 -17
  26. package/test/dynamicRbacFlowSchemas.test.js +0 -3
  27. package/test/functionYamlArtifact.test.js +4 -2
  28. package/test/resourceArtifacts.test.js +4 -3
@@ -28,21 +28,25 @@ export default async function CreateTargetRole(_izContext, requestParams) {
28
28
  _izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
29
29
 
30
30
  const targetIdentifiers = requestParams.targetIdentifiers;
31
- let identifiersConcat = requestParams.identifiersConcat;
31
+ let identifiersConcat =
32
+ requestParams.identifiersConcat || requestParams.identifierConcat;
32
33
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
33
- if (targetIdentifiers.identifierConcat) {
34
- identifiersConcat = targetIdentifiers.identifierConcat;
34
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
35
+ identifiersConcat =
36
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
35
37
  } else {
36
- const sortedKeys = Object.keys(targetIdentifiers).sort();
38
+ const sortedKeys = Object.keys(targetIdentifiers)
39
+ .filter(
40
+ (k) =>
41
+ k !== 'submittedByUserId' &&
42
+ k !== 'identifierConcat' &&
43
+ k !== 'identifiersConcat'
44
+ )
45
+ .sort();
37
46
  const parts = [];
38
47
  for (const key of sortedKeys) {
39
48
  const value = targetIdentifiers[key];
40
- if (
41
- key !== 'submittedByUserId' &&
42
- key !== 'identifierConcat' &&
43
- value !== undefined &&
44
- value !== null
45
- ) {
49
+ if (value !== undefined && value !== null) {
46
50
  parts.push(`${key}#${value}`);
47
51
  }
48
52
  }
@@ -61,7 +65,11 @@ export default async function CreateTargetRole(_izContext, requestParams) {
61
65
  permissions = [],
62
66
  assignUserIds = []
63
67
  } = requestParams;
64
- const roleId = inputRoleId || roleName || identifierUuid();
68
+ let defaultRoleId = identifierUuid();
69
+ if (roleName === 'owner') {
70
+ defaultRoleId = 'owner';
71
+ }
72
+ const roleId = inputRoleId || defaultRoleId;
65
73
  const roleIdKey = `${identifiersConcat}_${roleId}`;
66
74
 
67
75
  await dynamodbSharedLib.putItem(
@@ -70,8 +78,10 @@ export default async function CreateTargetRole(_izContext, requestParams) {
70
78
  {
71
79
  identifiersConcat,
72
80
  roleIdKey,
81
+ roleType: 'tenant_role',
73
82
  roleName,
74
- submittedByUserId
83
+ submittedByUserId,
84
+ createdAt: new Date().toISOString()
75
85
  }
76
86
  );
77
87
 
@@ -31,21 +31,25 @@ export default async function GetMyPermissions(_izContext, requestParams) {
31
31
  }
32
32
 
33
33
  const targetIdentifiers = requestParams.targetIdentifiers;
34
- let identifiersConcat = requestParams.identifiersConcat;
34
+ let identifiersConcat =
35
+ requestParams.identifiersConcat || requestParams.identifierConcat;
35
36
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
36
- if (targetIdentifiers.identifierConcat) {
37
- identifiersConcat = targetIdentifiers.identifierConcat;
37
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
38
+ identifiersConcat =
39
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
38
40
  } else {
39
- const sortedKeys = Object.keys(targetIdentifiers).sort();
41
+ const sortedKeys = Object.keys(targetIdentifiers)
42
+ .filter(
43
+ (k) =>
44
+ k !== 'submittedByUserId' &&
45
+ k !== 'identifierConcat' &&
46
+ k !== 'identifiersConcat'
47
+ )
48
+ .sort();
40
49
  const parts = [];
41
50
  for (const key of sortedKeys) {
42
51
  const value = targetIdentifiers[key];
43
- if (
44
- key !== 'submittedByUserId' &&
45
- key !== 'identifierConcat' &&
46
- value !== undefined &&
47
- value !== null
48
- ) {
52
+ if (value !== undefined && value !== null) {
49
53
  parts.push(`${key}#${value}`);
50
54
  }
51
55
  }
@@ -35,21 +35,25 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
35
35
  } = requestParams;
36
36
 
37
37
  const targetIdentifiers = requestParams.targetIdentifiers;
38
- let identifiersConcat = requestParams.identifiersConcat;
38
+ let identifiersConcat =
39
+ requestParams.identifiersConcat || requestParams.identifierConcat;
39
40
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
40
- if (targetIdentifiers.identifierConcat) {
41
- identifiersConcat = targetIdentifiers.identifierConcat;
41
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
42
+ identifiersConcat =
43
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
42
44
  } else {
43
- const sortedKeys = Object.keys(targetIdentifiers).sort();
45
+ const sortedKeys = Object.keys(targetIdentifiers)
46
+ .filter(
47
+ (k) =>
48
+ k !== 'submittedByUserId' &&
49
+ k !== 'identifierConcat' &&
50
+ k !== 'identifiersConcat'
51
+ )
52
+ .sort();
44
53
  const parts = [];
45
54
  for (const key of sortedKeys) {
46
55
  const value = targetIdentifiers[key];
47
- if (
48
- key !== 'submittedByUserId' &&
49
- key !== 'identifierConcat' &&
50
- value !== undefined &&
51
- value !== null
52
- ) {
56
+ if (value !== undefined && value !== null) {
53
57
  parts.push(`${key}#${value}`);
54
58
  }
55
59
  }
@@ -70,41 +74,79 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
70
74
  }
71
75
 
72
76
  const uniqueIdentify = `${usedTimestamp}_${_izContext.uniqueRequestId || Date.now()}`;
73
- const roleLimitKeys = Array.isArray(requestParams.roleLimitIds)
74
- ? requestParams.roleLimitIds
75
- : [roleLimitId || `${identifiersConcat}_${flowTypeConcat}`];
76
77
 
77
- let maxLimit = Infinity;
78
- const limitRecords = [];
79
-
80
- for (const key of roleLimitKeys) {
81
- const record = await dynamodbSharedLib.getItem(
78
+ let targetPlanTier = requestParams.planTier || null;
79
+ if (!targetPlanTier && identifiersConcat) {
80
+ const targetRolesResult = await dynamodbSharedLib.query(
82
81
  _izContext,
83
- dynamodbSharedLib.tableName(_izContext, 'RoleLimit'),
84
- { roleLimitId: key, limitType: 'runningTotal' }
82
+ dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
83
+ { identifiersConcat }
85
84
  );
86
- if (record && typeof record.limitValue === 'number') {
87
- limitRecords.push(record);
85
+ let targetRoleItems = [];
86
+ if (Array.isArray(targetRolesResult)) {
87
+ targetRoleItems = targetRolesResult;
88
+ } else if (targetRolesResult && targetRolesResult.Items) {
89
+ targetRoleItems = targetRolesResult.Items;
90
+ }
91
+ for (const roleItem of targetRoleItems) {
92
+ if (roleItem.roleType === 'plan_tier') {
93
+ targetPlanTier = roleItem.roleIdKey;
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ if (!targetPlanTier) {
99
+ targetPlanTier = 'tier-free';
100
+ }
101
+
102
+ const limitRecords = [];
103
+ const tierPermission = await dynamodbSharedLib.getItem(
104
+ _izContext,
105
+ dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
106
+ { roleIdKey: targetPlanTier, flowTypeConcat }
107
+ );
108
+ if (tierPermission && typeof tierPermission.limitValue === 'number') {
109
+ limitRecords.push(tierPermission);
110
+ }
111
+
112
+ if (Array.isArray(requestParams.roleIdKeys)) {
113
+ for (const rKey of requestParams.roleIdKeys) {
114
+ const perm = await dynamodbSharedLib.getItem(
115
+ _izContext,
116
+ dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
117
+ { roleIdKey: rKey, flowTypeConcat }
118
+ );
119
+ if (perm && typeof perm.limitValue === 'number') {
120
+ limitRecords.push(perm);
121
+ }
88
122
  }
89
123
  }
90
124
 
125
+ let maxLimit = Infinity;
91
126
  if (limitRecords.length > 0) {
92
- const isDecrease = (rec) =>
93
- rec.effect === 'decrease' ||
94
- rec.actionType === 'decrease' ||
95
- rec.action === 'decrease';
127
+ const isDecrease = function (rec) {
128
+ if (
129
+ rec.effect === 'decrease' ||
130
+ rec.actionType === 'decrease' ||
131
+ rec.action === 'decrease'
132
+ ) {
133
+ return true;
134
+ }
135
+ return false;
136
+ };
96
137
 
97
138
  const increaseLimits = limitRecords.filter((rec) => !isDecrease(rec));
98
139
  const decreaseLimits = limitRecords.filter((rec) => isDecrease(rec));
99
140
 
100
- const maxIncrease =
101
- increaseLimits.length > 0
102
- ? Math.max(...increaseLimits.map((r) => r.limitValue))
103
- : Infinity;
104
- const minDecrease =
105
- decreaseLimits.length > 0
106
- ? Math.min(...decreaseLimits.map((r) => r.limitValue))
107
- : Infinity;
141
+ let maxIncrease = Infinity;
142
+ if (increaseLimits.length > 0) {
143
+ maxIncrease = Math.max(...increaseLimits.map((r) => r.limitValue));
144
+ }
145
+
146
+ let minDecrease = Infinity;
147
+ if (decreaseLimits.length > 0) {
148
+ minDecrease = Math.min(...decreaseLimits.map((r) => r.limitValue));
149
+ }
108
150
 
109
151
  maxLimit = Math.min(maxIncrease, minDecrease);
110
152
  }
@@ -101,19 +101,22 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
101
101
  if (typeof targetIdentifiers === 'string') {
102
102
  targetId = targetIdentifiers;
103
103
  } else if (typeof targetIdentifiers === 'object') {
104
- if (targetIdentifiers.identifierConcat) {
105
- targetId = targetIdentifiers.identifierConcat;
104
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
105
+ targetId =
106
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
106
107
  } else {
107
- const sortedKeys = Object.keys(targetIdentifiers).sort();
108
+ const sortedKeys = Object.keys(targetIdentifiers)
109
+ .filter(
110
+ (k) =>
111
+ k !== 'submittedByUserId' &&
112
+ k !== 'identifierConcat' &&
113
+ k !== 'identifiersConcat'
114
+ )
115
+ .sort();
108
116
  const parts = [];
109
117
  for (const key of sortedKeys) {
110
118
  const value = targetIdentifiers[key];
111
- if (
112
- key !== 'submittedByUserId' &&
113
- key !== 'identifierConcat' &&
114
- value !== undefined &&
115
- value !== null
116
- ) {
119
+ if (value !== undefined && value !== null) {
117
120
  parts.push(`${key}#${value}`);
118
121
  }
119
122
  }
@@ -43,9 +43,6 @@ const RBAC_ACTIONS = [
43
43
  'DeleteUserFromRole',
44
44
  'GetMyPermissions',
45
45
  'ValidatorRbac',
46
- 'CreateRoleLimit',
47
- 'ListRoleLimits',
48
- 'DeleteRoleLimit',
49
46
  'ReservedDynamicUsage',
50
47
  'ConfirmUsage',
51
48
  'CancelUsage'
@@ -62,12 +59,12 @@ const SYSTEM_TABLES = [
62
59
  'AwaitingStep'
63
60
  ];
64
61
  const RBAC_TABLES = [
62
+ 'Roles',
65
63
  'TargetRoles',
66
64
  'RolePermissions',
67
65
  'RoleUsers',
68
66
  'UserRoles',
69
67
  'RbacPermissionCaches',
70
- 'RoleLimit',
71
68
  'RunningTotalUsage',
72
69
  'RunningTotalReservedUsage',
73
70
  'WebSocketTask'
@@ -417,12 +414,12 @@ function createResourceState({ objects, relationships, flows }) {
417
414
  const systemTables = [...SYSTEM_TABLES];
418
415
  if (rbac) {
419
416
  systemTables.push(
417
+ 'Roles',
420
418
  'TargetRoles',
421
419
  'RolePermissions',
422
420
  'RoleUsers',
423
421
  'UserRoles',
424
422
  'RbacPermissionCaches',
425
- 'RoleLimit',
426
423
  'RunningTotalUsage',
427
424
  'RunningTotalReservedUsage'
428
425
  );
@@ -736,6 +733,11 @@ function roleStatements(state, roleName) {
736
733
  ...roleExternalTopicArns(state, roleName)
737
734
  ]
738
735
  );
736
+ addStatement(
737
+ statements,
738
+ ['lambda:InvokeFunction'],
739
+ roleExternalLambdaArns(state, roleName)
740
+ );
739
741
  if (state.webSocketRoles.has(roleName)) {
740
742
  statements.push({
741
743
  action: ['execute-api:ManageConnections'],
@@ -771,11 +773,11 @@ function roleTableNames(state, roleName) {
771
773
  'WebSocketTask',
772
774
  ...(state.rbac
773
775
  ? [
776
+ 'Roles',
774
777
  'TargetRoles',
775
778
  'RolePermissions',
776
779
  'RoleUsers',
777
780
  'UserRoles',
778
- 'RoleLimit',
779
781
  'RunningTotalUsage',
780
782
  'RunningTotalReservedUsage'
781
783
  ]
@@ -1064,6 +1066,30 @@ function roleExternalTopicArns(state, roleName) {
1064
1066
  return [];
1065
1067
  }
1066
1068
 
1069
+ function roleExternalLambdaArns(state, roleName) {
1070
+ if (!state.rbac) {
1071
+ return [];
1072
+ }
1073
+ const extraTags = getRbacValidatorServiceTags(state).filter(
1074
+ (tag) => tag && tag !== 'Rbac'
1075
+ );
1076
+ const extraLambdas = extraTags.map(
1077
+ (tag) =>
1078
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`
1079
+ );
1080
+ if (
1081
+ roleName === 'FlowObjectsRole' ||
1082
+ roleName === 'FlowRbacRole' ||
1083
+ roleName === 'FlowRelationshipRole'
1084
+ ) {
1085
+ return [
1086
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
1087
+ ...extraLambdas
1088
+ ];
1089
+ }
1090
+ return [];
1091
+ }
1092
+
1067
1093
  function queueArns(queueNames) {
1068
1094
  return [...new Set(queueNames)]
1069
1095
  .sort()
@@ -138,6 +138,18 @@ Resources:
138
138
  KeyType: RANGE
139
139
 
140
140
  <% if (hasRbac) { %>
141
+ RolesTable:
142
+ Type: 'AWS::DynamoDB::Table'
143
+ Properties:
144
+ TableName: ${self:custom.iz_resourcePrefix}Roles
145
+ BillingMode: PAY_PER_REQUEST
146
+ AttributeDefinitions:
147
+ - AttributeName: roleIdKey
148
+ AttributeType: S
149
+ KeySchema:
150
+ - AttributeName: roleIdKey
151
+ KeyType: HASH
152
+
141
153
  TargetRolesTable:
142
154
  Type: 'AWS::DynamoDB::Table'
143
155
  Properties:
@@ -221,22 +233,6 @@ Resources:
221
233
  AttributeName: ttlTimestamp
222
234
  Enabled: true
223
235
 
224
- RoleLimitTable:
225
- Type: 'AWS::DynamoDB::Table'
226
- Properties:
227
- TableName: ${self:custom.iz_resourcePrefix}RoleLimit
228
- BillingMode: PAY_PER_REQUEST
229
- AttributeDefinitions:
230
- - AttributeName: roleLimitId
231
- AttributeType: S
232
- - AttributeName: limitType
233
- AttributeType: S
234
- KeySchema:
235
- - AttributeName: roleLimitId
236
- KeyType: HASH
237
- - AttributeName: limitType
238
- KeyType: RANGE
239
-
240
236
  RunningTotalUsageTable:
241
237
  Type: 'AWS::DynamoDB::Table'
242
238
  Properties:
@@ -245,12 +241,12 @@ Resources:
245
241
  AttributeDefinitions:
246
242
  - AttributeName: identifiersConcat
247
243
  AttributeType: S
248
- - AttributeName: limitTag
244
+ - AttributeName: flowTypeConcat
249
245
  AttributeType: S
250
246
  KeySchema:
251
247
  - AttributeName: identifiersConcat
252
248
  KeyType: HASH
253
- - AttributeName: limitTag
249
+ - AttributeName: flowTypeConcat
254
250
  KeyType: RANGE
255
251
 
256
252
  RunningTotalReservedUsageTable:
@@ -16,6 +16,8 @@ WebSocketCompleteHdrSqs:
16
16
  - body:
17
17
  MessageAttributes:
18
18
  callingFlow:
19
- Value:
20
- - exists: false
19
+ - exists: false
20
+ - body:
21
+ MessageAttributes:
22
+ - exists: false
21
23
  #<#/WebSocketCompleteHdrSqsFilterPatterns#>
@@ -15,16 +15,12 @@ const OWN_TOPIC_FLOWS = [
15
15
  'DeleteTargetRole',
16
16
  'CreateUserRole',
17
17
  'DeleteUserFromRole',
18
- 'CreateRoleLimit',
19
- 'DeleteRoleLimit',
20
18
  'ReservedDynamicUsage',
21
19
  'ConfirmUsage',
22
20
  'CancelUsage'
23
21
  ];
24
22
 
25
23
  const LIMIT_FLOWS = [
26
- 'CreateRoleLimit',
27
- 'DeleteRoleLimit',
28
24
  'ReservedDynamicUsage',
29
25
  'ConfirmUsage',
30
26
  'CancelUsage'
@@ -40,7 +36,7 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
40
36
  const rootPath = await createProject(true);
41
37
  const result = await generateCreateTargetRoleHandler(rootPath);
42
38
 
43
- assert.equal(result.files.length, 70);
39
+ assert.equal(result.files.length, 59);
44
40
  assert.match(
45
41
  await readFile(join(rootPath, result.files[0].path), 'utf8'),
46
42
  /CreateTargetRole/
@@ -130,16 +126,6 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
130
126
  ),
131
127
  /Math\.min\(maxIncrease, minDecrease\)/
132
128
  );
133
- assert.match(
134
- await readFile(
135
- join(
136
- rootPath,
137
- 'app/src/generatedCode/FlowLimit/CreateRoleLimit/source/CreateRoleLimit_Main.js'
138
- ),
139
- 'utf8'
140
- ),
141
- /actionType/
142
- );
143
129
  const rbacYaml = await readFile(
144
130
  join(rootPath, 'app/sls_yaml/generatedCode/source/flow-rbac.yml'),
145
131
  'utf8'
@@ -239,7 +239,7 @@ test('emits a single Complete RBAC handler for Update without Graph', async () =
239
239
  );
240
240
  });
241
241
 
242
- test('emits RbacCallback and Complete handlers for Update with Graph', async () => {
242
+ test('emits Complete handlers and inlines sync RBAC for Update with Graph', async () => {
243
243
  const rootPath = await createRbacProject(false, true);
244
244
  const result = await generateCrudApplicationArtifacts(rootPath, {
245
245
  serviceTag: 'orders'
@@ -248,19 +248,25 @@ test('emits RbacCallback and Complete handlers for Update with Graph', async ()
248
248
  .map((file) => file.path)
249
249
  .filter((path) => path.includes('/FlowObjects/Update/source/'));
250
250
 
251
- assert.ok(updatePaths.includes(
251
+ assert.ok(!updatePaths.includes(
252
252
  'app/src/generatedCode/FlowObjects/Update/source/UpdateRbacCallback_Main.js'
253
253
  ));
254
254
  assert.ok(updatePaths.includes(
255
255
  'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
256
256
  ));
257
+ const updateMainContent = await readFile(
258
+ join(rootPath, 'app/src/generatedCode/FlowObjects/Update/source/Update_Main.js'),
259
+ 'utf8'
260
+ );
261
+ assert.match(updateMainContent, /checkRbacPermission/);
262
+ assert.match(updateMainContent, /sync: true/);
257
263
  execFileSync(
258
264
  process.execPath,
259
265
  [
260
266
  '--check',
261
267
  join(
262
268
  rootPath,
263
- 'app/src/generatedCode/FlowObjects/Update/source/UpdateRbacCallback_Main.js'
269
+ 'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
264
270
  )
265
271
  ],
266
272
  { stdio: 'inherit' }
@@ -895,7 +895,7 @@ test('registers SQS queue, SNS subscription, and SNS out topic for custom flowSc
895
895
  );
896
896
  });
897
897
 
898
- test('renders RBAC Validator subscriptions in InitialSetupConfig when object has belongTo to external RBAC service', async () => {
898
+ test('uses synchronous RBAC without obsolete callback SQS subscriptions in InitialSetupConfig', async () => {
899
899
  const rootPath = await createProject();
900
900
  await writeFile(
901
901
  join(rootPath, 'app/src/schemas/ObjectSchemas/Member.js'),
@@ -920,10 +920,8 @@ test('renders RBAC Validator subscriptions in InitialSetupConfig when object has
920
920
  ),
921
921
  'utf8'
922
922
  );
923
- assert.match(initialSetupConfigContent, /serviceTag: 'UserAccount'/);
924
- assert.match(initialSetupConfigContent, /topicName: 'ValidatorRbac_Out'/);
925
- assert.match(initialSetupConfigContent, /sqsEndpoint: 'UpdateRbacCallbackHdrSqs'/);
926
- assert.match(initialSetupConfigContent, /sqsEndpoint: 'DeleteRbacCallbackHdrSqs'/);
923
+ assert.doesNotMatch(initialSetupConfigContent, /sqsEndpoint: 'UpdateRbacCallbackHdrSqs'/);
924
+ assert.doesNotMatch(initialSetupConfigContent, /sqsEndpoint: 'DeleteRbacCallbackHdrSqs'/);
927
925
  });
928
926
 
929
927
  test('deduplicates duplicate nextSteps topics across flowSteps in InitialSetupConfig', async () => {
@@ -142,7 +142,7 @@ test('generates a direct Complete step for RBAC-only Update flows', async () =>
142
142
  assert.equal(update.flowSteps[1].properties.length, 0);
143
143
  });
144
144
 
145
- test('generates RbacCallback and Complete for Create when RBAC and Graph are present', async () => {
145
+ test('generates CreateNodeCallback and Complete for Create when RBAC and Graph are present', async () => {
146
146
  const rootPath = await createProject({
147
147
  generatedBy: 'user',
148
148
  });
@@ -160,13 +160,12 @@ test('generates RbacCallback and Complete for Create when RBAC and Graph are pre
160
160
  const create = await readGeneratedFlow(rootPath, 'Create');
161
161
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
162
162
  'Start',
163
- 'RbacCallback',
164
163
  'CreateNodeCallback',
165
164
  'Complete'
166
165
  ]);
167
166
  });
168
167
 
169
- test('uses the renamed RBAC callback step when Graph storage is present', async () => {
168
+ test('uses CreateNodeCallback step when Graph storage is present with sync RBAC', async () => {
170
169
  const rootPath = await mkdtemp(
171
170
  join(tmpdir(), 'generate-service-code-v2-crud-rbac-graph-')
172
171
  );
@@ -186,11 +185,10 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
186
185
  const create = await readGeneratedFlow(rootPath, 'Create');
187
186
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
188
187
  'Start',
189
- 'RbacCallback',
190
188
  'CreateNodeCallback',
191
189
  'Complete'
192
190
  ]);
193
- assert.deepEqual(create.flowSteps[2].properties, [
191
+ assert.deepEqual(create.flowSteps[1].properties, [
194
192
  'returnValue',
195
193
  'parentFlowId',
196
194
  'status',
@@ -199,7 +197,7 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
199
197
  ]);
200
198
  });
201
199
 
202
- test('chains RbacCallback and Complete for Update with RBAC and Graph', async () => {
200
+ test('chains Start and Complete for Update with RBAC and Graph', async () => {
203
201
  const rootPath = await mkdtemp(
204
202
  join(tmpdir(), 'generate-service-code-v2-crud-update-rbac-graph-')
205
203
  );
@@ -219,19 +217,9 @@ test('chains RbacCallback and Complete for Update with RBAC and Graph', async ()
219
217
  const update = await readGeneratedFlow(rootPath, 'Update');
220
218
  assert.deepEqual(update.flowSteps.map((step) => step.stepName), [
221
219
  'Start',
222
- 'RbacCallback',
223
220
  'Complete'
224
221
  ]);
225
222
  assert.deepEqual(update.flowSteps[0].nextSteps, [
226
- { targetType: 'ownTopic', stepName: 'RbacCallback' },
227
- {
228
- targetType: 'extTopic',
229
- serviceTag: 'Rbac',
230
- topicName: 'ValidatorRbac_In',
231
- toStepNames: ['RbacCallback']
232
- }
233
- ]);
234
- assert.deepEqual(update.flowSteps[1].nextSteps, [
235
223
  { targetType: 'ownTopic', stepName: 'Complete' },
236
224
  {
237
225
  targetType: 'extTopic',
@@ -240,7 +228,7 @@ test('chains RbacCallback and Complete for Update with RBAC and Graph', async ()
240
228
  toStepNames: ['Complete']
241
229
  }
242
230
  ]);
243
- assert.deepEqual(update.flowSteps[2].properties, [
231
+ assert.deepEqual(update.flowSteps[1].properties, [
244
232
  'returnValue',
245
233
  'parentFlowId',
246
234
  'status',
@@ -24,9 +24,6 @@ const STATIC_RBAC_ACTIONS = [
24
24
  ];
25
25
 
26
26
  const STATIC_LIMIT_ACTIONS = [
27
- 'CreateRoleLimit',
28
- 'ListRoleLimits',
29
- 'DeleteRoleLimit',
30
27
  'ReservedDynamicUsage',
31
28
  'ConfirmUsage',
32
29
  'CancelUsage'
@@ -83,12 +83,14 @@ test('filters all SQS functions by their calling flow', () => {
83
83
  /#<#CreateCompleteHdrSqsFilterPatterns#>[\s\S]*filterPatterns:[\s\S]*\$\{self:custom\.iz_resourcePrefix\}CreateCompleteHdrSqs/
84
84
  );
85
85
  assert.match(completion, /#<#\/CreateCompleteHdrSqsFilterPatterns#>/);
86
- assert.match(completion, /exists: false/);
86
+ assert.match(completion, /callingFlow:\s*\n\s*- exists: false/);
87
+ assert.match(completion, /MessageAttributes:\s*\n\s*- exists: false/);
87
88
  assert.match(
88
89
  ordinary,
89
90
  /#<#CreateHdrSqsFilterPatterns#>[\s\S]*filterPatterns:[\s\S]*\$\{self:custom\.iz_resourcePrefix\}CreateHdrSqs/
90
91
  );
91
92
  assert.match(ordinary, /#<#\/CreateHdrSqsFilterPatterns#>/);
92
- assert.match(ordinary, /exists: false/);
93
+ assert.match(ordinary, /callingFlow:\s*\n\s*- exists: false/);
94
+ assert.match(ordinary, /MessageAttributes:\s*\n\s*- exists: false/);
93
95
  });
94
96
 
@@ -76,8 +76,9 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
76
76
  assert.match(dynamoYaml, /OrdersTable:/);
77
77
  assert.match(dynamoYaml, /#<#OrdersTableSetting#>/);
78
78
  assert.match(dynamoYaml, /#<#\/OrdersTableSetting#>/);
79
+ assert.match(dynamoYaml, /RolesTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}Roles/);
79
80
  assert.match(dynamoYaml, /TargetRolesTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+AttributeName: identifiersConcat/);
80
- assert.match(dynamoYaml, /RoleLimitTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RoleLimit/);
81
+ assert.doesNotMatch(dynamoYaml, /RoleLimitTable:/);
81
82
  assert.match(dynamoYaml, /RunningTotalUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalUsage/);
82
83
  assert.match(dynamoYaml, /RunningTotalReservedUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalReservedUsage/);
83
84
  const iam = await readFile(
@@ -108,9 +109,9 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
108
109
  roleBlock(iam, 'FlowRbacRole'),
109
110
  /RolePermissions|ProcessCreateTargetRoleHdrSqs/
110
111
  );
111
- assert.match(roleBlock(iam, 'FlowRbacRole'), /RoleLimit/);
112
+ assert.doesNotMatch(roleBlock(iam, 'FlowRbacRole'), /RoleLimit/);
112
113
  assert.match(roleBlock(iam, 'FlowRbacRole'), /RunningTotalUsage/);
113
- assert.match(roleBlock(iam, 'FlowObjectsRole'), /RoleLimit/);
114
+ assert.doesNotMatch(roleBlock(iam, 'FlowObjectsRole'), /RoleLimit/);
114
115
  // Per-object RBAC flow queue (e.g. ValidatorRbacHdrSqs from Order with rbac add-on)
115
116
  assert.match(roleBlock(iam, 'FlowRbacRole'), /ValidatorRbacHdrSqs/);
116
117