env-secrets 0.5.0 → 0.5.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.
@@ -0,0 +1,199 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+
5
+ import {
6
+ cliWithEnv,
7
+ cleanupTempFile,
8
+ execAwslocalCommand
9
+ } from './utils/test-utils';
10
+ import { registerAwsE2eContext } from './utils/aws-e2e-context';
11
+
12
+ describe('AWS Secret Mutation CLI Args', () => {
13
+ const { getLocalStackEnv } = registerAwsE2eContext();
14
+
15
+ test('should append and remove keys on a JSON secret', async () => {
16
+ const secretName = `managed-secret-append-remove-${Date.now()}`;
17
+ const tempFile = path.join(
18
+ os.tmpdir(),
19
+ `env-secrets-append-remove-${Date.now()}.env`
20
+ );
21
+ fs.writeFileSync(tempFile, 'API_KEY=first');
22
+
23
+ const createResult = await cliWithEnv(
24
+ [
25
+ 'aws',
26
+ 'secret',
27
+ 'upsert',
28
+ '--file',
29
+ tempFile,
30
+ '--name',
31
+ secretName,
32
+ '--output',
33
+ 'json'
34
+ ],
35
+ getLocalStackEnv()
36
+ );
37
+ expect(createResult.code).toBe(0);
38
+
39
+ const appendResult = await cliWithEnv(
40
+ [
41
+ 'aws',
42
+ 'secret',
43
+ 'append',
44
+ '-n',
45
+ secretName,
46
+ '--key',
47
+ 'JIRA_EMAIL_TOKEN',
48
+ '-v',
49
+ 'blah',
50
+ '--output',
51
+ 'json'
52
+ ],
53
+ getLocalStackEnv()
54
+ );
55
+ expect(appendResult.code).toBe(0);
56
+
57
+ const afterAppend = await execAwslocalCommand(
58
+ `awslocal secretsmanager get-secret-value --secret-id "${secretName}" --region us-east-1 --query SecretString --output text`,
59
+ getLocalStackEnv()
60
+ );
61
+ expect(JSON.parse(afterAppend.stdout.trim())).toEqual({
62
+ API_KEY: 'first',
63
+ JIRA_EMAIL_TOKEN: 'blah'
64
+ });
65
+
66
+ const removeResult = await cliWithEnv(
67
+ [
68
+ 'aws',
69
+ 'secret',
70
+ 'remove',
71
+ '-n',
72
+ secretName,
73
+ '--key',
74
+ 'API_KEY',
75
+ '--output',
76
+ 'json'
77
+ ],
78
+ getLocalStackEnv()
79
+ );
80
+ expect(removeResult.code).toBe(0);
81
+
82
+ const afterRemove = await execAwslocalCommand(
83
+ `awslocal secretsmanager get-secret-value --secret-id "${secretName}" --region us-east-1 --query SecretString --output text`,
84
+ getLocalStackEnv()
85
+ );
86
+ expect(JSON.parse(afterRemove.stdout.trim())).toEqual({
87
+ JIRA_EMAIL_TOKEN: 'blah'
88
+ });
89
+
90
+ const deleteResult = await cliWithEnv(
91
+ [
92
+ 'aws',
93
+ 'secret',
94
+ 'delete',
95
+ '-n',
96
+ secretName,
97
+ '--force-delete-without-recovery',
98
+ '--yes'
99
+ ],
100
+ getLocalStackEnv()
101
+ );
102
+ expect(deleteResult.code).toBe(0);
103
+ cleanupTempFile(tempFile);
104
+ });
105
+
106
+ test('should upsert secrets from env file', async () => {
107
+ const secretName = `e2e-upsert-${Date.now()}`;
108
+ const tempFile = path.join(
109
+ os.tmpdir(),
110
+ `env-secrets-upsert-${Date.now()}.env`
111
+ );
112
+
113
+ fs.writeFileSync(
114
+ tempFile,
115
+ ['# sample', 'export API_KEY=first', 'DB_URL = postgres://one'].join('\n')
116
+ );
117
+
118
+ const firstRun = await cliWithEnv(
119
+ [
120
+ 'aws',
121
+ 'secret',
122
+ 'upsert',
123
+ '--file',
124
+ tempFile,
125
+ '--name',
126
+ secretName,
127
+ '--output',
128
+ 'json'
129
+ ],
130
+ getLocalStackEnv()
131
+ );
132
+ expect(firstRun.code).toBe(0);
133
+ const firstJson = JSON.parse(firstRun.stdout) as {
134
+ summary: { created: number; updated: number; skipped: number };
135
+ };
136
+ expect(firstJson.summary.created).toBe(1);
137
+ expect(firstJson.summary.updated).toBe(0);
138
+
139
+ const firstSecret = await execAwslocalCommand(
140
+ `awslocal secretsmanager get-secret-value --secret-id "${secretName}" --region us-east-1 --query SecretString --output text`,
141
+ getLocalStackEnv()
142
+ );
143
+ expect(JSON.parse(firstSecret.stdout.trim())).toEqual({
144
+ API_KEY: 'first',
145
+ DB_URL: 'postgres://one'
146
+ });
147
+
148
+ fs.writeFileSync(
149
+ tempFile,
150
+ ['export API_KEY=second', 'DB_URL=postgres://two'].join('\n')
151
+ );
152
+
153
+ const secondRun = await cliWithEnv(
154
+ [
155
+ 'aws',
156
+ 'secret',
157
+ 'import',
158
+ '--file',
159
+ tempFile,
160
+ '--name',
161
+ secretName,
162
+ '--output',
163
+ 'json'
164
+ ],
165
+ getLocalStackEnv()
166
+ );
167
+ expect(secondRun.code).toBe(0);
168
+ const secondJson = JSON.parse(secondRun.stdout) as {
169
+ summary: { created: number; updated: number; skipped: number };
170
+ };
171
+ expect(secondJson.summary.created).toBe(0);
172
+ expect(secondJson.summary.updated).toBe(1);
173
+ expect(secondJson.summary.skipped).toBe(0);
174
+
175
+ const secondSecret = await execAwslocalCommand(
176
+ `awslocal secretsmanager get-secret-value --secret-id "${secretName}" --region us-east-1 --query SecretString --output text`,
177
+ getLocalStackEnv()
178
+ );
179
+ expect(JSON.parse(secondSecret.stdout.trim())).toEqual({
180
+ API_KEY: 'second',
181
+ DB_URL: 'postgres://two'
182
+ });
183
+
184
+ const deleteResult = await cliWithEnv(
185
+ [
186
+ 'aws',
187
+ 'secret',
188
+ 'delete',
189
+ '-n',
190
+ secretName,
191
+ '--force-delete-without-recovery',
192
+ '--yes'
193
+ ],
194
+ getLocalStackEnv()
195
+ );
196
+ expect(deleteResult.code).toBe(0);
197
+ cleanupTempFile(tempFile);
198
+ });
199
+ });
@@ -0,0 +1,50 @@
1
+ import {
2
+ LocalStackHelper,
3
+ createTestProfile,
4
+ restoreTestProfile,
5
+ TestProfileContext,
6
+ TestSecret,
7
+ CreatedSecret
8
+ } from './test-utils';
9
+
10
+ export interface AwsE2eContext {
11
+ createTestSecret: (
12
+ secret: TestSecret,
13
+ region?: string
14
+ ) => Promise<CreatedSecret>;
15
+ getLocalStackEnv: (
16
+ overrides?: Record<string, string>
17
+ ) => Record<string, string>;
18
+ }
19
+
20
+ export function registerAwsE2eContext(): AwsE2eContext {
21
+ let localStack: LocalStackHelper;
22
+ let profileContext: TestProfileContext | undefined;
23
+
24
+ beforeAll(async () => {
25
+ localStack = new LocalStackHelper();
26
+ await localStack.waitForLocalStack();
27
+ profileContext = createTestProfile();
28
+ });
29
+
30
+ afterAll(async () => {
31
+ await localStack.cleanupRunSecrets();
32
+ restoreTestProfile(profileContext);
33
+ });
34
+
35
+ return {
36
+ createTestSecret: async (
37
+ secret: TestSecret,
38
+ region?: string
39
+ ): Promise<CreatedSecret> => {
40
+ return await localStack.createSecret(secret, region);
41
+ },
42
+ getLocalStackEnv: (overrides: Record<string, string> = {}) => ({
43
+ AWS_ENDPOINT_URL: process.env.LOCALSTACK_URL || 'http://localhost:4566',
44
+ AWS_ACCESS_KEY_ID: 'test',
45
+ AWS_SECRET_ACCESS_KEY: 'test',
46
+ AWS_DEFAULT_REGION: 'us-east-1',
47
+ ...overrides
48
+ })
49
+ };
50
+ }
@@ -584,26 +584,11 @@ export function cleanupTempFile(filePath: string): void {
584
584
  }
