@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.31

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