@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.41

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 (198) hide show
  1. package/frigg-cli/.eslintrc.js +141 -0
  2. package/frigg-cli/__tests__/jest.config.js +102 -0
  3. package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
  4. package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
  5. package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
  6. package/frigg-cli/__tests__/utils/command-tester.js +170 -0
  7. package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
  8. package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
  9. package/frigg-cli/__tests__/utils/test-setup.js +286 -0
  10. package/frigg-cli/build-command/index.js +54 -0
  11. package/frigg-cli/deploy-command/index.js +175 -0
  12. package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
  13. package/frigg-cli/generate-command/azure-generator.js +43 -0
  14. package/frigg-cli/generate-command/gcp-generator.js +47 -0
  15. package/frigg-cli/generate-command/index.js +332 -0
  16. package/frigg-cli/generate-command/terraform-generator.js +555 -0
  17. package/frigg-cli/generate-iam-command.js +115 -0
  18. package/frigg-cli/index.js +47 -1
  19. package/frigg-cli/index.test.js +1 -4
  20. package/frigg-cli/init-command/backend-first-handler.js +756 -0
  21. package/frigg-cli/init-command/index.js +93 -0
  22. package/frigg-cli/init-command/template-handler.js +143 -0
  23. package/frigg-cli/install-command/index.js +1 -4
  24. package/frigg-cli/package.json +51 -0
  25. package/frigg-cli/start-command/index.js +30 -4
  26. package/frigg-cli/start-command/start-command.test.js +155 -0
  27. package/frigg-cli/test/init-command.test.js +180 -0
  28. package/frigg-cli/test/npm-registry.test.js +319 -0
  29. package/frigg-cli/ui-command/index.js +154 -0
  30. package/frigg-cli/utils/app-resolver.js +319 -0
  31. package/frigg-cli/utils/backend-path.js +16 -17
  32. package/frigg-cli/utils/npm-registry.js +167 -0
  33. package/frigg-cli/utils/process-manager.js +199 -0
  34. package/frigg-cli/utils/repo-detection.js +405 -0
  35. package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
  36. package/infrastructure/GENERATE-IAM-DOCS.md +278 -0
  37. package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
  38. package/infrastructure/README.md +443 -0
  39. package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
  40. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
  41. package/infrastructure/__tests__/helpers/test-utils.js +277 -0
  42. package/infrastructure/aws-discovery.js +1176 -0
  43. package/infrastructure/aws-discovery.test.js +1220 -0
  44. package/infrastructure/build-time-discovery.js +206 -0
  45. package/infrastructure/build-time-discovery.test.js +378 -0
  46. package/infrastructure/create-frigg-infrastructure.js +3 -5
  47. package/infrastructure/env-validator.js +77 -0
  48. package/infrastructure/frigg-deployment-iam-stack.yaml +401 -0
  49. package/infrastructure/iam-generator.js +836 -0
  50. package/infrastructure/iam-generator.test.js +172 -0
  51. package/infrastructure/iam-policy-basic.json +218 -0
  52. package/infrastructure/iam-policy-full.json +288 -0
  53. package/infrastructure/integration.test.js +383 -0
  54. package/infrastructure/run-discovery.js +110 -0
  55. package/infrastructure/serverless-template.js +1493 -138
  56. package/infrastructure/serverless-template.test.js +1804 -0
  57. package/management-ui/.eslintrc.js +22 -0
  58. package/management-ui/README.md +203 -0
  59. package/management-ui/components.json +21 -0
  60. package/management-ui/docs/phase2-integration-guide.md +320 -0
  61. package/management-ui/index.html +13 -0
  62. package/management-ui/package-lock.json +16517 -0
  63. package/management-ui/package.json +76 -0
  64. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  65. package/management-ui/postcss.config.js +6 -0
  66. package/management-ui/server/api/backend.js +256 -0
  67. package/management-ui/server/api/cli.js +315 -0
  68. package/management-ui/server/api/codegen.js +663 -0
  69. package/management-ui/server/api/connections.js +857 -0
  70. package/management-ui/server/api/discovery.js +185 -0
  71. package/management-ui/server/api/environment/index.js +1 -0
  72. package/management-ui/server/api/environment/router.js +378 -0
  73. package/management-ui/server/api/environment.js +328 -0
  74. package/management-ui/server/api/integrations.js +876 -0
  75. package/management-ui/server/api/logs.js +248 -0
  76. package/management-ui/server/api/monitoring.js +282 -0
  77. package/management-ui/server/api/open-ide.js +31 -0
  78. package/management-ui/server/api/project.js +1029 -0
  79. package/management-ui/server/api/users/sessions.js +371 -0
  80. package/management-ui/server/api/users/simulation.js +254 -0
  81. package/management-ui/server/api/users.js +362 -0
  82. package/management-ui/server/api-contract.md +275 -0
  83. package/management-ui/server/index.js +873 -0
  84. package/management-ui/server/middleware/errorHandler.js +93 -0
  85. package/management-ui/server/middleware/security.js +32 -0
  86. package/management-ui/server/processManager.js +296 -0
  87. package/management-ui/server/server.js +346 -0
  88. package/management-ui/server/services/aws-monitor.js +413 -0
  89. package/management-ui/server/services/npm-registry.js +347 -0
  90. package/management-ui/server/services/template-engine.js +538 -0
  91. package/management-ui/server/utils/cliIntegration.js +220 -0
  92. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  93. package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
  94. package/management-ui/server/utils/environment/encryption.js +278 -0
  95. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  96. package/management-ui/server/utils/import-commonjs.js +28 -0
  97. package/management-ui/server/utils/response.js +83 -0
  98. package/management-ui/server/websocket/handler.js +325 -0
  99. package/management-ui/src/App.jsx +109 -0
  100. package/management-ui/src/assets/FriggLogo.svg +1 -0
  101. package/management-ui/src/components/AppRouter.jsx +65 -0
  102. package/management-ui/src/components/Button.jsx +70 -0
  103. package/management-ui/src/components/Card.jsx +97 -0
  104. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  105. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  106. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  107. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  108. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  109. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  110. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  111. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  112. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  113. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  114. package/management-ui/src/components/Layout.jsx +716 -0
  115. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  116. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  117. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  118. package/management-ui/src/components/StatusBadge.jsx +208 -0
  119. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  120. package/management-ui/src/components/UserSimulation.jsx +327 -0
  121. package/management-ui/src/components/Welcome.jsx +434 -0
  122. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  123. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  124. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  125. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  126. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  127. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  128. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  129. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  130. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  131. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  132. package/management-ui/src/components/codegen/index.js +10 -0
  133. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  134. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  135. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  136. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  137. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  138. package/management-ui/src/components/connections/index.js +5 -0
  139. package/management-ui/src/components/index.js +21 -0
  140. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  141. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  142. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  143. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  144. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  145. package/management-ui/src/components/monitoring/index.js +6 -0
  146. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  147. package/management-ui/src/components/theme-provider.jsx +52 -0
  148. package/management-ui/src/components/theme-toggle.jsx +39 -0
  149. package/management-ui/src/components/ui/badge.tsx +36 -0
  150. package/management-ui/src/components/ui/button.test.jsx +56 -0
  151. package/management-ui/src/components/ui/button.tsx +57 -0
  152. package/management-ui/src/components/ui/card.tsx +76 -0
  153. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  154. package/management-ui/src/components/ui/select.tsx +157 -0
  155. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  156. package/management-ui/src/hooks/useFrigg.jsx +601 -0
  157. package/management-ui/src/hooks/useSocket.jsx +58 -0
  158. package/management-ui/src/index.css +193 -0
  159. package/management-ui/src/lib/utils.ts +6 -0
  160. package/management-ui/src/main.jsx +10 -0
  161. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  162. package/management-ui/src/pages/Connections.jsx +252 -0
  163. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  164. package/management-ui/src/pages/Dashboard.jsx +311 -0
  165. package/management-ui/src/pages/Environment.jsx +314 -0
  166. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  167. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  168. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  169. package/management-ui/src/pages/Integrations.jsx +253 -0
  170. package/management-ui/src/pages/Monitoring.jsx +17 -0
  171. package/management-ui/src/pages/Simulation.jsx +155 -0
  172. package/management-ui/src/pages/Users.jsx +492 -0
  173. package/management-ui/src/services/api.js +41 -0
  174. package/management-ui/src/services/apiModuleService.js +193 -0
  175. package/management-ui/src/services/websocket-handlers.js +120 -0
  176. package/management-ui/src/test/api/project.test.js +273 -0
  177. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  178. package/management-ui/src/test/mocks/server.js +178 -0
  179. package/management-ui/src/test/setup.js +61 -0
  180. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  181. package/management-ui/src/utils/repository.js +98 -0
  182. package/management-ui/src/utils/repository.test.js +118 -0
  183. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  184. package/management-ui/tailwind.config.js +63 -0
  185. package/management-ui/tsconfig.json +37 -0
  186. package/management-ui/tsconfig.node.json +10 -0
  187. package/management-ui/vite.config.js +26 -0
  188. package/management-ui/vitest.config.js +38 -0
  189. package/package.json +20 -9
  190. package/infrastructure/app-handler-helpers.js +0 -57
  191. package/infrastructure/backend-utils.js +0 -90
  192. package/infrastructure/routers/auth.js +0 -26
  193. package/infrastructure/routers/integration-defined-routers.js +0 -37
  194. package/infrastructure/routers/middleware/loadUser.js +0 -15
  195. package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
  196. package/infrastructure/routers/user.js +0 -41
  197. package/infrastructure/routers/websocket.js +0 -55
  198. package/infrastructure/workers/integration-defined-workers.js +0 -24
