env-secrets 0.5.0 → 0.5.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/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  } from './vaults/secretsmanager-admin';
19
19
  import {
20
20
  asOutputFormat,
21
+ parseEnvSecrets,
21
22
  parseEnvSecretsFile,
22
23
  printData,
23
24
  parseRecoveryDays,
@@ -58,6 +59,48 @@ const parseSecretJsonObject = (
58
59
  return parsed as Record<string, unknown>;
59
60
  };
60
61
 
62
+ const parseEnvToObject = (
63
+ value: string
64
+ ): Record<string, unknown> | undefined => {
65
+ try {
66
+ const parsed = parseEnvSecrets(value);
67
+ if (parsed.entries.length === 0) {
68
+ return undefined;
69
+ }
70
+
71
+ return Object.fromEntries(
72
+ parsed.entries.map((entry) => [entry.key, entry.value])
73
+ );
74
+ } catch {
75
+ return undefined;
76
+ }
77
+ };
78
+
79
+ const toSecretJsonObject = (value: string): Record<string, unknown> => {
80
+ try {
81
+ const parsed = JSON.parse(value) as unknown;
82
+ if (parsed && !Array.isArray(parsed) && typeof parsed === 'object') {
83
+ return parsed as Record<string, unknown>;
84
+ }
85
+
86
+ if (typeof parsed === 'string') {
87
+ const envPayload = parseEnvToObject(parsed);
88
+ if (envPayload) {
89
+ return envPayload;
90
+ }
91
+ }
92
+
93
+ return { value: parsed };
94
+ } catch {
95
+ const envPayload = parseEnvToObject(value);
96
+ if (envPayload) {
97
+ return envPayload;
98
+ }
99
+ }
100
+
101
+ return { value };
102
+ };
103
+
61
104
  // main program
62
105
  program
63
106
  .name('env-secrets')
@@ -87,6 +130,9 @@ const awsCommand = program
87
130
 
88
131
  const secrets = await secretsmanager(options);
89
132
  debug(secrets);
133
+ const envSecrets = Object.fromEntries(
134
+ Object.entries(secrets).map(([key, value]) => [key, String(value)])
135
+ );
90
136
 
91
137
  if (options.output) {
92
138
  // Check if file already exists
@@ -99,13 +145,13 @@ const awsCommand = program
99
145
  }
100
146
 
101
147
  // Write secrets to file with 0400 permissions
102
- const envContent = objectToExport(secrets);
148
+ const envContent = objectToExport(envSecrets);
103
149
  writeFileSync(options.output, envContent, { mode: 0o400 });
104
150
  // eslint-disable-next-line no-console
105
151
  console.log(`Secrets written to ${options.output}`);
106
152
  } else {
107
153
  // Original behavior: merge secrets into environment and run program
108
- const env = Object.assign({}, process.env, secrets);
154
+ const env = Object.assign({}, process.env, envSecrets);
109
155
  debug(env);
110
156
  if (program && program.length > 0) {
111
157
  debug(`${program[0]} ${program.slice(1)}`);
@@ -163,9 +209,10 @@ secretCommand
163
209
  );
164
210
  }
165
211
 
212
+ const payload = toSecretJsonObject(value);
166
213
  const result = await createSecret({
167
214
  name: options.name,
168
- value,
215
+ value: JSON.stringify(payload),
169
216
  description: options.description,
170
217
  kmsKeyId: options.kmsKeyId,
171
218
  tags: options.tag,
@@ -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) {