envilder 0.2.0 โ 0.2.2
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/README.md +20 -18
- package/lib/cli/cliRunner.js +1 -1
- package/lib/cli/cliRunner.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +23 -15
- package/lib/index.js.map +1 -1
- package/package.json +2 -1
- package/src/cli/cliRunner.ts +1 -1
- package/src/index.ts +26 -15
- package/tests/index.test.ts +2 -6
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
3
|
`Envilder` is a CLI tool to manage AWS SSM Parameter Store parameters and automatically generate the required `.env` file. This tool simplifies environment variable management for projects, avoiding manual updates and ensuring consistency across environments.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# โจ Features
|
|
6
6
|
|
|
7
7
|
- ๐ Fetch parameters securely from AWS SSM Parameter Store.
|
|
8
8
|
- โก Automatically generates a `.env` file with specified parameters.
|
|
9
|
-
- ๐ก๏ธ Handles
|
|
9
|
+
- ๐ก๏ธ Handles encrypted (currently only supported) SSM parameters.
|
|
10
10
|
- ๐ชถ Lightweight and simple to use.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Prerequisites
|
|
13
13
|
Before using `Envilder`, ensure that you have the AWS CLI installed and properly configured on your local machine. This configuration is required for `Envilder` to access and manage parameters in AWS SSM.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## AWS CLI Installation & Configuration
|
|
16
16
|
1. Install the AWS CLI by following the instructions [here](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
|
|
17
17
|
2. After installation, configure the AWS CLI using the following command:
|
|
18
18
|
|
|
@@ -28,14 +28,14 @@ Before using `Envilder`, ensure that you have the AWS CLI installed and properly
|
|
|
28
28
|
|
|
29
29
|
Make sure that the AWS credentials you're using have the appropriate permissions to access the SSM Parameter Store in your AWS account.
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
# Installation
|
|
32
32
|
You can install `Envilder` globally using yarn. This will allow you to use the `envilder` command from any directory on your system.
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
yarn global add envilder
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
# ๐ฆ Installation
|
|
39
39
|
|
|
40
40
|
You can install **envilder** globally or locally using npm:
|
|
41
41
|
|
|
@@ -43,21 +43,21 @@ You can install **envilder** globally or locally using npm:
|
|
|
43
43
|
npm install -g envilder
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
# ๐ Usage
|
|
47
47
|
|
|
48
48
|
Envilder requires two arguments:
|
|
49
49
|
|
|
50
50
|
- `--map <path>`: Path to a JSON file mapping environment variable names to SSM parameters.
|
|
51
51
|
- `--envfile <path>`: Path where the generated .env file will be saved.
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
# ๐ง Example
|
|
54
54
|
|
|
55
55
|
1. Create a mapping file `param_map.json`:
|
|
56
56
|
|
|
57
57
|
```json
|
|
58
58
|
{
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"SECRET_TOKEN": "/path/to/ssm/token",
|
|
60
|
+
"SECRET_KEY": "/path/to/ssm/password"
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
@@ -69,25 +69,27 @@ Envilder requires two arguments:
|
|
|
69
69
|
|
|
70
70
|
3. The `.env` file will be generated in the specified location.
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
# ๐ Sample `.env` Output
|
|
73
73
|
|
|
74
74
|
```makefile
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
SECRET_TOKEN=mockedEmail@example.com
|
|
76
|
+
SECRET_KEY=mockedPassword
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
# ๐งช Running Tests
|
|
80
80
|
|
|
81
|
-
To run the tests with coverage:
|
|
81
|
+
To run the tests with coverage:
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
84
|
yarn test
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Here you can see the current coverage report: https://macalbert.github.io/envilder/
|
|
88
|
+
|
|
89
|
+
# ๐ License
|
|
88
90
|
|
|
89
91
|
This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
# ๐ Contributing
|
|
92
94
|
|
|
93
95
|
Contributions are welcome! Feel free to submit issues and pull requests.
|
package/lib/cli/cliRunner.js
CHANGED
package/lib/cli/cliRunner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
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
CHANGED
|
@@ -9,6 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import * as fs from 'node:fs';
|
|
11
11
|
import { GetParameterCommand, SSM } from '@aws-sdk/client-ssm';
|
|
12
|
+
import * as dotenv from 'dotenv';
|
|
12
13
|
const ssm = new SSM({});
|
|
13
14
|
export function run(mapPath, envFilePath) {
|
|
14
15
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -16,46 +17,50 @@ export function run(mapPath, envFilePath) {
|
|
|
16
17
|
const existingEnvVariables = loadExistingEnvVariables(envFilePath);
|
|
17
18
|
const updatedEnvVariables = yield fetchAndUpdateEnvVariables(paramMap, existingEnvVariables);
|
|
18
19
|
writeEnvFile(envFilePath, updatedEnvVariables);
|
|
19
|
-
console.log(
|
|
20
|
+
console.log(`Environment File generated at '${envFilePath}'`);
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
function loadParamMap(mapPath) {
|
|
23
24
|
const content = fs.readFileSync(mapPath, 'utf-8');
|
|
24
|
-
|
|
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
|
+
}
|
|
25
32
|
}
|
|
26
33
|
function loadExistingEnvVariables(envFilePath) {
|
|
27
34
|
const envVariables = {};
|
|
28
35
|
if (!fs.existsSync(envFilePath))
|
|
29
36
|
return envVariables;
|
|
30
37
|
const existingEnvContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const [key, value] = line.split('=');
|
|
34
|
-
if (key && value) {
|
|
35
|
-
envVariables[key] = value;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
+
const parsedEnv = dotenv.parse(existingEnvContent);
|
|
39
|
+
Object.assign(envVariables, parsedEnv);
|
|
38
40
|
return envVariables;
|
|
39
41
|
}
|
|
40
42
|
function fetchAndUpdateEnvVariables(paramMap, existingEnvVariables) {
|
|
41
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
-
|
|
44
|
+
const errors = [];
|
|
43
45
|
for (const [envVar, ssmName] of Object.entries(paramMap)) {
|
|
44
46
|
try {
|
|
45
47
|
const value = yield fetchSSMParameter(ssmName);
|
|
46
48
|
if (value) {
|
|
47
49
|
existingEnvVariables[envVar] = value;
|
|
48
|
-
console.log(`${envVar}=${value}`);
|
|
50
|
+
console.log(`${envVar}=${value.length > 3 ? '*'.repeat(value.length - 3) + value.slice(-3) : '*'.repeat(value.length)}`);
|
|
49
51
|
}
|
|
50
52
|
else {
|
|
51
|
-
console.error(`Warning: No value found for ${ssmName}`);
|
|
53
|
+
console.error(`Warning: No value found for: '${ssmName}'`);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
catch (error) {
|
|
55
|
-
console.error(`Error fetching parameter ${ssmName}
|
|
56
|
-
|
|
57
|
+
console.error(`Error fetching parameter: '${ssmName}'`);
|
|
58
|
+
errors.push(`ParameterNotFound: ${ssmName}`);
|
|
57
59
|
}
|
|
58
60
|
}
|
|
61
|
+
if (errors.length > 0) {
|
|
62
|
+
throw new Error(`Some parameters could not be fetched:\n${errors.join('\n')}`);
|
|
63
|
+
}
|
|
59
64
|
return existingEnvVariables;
|
|
60
65
|
});
|
|
61
66
|
}
|
|
@@ -71,7 +76,10 @@ function fetchSSMParameter(ssmName) {
|
|
|
71
76
|
}
|
|
72
77
|
function writeEnvFile(envFilePath, envVariables) {
|
|
73
78
|
const envContent = Object.entries(envVariables)
|
|
74
|
-
.map(([key, value]) =>
|
|
79
|
+
.map(([key, value]) => {
|
|
80
|
+
const escapedValue = value.replace(/(\n|\r|\n\r)/g, '\\n').replace(/"/g, '\\"');
|
|
81
|
+
return `${key}=${escapedValue}`;
|
|
82
|
+
})
|
|
75
83
|
.join('\n');
|
|
76
84
|
fs.writeFileSync(envFilePath, envContent);
|
|
77
85
|
}
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "envilder",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A CLI tool to generate .env files from AWS SSM parameters",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@secretlint/secretlint-rule-preset-recommend": "^8.2.4",
|
|
43
43
|
"@types/node": "^22.5.5",
|
|
44
44
|
"commander": "^12.1.0",
|
|
45
|
+
"dotenv": "^16.4.5",
|
|
45
46
|
"picocolors": "^1.1.0"
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
package/src/cli/cliRunner.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import { GetParameterCommand, SSM } from '@aws-sdk/client-ssm';
|
|
3
|
+
import * as dotenv from 'dotenv';
|
|
3
4
|
|
|
4
5
|
const ssm = new SSM({});
|
|
5
6
|
|
|
@@ -10,26 +11,27 @@ export async function run(mapPath: string, envFilePath: string) {
|
|
|
10
11
|
const updatedEnvVariables = await fetchAndUpdateEnvVariables(paramMap, existingEnvVariables);
|
|
11
12
|
|
|
12
13
|
writeEnvFile(envFilePath, updatedEnvVariables);
|
|
13
|
-
console.log(
|
|
14
|
+
console.log(`Environment File generated at '${envFilePath}'`);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
function loadParamMap(mapPath: string): Record<string, string> {
|
|
17
18
|
const content = fs.readFileSync(mapPath, 'utf-8');
|
|
18
|
-
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(`Error parsing JSON from ${mapPath}`);
|
|
23
|
+
throw new Error(`Invalid JSON in parameter map file: ${mapPath}`);
|
|
24
|
+
}
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
function loadExistingEnvVariables(envFilePath: string): Record<string, string> {
|
|
22
28
|
const envVariables: Record<string, string> = {};
|
|
29
|
+
|
|
23
30
|
if (!fs.existsSync(envFilePath)) return envVariables;
|
|
24
31
|
|
|
25
32
|
const existingEnvContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const [key, value] = line.split('=');
|
|
29
|
-
if (key && value) {
|
|
30
|
-
envVariables[key] = value;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
+
const parsedEnv = dotenv.parse(existingEnvContent);
|
|
34
|
+
Object.assign(envVariables, parsedEnv);
|
|
33
35
|
|
|
34
36
|
return envVariables;
|
|
35
37
|
}
|
|
@@ -38,23 +40,29 @@ async function fetchAndUpdateEnvVariables(
|
|
|
38
40
|
paramMap: Record<string, string>,
|
|
39
41
|
existingEnvVariables: Record<string, string>,
|
|
40
42
|
): Promise<Record<string, string>> {
|
|
41
|
-
|
|
43
|
+
const errors: string[] = [];
|
|
42
44
|
|
|
43
45
|
for (const [envVar, ssmName] of Object.entries(paramMap)) {
|
|
44
46
|
try {
|
|
45
47
|
const value = await fetchSSMParameter(ssmName);
|
|
46
48
|
if (value) {
|
|
47
49
|
existingEnvVariables[envVar] = value;
|
|
48
|
-
console.log(
|
|
50
|
+
console.log(
|
|
51
|
+
`${envVar}=${value.length > 3 ? '*'.repeat(value.length - 3) + value.slice(-3) : '*'.repeat(value.length)}`,
|
|
52
|
+
);
|
|
49
53
|
} else {
|
|
50
|
-
console.error(`Warning: No value found for ${ssmName}`);
|
|
54
|
+
console.error(`Warning: No value found for: '${ssmName}'`);
|
|
51
55
|
}
|
|
52
56
|
} catch (error) {
|
|
53
|
-
console.error(`Error fetching parameter ${ssmName}
|
|
54
|
-
|
|
57
|
+
console.error(`Error fetching parameter: '${ssmName}'`);
|
|
58
|
+
errors.push(`ParameterNotFound: ${ssmName}`);
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
|
|
62
|
+
if (errors.length > 0) {
|
|
63
|
+
throw new Error(`Some parameters could not be fetched:\n${errors.join('\n')}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
58
66
|
return existingEnvVariables;
|
|
59
67
|
}
|
|
60
68
|
|
|
@@ -70,7 +78,10 @@ async function fetchSSMParameter(ssmName: string): Promise<string | undefined> {
|
|
|
70
78
|
|
|
71
79
|
function writeEnvFile(envFilePath: string, envVariables: Record<string, string>): void {
|
|
72
80
|
const envContent = Object.entries(envVariables)
|
|
73
|
-
.map(([key, value]) =>
|
|
81
|
+
.map(([key, value]) => {
|
|
82
|
+
const escapedValue = value.replace(/(\n|\r|\n\r)/g, '\\n').replace(/"/g, '\\"');
|
|
83
|
+
return `${key}=${escapedValue}`;
|
|
84
|
+
})
|
|
74
85
|
.join('\n');
|
|
75
86
|
|
|
76
87
|
fs.writeFileSync(envFilePath, envContent);
|
package/tests/index.test.ts
CHANGED
|
@@ -79,9 +79,7 @@ describe('Envilder CLI', () => {
|
|
|
79
79
|
const mockMapPath = './tests/param_map.json';
|
|
80
80
|
const mockEnvFilePath = './tests/.env.test';
|
|
81
81
|
|
|
82
|
-
const existingEnvContent =
|
|
83
|
-
EXISTING_VAR=existingValue
|
|
84
|
-
`;
|
|
82
|
+
const existingEnvContent = 'EXISTING_VAR=existingValue';
|
|
85
83
|
fs.writeFileSync(mockEnvFilePath, existingEnvContent);
|
|
86
84
|
const paramMapContent = {
|
|
87
85
|
NEXT_PUBLIC_CREDENTIAL_EMAIL: '/path/to/ssm/email',
|
|
@@ -105,9 +103,7 @@ describe('Envilder CLI', () => {
|
|
|
105
103
|
// Arrange
|
|
106
104
|
const mockMapPath = './tests/param_map.json';
|
|
107
105
|
const mockEnvFilePath = './tests/.env.test';
|
|
108
|
-
const existingEnvContent =
|
|
109
|
-
NEXT_PUBLIC_CREDENTIAL_EMAIL=oldEmail@example.com
|
|
110
|
-
`;
|
|
106
|
+
const existingEnvContent = 'NEXT_PUBLIC_CREDENTIAL_EMAIL=oldEmail@example.com';
|
|
111
107
|
fs.writeFileSync(mockEnvFilePath, existingEnvContent);
|
|
112
108
|
const paramMapContent = {
|
|
113
109
|
NEXT_PUBLIC_CREDENTIAL_EMAIL: '/path/to/ssm/email',
|