@friggframework/devtools 2.0.0-next.47 → 2.0.0-next.48

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 (69) hide show
  1. package/frigg-cli/README.md +1290 -0
  2. package/frigg-cli/__tests__/unit/commands/build.test.js +279 -0
  3. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +548 -0
  4. package/frigg-cli/__tests__/unit/commands/deploy.test.js +320 -0
  5. package/frigg-cli/__tests__/unit/commands/doctor.test.js +309 -0
  6. package/frigg-cli/__tests__/unit/commands/install.test.js +400 -0
  7. package/frigg-cli/__tests__/unit/commands/ui.test.js +346 -0
  8. package/frigg-cli/__tests__/unit/dependencies.test.js +74 -0
  9. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +366 -0
  10. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +304 -0
  11. package/frigg-cli/__tests__/unit/version-detection.test.js +171 -0
  12. package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
  13. package/frigg-cli/__tests__/utils/prisma-mock.js +194 -0
  14. package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
  15. package/frigg-cli/__tests__/utils/test-setup.js +287 -0
  16. package/frigg-cli/build-command/index.js +66 -0
  17. package/frigg-cli/db-setup-command/index.js +193 -0
  18. package/frigg-cli/deploy-command/SPEC-DEPLOY-DRY-RUN.md +981 -0
  19. package/frigg-cli/deploy-command/index.js +302 -0
  20. package/frigg-cli/doctor-command/index.js +335 -0
  21. package/frigg-cli/generate-command/__tests__/generate-command.test.js +301 -0
  22. package/frigg-cli/generate-command/azure-generator.js +43 -0
  23. package/frigg-cli/generate-command/gcp-generator.js +47 -0
  24. package/frigg-cli/generate-command/index.js +332 -0
  25. package/frigg-cli/generate-command/terraform-generator.js +555 -0
  26. package/frigg-cli/generate-iam-command.js +118 -0
  27. package/frigg-cli/index.js +173 -0
  28. package/frigg-cli/index.test.js +158 -0
  29. package/frigg-cli/init-command/backend-first-handler.js +756 -0
  30. package/frigg-cli/init-command/index.js +93 -0
  31. package/frigg-cli/init-command/template-handler.js +143 -0
  32. package/frigg-cli/install-command/backend-js.js +33 -0
  33. package/frigg-cli/install-command/commit-changes.js +16 -0
  34. package/frigg-cli/install-command/environment-variables.js +127 -0
  35. package/frigg-cli/install-command/environment-variables.test.js +136 -0
  36. package/frigg-cli/install-command/index.js +54 -0
  37. package/frigg-cli/install-command/install-package.js +13 -0
  38. package/frigg-cli/install-command/integration-file.js +30 -0
  39. package/frigg-cli/install-command/logger.js +12 -0
  40. package/frigg-cli/install-command/template.js +90 -0
  41. package/frigg-cli/install-command/validate-package.js +75 -0
  42. package/frigg-cli/jest.config.js +124 -0
  43. package/frigg-cli/package.json +63 -0
  44. package/frigg-cli/repair-command/index.js +564 -0
  45. package/frigg-cli/start-command/index.js +149 -0
  46. package/frigg-cli/start-command/start-command.test.js +297 -0
  47. package/frigg-cli/test/init-command.test.js +180 -0
  48. package/frigg-cli/test/npm-registry.test.js +319 -0
  49. package/frigg-cli/ui-command/index.js +154 -0
  50. package/frigg-cli/utils/app-resolver.js +319 -0
  51. package/frigg-cli/utils/backend-path.js +25 -0
  52. package/frigg-cli/utils/database-validator.js +154 -0
  53. package/frigg-cli/utils/error-messages.js +257 -0
  54. package/frigg-cli/utils/npm-registry.js +167 -0
  55. package/frigg-cli/utils/process-manager.js +199 -0
  56. package/frigg-cli/utils/repo-detection.js +405 -0
  57. package/infrastructure/create-frigg-infrastructure.js +125 -12
  58. package/infrastructure/docs/PRE-DEPLOYMENT-HEALTH-CHECK-SPEC.md +1317 -0
  59. package/infrastructure/domains/shared/resource-discovery.enhanced.test.js +306 -0
  60. package/infrastructure/domains/shared/resource-discovery.js +31 -2
  61. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -1
  62. package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +109 -5
  63. package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +310 -4
  64. package/infrastructure/domains/shared/validation/plugin-validator.js +187 -0
  65. package/infrastructure/domains/shared/validation/plugin-validator.test.js +323 -0
  66. package/infrastructure/infrastructure-composer.js +22 -0
  67. package/layers/prisma/.build-complete +3 -0
  68. package/package.json +18 -7
  69. package/management-ui/package-lock.json +0 -16517
