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.
@@ -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
- fs.unlinkSync(mockEnvFilePath);
141
- fs.unlinkSync(mockMapPath);
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
+ });
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export declare function cliRunner(): Promise<void>;
3
- //# sourceMappingURL=cliRunner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cliRunner.d.ts","sourceRoot":"","sources":["../../src/cli/cliRunner.ts"],"names":[],"mappings":";AAKA,wBAAsB,SAAS,kBAkB9B"}
@@ -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
@@ -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
@@ -1,2 +0,0 @@
1
- export declare function run(mapPath: string, envFilePath: string): Promise<void>;
2
- //# sourceMappingURL=index.d.ts.map
@@ -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