@friggframework/devtools 2.0.0--canary.622.eb44ae5.0 → 2.0.0--canary.625.27a7e7a.0

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 (39) hide show
  1. package/frigg-cli/__tests__/unit/commands/generate-iam.test.js +97 -0
  2. package/frigg-cli/deploy-command/index.js +44 -0
  3. package/frigg-cli/generate-command/index.js +2 -1
  4. package/frigg-cli/generate-iam-command.js +2 -1
  5. package/frigg-cli/index.js +16 -1
  6. package/frigg-cli/ssm-command/index.js +270 -0
  7. package/frigg-cli/ssm-command/index.test.js +301 -0
  8. package/infrastructure/__tests__/helpers/test-utils.js +3 -5
  9. package/infrastructure/__tests__/scoped-environment.test.js +126 -0
  10. package/infrastructure/domains/admin-scripts/admin-script-builder.js +17 -3
  11. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +45 -0
  12. package/infrastructure/domains/database/migration-builder.js +46 -9
  13. package/infrastructure/domains/database/migration-builder.test.js +101 -0
  14. package/infrastructure/domains/integration/integration-builder.js +65 -9
  15. package/infrastructure/domains/integration/integration-builder.test.js +95 -0
  16. package/infrastructure/domains/networking/vpc-builder.js +57 -7
  17. package/infrastructure/domains/networking/vpc-builder.test.js +41 -0
  18. package/infrastructure/domains/networking/vpc-resolver.js +12 -3
  19. package/infrastructure/domains/networking/vpc-resolver.test.js +40 -0
  20. package/infrastructure/domains/parameters/offload-utils.js +175 -0
  21. package/infrastructure/domains/parameters/offload-utils.test.js +193 -0
  22. package/infrastructure/domains/parameters/ssm-builder.js +60 -14
  23. package/infrastructure/domains/parameters/ssm-builder.test.js +145 -1
  24. package/infrastructure/domains/scheduler/scheduler-builder.js +44 -8
  25. package/infrastructure/domains/scheduler/scheduler-builder.test.js +118 -0
  26. package/infrastructure/domains/security/iam-generator.js +33 -1
  27. package/infrastructure/domains/security/iam-generator.test.js +73 -0
  28. package/infrastructure/domains/security/templates/frigg-deployment-iam-stack.yaml +15 -0
  29. package/infrastructure/domains/security/templates/iam-policy-full.json +7 -2
  30. package/infrastructure/domains/shared/builder-orchestrator.js +14 -0
  31. package/infrastructure/domains/shared/builder-orchestrator.test.js +45 -0
  32. package/infrastructure/domains/shared/environment-builder.js +48 -38
  33. package/infrastructure/domains/shared/environment-builder.test.js +113 -97
  34. package/infrastructure/domains/shared/function-environments.js +97 -0
  35. package/infrastructure/domains/shared/function-environments.test.js +146 -0
  36. package/infrastructure/infrastructure-composer.js +5 -0
  37. package/infrastructure/infrastructure-composer.test.js +69 -14
  38. package/infrastructure/integration.test.js +3 -5
  39. package/package.json +8 -7
@@ -1062,7 +1062,18 @@ describe('composeServerlessDefinition', () => {
1062
1062
  });
1063
1063
 