@@ -0,0 +1,555 @@
1
+ async function generateTerraformTemplate(options) {
2
+ const { appName, features, userPrefix } = options;
3
+ const userName = `${userPrefix}-${appName}`.replace(/[^a-zA-Z0-9-]/g, '-');
4
+
5
+ let template = `# Frigg Deployment IAM Configuration for ${appName}
6
+ # Generated by Frigg CLI
7
+
8
+ terraform {
9
+ required_providers {
10
+ aws = {
11
+ source = "hashicorp/aws"
12
+ version = "~> 5.0"
13
+ }
14
+ }
15
+ }
16
+
17
+ # Variables
18
+ variable "enable_vpc" {
19
+ description = "Enable VPC permissions"
20
+ type = bool
21
+ default = ${features.vpc}
22
+ }
23
+
24
+ variable "enable_kms" {
25
+ description = "Enable KMS permissions"
26
+ type = bool
27
+ default = ${features.kms}
28
+ }
29
+
30
+ variable "enable_ssm" {
31
+ description = "Enable SSM Parameter Store permissions"
32
+ type = bool
33
+ default = ${features.ssm}
34
+ }
35
+
36
+ variable "enable_websockets" {
37
+ description = "Enable WebSocket permissions"
38
+ type = bool
39
+ default = ${features.websockets}
40
+ }
41
+
42
+ # IAM User
43
+ resource "aws_iam_user" "frigg_deployment" {
44
+ name = "${userName}"
45
+ path = "/deployment/"
46
+
47
+ tags = {
48
+ Application = "${appName}"
49
+ ManagedBy = "Frigg"
50
+ Purpose = "Deployment"
51
+ }
52
+ }
53
+
54
+ # Access Key
55
+ resource "aws_iam_access_key" "frigg_deployment" {
56
+ user = aws_iam_user.frigg_deployment.name
57
+ }
58
+
59
+ # Core Discovery Policy
60
+ resource "aws_iam_policy" "frigg_discovery" {
61
+ name = "${userName}-discovery-policy"
62
+ description = "Allows discovery of AWS resources for Frigg deployment"
63
+
64
+ policy = jsonencode({
65
+ Version = "2012-10-17"
66
+ Statement = [
67
+ {
68
+ Effect = "Allow"
69
+ Action = [
70
+ "cloudformation:ListStacks",
71
+ "cloudformation:DescribeStacks",
72
+ "lambda:ListFunctions",
73
+ "lambda:GetFunction",
74
+ "apigateway:GET",
75
+ "s3:ListAllMyBuckets",
76
+ "s3:GetBucketLocation",
77
+ "s3:GetBucketVersioning",
78
+ "dynamodb:ListTables",
79
+ "dynamodb:DescribeTable",
80
+ "sqs:ListQueues",
81
+ "sqs:GetQueueAttributes",
82
+ "events:ListRules",
83
+ "events:DescribeRule",
84
+ "iam:GetRole",
85
+ "iam:GetPolicy",
86
+ "iam:GetPolicyVersion",
87
+ "iam:ListAttachedRolePolicies",
88
+ "tag:GetResources"
89
+ ]
90
+ Resource = "*"
91
+ }
92
+ ]
93
+ })
94
+ }
95
+
96
+ # Core Deployment Policy
97
+ resource "aws_iam_policy" "frigg_core_deployment" {
98
+ name = "${userName}-core-deployment-policy"
99
+ description = "Core permissions for Frigg deployment"
100
+
101
+ policy = jsonencode({
102
+ Version = "2012-10-17"
103
+ Statement = [
104
+ {
105
+ Sid = "CloudFormationManagement"
106
+ Effect = "Allow"
107
+ Action = [
108
+ "cloudformation:CreateStack",
109
+ "cloudformation:UpdateStack",
110
+ "cloudformation:DeleteStack",
111
+ "cloudformation:DescribeStacks",
112
+ "cloudformation:DescribeStackEvents",
113
+ "cloudformation:DescribeStackResources",
114
+ "cloudformation:DescribeStackResource",
115
+ "cloudformation:ListStackResources",
116
+ "cloudformation:GetTemplate",
117
+ "cloudformation:ValidateTemplate",
118
+ "cloudformation:CreateChangeSet",
119
+ "cloudformation:DeleteChangeSet",
120
+ "cloudformation:DescribeChangeSet",
121
+ "cloudformation:ExecuteChangeSet",
122
+ "cloudformation:TagResource",
123
+ "cloudformation:UntagResource"
124
+ ]
125
+ Resource = [
126
+ "arn:aws:cloudformation:*:*:stack/*frigg*/*",
127
+ "arn:aws:cloudformation:*:*:stack/${appName}*/*"
128
+ ]
129
+ },
130
+ {
131
+ Sid = "S3Management"
132
+ Effect = "Allow"
133
+ Action = [
134
+ "s3:CreateBucket",
135
+ "s3:DeleteBucket",
136
+ "s3:PutObject",
137
+ "s3:GetObject",
138
+ "s3:DeleteObject",
139
+ "s3:PutBucketPolicy",
140
+ "s3:GetBucketPolicy",
141
+ "s3:DeleteBucketPolicy",
142
+ "s3:PutBucketVersioning",
143
+ "s3:GetBucketVersioning",
144
+ "s3:PutBucketPublicAccessBlock",
145
+ "s3:GetBucketPublicAccessBlock",
146
+ "s3:PutBucketTagging",
147
+ "s3:GetBucketTagging",
148
+ "s3:DeleteBucketTagging",
149
+ "s3:PutBucketEncryption",
150
+ "s3:GetBucketEncryption",
151
+ "s3:PutEncryptionConfiguration",
152
+ "s3:PutBucketNotification",
153
+ "s3:GetBucketNotification",
154
+ "s3:GetBucketLocation",
155
+ "s3:ListBucket",
156
+ "s3:GetBucketAcl",
157
+ "s3:PutBucketAcl"
158
+ ]
159
+ Resource = [
160
+ "arn:aws:s3:::*frigg*",
161
+ "arn:aws:s3:::*frigg*/*",
162
+ "arn:aws:s3:::${appName}*",
163
+ "arn:aws:s3:::${appName}*/*"
164
+ ]
165
+ },
166
+ {
167
+ Sid = "LambdaManagement"
168
+ Effect = "Allow"
169
+ Action = [
170
+ "lambda:CreateFunction",
171
+ "lambda:UpdateFunctionCode",
172
+ "lambda:UpdateFunctionConfiguration",
173
+ "lambda:DeleteFunction",
174
+ "lambda:GetFunction",
175
+ "lambda:GetFunctionConfiguration",
176
+ "lambda:AddPermission",
177
+ "lambda:RemovePermission",
178
+ "lambda:InvokeFunction",
179
+ "lambda:TagResource",
180
+ "lambda:UntagResource",
181
+ "lambda:ListTags",
182
+ "lambda:PutFunctionConcurrency",
183
+ "lambda:DeleteFunctionConcurrency"
184
+ ]
185
+ Resource = [
186
+ "arn:aws:lambda:*:*:function:*frigg*",
187
+ "arn:aws:lambda:*:*:function:${appName}*"
188
+ ]
189
+ },
190
+ {
191
+ Sid = "IAMRoleManagement"
192
+ Effect = "Allow"
193
+ Action = [
194
+ "iam:CreateRole",
195
+ "iam:DeleteRole",
196
+ "iam:AttachRolePolicy",
197
+ "iam:DetachRolePolicy",
198
+ "iam:PutRolePolicy",
199
+ "iam:DeleteRolePolicy",
200
+ "iam:GetRole",
201
+ "iam:GetRolePolicy",
202
+ "iam:UpdateRole",
203
+ "iam:PassRole",
204
+ "iam:TagRole",
205
+ "iam:UntagRole"
206
+ ]
207
+ Resource = [
208
+ "arn:aws:iam::*:role/*frigg*",
209
+ "arn:aws:iam::*:role/${appName}*"
210
+ ]
211
+ },
212
+ {
213
+ Sid = "APIGatewayManagement"
214
+ Effect = "Allow"
215
+ Action = [
216
+ "apigateway:*"
217
+ ]
218
+ Resource = [
219
+ "arn:aws:apigateway:*::/restapis",
220
+ "arn:aws:apigateway:*::/restapis/*",
221
+ "arn:aws:apigateway:*::/apis",
222
+ "arn:aws:apigateway:*::/apis/*",
223
+ "arn:aws:apigateway:*::/tags/*"
224
+ ]
225
+ },
226
+ {
227
+ Sid = "DynamoDBManagement"
228
+ Effect = "Allow"
229
+ Action = [
230
+ "dynamodb:CreateTable",
231
+ "dynamodb:UpdateTable",
232
+ "dynamodb:DeleteTable",
233
+ "dynamodb:DescribeTable",
234
+ "dynamodb:TagResource",
235
+ "dynamodb:UntagResource",
236
+ "dynamodb:ListTagsOfResource",
237
+ "dynamodb:UpdateTimeToLive",
238
+ "dynamodb:DescribeTimeToLive",
239
+ "dynamodb:CreateBackup",
240
+ "dynamodb:DeleteBackup",
241
+ "dynamodb:DescribeBackup",
242
+ "dynamodb:ListBackups"
243
+ ]
244
+ Resource = [
245
+ "arn:aws:dynamodb:*:*:table/*frigg*",
246
+ "arn:aws:dynamodb:*:*:table/${appName}*"
247
+ ]
248
+ },
249
+ {
250
+ Sid = "EventBridgeManagement"
251
+ Effect = "Allow"
252
+ Action = [
253
+ "events:PutRule",
254
+ "events:DeleteRule",
255
+ "events:DescribeRule",
256
+ "events:EnableRule",
257
+ "events:DisableRule",
258
+ "events:PutTargets",
259
+ "events:RemoveTargets",
260
+ "events:ListTargetsByRule",
261
+ "events:TagResource",
262
+ "events:UntagResource"
263
+ ]
264
+ Resource = [
265
+ "arn:aws:events:*:*:rule/*frigg*",
266
+ "arn:aws:events:*:*:rule/${appName}*"
267
+ ]
268
+ },
269
+ {
270
+ Sid = "SQSManagement"
271
+ Effect = "Allow"
272
+ Action = [
273
+ "sqs:CreateQueue",
274
+ "sqs:DeleteQueue",
275
+ "sqs:SetQueueAttributes",
276
+ "sqs:GetQueueAttributes",
277
+ "sqs:TagQueue",
278
+ "sqs:UntagQueue",
279
+ "sqs:ListQueueTags",
280
+ "sqs:AddPermission",
281
+ "sqs:RemovePermission"
282
+ ]
283
+ Resource = [
284
+ "arn:aws:sqs:*:*:*frigg*",
285
+ "arn:aws:sqs:*:*:${appName}*"
286
+ ]
287
+ },
288
+ {
289
+ Sid = "LogsManagement"
290
+ Effect = "Allow"
291
+ Action = [
292
+ "logs:CreateLogGroup",
293
+ "logs:DeleteLogGroup",
294
+ "logs:PutRetentionPolicy",
295
+ "logs:DeleteRetentionPolicy",
296
+ "logs:TagLogGroup",
297
+ "logs:UntagLogGroup"
298
+ ]
299
+ Resource = [
300
+ "arn:aws:logs:*:*:log-group:/aws/lambda/*frigg*",
301
+ "arn:aws:logs:*:*:log-group:/aws/lambda/${appName}*",
302
+ "arn:aws:logs:*:*:log-group:/aws/apigateway/*frigg*",
303
+ "arn:aws:logs:*:*:log-group:/aws/apigateway/${appName}*"
304
+ ]
305
+ }
306
+ ]
307
+ })
308
+ }
309
+ `;
310
+
311
+ // Add VPC policy if enabled
312
+ if (features.vpc) {
313
+ template += `
314
+ # VPC Management Policy
315
+ resource "aws_iam_policy" "frigg_vpc" {
316
+ name = "${userName}-vpc-policy"
317
+ description = "VPC management permissions for Frigg"
318
+
319
+ policy = jsonencode({
320
+ Version = "2012-10-17"
321
+ Statement = [
322
+ {
323
+ Sid = "VPCDiscovery"
324
+ Effect = "Allow"
325
+ Action = [
326
+ "ec2:DescribeVpcs",
327
+ "ec2:DescribeSubnets",
328
+ "ec2:DescribeSecurityGroups",
329
+ "ec2:DescribeRouteTables",
330
+ "ec2:DescribeNatGateways",
331
+ "ec2:DescribeInternetGateways",
332
+ "ec2:DescribeVpcEndpoints",
333
+ "ec2:DescribeNetworkInterfaces",
334
+ "ec2:DescribeAddresses"
335
+ ]
336
+ Resource = "*"
337
+ },
338
+ {
339
+ Sid = "VPCManagement"
340
+ Effect = "Allow"
341
+ Action = [
342
+ "ec2:CreateVpc",
343
+ "ec2:DeleteVpc",
344
+ "ec2:ModifyVpcAttribute",
345
+ "ec2:CreateSubnet",
346
+ "ec2:DeleteSubnet",
347
+ "ec2:CreateSecurityGroup",
348
+ "ec2:DeleteSecurityGroup",
349
+ "ec2:AuthorizeSecurityGroupIngress",
350
+ "ec2:AuthorizeSecurityGroupEgress",
351
+ "ec2:RevokeSecurityGroupIngress",
352
+ "ec2:RevokeSecurityGroupEgress",
353
+ "ec2:CreateRouteTable",
354
+ "ec2:DeleteRouteTable",
355
+ "ec2:CreateRoute",
356
+ "ec2:DeleteRoute",
357
+ "ec2:AssociateRouteTable",
358
+ "ec2:DisassociateRouteTable",
359
+ "ec2:CreateInternetGateway",
360
+ "ec2:DeleteInternetGateway",
361
+ "ec2:AttachInternetGateway",
362
+ "ec2:DetachInternetGateway",
363
+ "ec2:CreateNatGateway",
364
+ "ec2:DeleteNatGateway",
365
+ "ec2:AllocateAddress",
366
+ "ec2:ReleaseAddress",
367
+ "ec2:CreateVpcEndpoint",
368
+ "ec2:DeleteVpcEndpoints",
369
+ "ec2:CreateTags",
370
+ "ec2:DeleteTags"
371
+ ]
372
+ Resource = "*"
373
+ Condition = {
374
+ StringLike = {
375
+ "aws:RequestTag/Name" = ["*frigg*", "*${appName}*"]
376
+ }
377
+ }
378
+ }
379
+ ]
380
+ })
381
+ }
382
+ `;
383
+ }
384
+
385
+ // Add KMS policy if enabled
386
+ if (features.kms) {
387
+ template += `
388
+ # KMS Management Policy
389
+ resource "aws_iam_policy" "frigg_kms" {
390
+ name = "${userName}-kms-policy"
391
+ description = "KMS management permissions for Frigg"
392
+
393
+ policy = jsonencode({
394
+ Version = "2012-10-17"
395
+ Statement = [
396
+ {
397
+ Sid = "KMSKeyManagement"
398
+ Effect = "Allow"
399
+ Action = [
400
+ "kms:CreateKey",
401
+ "kms:DescribeKey",
402
+ "kms:ListKeys",
403
+ "kms:ListAliases",
404
+ "kms:CreateAlias",
405
+ "kms:UpdateAlias",
406
+ "kms:DeleteAlias",
407
+ "kms:EnableKey",
408
+ "kms:DisableKey",
409
+ "kms:ScheduleKeyDeletion",
410
+ "kms:CancelKeyDeletion",
411
+ "kms:GetKeyPolicy",
412
+ "kms:PutKeyPolicy",
413
+ "kms:TagResource",
414
+ "kms:UntagResource",
415
+ "kms:ListResourceTags",
416
+ "kms:Encrypt",
417
+ "kms:Decrypt",
418
+ "kms:GenerateDataKey"
419
+ ]
420
+ Resource = "*"
421
+ }
422
+ ]
423
+ })
424
+ }
425
+ `;
426
+ }
427
+
428
+ // Add SSM policy if enabled
429
+ if (features.ssm) {
430
+ template += `
431
+ # SSM Parameter Store Policy
432
+ resource "aws_iam_policy" "frigg_ssm" {
433
+ name = "${userName}-ssm-policy"
434
+ description = "SSM Parameter Store permissions for Frigg"
435
+
436
+ policy = jsonencode({
437
+ Version = "2012-10-17"
438
+ Statement = [
439
+ {
440
+ Sid = "SSMParameterManagement"
441
+ Effect = "Allow"
442
+ Action = [
443
+ "ssm:PutParameter",
444
+ "ssm:GetParameter",
445
+ "ssm:GetParameters",
446
+ "ssm:GetParametersByPath",
447
+ "ssm:DeleteParameter",
448
+ "ssm:DeleteParameters",
449
+ "ssm:DescribeParameters",
450
+ "ssm:AddTagsToResource",
451
+ "ssm:RemoveTagsFromResource",
452
+ "ssm:ListTagsForResource"
453
+ ]
454
+ Resource = [
455
+ "arn:aws:ssm:*:*:parameter/*frigg*",
456
+ "arn:aws:ssm:*:*:parameter/${appName}*"
457
+ ]
458
+ },
459
+ {
460
+ Sid = "SSMParameterDiscovery"
461
+ Effect = "Allow"
462
+ Action = [
463
+ "ssm:DescribeParameters"
464
+ ]
465
+ Resource = "*"
466
+ }
467
+ ]
468
+ })
469
+ }
470
+ `;
471
+ }
472
+
473
+ // Attach policies to user
474
+ template += `
475
+ # Attach policies to user
476
+ resource "aws_iam_user_policy_attachment" "frigg_discovery" {
477
+ user = aws_iam_user.frigg_deployment.name
478
+ policy_arn = aws_iam_policy.frigg_discovery.arn
479
+ }
480
+
481
+ resource "aws_iam_user_policy_attachment" "frigg_core_deployment" {
482
+ user = aws_iam_user.frigg_deployment.name
483
+ policy_arn = aws_iam_policy.frigg_core_deployment.arn
484
+ }
485
+ `;
486
+
487
+ if (features.vpc) {
488
+ template += `
489
+ resource "aws_iam_user_policy_attachment" "frigg_vpc" {
490
+ count = var.enable_vpc ? 1 : 0
491
+ user = aws_iam_user.frigg_deployment.name
492
+ policy_arn = aws_iam_policy.frigg_vpc.arn
493
+ }
494
+ `;
495
+ }
496
+
497
+ if (features.kms) {
498
+ template += `
499
+ resource "aws_iam_user_policy_attachment" "frigg_kms" {
500
+ count = var.enable_kms ? 1 : 0
501
+ user = aws_iam_user.frigg_deployment.name
502
+ policy_arn = aws_iam_policy.frigg_kms.arn
503
+ }
504
+ `;
505
+ }
506
+
507
+ if (features.ssm) {
508
+ template += `
509
+ resource "aws_iam_user_policy_attachment" "frigg_ssm" {
510
+ count = var.enable_ssm ? 1 : 0
511
+ user = aws_iam_user.frigg_deployment.name
512
+ policy_arn = aws_iam_policy.frigg_ssm.arn
513
+ }
514
+ `;
515
+ }
516
+
517
+ // Add outputs
518
+ template += `
519
+ # Outputs
520
+ output "user_arn" {
521
+ description = "ARN of the created IAM user"
522
+ value = aws_iam_user.frigg_deployment.arn
523
+ }
524
+
525
+ output "user_name" {
526
+ description = "Name of the created IAM user"
527
+ value = aws_iam_user.frigg_deployment.name
528
+ }
529
+
530
+ output "access_key_id" {
531
+ description = "Access key ID for the IAM user"
532
+ value = aws_iam_access_key.frigg_deployment.id
533
+ }
534
+
535
+ output "secret_access_key" {
536
+ description = "Secret access key for the IAM user"
537
+ value = aws_iam_access_key.frigg_deployment.secret
538
+ sensitive = true
539
+ }
540
+
541
+ output "enabled_features" {
542
+ description = "Features enabled for this deployment user"
543
+ value = {
544
+ vpc = var.enable_vpc
545
+ kms = var.enable_kms
546
+ ssm = var.enable_ssm
547
+ websockets = var.enable_websockets
548
+ }
549
+ }
550
+ `;
551
+
552
+ return template;
553
+ }
554
+
555
+ module.exports = { generateTerraformTemplate };
@@ -0,0 +1,118 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const { findNearestBackendPackageJson } = require('@friggframework/core');
4
+ const { generateIAMCloudFormation, getFeatureSummary } = require('../infrastructure/domains/security/iam-generator');
5
+
6
+ /**
7
+ * Generate IAM CloudFormation stack based on current app definition
8
+ * @param {Object} options - Command options
9
+ */
10
+ async function generateIamCommand(options = {}) {
11
+ try {
12
+ console.log('šŸ” Finding Frigg application...');
13
+
14
+ // Find the backend package.json
15
+ const backendPath = findNearestBackendPackageJson();
16
+ if (!backendPath) {
17
+ console.error('āŒ Could not find backend package.json');
18
+ console.error(' Make sure you are in a Frigg application directory');
19
+ process.exit(1);
20
+ }
21
+
22
+ const backendDir = path.dirname(backendPath);
23
+ const backendFilePath = path.join(backendDir, 'index.js');
24
+
25
+ if (!fs.existsSync(backendFilePath)) {
26
+ console.error('āŒ Could not find backend/index.js');
27
+ console.error(' Make sure your Frigg application has a backend/index.js file');
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log(`šŸ“± Found Frigg application at: ${backendDir}`);
32
+
33
+ // Load the app definition
34
+ const backend = require(backendFilePath);
35
+ const appDefinition = backend.Definition;
36
+
37
+ if (!appDefinition) {
38
+ console.error('āŒ No Definition found in backend/index.js');
39
+ console.error(' Make sure your backend exports a Definition object');
40
+ process.exit(1);
41
+ }
42
+
43
+ // Get feature summary
44
+ const summary = getFeatureSummary(appDefinition);
45
+
46
+ console.log('\\nšŸ“‹ Application Analysis:');
47
+ console.log(` App Name: ${summary.appName}`);
48
+ console.log(` Integrations: ${summary.integrationCount}`);
49
+ console.log('\\nšŸ”§ Features Detected:');
50
+ console.log(` āœ… Core deployment (always included)`);
51
+ console.log(` ${summary.features.vpc ? 'āœ…' : 'āŒ'} VPC support`);
52
+ console.log(` ${summary.features.kms ? 'āœ…' : 'āŒ'} KMS encryption`);
53
+ console.log(` ${summary.features.ssm ? 'āœ…' : 'āŒ'} SSM Parameter Store`);
54
+ console.log(` ${summary.features.websockets ? 'āœ…' : 'āŒ'} WebSocket support`);
55
+
56
+ // Generate the CloudFormation template
57
+ console.log('\\nšŸ—ļø Generating IAM CloudFormation template...');
58
+
59
+ const deploymentUserName = options.user || 'frigg-deployment-user';
60
+ const stackName = options.stackName || 'frigg-deployment-iam';
61
+
62
+ // Use the summary already extracted above (line 44)
63
+ const cloudFormationYaml = generateIAMCloudFormation({
64
+ appName: summary.appName,
65
+ features: summary.features,
66
+ userPrefix: deploymentUserName,
67
+ stackName
68
+ });
69
+
70
+ // Determine output file path
71
+ const outputDir = options.output || path.join(backendDir, 'infrastructure');
72
+ await fs.ensureDir(outputDir);
73
+
74
+ const outputFile = path.join(outputDir, `${stackName}.yaml`);
75
+
76
+ // Write the file
77
+ await fs.writeFile(outputFile, cloudFormationYaml);
78
+
79
+ console.log(`\\nāœ… IAM CloudFormation template generated successfully!`);
80
+ console.log(`šŸ“„ File: ${outputFile}`);
81
+
82
+ // Show deployment instructions
83
+ console.log('\\nšŸ“š Next Steps:');
84
+ console.log('\\n1. Deploy the CloudFormation stack:');
85
+ console.log(` aws cloudformation deploy \\\\`);
86
+ console.log(` --template-file ${path.relative(process.cwd(), outputFile)} \\\\`);
87
+ console.log(` --stack-name ${stackName} \\\\`);
88
+ console.log(` --capabilities CAPABILITY_NAMED_IAM \\\\`);
89
+ console.log(` --parameter-overrides DeploymentUserName=${deploymentUserName}`);
90
+
91
+ console.log('\\n2. Retrieve credentials:');
92
+ console.log(` aws cloudformation describe-stacks \\\\`);
93
+ console.log(` --stack-name ${stackName} \\\\`);
94
+ console.log(` --query 'Stacks[0].Outputs[?OutputKey==\`AccessKeyId\`].OutputValue' \\\\`);
95
+ console.log(` --output text`);
96
+
97
+ console.log('\\n3. Get secret access key:');
98
+ console.log(` aws secretsmanager get-secret-value \\\\`);
99
+ console.log(` --secret-id frigg-deployment-credentials \\\\`);
100
+ console.log(` --query SecretString \\\\`);
101
+ console.log(` --output text | jq -r .SecretAccessKey`);
102
+
103
+ if (options.verbose) {
104
+ console.log('\\nšŸ” Generated Template Summary:');
105
+ console.log(` File size: ${Math.round(cloudFormationYaml.length / 1024)}KB`);
106
+ console.log(` Features enabled: ${Object.values(summary.features).filter(Boolean).length}`);
107
+ }
108
+
109
+ } catch (error) {
110
+ console.error('āŒ Error generating IAM template:', error.message);
111
+ if (options.verbose) {
112
+ console.error('Stack trace:', error.stack);
113
+ }
114
+ process.exit(1);
115
+ }
116
+ }
117
+
118
+ module.exports = { generateIamCommand };