@@ -0,0 +1,836 @@
1
+ const path = require('path');
2
+
3
+ /**
4
+ * Generate IAM CloudFormation template based on AppDefinition
5
+ * @param {Object} appDefinition - Application definition object
6
+ * @param {Object} options - Generation options
7
+ * @param {string} [options.deploymentUserName='frigg-deployment-user'] - IAM user name
8
+ * @param {string} [options.stackName='frigg-deployment-iam'] - CloudFormation stack name
9
+ * @param {string} [options.mode='auto'] - Policy mode: 'basic', 'full', or 'auto' (auto-detect from appDefinition)
10
+ * @returns {string} CloudFormation YAML template
11
+ */
12
+ function generateIAMCloudFormation(appDefinition, options = {}) {
13
+ const { deploymentUserName = 'frigg-deployment-user', mode = 'auto' } =
14
+ options;
15
+
16
+ // Determine which features are enabled based on mode
17
+ let features;
18
+ if (mode === 'basic') {
19
+ features = {
20
+ vpc: false,
21
+ kms: false,
22
+ ssm: false,
23
+ websockets: appDefinition.websockets?.enable === true,
24
+ };
25
+ } else if (mode === 'full') {
26
+ features = {
27
+ vpc: true,
28
+ kms: true,
29
+ ssm: true,
30
+ websockets: appDefinition.websockets?.enable === true,
31
+ };
32
+ } else {
33
+ // mode === 'auto'
34
+ features = {
35
+ vpc: appDefinition.vpc?.enable === true,
36
+ kms:
37
+ appDefinition.encryption
38
+ ?.fieldLevelEncryptionMethod === 'kms',
39
+ ssm: appDefinition.ssm?.enable === true,
40
+ websockets: appDefinition.websockets?.enable === true,
41
+ };
42
+ }
43
+
44
+ // Build the CloudFormation template
45
+ const template = {
46
+ AWSTemplateFormatVersion: '2010-09-09',
47
+ Description: `IAM roles and policies for ${
48
+ appDefinition.name || 'Frigg'
49
+ } application deployment pipeline`,
50
+
51
+ Parameters: {
52
+ DeploymentUserName: {
53
+ Type: 'String',
54
+ Default: deploymentUserName,
55
+ Description:
56
+ 'Name for the IAM user that will deploy Frigg applications',
57
+ },
58
+ EnableVPCSupport: {
59
+ Type: 'String',
60
+ Default: features.vpc ? 'true' : 'false',
61
+ AllowedValues: ['true', 'false'],
62
+ Description:
63
+ 'Enable VPC-related permissions for Frigg applications',
64
+ },
65
+ EnableKMSSupport: {
66
+ Type: 'String',
67
+ Default: features.kms ? 'true' : 'false',
68
+ AllowedValues: ['true', 'false'],
69
+ Description:
70
+ 'Enable KMS encryption permissions for Frigg applications',
71
+ },
72
+ EnableSSMSupport: {
73
+ Type: 'String',
74
+ Default: features.ssm ? 'true' : 'false',
75
+ AllowedValues: ['true', 'false'],
76
+ Description:
77
+ 'Enable SSM Parameter Store permissions for Frigg applications',
78
+ },
79
+ DeploymentKmsAliasName: {
80
+ Type: 'String',
81
+ Default: 'alias/frigg-deployment',
82
+ Description:
83
+ 'Alias name to create or manage for the deployment KMS key',
84
+ },
85
+ DeploymentKmsTargetKeyArn: {
86
+ Type: 'String',
87
+ Default: '',
88
+ Description:
89
+ 'Optional existing KMS key ARN that the deployment alias should reference',
90
+ },
91
+ },
92
+
93
+ Conditions: {
94
+ CreateVPCPermissions: {
95
+ 'Fn::Equals': [{ Ref: 'EnableVPCSupport' }, 'true'],
96
+ },
97
+ CreateKMSPermissions: {
98
+ 'Fn::Equals': [{ Ref: 'EnableKMSSupport' }, 'true'],
99
+ },
100
+ CreateSSMPermissions: {
101
+ 'Fn::Equals': [{ Ref: 'EnableSSMSupport' }, 'true'],
102
+ },
103
+ CreateKMSAlias: {
104
+ 'Fn::And': [
105
+ {
106
+ 'Fn::Equals': [{ Ref: 'EnableKMSSupport' }, 'true'],
107
+ },
108
+ {
109
+ 'Fn::Not': [
110
+ {
111
+ 'Fn::Equals': [
112
+ { Ref: 'DeploymentKmsTargetKeyArn' },
113
+ '',
114
+ ],
115
+ },
116
+ ],
117
+ },
118
+ ],
119
+ },
120
+ },
121
+
122
+ Resources: {},
123
+ };
124
+
125
+ // Add IAM User
126
+ template.Resources.FriggDeploymentUser = {
127
+ Type: 'AWS::IAM::User',
128
+ Properties: {
129
+ UserName: { Ref: 'DeploymentUserName' },
130
+ ManagedPolicyArns: [
131
+ { Ref: 'FriggDiscoveryPolicy' },
132
+ { Ref: 'FriggCoreDeploymentPolicy' },
133
+ ],
134
+ },
135
+ };
136
+
137
+ // Conditionally add feature-specific policies
138
+ if (features.vpc) {
139
+ template.Resources.FriggDeploymentUser.Properties.ManagedPolicyArns.push(
140
+ {
141
+ 'Fn::If': [
142
+ 'CreateVPCPermissions',
143
+ { Ref: 'FriggVPCPolicy' },
144
+ { Ref: 'AWS::NoValue' },
145
+ ],
146
+ }
147
+ );
148
+ }
149
+ if (features.kms) {
150
+ template.Resources.FriggDeploymentUser.Properties.ManagedPolicyArns.push(
151
+ {
152
+ 'Fn::If': [
153
+ 'CreateKMSPermissions',
154
+ { Ref: 'FriggKMSPolicy' },
155
+ { Ref: 'AWS::NoValue' },
156
+ ],
157
+ }
158
+ );
159
+ }
160
+ if (features.ssm) {
161
+ template.Resources.FriggDeploymentUser.Properties.ManagedPolicyArns.push(
162
+ {
163
+ 'Fn::If': [
164
+ 'CreateSSMPermissions',
165
+ { Ref: 'FriggSSMPolicy' },
166
+ { Ref: 'AWS::NoValue' },
167
+ ],
168
+ }
169
+ );
170
+ }
171
+
172
+ // Add Access Key
173
+ template.Resources.FriggDeploymentAccessKey = {
174
+ Type: 'AWS::IAM::AccessKey',
175
+ Properties: {
176
+ UserName: { Ref: 'FriggDeploymentUser' },
177
+ },
178
+ };
179
+
180
+ // Add Discovery Policy (always needed)
181
+ template.Resources.FriggDiscoveryPolicy = {
182
+ Type: 'AWS::IAM::ManagedPolicy',
183
+ Properties: {
184
+ ManagedPolicyName: 'FriggDiscoveryPolicy',
185
+ Description:
186
+ 'Permissions for AWS resource discovery during Frigg build process',
187
+ PolicyDocument: {
188
+ Version: '2012-10-17',
189
+ Statement: [
190
+ {
191
+ Sid: 'AWSDiscoveryPermissions',
192
+ Effect: 'Allow',
193
+ Action: [
194
+ 'sts:GetCallerIdentity',
195
+ 'ec2:DescribeVpcs',
196
+ 'ec2:DescribeSubnets',
197
+ 'ec2:DescribeSecurityGroups',
198
+ 'ec2:DescribeRouteTables',
199
+ 'ec2:DescribeNatGateways',
200
+ 'ec2:DescribeAddresses',
201
+ 'kms:ListKeys',
202
+ 'kms:DescribeKey',
203
+ ],
204
+ Resource: '*',
205
+ },
206
+ ],
207
+ },
208
+ },
209
+ };
210
+
211
+ // Add Core Deployment Policy (always needed)
212
+ const coreActions = [
213
+ // CloudFormation permissions
214
+ 'cloudformation:CreateStack',
215
+ 'cloudformation:UpdateStack',
216
+ 'cloudformation:DeleteStack',
217
+ 'cloudformation:DescribeStacks',
218
+ 'cloudformation:DescribeStackEvents',
219
+ 'cloudformation:DescribeStackResources',
220
+ 'cloudformation:DescribeStackResource',
221
+ 'cloudformation:ListStackResources',
222
+ 'cloudformation:GetTemplate',
223
+ 'cloudformation:DescribeChangeSet',
224
+ 'cloudformation:CreateChangeSet',
225
+ 'cloudformation:DeleteChangeSet',
226
+ 'cloudformation:ExecuteChangeSet',
227
+ 'cloudformation:ValidateTemplate',
228
+
229
+ // Lambda permissions
230
+ 'lambda:CreateFunction',
231
+ 'lambda:UpdateFunctionCode',
232
+ 'lambda:UpdateFunctionConfiguration',
233
+ 'lambda:DeleteFunction',
234
+ 'lambda:GetFunction',
235
+ 'lambda:ListFunctions',
236
+ 'lambda:PublishVersion',
237
+ 'lambda:CreateAlias',
238
+ 'lambda:UpdateAlias',
239
+ 'lambda:DeleteAlias',
240
+ 'lambda:GetAlias',
241
+ 'lambda:AddPermission',
242
+ 'lambda:RemovePermission',
243
+ 'lambda:GetPolicy',
244
+ 'lambda:PutProvisionedConcurrencyConfig',
245
+ 'lambda:DeleteProvisionedConcurrencyConfig',
246
+ 'lambda:PutConcurrency',
247
+ 'lambda:DeleteConcurrency',
248
+ 'lambda:TagResource',
249
+ 'lambda:UntagResource',
250
+ 'lambda:ListVersionsByFunction',
251
+
252
+ // IAM permissions
253
+ 'iam:CreateRole',
254
+ 'iam:DeleteRole',
255
+ 'iam:GetRole',
256
+ 'iam:PassRole',
257
+ 'iam:PutRolePolicy',
258
+ 'iam:DeleteRolePolicy',
259
+ 'iam:GetRolePolicy',
260
+ 'iam:AttachRolePolicy',
261
+ 'iam:DetachRolePolicy',
262
+ 'iam:TagRole',
263
+ 'iam:UntagRole',
264
+ 'iam:ListPolicyVersions',
265
+
266
+ // S3 permissions
267
+ 's3:CreateBucket',
268
+ 's3:PutObject',
269
+ 's3:GetObject',
270
+ 's3:DeleteObject',
271
+ 's3:PutBucketPolicy',
272
+ 's3:PutBucketVersioning',
273
+ 's3:PutBucketPublicAccessBlock',
274
+ 's3:GetBucketLocation',
275
+ 's3:ListBucket',
276
+
277
+ // SQS permissions
278
+ 'sqs:CreateQueue',
279
+ 'sqs:DeleteQueue',
280
+ 'sqs:GetQueueAttributes',
281
+ 'sqs:SetQueueAttributes',
282
+ 'sqs:GetQueueUrl',
283
+ 'sqs:TagQueue',
284
+ 'sqs:UntagQueue',
285
+
286
+ // SNS permissions
287
+ 'sns:CreateTopic',
288
+ 'sns:DeleteTopic',
289
+ 'sns:GetTopicAttributes',
290
+ 'sns:SetTopicAttributes',
291
+ 'sns:Subscribe',
292
+ 'sns:Unsubscribe',
293
+ 'sns:ListSubscriptionsByTopic',
294
+ 'sns:TagResource',
295
+ 'sns:UntagResource',
296
+
297
+ // CloudWatch and Logs permissions
298
+ 'cloudwatch:PutMetricAlarm',
299
+ 'cloudwatch:DeleteAlarms',
300
+ 'cloudwatch:DescribeAlarms',
301
+ 'logs:CreateLogGroup',
302
+ 'logs:CreateLogStream',
303
+ 'logs:DeleteLogGroup',
304
+ 'logs:DescribeLogGroups',
305
+ 'logs:DescribeLogStreams',
306
+ 'logs:FilterLogEvents',
307
+ 'logs:PutLogEvents',
308
+ 'logs:PutRetentionPolicy',
309
+
310
+ // API Gateway permissions
311
+ 'apigateway:POST',
312
+ 'apigateway:PUT',
313
+ 'apigateway:DELETE',
314
+ 'apigateway:GET',
315
+ 'apigateway:PATCH',
316
+ 'apigateway:TagResource',
317
+ 'apigateway:UntagResource',
318
+ ];
319
+
320
+ const coreStatements = [
321
+ {
322
+ Sid: 'CloudFormationFriggStacks',
323
+ Effect: 'Allow',
324
+ Action: [
325
+ 'cloudformation:CreateStack',
326
+ 'cloudformation:UpdateStack',
327
+ 'cloudformation:DeleteStack',
328
+ 'cloudformation:DescribeStacks',
329
+ 'cloudformation:DescribeStackEvents',
330
+ 'cloudformation:DescribeStackResources',
331
+ 'cloudformation:DescribeStackResource',
332
+ 'cloudformation:ListStackResources',
333
+ 'cloudformation:GetTemplate',
334
+ 'cloudformation:DescribeChangeSet',
335
+ 'cloudformation:CreateChangeSet',
336
+ 'cloudformation:DeleteChangeSet',
337
+ 'cloudformation:ExecuteChangeSet',
338
+ ],
339
+ Resource: [
340
+ {
341
+ 'Fn::Sub':
342
+ 'arn:aws:cloudformation:*:${AWS::AccountId}:stack/*frigg*/*',
343
+ },
344
+ ],
345
+ },
346
+ {
347
+ Sid: 'CloudFormationValidateTemplate',
348
+ Effect: 'Allow',
349
+ Action: ['cloudformation:ValidateTemplate'],
350
+ Resource: '*',
351
+ },
352
+ {
353
+ Sid: 'S3DeploymentBucket',
354
+ Effect: 'Allow',
355
+ Action: [
356
+ 's3:CreateBucket',
357
+ 's3:PutObject',
358
+ 's3:GetObject',
359
+ 's3:DeleteObject',
360
+ 's3:PutBucketPolicy',
361
+ 's3:PutBucketVersioning',
362
+ 's3:PutBucketPublicAccessBlock',
363
+ 's3:GetBucketLocation',
364
+ 's3:ListBucket',
365
+ ],
366
+ Resource: [
367
+ 'arn:aws:s3:::*serverless*',
368
+ 'arn:aws:s3:::*serverless*/*',
369
+ ],
370
+ },
371
+ {
372
+ Sid: 'LambdaFriggFunctions',
373
+ Effect: 'Allow',
374
+ Action: [
375
+ 'lambda:CreateFunction',
376
+ 'lambda:UpdateFunctionCode',
377
+ 'lambda:UpdateFunctionConfiguration',
378
+ 'lambda:DeleteFunction',
379
+ 'lambda:GetFunction',
380
+ 'lambda:ListFunctions',
381
+ 'lambda:PublishVersion',
382
+ 'lambda:CreateAlias',
383
+ 'lambda:UpdateAlias',
384
+ 'lambda:DeleteAlias',
385
+ 'lambda:GetAlias',
386
+ 'lambda:AddPermission',
387
+ 'lambda:RemovePermission',
388
+ 'lambda:GetPolicy',
389
+ 'lambda:PutProvisionedConcurrencyConfig',
390
+ 'lambda:DeleteProvisionedConcurrencyConfig',
391
+ 'lambda:PutConcurrency',
392
+ 'lambda:DeleteConcurrency',
393
+ 'lambda:TagResource',
394
+ 'lambda:UntagResource',
395
+ 'lambda:ListVersionsByFunction',
396
+ ],
397
+ Resource: [
398
+ {
399
+ 'Fn::Sub':
400
+ 'arn:aws:lambda:*:${AWS::AccountId}:function:*frigg*',
401
+ },
402
+ ],
403
+ },
404
+ {
405
+ Sid: 'IAMRolesForFriggLambda',
406
+ Effect: 'Allow',
407
+ Action: [
408
+ 'iam:CreateRole',
409
+ 'iam:DeleteRole',
410
+ 'iam:GetRole',
411
+ 'iam:PassRole',
412
+ 'iam:PutRolePolicy',
413
+ 'iam:DeleteRolePolicy',
414
+ 'iam:GetRolePolicy',
415
+ 'iam:AttachRolePolicy',
416
+ 'iam:DetachRolePolicy',
417
+ 'iam:TagRole',
418
+ 'iam:UntagRole',
419
+ ],
420
+ Resource: [
421
+ { 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:role/*frigg*' },
422
+ {
423
+ 'Fn::Sub':
424
+ 'arn:aws:iam::${AWS::AccountId}:role/*frigg*LambdaRole*',
425
+ },
426
+ ],
427
+ },
428
+ {
429
+ Sid: 'IAMPolicyVersionPermissions',
430
+ Effect: 'Allow',
431
+ Action: ['iam:ListPolicyVersions'],
432
+ Resource: [
433
+ { 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:policy/*' },
434
+ ],
435
+ },
436
+ {
437
+ Sid: 'FriggMessagingServices',
438
+ Effect: 'Allow',
439
+ Action: [
440
+ 'sqs:CreateQueue',
441
+ 'sqs:DeleteQueue',
442
+ 'sqs:GetQueueAttributes',
443
+ 'sqs:SetQueueAttributes',
444
+ 'sqs:GetQueueUrl',
445
+ 'sqs:TagQueue',
446
+ 'sqs:UntagQueue',
447
+ ],
448
+ Resource: [
449
+ { 'Fn::Sub': 'arn:aws:sqs:*:${AWS::AccountId}:*frigg*' },
450
+ {
451
+ 'Fn::Sub':
452
+ 'arn:aws:sqs:*:${AWS::AccountId}:internal-error-queue-*',
453
+ },
454
+ ],
455
+ },
456
+ {
457
+ Sid: 'FriggSNSTopics',
458
+ Effect: 'Allow',
459
+ Action: [
460
+ 'sns:CreateTopic',
461
+ 'sns:DeleteTopic',
462
+ 'sns:GetTopicAttributes',
463
+ 'sns:SetTopicAttributes',
464
+ 'sns:Subscribe',
465
+ 'sns:Unsubscribe',
466
+ 'sns:ListSubscriptionsByTopic',
467
+ 'sns:TagResource',
468
+ 'sns:UntagResource',
469
+ ],
470
+ Resource: [
471
+ { 'Fn::Sub': 'arn:aws:sns:*:${AWS::AccountId}:*frigg*' },
472
+ ],
473
+ },
474
+ {
475
+ Sid: 'FriggMonitoringAndLogs',
476
+ Effect: 'Allow',
477
+ Action: [
478
+ 'cloudwatch:PutMetricAlarm',
479
+ 'cloudwatch:DeleteAlarms',
480
+ 'cloudwatch:DescribeAlarms',
481
+ 'logs:CreateLogGroup',
482
+ 'logs:CreateLogStream',
483
+ 'logs:DeleteLogGroup',
484
+ 'logs:DescribeLogGroups',
485
+ 'logs:DescribeLogStreams',
486
+ 'logs:FilterLogEvents',
487
+ 'logs:PutLogEvents',
488
+ 'logs:PutRetentionPolicy',
489
+ ],
490
+ Resource: [
491
+ {
492
+ 'Fn::Sub':
493
+ 'arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/lambda/*frigg*',
494
+ },
495
+ {
496
+ 'Fn::Sub':
497
+ 'arn:aws:logs:*:${AWS::AccountId}:log-group:/aws/lambda/*frigg*:*',
498
+ },
499
+ {
500
+ 'Fn::Sub':
501
+ 'arn:aws:cloudwatch:*:${AWS::AccountId}:alarm:*frigg*',
502
+ },
503
+ ],
504
+ },
505
+ {
506
+ Sid: 'FriggAPIGateway',
507
+ Effect: 'Allow',
508
+ Action: [
509
+ 'apigateway:POST',
510
+ 'apigateway:PUT',
511
+ 'apigateway:DELETE',
512
+ 'apigateway:GET',
513
+ 'apigateway:PATCH',
514
+ 'apigateway:TagResource',
515
+ 'apigateway:UntagResource',
516
+ ],
517
+ Resource: [
518
+ 'arn:aws:apigateway:*::/restapis',
519
+ 'arn:aws:apigateway:*::/restapis/*',
520
+ 'arn:aws:apigateway:*::/domainnames',
521
+ 'arn:aws:apigateway:*::/domainnames/*',
522
+ ],
523
+ },
524
+ {
525
+ Sid: 'FriggAPIGatewayV2',
526
+ Effect: 'Allow',
527
+ Action: [
528
+ 'apigateway:GET',
529
+ 'apigateway:DELETE',
530
+ 'apigateway:PATCH',
531
+ 'apigateway:POST',
532
+ 'apigateway:PUT',
533
+ ],
534
+ Resource: [
535
+ 'arn:aws:apigateway:*::/apis',
536
+ 'arn:aws:apigateway:*::/apis/*',
537
+ 'arn:aws:apigateway:*::/apis/*/stages',
538
+ 'arn:aws:apigateway:*::/apis/*/stages/*',
539
+ 'arn:aws:apigateway:*::/domainnames',
540
+ 'arn:aws:apigateway:*::/domainnames/*',
541
+ 'arn:aws:apigateway:*::/domainnames/*/apimappings',
542
+ ],
543
+ },
544
+ ];
545
+
546
+ template.Resources.FriggCoreDeploymentPolicy = {
547
+ Type: 'AWS::IAM::ManagedPolicy',
548
+ Properties: {
549
+ ManagedPolicyName: 'FriggCoreDeploymentPolicy',
550
+ Description: 'Core permissions for deploying Frigg applications',
551
+ PolicyDocument: {
552
+ Version: '2012-10-17',
553
+ Statement: coreStatements,
554
+ },
555
+ },
556
+ };
557
+
558
+ // Add feature-specific policies only if needed
559
+ if (features.vpc) {
560
+ template.Resources.FriggVPCPolicy = {
561
+ Type: 'AWS::IAM::ManagedPolicy',
562
+ Condition: 'CreateVPCPermissions',
563
+ Properties: {
564
+ ManagedPolicyName: 'FriggVPCPolicy',
565
+ Description: 'VPC-related permissions for Frigg applications',
566
+ PolicyDocument: {
567
+ Version: '2012-10-17',
568
+ Statement: [
569
+ {
570
+ Sid: 'FriggVPCEndpointManagement',
571
+ Effect: 'Allow',
572
+ Action: [
573
+ 'ec2:CreateVpcEndpoint',
574
+ 'ec2:DeleteVpcEndpoint',
575
+ 'ec2:DescribeVpcEndpoints',
576
+ 'ec2:ModifyVpcEndpoint',
577
+ 'ec2:CreateNatGateway',
578
+ 'ec2:DeleteNatGateway',
579
+ 'ec2:DescribeNatGateways',
580
+ 'ec2:AllocateAddress',
581
+ 'ec2:ReleaseAddress',
582
+ 'ec2:DescribeAddresses',
583
+ 'ec2:CreateRouteTable',
584
+ 'ec2:DeleteRouteTable',
585
+ 'ec2:DescribeRouteTables',
586
+ 'ec2:CreateRoute',
587
+ 'ec2:DeleteRoute',
588
+ 'ec2:ReplaceRoute',
589
+ 'ec2:AssociateRouteTable',
590
+ 'ec2:DisassociateRouteTable',
591
+ 'ec2:CreateSecurityGroup',
592
+ 'ec2:DeleteSecurityGroup',
593
+ 'ec2:AuthorizeSecurityGroupEgress',
594
+ 'ec2:AuthorizeSecurityGroupIngress',
595
+ 'ec2:RevokeSecurityGroupEgress',
596
+ 'ec2:RevokeSecurityGroupIngress',
597
+ 'ec2:DetachInternetGateway',
598
+ 'ec2:DeleteSubnet',
599
+ ],
600
+ Resource: '*',
601
+ },
602
+ ],
603
+ },
604
+ },
605
+ };
606
+ }
607
+
608
+ if (features.kms) {
609
+ template.Resources.FriggKMSPolicy = {
610
+ Type: 'AWS::IAM::ManagedPolicy',
611
+ Condition: 'CreateKMSPermissions',
612
+ Properties: {
613
+ ManagedPolicyName: 'FriggKMSPolicy',
614
+ Description:
615
+ 'KMS encryption permissions for Frigg applications',
616
+ PolicyDocument: {
617
+ Version: '2012-10-17',
618
+ Statement: [
619
+ {
620
+ Sid: 'FriggKMSEncryptionRuntime',
621
+ Effect: 'Allow',
622
+ Action: ['kms:GenerateDataKey', 'kms:Decrypt'],
623
+ Resource: [
624
+ {
625
+ 'Fn::Sub':
626
+ 'arn:aws:kms:*:${AWS::AccountId}:key/*',
627
+ },
628
+ ],
629
+ Condition: {
630
+ StringEquals: {
631
+ 'kms:ViaService': [
632
+ 'lambda.*.amazonaws.com',
633
+ 's3.*.amazonaws.com',
634
+ ],
635
+ },
636
+ },
637
+ },
638
+ {
639
+ Sid: 'FriggKMSManagement',
640
+ Effect: 'Allow',
641
+ Action: [
642
+ 'kms:CreateKey',
643
+ 'kms:PutKeyPolicy',
644
+ 'kms:EnableKeyRotation',
645
+ 'kms:TagResource',
646
+ 'kms:UntagResource',
647
+ 'kms:ListResourceTags',
648
+ 'kms:CreateAlias',
649
+ 'kms:UpdateAlias',
650
+ 'kms:DeleteAlias',
651
+ 'kms:ListAliases',
652
+ 'kms:DescribeKey',
653
+ ],
654
+ Resource: '*',
655
+ },
656
+ ],
657
+ },
658
+ },
659
+ };
660
+ }
661
+
662
+ template.Resources.FriggKMSKeyAlias = {
663
+ Type: 'AWS::KMS::Alias',
664
+ Condition: 'CreateKMSAlias',
665
+ DeletionPolicy: 'Retain',
666
+ UpdateReplacePolicy: 'Retain',
667
+ Properties: {
668
+ AliasName: { Ref: 'DeploymentKmsAliasName' },
669
+ TargetKeyId: { Ref: 'DeploymentKmsTargetKeyArn' },
670
+ },
671
+ };
672
+
673
+ if (features.ssm) {
674
+ template.Resources.FriggSSMPolicy = {
675
+ Type: 'AWS::IAM::ManagedPolicy',
676
+ Condition: 'CreateSSMPermissions',
677
+ Properties: {
678
+ ManagedPolicyName: 'FriggSSMPolicy',
679
+ Description:
680
+ 'SSM Parameter Store permissions for Frigg applications',
681
+ PolicyDocument: {
682
+ Version: '2012-10-17',
683
+ Statement: [
684
+ {
685
+ Sid: 'FriggSSMParameterAccess',
686
+ Effect: 'Allow',
687
+ Action: [
688
+ 'ssm:GetParameter',
689
+ 'ssm:GetParameters',
690
+ 'ssm:GetParametersByPath',
691
+ ],
692
+ Resource: [
693
+ {
694
+ 'Fn::Sub':
695
+ 'arn:aws:ssm:*:${AWS::AccountId}:parameter/*frigg*',
696
+ },
697
+ {
698
+ 'Fn::Sub':
699
+ 'arn:aws:ssm:*:${AWS::AccountId}:parameter/*frigg*/*',
700
+ },
701
+ ],
702
+ },
703
+ ],
704
+ },
705
+ },
706
+ };
707
+ }
708
+
709
+ // Add Secrets Manager for credentials
710
+ template.Resources.FriggDeploymentCredentials = {
711
+ Type: 'AWS::SecretsManager::Secret',
712
+ Properties: {
713
+ Name: 'frigg-deployment-credentials',
714
+ Description: 'Access credentials for Frigg deployment user',
715
+ SecretString: {
716
+ 'Fn::Sub': JSON.stringify({
717
+ AccessKeyId: '${FriggDeploymentAccessKey}',
718
+ SecretAccessKey:
719
+ '${FriggDeploymentAccessKey.SecretAccessKey}',
720
+ }),
721
+ },
722
+ },
723
+ };
724
+
725
+ // Add Outputs
726
+ template.Outputs = {
727
+ DeploymentUserArn: {
728
+ Description: 'ARN of the Frigg deployment user',
729
+ Value: { 'Fn::GetAtt': ['FriggDeploymentUser', 'Arn'] },
730
+ Export: {
731
+ Name: { 'Fn::Sub': '${AWS::StackName}-UserArn' },
732
+ },
733
+ },
734
+ AccessKeyId: {
735
+ Description: 'Access Key ID for the deployment user',
736
+ Value: { Ref: 'FriggDeploymentAccessKey' },
737
+ Export: {
738
+ Name: { 'Fn::Sub': '${AWS::StackName}-AccessKeyId' },
739
+ },
740
+ },
741
+ SecretAccessKeyCommand: {
742
+ Description: 'Command to retrieve the secret access key',
743
+ Value: {
744
+ 'Fn::Sub':
745
+ 'aws secretsmanager get-secret-value --secret-id frigg-deployment-credentials --query SecretString --output text | jq -r .SecretAccessKey',
746
+ },
747
+ },
748
+ CredentialsSecretArn: {
749
+ Description: 'ARN of the secret containing deployment credentials',
750
+ Value: { Ref: 'FriggDeploymentCredentials' },
751
+ Export: {
752
+ Name: { 'Fn::Sub': '${AWS::StackName}-CredentialsSecretArn' },
753
+ },
754
+ },
755
+ };
756
+
757
+ // Convert to YAML
758
+ return convertToYAML(template);
759
+ }
760
+
761
+ /**
762
+ * Convert JavaScript object to CloudFormation YAML
763
+ * @param {Object} obj - JavaScript object
764
+ * @returns {string} YAML string
765
+ */
766
+ function convertToYAML(obj) {
767
+ const yaml = require('js-yaml');
768
+ return yaml.dump(obj, {
769
+ indent: 2,
770
+ lineWidth: 120,
771
+ noRefs: true,
772
+ sortKeys: false,
773
+ });
774
+ }
775
+
776
+ /**
777
+ * Generate summary of what features will be included in the IAM policy
778
+ * @param {Object} appDefinition - Application definition
779
+ * @returns {Object} Feature summary
780
+ */
781
+ function getFeatureSummary(appDefinition) {
782
+ const features = {
783
+ core: true, // Always enabled
784
+ vpc: appDefinition.vpc?.enable === true,
785
+ kms:
786
+ appDefinition.encryption?.fieldLevelEncryptionMethod === 'kms',
787
+ ssm: appDefinition.ssm?.enable === true,
788
+ websockets: appDefinition.websockets?.enable === true,
789
+ };
790
+
791
+ const integrationCount = appDefinition.integrations?.length || 0;
792
+
793
+ return {
794
+ features,
795
+ integrationCount,
796
+ appName: appDefinition.name || 'Unnamed Frigg App',
797
+ };
798
+ }
799
+
800
+ /**
801
+ * Generate basic IAM policy (JSON format) - Core Frigg permissions only
802
+ * @returns {Object} Basic IAM policy document
803
+ */
804
+ function generateBasicIAMPolicy() {
805
+ const basicPolicyPath = path.join(__dirname, 'iam-policy-basic.json');
806
+ return require(basicPolicyPath);
807
+ }
808
+
809
+ /**
810
+ * Generate full IAM policy (JSON format) - All features enabled
811
+ * @returns {Object} Full IAM policy document
812
+ */
813
+ function generateFullIAMPolicy() {
814
+ const fullPolicyPath = path.join(__dirname, 'iam-policy-full.json');
815
+ return require(fullPolicyPath);
816
+ }
817
+
818
+ /**
819
+ * Generate IAM policy based on mode
820
+ * @param {string} mode - 'basic' or 'full'
821
+ * @returns {Object} IAM policy document
822
+ */
823
+ function generateIAMPolicy(mode = 'basic') {
824
+ if (mode === 'full') {
825
+ return generateFullIAMPolicy();
826
+ }
827
+ return generateBasicIAMPolicy();
828
+ }
829
+
830
+ module.exports = {
831
+ generateIAMCloudFormation,
832
+ getFeatureSummary,
833
+ generateBasicIAMPolicy,
834
+ generateFullIAMPolicy,
835
+ generateIAMPolicy,
836
+ };