@friggframework/devtools 2.0.0--canary.461.ec909cf.0 → 2.0.0--canary.461.7b36f0f.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.
- package/frigg-cli/__tests__/unit/commands/build.test.js +6 -6
- package/frigg-cli/build-command/index.js +1 -1
- package/frigg-cli/deploy-command/index.js +6 -6
- package/frigg-cli/generate-command/index.js +2 -2
- package/frigg-cli/generate-iam-command.js +10 -10
- package/frigg-cli/start-command/index.js +1 -1
- package/frigg-cli/start-command/start-command.test.js +3 -3
- package/frigg-cli/utils/database-validator.js +14 -21
- package/infrastructure/REFACTOR.md +532 -0
- package/infrastructure/TRANSFORMATION-VISUAL.md +239 -0
- package/infrastructure/__tests__/postgres-config.test.js +1 -1
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-discovery.js +81 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/integration/integration-builder.js +178 -0
- package/infrastructure/domains/integration/integration-builder.test.js +362 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +257 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +188 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +169 -0
- package/infrastructure/domains/security/kms-builder.test.js +354 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +176 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/environment-builder.js +118 -0
- package/infrastructure/domains/shared/environment-builder.test.js +246 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +366 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +132 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +410 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +259 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +134 -0
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +85 -0
- package/infrastructure/scripts/build-prisma-layer.js +60 -47
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +8 -8
- package/infrastructure/aws-discovery.js +0 -1704
- package/infrastructure/aws-discovery.test.js +0 -1666
- package/infrastructure/serverless-template.js +0 -2804
- package/infrastructure/serverless-template.test.js +0 -1897
- /package/infrastructure/{POSTGRES-CONFIGURATION.md → docs/POSTGRES-CONFIGURATION.md} +0 -0
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +0 -0
- /package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Infrastructure Composer
|
|
3
|
+
*
|
|
4
|
+
* Application Layer - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Orchestrates the composition of serverless infrastructure definitions
|
|
7
|
+
* using domain builders and shared utilities.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Domain Builders
|
|
11
|
+
const { BuilderOrchestrator } = require('./domains/shared/builder-orchestrator');
|
|
12
|
+
const { VpcBuilder } = require('./domains/networking/vpc-builder');
|
|
13
|
+
const { KmsBuilder } = require('./domains/security/kms-builder');
|
|
14
|
+
const { AuroraBuilder } = require('./domains/database/aurora-builder');
|
|
15
|
+
const { SsmBuilder } = require('./domains/parameters/ssm-builder');
|
|
16
|
+
const { WebsocketBuilder } = require('./domains/integration/websocket-builder');
|
|
17
|
+
const { IntegrationBuilder } = require('./domains/integration/integration-builder');
|
|
18
|
+
|
|
19
|
+
// Utilities
|
|
20
|
+
const { modifyHandlerPaths } = require('./domains/shared/utilities/handler-path-resolver');
|
|
21
|
+
const { createBaseDefinition } = require('./domains/shared/utilities/base-definition-factory');
|
|
22
|
+
const { ensurePrismaLayerExists } = require('./domains/shared/utilities/prisma-layer-manager');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Compose serverless definition using domain builders
|
|
26
|
+
*
|
|
27
|
+
* This is the main entry point that orchestrates all infrastructure building
|
|
28
|
+
* using the DDD/Hexagonal architecture pattern.
|
|
29
|
+
*/
|
|
30
|
+
const composeServerlessDefinition = async (AppDefinition) => {
|
|
31
|
+
console.log('🏗️ Composing serverless definition with domain builders...');
|
|
32
|
+
|
|
33
|
+
// Ensure Prisma layer exists (minimal, runtime only)
|
|
34
|
+
await ensurePrismaLayerExists(AppDefinition.database || {});
|
|
35
|
+
|
|
36
|
+
// Create orchestrator with all domain builders
|
|
37
|
+
const orchestrator = new BuilderOrchestrator([
|
|
38
|
+
new VpcBuilder(),
|
|
39
|
+
new KmsBuilder(),
|
|
40
|
+
new AuroraBuilder(),
|
|
41
|
+
new SsmBuilder(),
|
|
42
|
+
new WebsocketBuilder(),
|
|
43
|
+
new IntegrationBuilder(),
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
// Build all infrastructure (orchestrator handles validation, dependencies, parallel execution)
|
|
47
|
+
// Builders automatically skip if shouldExecute() returns false (e.g., local mode)
|
|
48
|
+
const { merged, discoveredResources, appEnvironmentVars } =
|
|
49
|
+
await orchestrator.buildAll(AppDefinition);
|
|
50
|
+
|
|
51
|
+
// Create base definition with core functions
|
|
52
|
+
const definition = createBaseDefinition(
|
|
53
|
+
AppDefinition,
|
|
54
|
+
appEnvironmentVars,
|
|
55
|
+
discoveredResources
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// Merge builder results into definition
|
|
59
|
+
Object.assign(definition.resources.Resources, merged.resources);
|
|
60
|
+
definition.provider.iamRoleStatements.push(...merged.iamStatements);
|
|
61
|
+
Object.assign(definition.provider.environment, merged.environment);
|
|
62
|
+
Object.assign(definition.functions, merged.functions);
|
|
63
|
+
|
|
64
|
+
if (merged.vpcConfig) {
|
|
65
|
+
definition.provider.vpc = merged.vpcConfig;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Add unique plugins (avoid duplicates)
|
|
69
|
+
merged.plugins.forEach(plugin => {
|
|
70
|
+
if (!definition.plugins.includes(plugin)) {
|
|
71
|
+
definition.plugins.push(plugin);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
Object.assign(definition.custom, merged.custom);
|
|
76
|
+
|
|
77
|
+
// Modify handler paths for offline mode
|
|
78
|
+
definition.functions = modifyHandlerPaths(definition.functions);
|
|
79
|
+
|
|
80
|
+
console.log('✅ Serverless definition composed successfully');
|
|
81
|
+
return definition;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
module.exports = { composeServerlessDefinition };
|
|
85
|
+
|
|
@@ -3,25 +3,26 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Build Prisma Lambda Layer
|
|
5
5
|
*
|
|
6
|
-
* Creates a Lambda Layer containing Prisma
|
|
6
|
+
* Creates a MINIMAL Lambda Layer containing only Prisma runtime client and query engines.
|
|
7
7
|
* This reduces individual Lambda function sizes by ~60% (120MB → 45MB).
|
|
8
8
|
*
|
|
9
|
+
* IMPORTANT: This layer does NOT include the Prisma CLI (saves ~82MB).
|
|
10
|
+
* The CLI is only needed for migrations and is packaged separately with the dbMigrate function.
|
|
11
|
+
*
|
|
9
12
|
* The layer is configured based on AppDefinition database settings:
|
|
10
|
-
* - PostgreSQL: Includes PostgreSQL client + query engine
|
|
11
|
-
* - MongoDB: Includes MongoDB client + query engine (if needed)
|
|
13
|
+
* - PostgreSQL: Includes PostgreSQL client + query engine only
|
|
14
|
+
* - MongoDB: Includes MongoDB client + query engine only (if needed)
|
|
12
15
|
* - Defaults to PostgreSQL only if not specified
|
|
13
16
|
*
|
|
14
17
|
* Usage:
|
|
15
|
-
* node scripts/build-prisma-layer.js
|
|
18
|
+
* node scripts/build-prisma-layer.js
|
|
16
19
|
* npm run build:prisma-layer
|
|
17
20
|
*
|
|
18
21
|
* Output:
|
|
19
22
|
* layers/prisma/nodejs/node_modules/
|
|
20
|
-
* ├── @prisma/client
|
|
21
|
-
* ├── @prisma/engines
|
|
23
|
+
* ├── @prisma/client (runtime only, ~10-15MB)
|
|
22
24
|
* ├── generated/prisma-postgresql (if PostgreSQL enabled)
|
|
23
|
-
*
|
|
24
|
-
* └── prisma (CLI for migrations)
|
|
25
|
+
* └── generated/prisma-mongodb (if MongoDB enabled)
|
|
25
26
|
*
|
|
26
27
|
* See: LAMBDA-LAYER-PRISMA.md for complete documentation
|
|
27
28
|
*/
|
|
@@ -108,6 +109,10 @@ const FILES_TO_REMOVE = [
|
|
|
108
109
|
'CHANGELOG*', // Changelog files
|
|
109
110
|
'*.test.js', // Test files
|
|
110
111
|
'*.spec.js', // Spec files
|
|
112
|
+
'*mysql.wasm*', // MySQL WASM files (not needed for PostgreSQL)
|
|
113
|
+
'*cockroachdb.wasm*', // CockroachDB WASM files
|
|
114
|
+
'*sqlite.wasm*', // SQLite WASM files
|
|
115
|
+
'*sqlserver.wasm*', // SQL Server WASM files
|
|
111
116
|
];
|
|
112
117
|
|
|
113
118
|
// ANSI color codes for output
|
|
@@ -179,25 +184,20 @@ async function createLayerStructure() {
|
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
/**
|
|
182
|
-
* Install Prisma
|
|
183
|
-
*
|
|
187
|
+
* Install Prisma client directly into layer (RUNTIME ONLY - NO CLI)
|
|
188
|
+
*
|
|
189
|
+
* The Prisma CLI is NOT included in this layer to keep it small.
|
|
190
|
+
* For migrations, the dbMigrate function has its own separate packaging with CLI.
|
|
184
191
|
*/
|
|
185
|
-
async function installPrismaPackages(
|
|
186
|
-
logStep(3,
|
|
192
|
+
async function installPrismaPackages() {
|
|
193
|
+
logStep(3, 'Installing Prisma runtime client (CLI excluded)');
|
|
187
194
|
|
|
188
|
-
// Create a minimal package.json
|
|
195
|
+
// Create a minimal package.json with ONLY the runtime client
|
|
189
196
|
const dependencies = {
|
|
190
197
|
'@prisma/client': '^6.16.3',
|
|
191
|
-
'@prisma/engines': '^6.16.3',
|
|
192
198
|
};
|
|
193
199
|
|
|
194
|
-
|
|
195
|
-
if (includeCLI) {
|
|
196
|
-
dependencies['prisma'] = '^6.16.3';
|
|
197
|
-
log(' Including Prisma CLI for migrations', 'yellow');
|
|
198
|
-
} else {
|
|
199
|
-
log(' Runtime only - CLI excluded (saves ~82MB)', 'green');
|
|
200
|
-
}
|
|
200
|
+
log(' Runtime client only - CLI excluded (saves ~82MB)', 'green');
|
|
201
201
|
|
|
202
202
|
const layerPackageJson = {
|
|
203
203
|
name: 'prisma-lambda-layer',
|
|
@@ -210,14 +210,21 @@ async function installPrismaPackages(includeCLI = false) {
|
|
|
210
210
|
await fs.writeJson(packageJsonPath, layerPackageJson, { spaces: 2 });
|
|
211
211
|
logSuccess('Created layer package.json');
|
|
212
212
|
|
|
213
|
-
// Install Prisma packages
|
|
214
|
-
|
|
213
|
+
// Install Prisma packages with Lambda binary target
|
|
214
|
+
// Setting PRISMA_CLI_BINARY_TARGETS ensures only rhel-openssl-3.0.x binary is downloaded
|
|
215
|
+
log('Installing @prisma/client for AWS Lambda (rhel-openssl-3.0.x)...');
|
|
215
216
|
try {
|
|
216
|
-
|
|
217
|
+
const env = {
|
|
218
|
+
...process.env,
|
|
219
|
+
PRISMA_CLI_BINARY_TARGETS: 'rhel-openssl-3.0.x',
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
execSync('npm install --omit=dev --no-package-lock', {
|
|
217
223
|
cwd: path.join(LAYER_OUTPUT_PATH, 'nodejs'),
|
|
218
|
-
stdio: 'inherit'
|
|
224
|
+
stdio: 'inherit',
|
|
225
|
+
env,
|
|
219
226
|
});
|
|
220
|
-
logSuccess('Prisma packages installed');
|
|
227
|
+
logSuccess('Prisma packages installed with Lambda binary target');
|
|
221
228
|
} catch (error) {
|
|
222
229
|
throw new Error(`Failed to install Prisma packages: ${error.message}`);
|
|
223
230
|
}
|
|
@@ -402,23 +409,22 @@ async function verifyRhelBinaries(expectedClients) {
|
|
|
402
409
|
|
|
403
410
|
/**
|
|
404
411
|
* Verify required files exist
|
|
405
|
-
*
|
|
412
|
+
* Runtime layer should NOT have CLI files
|
|
406
413
|
*/
|
|
407
|
-
async function verifyLayerStructure(
|
|
408
|
-
logStep(8, 'Verifying layer structure');
|
|
414
|
+
async function verifyLayerStructure() {
|
|
415
|
+
logStep(8, 'Verifying layer structure (runtime only)');
|
|
409
416
|
|
|
410
417
|
const requiredPaths = [
|
|
411
418
|
'@prisma/client/runtime',
|
|
412
419
|
'@prisma/client/index.d.ts',
|
|
413
|
-
'
|
|
414
|
-
'generated/prisma-postgresql/schema.prisma', // PostgreSQL
|
|
420
|
+
'generated/prisma-postgresql/schema.prisma', // PostgreSQL (default)
|
|
415
421
|
];
|
|
416
422
|
|
|
417
|
-
//
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
423
|
+
// Verify CLI is NOT present (keeps layer small)
|
|
424
|
+
const forbiddenPaths = [
|
|
425
|
+
'prisma/build',
|
|
426
|
+
'.bin/prisma',
|
|
427
|
+
];
|
|
422
428
|
|
|
423
429
|
let allPresent = true;
|
|
424
430
|
|
|
@@ -436,7 +442,15 @@ async function verifyLayerStructure(includeCLI) {
|
|
|
436
442
|
throw new Error('Layer structure verification failed - missing required files');
|
|
437
443
|
}
|
|
438
444
|
|
|
439
|
-
logSuccess('All required files present');
|
|
445
|
+
logSuccess('All required runtime files present');
|
|
446
|
+
|
|
447
|
+
// Verify CLI is NOT present
|
|
448
|
+
for (const forbiddenPath of forbiddenPaths) {
|
|
449
|
+
const fullPath = path.join(LAYER_NODE_MODULES, forbiddenPath);
|
|
450
|
+
if (await fs.pathExists(fullPath)) {
|
|
451
|
+
logWarning(` ⚠ ${forbiddenPath} found (should be excluded for minimal layer)`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
440
454
|
}
|
|
441
455
|
|
|
442
456
|
/**
|
|
@@ -455,11 +469,11 @@ async function displayLayerSummary() {
|
|
|
455
469
|
log(`Layer size: ~${layerSizeMB} MB`, 'green');
|
|
456
470
|
|
|
457
471
|
log('\nPackages included:', 'bright');
|
|
458
|
-
log(' - prisma (
|
|
459
|
-
log(' -
|
|
460
|
-
log('
|
|
461
|
-
log(' -
|
|
462
|
-
log('
|
|
472
|
+
log(' - @prisma/client (runtime only - ~10-15MB)', 'reset');
|
|
473
|
+
log(' - generated/prisma-postgresql (PostgreSQL client)', 'reset');
|
|
474
|
+
log('\nPackages EXCLUDED for minimal size:', 'bright');
|
|
475
|
+
log(' - prisma CLI (excluded - only in dbMigrate function)', 'yellow');
|
|
476
|
+
log(' - @prisma/engines (minimal - only rhel binary)', 'yellow');
|
|
463
477
|
|
|
464
478
|
log('\nNext steps:', 'bright');
|
|
465
479
|
log(' 1. Verify layer structure: ls -lah layers/prisma/nodejs/node_modules/', 'reset');
|
|
@@ -473,13 +487,12 @@ async function displayLayerSummary() {
|
|
|
473
487
|
/**
|
|
474
488
|
* Main build function
|
|
475
489
|
* @param {Object} databaseConfig - Database configuration from AppDefinition.database
|
|
476
|
-
* @param {Boolean} includeCLI - Whether to include Prisma CLI (false = runtime only)
|
|
477
490
|
*/
|
|
478
|
-
async function buildPrismaLayer(databaseConfig = {}
|
|
491
|
+
async function buildPrismaLayer(databaseConfig = {}) {
|
|
479
492
|
const startTime = Date.now();
|
|
480
493
|
|
|
481
494
|
log('\n' + '='.repeat(60), 'bright');
|
|
482
|
-
log(
|
|
495
|
+
log(' Building Minimal Prisma Lambda Layer (Runtime Only)', 'bright');
|
|
483
496
|
log('='.repeat(60) + '\n', 'bright');
|
|
484
497
|
|
|
485
498
|
// Log paths
|
|
@@ -493,12 +506,12 @@ async function buildPrismaLayer(databaseConfig = {}, includeCLI = false) {
|
|
|
493
506
|
try {
|
|
494
507
|
await cleanLayerDirectory();
|
|
495
508
|
await createLayerStructure();
|
|
496
|
-
await installPrismaPackages(
|
|
509
|
+
await installPrismaPackages(); // Install runtime client only (NO CLI)
|
|
497
510
|
await copyPrismaPackages(clientPackages); // Copy generated clients from core
|
|
498
511
|
await removeUnnecessaryFiles(); // Remove source maps, docs, tests (37MB+)
|
|
499
512
|
await removeNonRhelBinaries(); // Remove non-Linux binaries
|
|
500
513
|
await verifyRhelBinaries(clientPackages); // Verify query engines present
|
|
501
|
-
await verifyLayerStructure(
|
|
514
|
+
await verifyLayerStructure(); // Verify minimal runtime structure
|
|
502
515
|
await displayLayerSummary();
|
|
503
516
|
|
|
504
517
|
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js}
RENAMED
|
@@ -5,7 +5,8 @@ const { AWSDiscovery } = require('./aws-discovery');
|
|
|
5
5
|
|
|
6
6
|
// Mock dependencies
|
|
7
7
|
jest.mock('fs');
|
|
8
|
-
|
|
8
|
+
// Mock will be updated when tests are rewritten for new provider architecture
|
|
9
|
+
// jest.mock('./aws-discovery');
|
|
9
10
|
|
|
10
11
|
describe('BuildTimeDiscovery', () => {
|
|
11
12
|
let buildTimeDiscovery;
|
|
@@ -14,7 +15,7 @@ describe('BuildTimeDiscovery', () => {
|
|
|
14
15
|
|
|
15
16
|
beforeEach(() => {
|
|
16
17
|
buildTimeDiscovery = new BuildTimeDiscovery('us-east-1');
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
// Mock AWSDiscovery
|
|
19
20
|
mockAWSDiscovery = {
|
|
20
21
|
discoverResources: jest.fn(),
|
|
@@ -27,7 +28,7 @@ describe('BuildTimeDiscovery', () => {
|
|
|
27
28
|
|
|
28
29
|
// Reset environment
|
|
29
30
|
process.env = { ...originalEnv };
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
jest.clearAllMocks();
|
|
32
33
|
});
|
|
33
34
|
|
|
@@ -338,7 +339,7 @@ describe('BuildTimeDiscovery', () => {
|
|
|
338
339
|
it('should process config file when configPath provided', async () => {
|
|
339
340
|
const mockConfigContent = 'provider: aws';
|
|
340
341
|
const mockResources = { defaultVpcId: 'vpc-12345678' };
|
|
341
|
-
|
|
342
|
+
|
|
342
343
|
fs.readFileSync.mockReturnValue(mockConfigContent);
|
|
343
344
|
mockAWSDiscovery.discoverResources.mockResolvedValue(mockResources);
|
|
344
345
|
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
SSMClient,
|
|
3
|
+
GetParametersByPathCommand,
|
|
4
|
+
PutParameterCommand,
|
|
5
|
+
DeleteParameterCommand,
|
|
6
|
+
DescribeParametersCommand,
|
|
7
|
+
GetParameterHistoryCommand,
|
|
8
|
+
} from '@aws-sdk/client-ssm';
|
|
2
9
|
|
|
3
10
|
class AWSParameterStore {
|
|
4
11
|
constructor(config = {}) {
|
|
5
|
-
this.ssm = new
|
|
12
|
+
this.ssm = new SSMClient({
|
|
6
13
|
region: config.region || process.env.AWS_REGION || 'us-east-1',
|
|
7
14
|
...config.awsConfig
|
|
8
15
|
});
|
|
@@ -20,16 +27,16 @@ class AWSParameterStore {
|
|
|
20
27
|
|
|
21
28
|
try {
|
|
22
29
|
do {
|
|
23
|
-
const
|
|
30
|
+
const command = new GetParametersByPathCommand({
|
|
24
31
|
Path: path,
|
|
25
32
|
Recursive: true,
|
|
26
33
|
WithDecryption: true,
|
|
27
34
|
MaxResults: 10,
|
|
28
35
|
NextToken: nextToken
|
|
29
|
-
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const response = await this.ssm.send(command);
|
|
30
39
|
|
|
31
|
-
const response = await this.ssm.getParametersByPath(params).promise();
|
|
32
|
-
|
|
33
40
|
for (const param of response.Parameters) {
|
|
34
41
|
const key = this.extractKeyFromPath(param.Name, environment);
|
|
35
42
|
parameters.push({
|
|
@@ -60,7 +67,7 @@ class AWSParameterStore {
|
|
|
60
67
|
*/
|
|
61
68
|
async setParameter(environment, variable) {
|
|
62
69
|
const parameterName = `${this.prefix}/${environment}/${variable.key}`;
|
|
63
|
-
|
|
70
|
+
|
|
64
71
|
try {
|
|
65
72
|
const params = {
|
|
66
73
|
Name: parameterName,
|
|
@@ -89,8 +96,9 @@ class AWSParameterStore {
|
|
|
89
96
|
params.KeyId = this.kmsKeyId;
|
|
90
97
|
}
|
|
91
98
|
|
|
92
|
-
const
|
|
93
|
-
|
|
99
|
+
const command = new PutParameterCommand(params);
|
|
100
|
+
const response = await this.ssm.send(command);
|
|
101
|
+
|
|
94
102
|
return {
|
|
95
103
|
success: true,
|
|
96
104
|
version: response.Version,
|
|
@@ -107,9 +115,10 @@ class AWSParameterStore {
|
|
|
107
115
|
*/
|
|
108
116
|
async deleteParameter(environment, key) {
|
|
109
117
|
const parameterName = `${this.prefix}/${environment}/${key}`;
|
|
110
|
-
|
|
118
|
+
|
|
111
119
|
try {
|
|
112
|
-
|
|
120
|
+
const command = new DeleteParameterCommand({ Name: parameterName });
|
|
121
|
+
await this.ssm.send(command);
|
|
113
122
|
return { success: true };
|
|
114
123
|
} catch (error) {
|
|
115
124
|
if (error.code === 'ParameterNotFound') {
|
|
@@ -142,7 +151,7 @@ class AWSParameterStore {
|
|
|
142
151
|
try {
|
|
143
152
|
const existing = existingParams.find(p => p.key === variable.key);
|
|
144
153
|
const result = await this.setParameter(environment, variable);
|
|
145
|
-
|
|
154
|
+
|
|
146
155
|
if (existing) {
|
|
147
156
|
results.updated.push({ key: variable.key, ...result });
|
|
148
157
|
} else {
|
|
@@ -201,7 +210,8 @@ class AWSParameterStore {
|
|
|
201
210
|
async validateAccess() {
|
|
202
211
|
try {
|
|
203
212
|
// Try to list parameters to check access
|
|
204
|
-
|
|
213
|
+
const command = new DescribeParametersCommand({ MaxResults: 1 });
|
|
214
|
+
await this.ssm.send(command);
|
|
205
215
|
return { valid: true };
|
|
206
216
|
} catch (error) {
|
|
207
217
|
return {
|
|
@@ -221,12 +231,12 @@ class AWSParameterStore {
|
|
|
221
231
|
content += `# Generated on ${new Date().toISOString()}\n\n`;
|
|
222
232
|
|
|
223
233
|
const sorted = parameters.sort((a, b) => a.key.localeCompare(b.key));
|
|
224
|
-
|
|
234
|
+
|
|
225
235
|
for (const param of sorted) {
|
|
226
236
|
if (param.description) {
|
|
227
237
|
content += `# ${param.description}\n`;
|
|
228
238
|
}
|
|
229
|
-
|
|
239
|
+
|
|
230
240
|
// Mask secret values in export
|
|
231
241
|
const value = param.isSecret ? '**REDACTED**' : param.value;
|
|
232
242
|
content += `${param.key}=${value}\n\n`;
|
|
@@ -240,13 +250,14 @@ class AWSParameterStore {
|
|
|
240
250
|
*/
|
|
241
251
|
async getParameterHistory(environment, key, maxResults = 10) {
|
|
242
252
|
const parameterName = `${this.prefix}/${environment}/${key}`;
|
|
243
|
-
|
|
253
|
+
|
|
244
254
|
try {
|
|
245
|
-
const
|
|
255
|
+
const command = new GetParameterHistoryCommand({
|
|
246
256
|
Name: parameterName,
|
|
247
257
|
WithDecryption: false,
|
|
248
258
|
MaxResults: maxResults
|
|
249
|
-
})
|
|
259
|
+
});
|
|
260
|
+
const response = await this.ssm.send(command);
|
|
250
261
|
|
|
251
262
|
return response.Parameters.map(p => ({
|
|
252
263
|
version: p.Version,
|
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.461.
|
|
4
|
+
"version": "2.0.0--canary.461.7b36f0f.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-ec2": "^3.835.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.835.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@babel/eslint-parser": "^7.18.9",
|
|
12
12
|
"@babel/parser": "^7.25.3",
|
|
13
13
|
"@babel/traverse": "^7.25.3",
|
|
14
|
-
"@friggframework/schemas": "2.0.0--canary.461.
|
|
15
|
-
"@friggframework/test": "2.0.0--canary.461.
|
|
14
|
+
"@friggframework/schemas": "2.0.0--canary.461.7b36f0f.0",
|
|
15
|
+
"@friggframework/test": "2.0.0--canary.461.7b36f0f.0",
|
|
16
16
|
"@hapi/boom": "^10.0.1",
|
|
17
17
|
"@inquirer/prompts": "^5.3.8",
|
|
18
18
|
"axios": "^1.7.2",
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
"serverless-http": "^2.7.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@friggframework/eslint-config": "2.0.0--canary.461.
|
|
38
|
-
"@friggframework/prettier-config": "2.0.0--canary.461.
|
|
37
|
+
"@friggframework/eslint-config": "2.0.0--canary.461.7b36f0f.0",
|
|
38
|
+
"@friggframework/prettier-config": "2.0.0--canary.461.7b36f0f.0",
|
|
39
39
|
"aws-sdk-client-mock": "^4.1.0",
|
|
40
40
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
41
41
|
"jest": "^30.1.3",
|
|
42
|
+
"osls": "^3.40.1",
|
|
42
43
|
"prettier": "^2.7.1",
|
|
43
|
-
"serverless": "3.39.0",
|
|
44
44
|
"serverless-dotenv-plugin": "^6.0.0",
|
|
45
|
-
"serverless-
|
|
45
|
+
"serverless-esbuild": "^1.54.3",
|
|
46
46
|
"serverless-kms-grants": "^1.0.0",
|
|
47
47
|
"serverless-offline": "^13.8.0",
|
|
48
48
|
"serverless-offline-sqs": "^8.0.0",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "7b36f0f437980499b06c66adc4ddbc3e80f6d8e6"
|
|
74
74
|
}
|