1064
1064
  describe('SSM Configuration', () => {
1065
- it('should add SSM configuration when ssm.enable is true', async () => {
1065
+ const originalSkipDiscovery = process.env.FRIGG_SKIP_AWS_DISCOVERY;
1066
+
1067
+ afterEach(() => {
1068
+ if (originalSkipDiscovery === undefined) {
1069
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1070
+ } else {
1071
+ process.env.FRIGG_SKIP_AWS_DISCOVERY = originalSkipDiscovery;
1072
+ }
1073
+ });
1074
+
1075
+ it('should add the broad SSM read grant when ssm.enable is true without offload', async () => {
1076
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1066
1077
  const appDefinition = {
1067
1078
  ssm: { enable: true },
1068
1079
  integrations: []
@@ -1070,12 +1081,10 @@ describe('composeServerlessDefinition', () => {
1070
1081
 
1071
1082
  const result = await composeServerlessDefinition(appDefinition);
1072
1083
 
1073
- // Check lambda layers
1074
- expect(result.provider.layers).toEqual([
1075
- 'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
1076
- ]);
1084
+ // We deliberately do NOT use the AWS Parameters-and-Secrets extension layer
1085
+ expect(result.provider.layers).toBeUndefined();
1077
1086
 
1078
- // Check IAM permissions
1087
+ // Broad read grant present
1079
1088
  const ssmPermission = result.provider.iamRoleStatements.find(
1080
1089
  statement => statement.Action.includes('ssm:GetParameter')
1081
1090
  );
@@ -1086,13 +1095,56 @@ describe('composeServerlessDefinition', () => {
1086
1095
  'ssm:GetParameters',
1087
1096
  'ssm:GetParametersByPath'
1088
1097
  ],
1089
- Resource: [
1090
- 'arn:aws:ssm:${self:provider.region}:*:parameter/${self:service}/${self:provider.stage}/*'
1091
- ]
1098
+ Resource: {
1099
+ 'Fn::Sub': 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/*'
1100
+ }
1092
1101
  });
1093
1102
 
1094
- // Check environment variable
1095
- expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBe('/${self:service}/${self:provider.stage}');
1103
+ // No offload markers -> no offload env vars
1104
+ expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBeUndefined();
1105
+ expect(result.provider.environment.FRIGG_SSM_OFFLOADED_KEYS).toBeUndefined();
1106
+ });
1107
+
1108
+ it('should offload marked keys and expose prefix + offloaded keys env vars', async () => {
1109
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1110
+ const appDefinition = {
1111
+ ssm: { enable: true },
1112
+ environment: { FOO: 'ssm', BAR: true },
1113
+ integrations: []
1114
+ };
1115
+
1116
+ const result = await composeServerlessDefinition(appDefinition);
1117
+
1118
+ // BAR stays in the Lambda env, FOO is offloaded out of it
1119
+ expect(result.provider.environment.BAR).toBe("${env:BAR, ''}");
1120
+ expect(result.provider.environment.FOO).toBeUndefined();
1121
+
1122
+ // Offload env contract
1123
+ expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBe(
1124
+ '/frigg/${self:service}/${self:provider.stage}'
1125
+ );
1126
+ expect(result.provider.environment.FRIGG_SSM_OFFLOADED_KEYS).toBe('FOO');
1127
+
1128
+ // Prefix-scoped read grant present alongside the broad grant
1129
+ const scoped = result.provider.iamRoleStatements.find(
1130
+ statement => statement.Resource === 'arn:aws:ssm:${self:provider.region}:${aws:accountId}:parameter/frigg/${self:service}/${self:provider.stage}/*'
1131
+ );
1132
+ expect(scoped).toBeDefined();
1133
+ });
1134
+
1135
+ it('should not add offload env vars when ssm.enable is true but nothing is marked', async () => {
1136
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1137
+ const appDefinition = {
1138
+ ssm: { enable: true },
1139
+ environment: { BAR: true },
1140
+ integrations: []
1141
+ };
1142
+
1143
+ const result = await composeServerlessDefinition(appDefinition);
1144
+
1145
+ expect(result.provider.environment.BAR).toBe("${env:BAR, ''}");
1146
+ expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBeUndefined();
1147
+ expect(result.provider.environment.FRIGG_SSM_OFFLOADED_KEYS).toBeUndefined();
1096
1148
  });
1097
1149
 
1098
1150
  it('should not add SSM configuration when ssm.enable is false', async () => {
@@ -1397,9 +1449,12 @@ describe('composeServerlessDefinition', () => {
1397
1449
  expect(result.provider.environment.KMS_KEY_ARN).toBeDefined();
1398
1450
  expect(result.custom.kmsGrants).toBeDefined();
1399
1451
 
1400
- // SSM
1401
- expect(result.provider.layers).toBeDefined();
1402
- expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBeDefined();
1452
+ // SSM (enabled without offload markers -> broad grant only, no offload env vars)
1453
+ const ssmPermission = result.provider.iamRoleStatements.find(
1454
+ statement => statement.Action && statement.Action.includes('ssm:GetParameter')
1455
+ );
1456
+ expect(ssmPermission).toBeDefined();
1457
+ expect(result.provider.environment.SSM_PARAMETER_PREFIX).toBeUndefined();
1403
1458
 
1404
1459
  // Integration
1405
1460
  expect(result.functions.testIntegration).toBeDefined();
@@ -108,11 +108,9 @@ describe('VPC/KMS/SSM Integration Tests', () => {
108
108
  );
109
109
  expect(kmsPermission).toBeDefined();
110
110
 
111
- // Verify SSM configuration
112
- expect(serverlessConfig.provider.layers).toEqual([
113
- 'arn:aws:lambda:${self:provider.region}:177933569100:layer:AWS-Parameters-and-Secrets-Lambda-Extension:11'
114
- ]);
115
- expect(serverlessConfig.provider.environment.SSM_PARAMETER_PREFIX).toBe('/${self:service}/${self:provider.stage}');
111
+ // Verify SSM configuration (enabled without offload markers -> broad grant only)
112
+ expect(serverlessConfig.provider.layers).toBeUndefined();
113
+ expect(serverlessConfig.provider.environment.SSM_PARAMETER_PREFIX).toBeUndefined();
116
114
 
117
115
  // Verify SSM IAM permissions
118
116
  const ssmPermission = serverlessConfig.provider.iamRoleStatements.find(
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.622.eb44ae5.0",
4
+ "version": "2.0.0--canary.625.27a7e7a.0",
5
5
  "bin": {
6
6
  "frigg": "./frigg-cli/index.js"
7
7
  },
@@ -21,13 +21,14 @@
21
21
  "@aws-sdk/client-rds": "^3.906.0",
22
22
  "@aws-sdk/client-s3": "^3.917.0",
23
23
  "@aws-sdk/client-secrets-manager": "^3.906.0",
24
+ "@aws-sdk/client-ssm": "^3.906.0",
24
25
  "@aws-sdk/client-sts": "^3.835.0",
25
26
  "@babel/eslint-parser": "^7.18.9",
26
27
  "@babel/parser": "^7.25.3",
27
28
  "@babel/traverse": "^7.25.3",
28
- "@friggframework/core": "2.0.0--canary.622.eb44ae5.0",
29
- "@friggframework/schemas": "2.0.0--canary.622.eb44ae5.0",
30
- "@friggframework/test": "2.0.0--canary.622.eb44ae5.0",
29
+ "@friggframework/core": "2.0.0--canary.625.27a7e7a.0",
30
+ "@friggframework/schemas": "2.0.0--canary.625.27a7e7a.0",
31
+ "@friggframework/test": "2.0.0--canary.625.27a7e7a.0",
31
32
  "@hapi/boom": "^10.0.1",
32
33
  "@inquirer/prompts": "^5.3.8",
33
34
  "axios": "^1.18.0",
@@ -55,8 +56,8 @@
55
56
  "validate-npm-package-name": "^5.0.0"
56
57
  },
57
58
  "devDependencies": {
58
- "@friggframework/eslint-config": "2.0.0--canary.622.eb44ae5.0",
59
- "@friggframework/prettier-config": "2.0.0--canary.622.eb44ae5.0",
59
+ "@friggframework/eslint-config": "2.0.0--canary.625.27a7e7a.0",
60
+ "@friggframework/prettier-config": "2.0.0--canary.625.27a7e7a.0",
60
61
  "aws-sdk-client-mock": "^4.1.0",
61
62
  "aws-sdk-client-mock-jest": "^4.1.0",
62
63
  "jest": "^30.1.3",
@@ -88,5 +89,5 @@
88
89
  "publishConfig": {
89
90
  "access": "public"
90
91
  },
91
- "gitHead": "eb44ae57f5765c305999cb7604edc6b1b1c537db"
92
+ "gitHead": "27a7e7ae02d6dc5789f5aba0fe5c4cf82320dc38"
92
93
  }