585
585
 
586
586
  export function createTestProfile() {
587
- const homeDir = os.homedir();
588
- const awsDir = path.join(homeDir, '.aws');
589
- const credentialsFile = path.join(awsDir, 'credentials');
590
- const configFile = path.join(awsDir, 'config');
591
-
592
- // Create .aws directory if it doesn't exist
593
- if (!fs.existsSync(awsDir)) {
594
- fs.mkdirSync(awsDir, { mode: 0o700 });
595
- }
596
-
597
- // Backup existing files if they exist
598
- const backupCredentials = credentialsFile + '.backup';
599
- const backupConfig = configFile + '.backup';
600
-
601
- if (fs.existsSync(credentialsFile)) {
602
- fs.copyFileSync(credentialsFile, backupCredentials);
603
- }
604
- if (fs.existsSync(configFile)) {
605
- fs.copyFileSync(configFile, backupConfig);
606
- }
587
+ const tempAwsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'env-secrets-aws-'));
588
+ const credentialsFile = path.join(tempAwsDir, 'credentials');
589
+ const configFile = path.join(tempAwsDir, 'config');
590
+ const previousCredentialsFile = process.env.AWS_SHARED_CREDENTIALS_FILE;
591
+ const previousConfigFile = process.env.AWS_CONFIG_FILE;
607
592
 
