envilder 0.2.3 → 0.3.1
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/.gitattributes +66 -66
- package/.gitconfig +2 -2
- package/.github/dependabot.yml +39 -39
- package/.github/pull_request_template.md +20 -20
- package/.github/workflows/codeql-analysis.yml +49 -49
- package/.github/workflows/coverage-report.yml +73 -73
- package/.github/workflows/publish.yml +78 -0
- package/.github/workflows/unit-tests.yml +51 -48
- package/LICENSE +21 -21
- package/README.md +144 -95
- package/biome.json +2 -11
- package/package.json +19 -20
- package/src/cli/cliRunner.ts +10 -3
- package/src/index.ts +36 -5
- package/tests/cli/cliRunner.test.ts +16 -2
- package/tests/index.test.ts +27 -20
- package/tests/sample/autogenerated.env +1 -0
- package/vitest.config.js +12 -12
- package/lib/cli/cliRunner.d.ts +0 -3
- package/lib/cli/cliRunner.d.ts.map +0 -1
- package/lib/cli/cliRunner.js +0 -33
- package/lib/cli/cliRunner.js.map +0 -1
- package/lib/index.d.ts +0 -2
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -86
- package/lib/index.js.map +0 -1
- /package/tests/sample/{param_map.json → param-map.json} +0 -0
package/tests/index.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
|
+
import { SSM } from '@aws-sdk/client-ssm';
|
|
2
3
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
4
|
import { run } from '../src/index';
|
|
4
5
|
|
|
@@ -32,14 +33,23 @@ vi.mock('@aws-sdk/client-ssm', () => {
|
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
describe('Envilder CLI', () => {
|
|
36
|
+
const mockMapPath = './tests/param-map.json';
|
|
37
|
+
const mockEnvFilePath = './tests/.env.test';
|
|
38
|
+
|
|
35
39
|
afterEach(() => {
|
|
36
40
|
vi.clearAllMocks();
|
|
41
|
+
|
|
42
|
+
if (fs.existsSync(mockEnvFilePath)) {
|
|
43
|
+
fs.unlinkSync(mockEnvFilePath);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (fs.existsSync(mockMapPath)) {
|
|
47
|
+
fs.unlinkSync(mockMapPath);
|
|
48
|
+
}
|
|
37
49
|
});
|
|
38
50
|
|
|
39
51
|
it('Should_GenerateEnvFileFromSSMParameters_When_ValidSSMParametersAreProvided', async () => {
|
|
40
52
|
// Arrange
|
|
41
|
-
const mockMapPath = './tests/param_map.json';
|
|
42
|
-
const mockEnvFilePath = './tests/.env.test';
|
|
43
53
|
const paramMapContent = {
|
|
44
54
|
NEXT_PUBLIC_CREDENTIAL_EMAIL: '/path/to/ssm/email',
|
|
45
55
|
NEXT_PUBLIC_CREDENTIAL_PASSWORD: '/path/to/ssm/password',
|
|
@@ -53,14 +63,10 @@ describe('Envilder CLI', () => {
|
|
|
53
63
|
const envFileContent = fs.readFileSync(mockEnvFilePath, 'utf-8');
|
|
54
64
|
expect(envFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_EMAIL=mockedEmail@example.com');
|
|
55
65
|
expect(envFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_PASSWORD=mockedPassword');
|
|
56
|
-
fs.unlinkSync(mockEnvFilePath);
|
|
57
|
-
fs.unlinkSync(mockMapPath);
|
|
58
66
|
});
|
|
59
67
|
|
|
60
68
|
it('Should_ThrowError_When_SSMParameterIsNotFound', async () => {
|
|
61
69
|
// Arrange
|
|
62
|
-
const mockMapPath = './tests/param_map.json';
|
|
63
|
-
const mockEnvFilePath = './tests/.env.test';
|
|
64
70
|
const paramMapContent = {
|
|
65
71
|
NEXT_PUBLIC_CREDENTIAL_EMAIL: 'non-existent parameter',
|
|
66
72
|
};
|
|
@@ -71,14 +77,10 @@ describe('Envilder CLI', () => {
|
|
|
71
77
|
|
|
72
78
|
// Assert
|
|
73
79
|
await expect(action).rejects.toThrow('ParameterNotFound: non-existent parameter');
|
|
74
|
-
fs.unlinkSync(mockMapPath);
|
|
75
80
|
});
|
|
76
81
|
|
|
77
82
|
it('Should_AppendNewSSMParameters_When_EnvFileContainsExistingVariables', async () => {
|
|
78
83
|
// Arrange
|
|
79
|
-
const mockMapPath = './tests/param_map.json';
|
|
80
|
-
const mockEnvFilePath = './tests/.env.test';
|
|
81
|
-
|
|
82
84
|
const existingEnvContent = 'EXISTING_VAR=existingValue';
|
|
83
85
|
fs.writeFileSync(mockEnvFilePath, existingEnvContent);
|
|
84
86
|
const paramMapContent = {
|
|
@@ -95,14 +97,10 @@ describe('Envilder CLI', () => {
|
|
|
95
97
|
expect(updatedEnvFileContent).toContain('EXISTING_VAR=existingValue');
|
|
96
98
|
expect(updatedEnvFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_EMAIL=mockedEmail@example.com');
|
|
97
99
|
expect(updatedEnvFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_PASSWORD=mockedPassword');
|
|
98
|
-
fs.unlinkSync(mockEnvFilePath);
|
|
99
|
-
fs.unlinkSync(mockMapPath);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
it('Should_OverwriteSSMParameters_When_EnvFileContainsSameVariables', async () => {
|
|
103
103
|
// Arrange
|
|
104
|
-
const mockMapPath = './tests/param_map.json';
|
|
105
|
-
const mockEnvFilePath = './tests/.env.test';
|
|
106
104
|
const existingEnvContent = 'NEXT_PUBLIC_CREDENTIAL_EMAIL=oldEmail@example.com';
|
|
107
105
|
fs.writeFileSync(mockEnvFilePath, existingEnvContent);
|
|
108
106
|
const paramMapContent = {
|
|
@@ -118,14 +116,10 @@ describe('Envilder CLI', () => {
|
|
|
118
116
|
const updatedEnvFileContent = fs.readFileSync(mockEnvFilePath, 'utf-8');
|
|
119
117
|
expect(updatedEnvFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_EMAIL=mockedEmail@example.com');
|
|
120
118
|
expect(updatedEnvFileContent).toContain('NEXT_PUBLIC_CREDENTIAL_PASSWORD=mockedPassword');
|
|
121
|
-
fs.unlinkSync(mockEnvFilePath);
|
|
122
|
-
fs.unlinkSync(mockMapPath);
|
|
123
119
|
});
|
|
124
120
|
|
|
125
121
|
it('Should_LogWarning_When_SSMParameterHasNoValue', async () => {
|
|
126
122
|
// Arrange
|
|
127
|
-
const mockMapPath = './tests/param_map.json';
|
|
128
|
-
const mockEnvFilePath = './tests/.env.test';
|
|
129
123
|
const paramMapContent = {
|
|
130
124
|
NEXT_PUBLIC_CREDENTIAL_PASSWORD: '/path/to/ssm/password_no_value',
|
|
131
125
|
};
|
|
@@ -137,7 +131,20 @@ describe('Envilder CLI', () => {
|
|
|
137
131
|
|
|
138
132
|
// Assert
|
|
139
133
|
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Warning: No value found for'));
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('Should_ConfigureSSMClientWithProfile_When_ProfileIsProvided', async () => {
|
|
137
|
+
// Arrange
|
|
138
|
+
const mockProfile = 'test-profile';
|
|
139
|
+
const paramMapContent = {
|
|
140
|
+
NEXT_PUBLIC_CREDENTIAL_EMAIL: '/path/to/ssm/email',
|
|
141
|
+
};
|
|
142
|
+
fs.writeFileSync(mockMapPath, JSON.stringify(paramMapContent));
|
|
143
|
+
|
|
144
|
+
// Act
|
|
145
|
+
await run(mockMapPath, mockEnvFilePath, mockProfile);
|
|
146
|
+
|
|
147
|
+
// Assert
|
|
148
|
+
expect(vi.mocked(SSM).mock.calls[0][0]).toEqual(expect.objectContaining({ credentials: expect.anything() }));
|
|
142
149
|
});
|
|
143
150
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TOKEN_SECRET=this_is_for_test
|
package/vitest.config.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// vitest.config.js
|
|
2
|
-
import { defineConfig } from 'vitest/config';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
test: {
|
|
6
|
-
coverage: {
|
|
7
|
-
provider: 'v8',
|
|
8
|
-
reporter: ['text', 'html'],
|
|
9
|
-
reportsDirectory: './coverage',
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
});
|
|
1
|
+
// vitest.config.js
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
test: {
|
|
6
|
+
coverage: {
|
|
7
|
+
provider: 'v8',
|
|
8
|
+
reporter: ['text', 'html'],
|
|
9
|
+
reportsDirectory: './coverage',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
});
|
package/lib/cli/cliRunner.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cliRunner.d.ts","sourceRoot":"","sources":["../../src/cli/cliRunner.ts"],"names":[],"mappings":";AAKA,wBAAsB,SAAS,kBAkB9B"}
|
package/lib/cli/cliRunner.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
import { Command } from 'commander';
|
|
12
|
-
import { run } from '../index.js';
|
|
13
|
-
export function cliRunner() {
|
|
14
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const program = new Command();
|
|
16
|
-
program
|
|
17
|
-
.name('envilder')
|
|
18
|
-
.description('A CLI tool to generate .env files from AWS SSM parameters')
|
|
19
|
-
.version('0.1.0')
|
|
20
|
-
.requiredOption('--map <path>', 'Path to the JSON file with environment variable mapping')
|
|
21
|
-
.requiredOption('--envfile <path>', 'Path to the .env file to be generated');
|
|
22
|
-
yield program.parseAsync(process.argv);
|
|
23
|
-
const options = program.opts();
|
|
24
|
-
if (!options.map || !options.envfile) {
|
|
25
|
-
throw new Error('Missing required arguments: --map and --envfile');
|
|
26
|
-
}
|
|
27
|
-
yield run(options.map, options.envfile);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
cliRunner().catch((error) => {
|
|
31
|
-
console.error('🚨 Uh-oh! Looks like Mario fell into the wrong pipe! 🍄💥');
|
|
32
|
-
});
|
|
33
|
-
//# sourceMappingURL=cliRunner.js.map
|
package/lib/cli/cliRunner.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cliRunner.js","sourceRoot":"","sources":["../../src/cli/cliRunner.ts"],"names":[],"mappings":";;;;;;;;;;AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,UAAgB,SAAS;;QAC7B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;QAE9B,OAAO;aACJ,IAAI,CAAC,UAAU,CAAC;aAChB,WAAW,CAAC,2DAA2D,CAAC;aACxE,OAAO,CAAC,OAAO,CAAC;aAChB,cAAc,CAAC,cAAc,EAAE,yDAAyD,CAAC;aACzF,cAAc,CAAC,kBAAkB,EAAE,uCAAuC,CAAC,CAAC;QAE/E,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE/B,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;CAAA;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC"}
|
package/lib/index.d.ts
DELETED
package/lib/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAQ7D"}
|
package/lib/index.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import * as fs from 'node:fs';
|
|
11
|
-
import { GetParameterCommand, SSM } from '@aws-sdk/client-ssm';
|
|
12
|
-
import * as dotenv from 'dotenv';
|
|
13
|
-
const ssm = new SSM({});
|
|
14
|
-
export function run(mapPath, envFilePath) {
|
|
15
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
-
const paramMap = loadParamMap(mapPath);
|
|
17
|
-
const existingEnvVariables = loadExistingEnvVariables(envFilePath);
|
|
18
|
-
const updatedEnvVariables = yield fetchAndUpdateEnvVariables(paramMap, existingEnvVariables);
|
|
19
|
-
writeEnvFile(envFilePath, updatedEnvVariables);
|
|
20
|
-
console.log(`Environment File generated at '${envFilePath}'`);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
function loadParamMap(mapPath) {
|
|
24
|
-
const content = fs.readFileSync(mapPath, 'utf-8');
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(content);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error(`Error parsing JSON from ${mapPath}`);
|
|
30
|
-
throw new Error(`Invalid JSON in parameter map file: ${mapPath}`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function loadExistingEnvVariables(envFilePath) {
|
|
34
|
-
const envVariables = {};
|
|
35
|
-
if (!fs.existsSync(envFilePath))
|
|
36
|
-
return envVariables;
|
|
37
|
-
const existingEnvContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
38
|
-
const parsedEnv = dotenv.parse(existingEnvContent);
|
|
39
|
-
Object.assign(envVariables, parsedEnv);
|
|
40
|
-
return envVariables;
|
|
41
|
-
}
|
|
42
|
-
function fetchAndUpdateEnvVariables(paramMap, existingEnvVariables) {
|
|
43
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
-
const errors = [];
|
|
45
|
-
for (const [envVar, ssmName] of Object.entries(paramMap)) {
|
|
46
|
-
try {
|
|
47
|
-
const value = yield fetchSSMParameter(ssmName);
|
|
48
|
-
if (value) {
|
|
49
|
-
existingEnvVariables[envVar] = value;
|
|
50
|
-
console.log(`${envVar}=${value.length > 3 ? '*'.repeat(value.length - 3) + value.slice(-3) : '*'.repeat(value.length)}`);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
console.error(`Warning: No value found for: '${ssmName}'`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
console.error(`Error fetching parameter: '${ssmName}'`);
|
|
58
|
-
errors.push(`ParameterNotFound: ${ssmName}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (errors.length > 0) {
|
|
62
|
-
throw new Error(`Some parameters could not be fetched:\n${errors.join('\n')}`);
|
|
63
|
-
}
|
|
64
|
-
return existingEnvVariables;
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function fetchSSMParameter(ssmName) {
|
|
68
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
69
|
-
const command = new GetParameterCommand({
|
|
70
|
-
Name: ssmName,
|
|
71
|
-
WithDecryption: true,
|
|
72
|
-
});
|
|
73
|
-
const { Parameter } = yield ssm.send(command);
|
|
74
|
-
return Parameter === null || Parameter === void 0 ? void 0 : Parameter.Value;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function writeEnvFile(envFilePath, envVariables) {
|
|
78
|
-
const envContent = Object.entries(envVariables)
|
|
79
|
-
.map(([key, value]) => {
|
|
80
|
-
const escapedValue = value.replace(/(\n|\r|\n\r)/g, '\\n').replace(/"/g, '\\"');
|
|
81
|
-
return `${key}=${escapedValue}`;
|
|
82
|
-
})
|
|
83
|
-
.join('\n');
|
|
84
|
-
fs.writeFileSync(envFilePath, envContent);
|
|
85
|
-
}
|
|
86
|
-
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
File without changes
|