608
593
  // Create test profile
609
594
  const credentialsContent = `[default]
@@ -625,34 +610,45 @@ region = us-east-1
625
610
  fs.writeFileSync(credentialsFile, credentialsContent, { mode: 0o600 });
626
611
  fs.writeFileSync(configFile, configContent, { mode: 0o600 });
627
612
 
628
- return awsDir;
613
+ process.env.AWS_SHARED_CREDENTIALS_FILE = credentialsFile;
614
+ process.env.AWS_CONFIG_FILE = configFile;
615
+
616
+ return {
617
+ tempAwsDir,
618
+ previousCredentialsFile,
619
+ previousConfigFile
620
+ };
629
621
  }
630
622
 
631
- export function restoreTestProfile(awsDir: string | undefined): void {
632
- if (!awsDir) {
633
- debugWarn('No AWS directory provided for profile restoration');
623
+ export interface TestProfileContext {
624
+ tempAwsDir: string;
625
+ previousCredentialsFile?: string;
626
+ previousConfigFile?: string;
627
+ }
628
+
629
+ export function restoreTestProfile(
630
+ profileContext: TestProfileContext | undefined
631
+ ): void {
632
+ if (!profileContext) {
633
+ debugWarn('No test profile context provided for profile restoration');
634
634
  return;
635
635
  }
636
636
 
637
- const credentialsFile = path.join(awsDir, 'credentials');
638
- const configFile = path.join(awsDir, 'config');
639
- const backupCredentials = credentialsFile + '.backup';
640
- const backupConfig = configFile + '.backup';
641
-
642
637
  try {
643
- if (fs.existsSync(backupCredentials)) {
644
- fs.copyFileSync(backupCredentials, credentialsFile);
645
- fs.unlinkSync(backupCredentials);
646
- } else if (fs.existsSync(credentialsFile)) {
647
- fs.unlinkSync(credentialsFile);
638
+ if (profileContext.previousCredentialsFile) {
639
+ process.env.AWS_SHARED_CREDENTIALS_FILE =
640
+ profileContext.previousCredentialsFile;
641
+ } else {
642
+ delete process.env.AWS_SHARED_CREDENTIALS_FILE;
648
643
  }
649
644
 
650
- if (fs.existsSync(backupConfig)) {
651
- fs.copyFileSync(backupConfig, configFile);
652
- fs.unlinkSync(backupConfig);
653
- } else if (fs.existsSync(configFile)) {
654
- fs.unlinkSync(configFile);
645
+ if (profileContext.previousConfigFile) {
646
+ process.env.AWS_CONFIG_FILE = profileContext.previousConfigFile;
647
+ } else {
648
+ delete process.env.AWS_CONFIG_FILE;
655
649
  }
650
+
651
+ fs.rmSync(profileContext.tempAwsDir, { recursive: true, force: true });
656
652
  } catch (error) {
657
653
  debugWarn('Failed to restore AWS profile:', error);
658
654
  }
@@ -30,9 +30,11 @@ const mockWriteFileSync = writeFileSync as jest.MockedFunction<
30
30
  >;
31
31
  const mockExistsSync = existsSync as jest.MockedFunction<typeof existsSync>;
32
32
  const mockDebug = Debug as jest.MockedFunction<typeof Debug>;
33
- const mockSecretsmanager = secretsmanager as jest.MockedFunction<
34
- typeof secretsmanager
35
- >;
33
+ interface SecretsmanagerMockFn {
34
+ (options: Record<string, unknown>): Promise<Record<string, string>>;
35
+ }
36
+ const mockSecretsmanager =
37
+ secretsmanager as unknown as jest.MockedFunction<SecretsmanagerMockFn>;
36
38
  const mockObjectToExport = objectToExport as jest.MockedFunction<
37
39
  typeof objectToExport
38
40
  >;
@@ -247,6 +247,40 @@ describe('secretsmanager', () => {
247
247
  expect(result).toEqual({});
248
248
  });
249
249
 
250
+ it('should parse dotenv style secret values', async () => {
251
+ mockSecretsManagerSend.mockResolvedValueOnce({
252
+ SecretString:
253
+ 'GITHUB_PAT=github_pat_123\nexport API_URL=https://example.com'
254
+ });
255
+
256
+ const result = await secretsmanager({
257
+ secret: 'my-secret',
258
+ region: 'us-east-1'
259
+ });
260
+
261
+ expect(result).toEqual({
262
+ GITHUB_PAT: 'github_pat_123',
263
+ API_URL: 'https://example.com'
264
+ });
265
+ });
266
+
267
+ it('should parse JSON-encoded dotenv style secret values', async () => {
268
+ mockSecretsManagerSend.mockResolvedValueOnce({
269
+ SecretString:
270
+ '"GITHUB_PAT=github_pat_123\\nexport API_URL=https://example.com"'
271
+ });
272
+
273
+ const result = await secretsmanager({
274
+ secret: 'my-secret',
275
+ region: 'us-east-1'
276
+ });
277
+
278
+ expect(result).toEqual({
279
+ GITHUB_PAT: 'github_pat_123',
280
+ API_URL: 'https://example.com'
281
+ });
282
+ });
283
+
250
284
  it('should handle empty secret values', async () => {
251
285
  mockSecretsManagerSend.mockResolvedValueOnce({
252
286
  SecretString: ''
@@ -286,6 +320,19 @@ describe('secretsmanager', () => {
286
320
  expect(result).toEqual({});
287
321
  });
288
322
 
323
+ it('should return empty object for malformed dotenv lines', async () => {
324
+ mockSecretsManagerSend.mockResolvedValueOnce({
325
+ SecretString: 'NOT_VALID_LINE'
326
+ });
327
+
328
+ const result = await secretsmanager({
329
+ secret: 'my-secret',
330
+ region: 'us-east-1'
331
+ });
332
+
333
+ expect(result).toEqual({});
334
+ });
335
+
289
336
  it('should handle secrets with special characters', async () => {
290
337
  mockSecretsManagerSend.mockResolvedValueOnce({
291
338
  SecretString: '{"SPECIAL_KEY": "value with spaces & symbols!@#$%"}'
package/dist/index.js CHANGED
@@ -63,6 +63,7 @@ const awsCommand = program
63
63
  }
64
64
  const secrets = yield (0, secretsmanager_1.secretsmanager)(options);
65
65
  debug(secrets);
66
+ const envSecrets = Object.fromEntries(Object.entries(secrets).map(([key, value]) => [key, String(value)]));
66
67
  if (options.output) {
67
68
  // Check if file already exists
68
69
  if ((0, node_fs_1.existsSync)(options.output)) {
@@ -71,14 +72,14 @@ const awsCommand = program
71
72
  process.exit(1);
72
73
  }
73
74
  // Write secrets to file with 0400 permissions
74
- const envContent = (0, utils_1.objectToExport)(secrets);
75
+ const envContent = (0, utils_1.objectToExport)(envSecrets);
75
76
  (0, node_fs_1.writeFileSync)(options.output, envContent, { mode: 0o400 });
76
77
  // eslint-disable-next-line no-console
77
78
  console.log(`Secrets written to ${options.output}`);
78
79
  }
79
80
  else {
80
81
  // Original behavior: merge secrets into environment and run program
81
- const env = Object.assign({}, process.env, secrets);
82
+ const env = Object.assign({}, process.env, envSecrets);
82
83
  debug(env);
83
84
  if (program && program.length > 0) {
84
85
  debug(`${program[0]} ${program.slice(1)}`);
@@ -17,7 +17,52 @@ const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
17
17
  const client_sts_1 = require("@aws-sdk/client-sts");
18
18
  const debug_1 = __importDefault(require("debug"));
19
19
  const aws_config_1 = require("./aws-config");
20
+ const helpers_1 = require("../cli/helpers");
20
21
  const debug = (0, debug_1.default)('env-secrets:secretsmanager');
22
+ const isSecretValue = (value) => {
23
+ return (typeof value === 'string' ||
24
+ typeof value === 'number' ||
25
+ typeof value === 'boolean');
26
+ };
27
+ const asSecretRecord = (value) => {
28
+ if (!value || Array.isArray(value) || typeof value !== 'object') {
29
+ return {};
30
+ }
31
+ return Object.entries(value).reduce((result, [key, entryValue]) => {
32
+ if (isSecretValue(entryValue)) {
33
+ result[key] = entryValue;
34
+ }
35
+ return result;
36
+ }, {});
37
+ };
38
+ const parseSecretString = (secretvalue) => {
39
+ const parseAsEnvRecord = (envSource) => {
40
+ try {
41
+ const parsedEnv = (0, helpers_1.parseEnvSecrets)(envSource);
42
+ if (parsedEnv.entries.length === 0) {
43
+ return {};
44
+ }
45
+ return Object.fromEntries(parsedEnv.entries.map((entry) => [entry.key, entry.value]));
46
+ }
47
+ catch (_a) {
48
+ return {};
49
+ }
50
+ };
51
+ try {
52
+ const parsedJson = JSON.parse(secretvalue);
53
+ const parsedRecord = asSecretRecord(parsedJson);
54
+ if (Object.keys(parsedRecord).length > 0) {
55
+ return parsedRecord;
56
+ }
57
+ if (typeof parsedJson === 'string') {
58
+ return parseAsEnvRecord(parsedJson);
59
+ }
60
+ return {};
61
+ }
62
+ catch (_a) {
63
+ return parseAsEnvRecord(secretvalue);
64
+ }
65
+ };
21
66
  const isCredentialsError = (error) => {
22
67
  if (!error || typeof error !== 'object') {
23
68
  return false;
@@ -68,14 +113,8 @@ const secretsmanager = (options) => __awaiter(void 0, void 0, void 0, function*
68
113
  });
69
114
  const response = yield client.send(command);
70
115
  const secretvalue = response.SecretString;
71
- try {
72
- if (secretvalue) {
73
- return JSON.parse(secretvalue);
74
- }
75
- }
76
- catch (err) {
77
- // eslint-disable-next-line no-console
78
- console.error(err);
116
+ if (secretvalue) {
117
+ return parseSecretString(secretvalue);
79
118
  }
80
119
  }
81
120
  catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "env-secrets",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "get secrets from a secrets vault and inject them into the running environment",
5
5
  "main": "index.js",
6
6
  "author": "Mark C Allen (@markcallen)",
@@ -26,6 +26,7 @@
26
26
  "test:unit": "jest __tests__",
27
27
  "test:unit:coverage": "jest __tests__ --coverage",
28
28
  "test:e2e": "npm run build && jest --config jest.e2e.config.js",
29
+ "test:e2e:coverage": "npm run build && jest --config jest.e2e.config.js --coverage --coverageDirectory=coverage-e2e",
29
30
  "test:e2e:debug": "npm run build && DEBUG=true jest --config jest.e2e.config.js"
30
31
  },
31
32
  "devDependencies": {
@@ -52,9 +53,9 @@
52
53
  "typescript": "^4.9.5"
53
54
  },
54
55
  "dependencies": {
55
- "@aws-sdk/client-secrets-manager": "^3.996.0",
56
- "@aws-sdk/client-sts": "^3.996.0",
57
- "@aws-sdk/credential-providers": "^3.996.0",
56
+ "@aws-sdk/client-secrets-manager": "^3.1004.0",
57
+ "@aws-sdk/client-sts": "^3.1004.0",
58
+ "@aws-sdk/credential-providers": "^3.1004.0",
58
59
  "commander": "^9.5.0",
59
60
  "debug": "^4.4.3"
60
61
  },
package/src/index.ts CHANGED
@@ -87,6 +87,9 @@ const awsCommand = program
87
87
 
88
88
  const secrets = await secretsmanager(options);
89
89
  debug(secrets);
90
+ const envSecrets = Object.fromEntries(
91
+ Object.entries(secrets).map(([key, value]) => [key, String(value)])
92
+ );
90
93
 
91
94
  if (options.output) {
92
95
  // Check if file already exists
@@ -99,13 +102,13 @@ const awsCommand = program
99
102
  }
100
103
 
101
104
  // Write secrets to file with 0400 permissions
102
- const envContent = objectToExport(secrets);
105
+ const envContent = objectToExport(envSecrets);
103
106
  writeFileSync(options.output, envContent, { mode: 0o400 });
104
107
  // eslint-disable-next-line no-console
105
108
  console.log(`Secrets written to ${options.output}`);
106
109
  } else {
107
110
  // Original behavior: merge secrets into environment and run program
108
- const env = Object.assign({}, process.env, secrets);
111
+ const env = Object.assign({}, process.env, envSecrets);
109
112
  debug(env);
110
113
  if (program && program.length > 0) {
111
114
  debug(`${program[0]} ${program.slice(1)}`);
@@ -5,6 +5,7 @@ import {
5
5
  import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';
6
6
  import Debug from 'debug';
7
7
  import { buildAwsClientConfig } from './aws-config';
8
+ import { parseEnvSecrets } from '../cli/helpers';
8
9
 
9
10
  const debug = Debug('env-secrets:secretsmanager');
10
11
 
@@ -19,6 +20,68 @@ interface AWSLikeError {
19
20
  message?: string;
20
21
  }
21
22
 
23
+ type SecretValue = string | number | boolean;
24
+
25
+ const isSecretValue = (value: unknown): value is SecretValue => {
26
+ return (
27
+ typeof value === 'string' ||
28
+ typeof value === 'number' ||
29
+ typeof value === 'boolean'
30
+ );
31
+ };
32
+
33
+ const asSecretRecord = (value: unknown): Record<string, SecretValue> => {
34
+ if (!value || Array.isArray(value) || typeof value !== 'object') {
35
+ return {};
36
+ }
37
+
38
+ return Object.entries(value).reduce<Record<string, SecretValue>>(
39
+ (result, [key, entryValue]) => {
40
+ if (isSecretValue(entryValue)) {
41
+ result[key] = entryValue;
42
+ }
43
+
44
+ return result;
45
+ },
46
+ {}
47
+ );
48
+ };
49
+
50
+ const parseSecretString = (
51
+ secretvalue: string
52
+ ): Record<string, SecretValue> => {
53
+ const parseAsEnvRecord = (envSource: string): Record<string, SecretValue> => {
54
+ try {
55
+ const parsedEnv = parseEnvSecrets(envSource);
56
+ if (parsedEnv.entries.length === 0) {
57
+ return {};
58
+ }
59
+
60
+ return Object.fromEntries(
61
+ parsedEnv.entries.map((entry) => [entry.key, entry.value])
62
+ );
63
+ } catch {
64
+ return {};
65
+ }
66
+ };
67
+
68
+ try {
69
+ const parsedJson = JSON.parse(secretvalue);
70
+ const parsedRecord = asSecretRecord(parsedJson);
71
+ if (Object.keys(parsedRecord).length > 0) {
72
+ return parsedRecord;
73
+ }
74
+
75
+ if (typeof parsedJson === 'string') {
76
+ return parseAsEnvRecord(parsedJson);
77
+ }
78
+
79
+ return {};
80
+ } catch {
81
+ return parseAsEnvRecord(secretvalue);
82
+ }
83
+ };
84
+
22
85
  const isCredentialsError = (error: unknown): error is AWSLikeError => {
23
86
  if (!error || typeof error !== 'object') {
24
87
  return false;
@@ -81,13 +144,8 @@ export const secretsmanager = async (options: secretsmanagerType) => {
81
144
  const response = await client.send(command);
82
145
  const secretvalue = response.SecretString;
83
146
 
84
- try {
85
- if (secretvalue) {
86
- return JSON.parse(secretvalue);
87
- }
88
- } catch (err) {
89
- // eslint-disable-next-line no-console
90
- console.error(err);
147
+ if (secretvalue) {
148
+ return parseSecretString(secretvalue);
91
149
  }
92
150
  } catch (err: unknown) {
93
151
  if (err && typeof err === 'object' && 'name' in err) {