dotsec 0.1.1 → 0.4.0

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/dist/cli.js CHANGED
@@ -24,11 +24,11 @@ var __export = (target, all) => {
24
24
  for (var name in all)
25
25
  __defProp(target, name, { get: all[name], enumerable: true });
26
26
  };
27
- var __reExport = (target, module2, desc4) => {
27
+ var __reExport = (target, module2, desc8) => {
28
28
  if (module2 && typeof module2 === "object" || typeof module2 === "function") {
29
29
  for (let key of __getOwnPropNames(module2))
30
30
  if (!__hasOwnProp.call(target, key) && key !== "default")
31
- __defProp(target, key, { get: () => module2[key], enumerable: !(desc4 = __getOwnPropDesc(module2, key)) || desc4.enumerable });
31
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc8 = __getOwnPropDesc(module2, key)) || desc8.enumerable });
32
32
  }
33
33
  return target;
34
34
  };
@@ -40,19 +40,15 @@ var __toModule = (module2) => {
40
40
  var import_helpers = __toModule(require("yargs/helpers"));
41
41
  var import_yargs = __toModule(require("yargs/yargs"));
42
42
 
43
- // src/commands/decryptSecCommand.ts
44
- var decryptSecCommand_exports = {};
45
- __export(decryptSecCommand_exports, {
43
+ // src/commands/debugCommand.ts
44
+ var debugCommand_exports = {};
45
+ __export(debugCommand_exports, {
46
46
  builder: () => builder,
47
47
  command: () => command,
48
48
  desc: () => desc,
49
49
  handler: () => handler
50
50
  });
51
- var import_client_kms = __toModule(require("@aws-sdk/client-kms"));
52
- var import_chalk2 = __toModule(require("chalk"));
53
- var import_dotenv = __toModule(require("dotenv"));
54
- var import_node_fs = __toModule(require("node:fs"));
55
- var import_node_path = __toModule(require("node:path"));
51
+ var import_client_ssm2 = __toModule(require("@aws-sdk/client-ssm"));
56
52
 
57
53
  // src/commonCliOptions.ts
58
54
  var commonCliOptions = {
@@ -66,11 +62,30 @@ var commonCliOptions = {
66
62
  },
67
63
  awsKeyAlias: {
68
64
  string: true,
69
- describe: "AWS KMS asymmetric key alias"
65
+ default: "alias/top-secret",
66
+ describe: "AWS KMS key alias"
67
+ },
68
+ awsKeyArn: {
69
+ string: true,
70
+ describe: "AWS KMS key id"
70
71
  },
71
72
  awsKey: {
72
73
  string: true,
73
- describe: "AWS KMS asymmetric key arn"
74
+ describe: "AWS KMS key arn"
75
+ },
76
+ envFile: {
77
+ string: true,
78
+ describe: ".env file",
79
+ default: ".env"
80
+ },
81
+ secFile: {
82
+ string: true,
83
+ describe: ".sec file",
84
+ default: ".sec"
85
+ },
86
+ awsAssumeRoleArn: {
87
+ string: true,
88
+ describe: "arn or role to assume"
74
89
  },
75
90
  verbose: {
76
91
  boolean: true,
@@ -92,7 +107,14 @@ var import_shared_ini_file_loader = __toModule(require("@aws-sdk/shared-ini-file
92
107
 
93
108
  // src/utils/logger.ts
94
109
  var import_chalk = __toModule(require("chalk"));
95
- var bold = (str) => import_chalk.default.yellowBright.bold(str);
110
+ var _logger;
111
+ var getLogger = () => {
112
+ if (!_logger) {
113
+ _logger = console;
114
+ }
115
+ return _logger;
116
+ };
117
+ var bold = (str) => import_chalk.default.greenBright.bold(str);
96
118
  var underline = (str) => import_chalk.default.cyanBright.bold(str);
97
119
 
98
120
  // src/utils/getCredentialsProfileRegion.ts
@@ -106,12 +128,25 @@ var getCredentialsProfileRegion = async ({
106
128
  let profileAndOrigin = void 0;
107
129
  let regionAndOrigin = void 0;
108
130
  if (argv.profile) {
109
- profileAndOrigin = { value: argv.profile, origin: `command line option: ${bold(argv.profile)}` };
110
- credentialsAndOrigin = { value: await (0, import_credential_providers.fromIni)({ profile: argv.profile })(), origin: `${bold(`[${argv.profile}]`)} in credentials file` };
131
+ profileAndOrigin = {
132
+ value: argv.profile,
133
+ origin: `command line option: ${bold(argv.profile)}`
134
+ };
135
+ credentialsAndOrigin = {
136
+ value: await (0, import_credential_providers.fromIni)({
137
+ profile: argv.profile
138
+ })(),
139
+ origin: `${bold(`[${argv.profile}]`)} in credentials file`
140
+ };
111
141
  } else if (env.AWS_PROFILE) {
112
- profileAndOrigin = { value: env.AWS_PROFILE, origin: `env variable ${bold("AWS_PROFILE")}: ${underline(env.AWS_PROFILE)}` };
142
+ profileAndOrigin = {
143
+ value: env.AWS_PROFILE,
144
+ origin: `env variable ${bold("AWS_PROFILE")}: ${underline(env.AWS_PROFILE)}`
145
+ };
113
146
  credentialsAndOrigin = {
114
- value: await (0, import_credential_providers.fromIni)({ profile: env.AWS_PROFILE })(),
147
+ value: await (0, import_credential_providers.fromIni)({
148
+ profile: env.AWS_PROFILE
149
+ })(),
115
150
  origin: `env variable ${underline("AWS_PROFILE")}: ${bold(env.AWS_PROFILE)}`
116
151
  };
117
152
  } else if (env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY) {
@@ -120,13 +155,27 @@ var getCredentialsProfileRegion = async ({
120
155
  origin: `env variables ${bold("AWS_ACCESS_KEY_ID")} and ${bold("AWS_SECRET_ACCESS_KEY")}`
121
156
  };
122
157
  } else if ((_a = sharedConfigFiles.credentialsFile) == null ? void 0 : _a.default) {
123
- profileAndOrigin = { value: "default", origin: `${bold("[default]")} in credentials file` };
124
- credentialsAndOrigin = { value: await (0, import_credential_providers.fromIni)({ profile: "default" })(), origin: `profile ${bold("[default]")}` };
158
+ profileAndOrigin = {
159
+ value: "default",
160
+ origin: `${bold("[default]")} in credentials file`
161
+ };
162
+ credentialsAndOrigin = {
163
+ value: await (0, import_credential_providers.fromIni)({
164
+ profile: "default"
165
+ })(),
166
+ origin: `profile ${bold("[default]")}`
167
+ };
125
168
  }
126
169
  if (argv.region) {
127
- regionAndOrigin = { value: argv.region, origin: `command line option: ${bold(argv.region)}` };
170
+ regionAndOrigin = {
171
+ value: argv.region,
172
+ origin: `command line option: ${bold(argv.region)}`
173
+ };
128
174
  } else if (env.AWS_REGION) {
129
- regionAndOrigin = { value: env.AWS_REGION, origin: `env variable ${bold("AWS_REGION")}: ${underline(env.AWS_REGION)}` };
175
+ regionAndOrigin = {
176
+ value: env.AWS_REGION,
177
+ origin: `env variable ${bold("AWS_REGION")}: ${underline(env.AWS_REGION)}`
178
+ };
130
179
  } else if (env.AWS_DEFAULT_REGION) {
131
180
  regionAndOrigin = {
132
181
  value: env.AWS_DEFAULT_REGION,
@@ -135,9 +184,27 @@ var getCredentialsProfileRegion = async ({
135
184
  } else if (profileAndOrigin) {
136
185
  const foundRegion = (_c = (_b = sharedConfigFiles == null ? void 0 : sharedConfigFiles.configFile) == null ? void 0 : _b[profileAndOrigin.value]) == null ? void 0 : _c.region;
137
186
  if (foundRegion) {
138
- regionAndOrigin = { value: foundRegion, origin: `${bold(`[profile ${profileAndOrigin.value}]`)} in config file` };
187
+ regionAndOrigin = {
188
+ value: foundRegion,
189
+ origin: `${bold(`[profile ${profileAndOrigin.value}]`)} in config file`
190
+ };
139
191
  }
140
192
  }
193
+ if (argv.assumeRoleArn) {
194
+ console.log("assume this yo");
195
+ credentialsAndOrigin = {
196
+ value: await (0, import_credential_providers.fromTemporaryCredentials)({
197
+ masterCredentials: credentialsAndOrigin == null ? void 0 : credentialsAndOrigin.value,
198
+ params: {
199
+ RoleArn: argv.assumeRoleArn
200
+ },
201
+ clientConfig: {
202
+ region: regionAndOrigin == null ? void 0 : regionAndOrigin.value
203
+ }
204
+ })(),
205
+ origin: `assume role ${bold(`[${argv.assumeRoleArn}]`)}`
206
+ };
207
+ }
141
208
  return { credentialsAndOrigin, regionAndOrigin, profileAndOrigin };
142
209
  };
143
210
  var printVerboseCredentialsProfileRegion = ({
@@ -163,12 +230,20 @@ var handleCredentialsAndRegion = async ({
163
230
  argv,
164
231
  env
165
232
  }) => {
166
- const { credentialsAndOrigin, regionAndOrigin } = await getCredentialsProfileRegion({
167
- argv: { region: argv.awsRegion, profile: argv.awsProfile },
233
+ const { credentialsAndOrigin, regionAndOrigin, profileAndOrigin } = await getCredentialsProfileRegion({
234
+ argv: {
235
+ region: argv.awsRegion,
236
+ profile: argv.awsProfile,
237
+ assumeRoleArn: argv.awsAssumeRoleArn
238
+ },
168
239
  env: __spreadValues({}, env)
169
240
  });
170
241
  if (argv.verbose === true) {
171
- console.log(printVerboseCredentialsProfileRegion({ credentialsAndOrigin, regionAndOrigin }));
242
+ console.log(printVerboseCredentialsProfileRegion({
243
+ credentialsAndOrigin,
244
+ regionAndOrigin,
245
+ profileAndOrigin
246
+ }));
172
247
  }
173
248
  if (!credentialsAndOrigin || !regionAndOrigin) {
174
249
  if (!credentialsAndOrigin) {
@@ -183,8 +258,67 @@ var handleCredentialsAndRegion = async ({
183
258
  return { credentialsAndOrigin, regionAndOrigin };
184
259
  };
185
260
 
261
+ // src/utils/ssm.ts
262
+ var import_client_ssm = __toModule(require("@aws-sdk/client-ssm"));
263
+ var getSSMClient = ({
264
+ configuration
265
+ }) => {
266
+ const ssmClient = new import_client_ssm.SSMClient(configuration);
267
+ return ssmClient;
268
+ };
269
+
270
+ // src/commands/debugCommand.ts
271
+ var command = "debug";
272
+ var desc = "Debugs all the things";
273
+ var builder = {
274
+ "aws-profile": commonCliOptions.awsProfile,
275
+ "aws-region": commonCliOptions.awsRegion,
276
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
277
+ "aws-assume-role-arn": commonCliOptions.awsAssumeRoleArn,
278
+ verbose: commonCliOptions.verbose,
279
+ yes: __spreadValues({}, commonCliOptions.yes)
280
+ };
281
+ var handler = async (argv) => {
282
+ try {
283
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
284
+ argv: __spreadValues({}, argv),
285
+ env: __spreadValues({}, process.env)
286
+ });
287
+ const ssmClient = getSSMClient({
288
+ configuration: {
289
+ credentials: credentialsAndOrigin.value,
290
+ region: regionAndOrigin.value
291
+ },
292
+ verbose: argv.verbose
293
+ });
294
+ const getParametersByPathCommand = new import_client_ssm2.GetParametersByPathCommand({
295
+ Path: `arn:aws:ssm:eu-west-1:060014838622:parameter/dotsec/*`,
296
+ Recursive: true
297
+ });
298
+ const commandResult = await ssmClient.send(getParametersByPathCommand);
299
+ console.log(commandResult);
300
+ } catch (e) {
301
+ console.error(e);
302
+ }
303
+ };
304
+
305
+ // src/commands/decryptSecCommand.ts
306
+ var decryptSecCommand_exports = {};
307
+ __export(decryptSecCommand_exports, {
308
+ builder: () => builder2,
309
+ command: () => command2,
310
+ desc: () => desc2,
311
+ handler: () => handler2
312
+ });
313
+ var import_client_kms = __toModule(require("@aws-sdk/client-kms"));
314
+ var import_chalk2 = __toModule(require("chalk"));
315
+ var import_dotenv = __toModule(require("dotenv"));
316
+ var import_node_fs = __toModule(require("node:fs"));
317
+ var import_node_path = __toModule(require("node:path"));
318
+
186
319
  // src/utils/io.ts
187
320
  var import_promises = __toModule(require("fs/promises"));
321
+ var import_prompts = __toModule(require("prompts"));
188
322
  var fileExists = async (source) => {
189
323
  try {
190
324
  await (0, import_promises.stat)(source);
@@ -193,30 +327,43 @@ var fileExists = async (source) => {
193
327
  return false;
194
328
  }
195
329
  };
330
+ var promptOverwriteIfFileExists = async ({
331
+ filePath,
332
+ skip
333
+ }) => {
334
+ let overwriteResponse;
335
+ if (await fileExists(filePath) && skip !== true) {
336
+ overwriteResponse = await (0, import_prompts.default)({
337
+ type: "confirm",
338
+ name: "overwrite",
339
+ message: () => {
340
+ return `Overwrite '${filePath}' ?`;
341
+ }
342
+ });
343
+ } else {
344
+ overwriteResponse = void 0;
345
+ }
346
+ return overwriteResponse;
347
+ };
196
348
 
197
349
  // src/commands/decryptSecCommand.ts
198
- var command = "decrypt-sec";
199
- var desc = "Decrypts a dotsec file";
200
- var builder = {
201
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
202
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
203
- "aws-key-alias": { string: true, default: "alias/top-secret" },
204
- "env-file": {
205
- string: true,
206
- describe: ".env file",
207
- default: ".env"
208
- },
209
- "sec-file": {
210
- string: true,
211
- describe: ".sec file",
212
- default: ".sec"
213
- },
214
- verbose: __spreadValues({}, commonCliOptions.verbose),
215
- yes: __spreadValues({}, commonCliOptions.yes)
350
+ var command2 = "decrypt-sec";
351
+ var desc2 = "Decrypts a dotsec file";
352
+ var builder2 = {
353
+ "aws-profile": commonCliOptions.awsProfile,
354
+ "aws-region": commonCliOptions.awsRegion,
355
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
356
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
357
+ "env-file": commonCliOptions.envFile,
358
+ "sec-file": commonCliOptions.secFile,
359
+ verbose: commonCliOptions.verbose
216
360
  };
217
- var handler = async (argv) => {
361
+ var handler2 = async (argv) => {
218
362
  try {
219
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
363
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
364
+ argv: __spreadValues({}, argv),
365
+ env: __spreadValues({}, process.env)
366
+ });
220
367
  const secSource = import_node_path.default.resolve(process.cwd(), argv.secFile);
221
368
  if (!await fileExists(secSource)) {
222
369
  console.error(`Could not open ${(0, import_chalk2.redBright)(secSource)}`);
@@ -235,7 +382,11 @@ var handler = async (argv) => {
235
382
  });
236
383
  const decryptionResult = await kmsClient.send(decryptCommand);
237
384
  if (!(decryptionResult == null ? void 0 : decryptionResult.Plaintext)) {
238
- throw new Error(`No: ${JSON.stringify({ key, cipherText, decryptCommand })}`);
385
+ throw new Error(`No: ${JSON.stringify({
386
+ key,
387
+ cipherText,
388
+ decryptCommand
389
+ })}`);
239
390
  }
240
391
  const value = Buffer.from(decryptionResult.Plaintext).toString();
241
392
  return [key, value];
@@ -246,62 +397,203 @@ var handler = async (argv) => {
246
397
  }
247
398
  };
248
399
 
249
- // src/commands/defaultCommand.ts
250
- var defaultCommand_exports = {};
251
- __export(defaultCommand_exports, {
252
- builder: () => builder2,
253
- command: () => command2,
254
- desc: () => desc2,
255
- handler: () => handler2
400
+ // src/commands/decryptSecretsJson.ts
401
+ var decryptSecretsJson_exports = {};
402
+ __export(decryptSecretsJson_exports, {
403
+ builder: () => builder3,
404
+ command: () => command3,
405
+ desc: () => desc3,
406
+ handler: () => handler3
256
407
  });
257
- var import_client_kms2 = __toModule(require("@aws-sdk/client-kms"));
408
+ var import_client_kms3 = __toModule(require("@aws-sdk/client-kms"));
258
409
  var import_chalk3 = __toModule(require("chalk"));
259
- var import_cross_spawn = __toModule(require("cross-spawn"));
260
- var import_dotenv2 = __toModule(require("dotenv"));
410
+ var import_flat = __toModule(require("flat"));
261
411
  var import_node_fs2 = __toModule(require("node:fs"));
262
412
  var import_node_path2 = __toModule(require("node:path"));
263
- var command2 = "$0 <command>";
264
- var desc2 = "Decrypts a .sec file, injects the results into a separate process and runs a command";
265
- var builder2 = {
266
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
267
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
268
- "aws-key-alias": { string: true, default: "alias/top-secret" },
269
- "sec-file": {
413
+
414
+ // src/utils/kms.ts
415
+ var import_client_kms2 = __toModule(require("@aws-sdk/client-kms"));
416
+ var getKMSClient = ({
417
+ configuration
418
+ }) => {
419
+ const kmsClient = new import_client_kms2.KMSClient(configuration);
420
+ return kmsClient;
421
+ };
422
+
423
+ // src/commands/decryptSecretsJson.ts
424
+ var command3 = "decrypt-secrets-json";
425
+ var desc3 = "Derypts an encrypted file";
426
+ var builder3 = {
427
+ "aws-profile": commonCliOptions.awsProfile,
428
+ "aws-region": commonCliOptions.awsRegion,
429
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
430
+ "secrets-file": {
270
431
  string: true,
271
- describe: ".sec file",
272
- default: ".sec"
432
+ describe: "filename of json file writing secrets",
433
+ default: "secrets.json"
273
434
  },
274
- verbose: __spreadValues({}, commonCliOptions.verbose),
275
- yes: __spreadValues({}, commonCliOptions.yes),
276
- command: { string: true, required: true }
435
+ "encrypted-secrets-file": {
436
+ string: true,
437
+ describe: "filename of json file for reading encrypted secrets",
438
+ default: "secrets.encrypted.json"
439
+ },
440
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
441
+ verbose: commonCliOptions.verbose,
442
+ yes: __spreadValues({}, commonCliOptions.yes)
277
443
  };
278
- var handler2 = async (argv) => {
444
+ var handler3 = async (argv) => {
445
+ const { info, error } = getLogger();
279
446
  try {
280
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
281
- const secSource = import_node_path2.default.resolve(process.cwd(), argv.secFile);
282
- if (!await fileExists(secSource)) {
283
- console.error(`Could not open ${(0, import_chalk3.redBright)(secSource)}`);
447
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
448
+ argv: __spreadValues({}, argv),
449
+ env: __spreadValues({}, process.env)
450
+ });
451
+ const encryptedSecretsPath = import_node_path2.default.resolve(process.cwd(), argv.encryptedSecretsFile);
452
+ if (!await fileExists(encryptedSecretsPath)) {
453
+ error(`Could not open ${(0, import_chalk3.redBright)(encryptedSecretsPath)}`);
284
454
  return;
285
455
  }
286
- const parsedSec = (0, import_dotenv2.parse)(import_node_fs2.default.readFileSync(secSource, { encoding: "utf8" }));
287
- const kmsClient = new import_client_kms2.KMSClient({
288
- credentials: credentialsAndOrigin.value,
289
- region: regionAndOrigin.value
456
+ const encryptedSecrets = JSON.parse(import_node_fs2.default.readFileSync(encryptedSecretsPath, { encoding: "utf8" }));
457
+ if (!encryptedSecrets.encryptedParameters) {
458
+ throw new Error(`Expected 'encryptedParameters' property, but got none`);
459
+ }
460
+ const flatEncryptedParameters = (0, import_flat.default)(encryptedSecrets.encryptedParameters, { delimiter: "/" });
461
+ const kmsClient = getKMSClient({
462
+ configuration: {
463
+ credentials: credentialsAndOrigin.value,
464
+ region: regionAndOrigin.value
465
+ },
466
+ verbose: argv.verbose
290
467
  });
291
- const envEntries = await Promise.all(Object.entries(parsedSec).map(async ([key, cipherText]) => {
292
- const decryptCommand = new import_client_kms2.DecryptCommand({
468
+ if (argv.verbose) {
469
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
470
+ const describeKeyCommand = new import_client_kms3.DescribeKeyCommand({
471
+ KeyId: argv.awsKeyAlias
472
+ });
473
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
474
+ console.log("describeKeyResult", { describeKeyResult });
475
+ }
476
+ const flatParameters = Object.fromEntries(await Promise.all(Object.entries(flatEncryptedParameters).map(async ([parameterName, encryptedParameter]) => {
477
+ const decryptCommand = new import_client_kms3.DecryptCommand({
293
478
  KeyId: argv.awsKeyAlias,
294
- CiphertextBlob: Buffer.from(cipherText, "base64"),
479
+ CiphertextBlob: Buffer.from(encryptedParameter, "base64"),
295
480
  EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
296
481
  });
297
482
  const decryptionResult = await kmsClient.send(decryptCommand);
298
- if (!(decryptionResult == null ? void 0 : decryptionResult.Plaintext)) {
299
- throw new Error(`No: ${JSON.stringify({ key, cipherText, decryptCommand })}`);
483
+ if (!decryptionResult.Plaintext) {
484
+ throw new Error(`Something bad happened: ${JSON.stringify({
485
+ key: parameterName,
486
+ cipherText: encryptedParameter,
487
+ decryptCommand
488
+ })}`);
489
+ }
490
+ if (argv.verbose) {
491
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
300
492
  }
301
493
  const value = Buffer.from(decryptionResult.Plaintext).toString();
302
- return [key, value];
303
- }));
304
- const env = Object.fromEntries(envEntries);
494
+ return [parameterName, value];
495
+ })));
496
+ const parameters = import_flat.default.unflatten(flatParameters, { delimiter: "/" });
497
+ const secrets = {
498
+ config: encryptedSecrets.config,
499
+ parameters
500
+ };
501
+ const secretsPath = import_node_path2.default.resolve(process.cwd(), argv.secretsFile);
502
+ const overwriteResponse = await promptOverwriteIfFileExists({
503
+ filePath: secretsPath,
504
+ skip: argv.yes
505
+ });
506
+ if (overwriteResponse === void 0 || overwriteResponse.overwrite === true) {
507
+ import_node_fs2.default.writeFileSync(secretsPath, JSON.stringify(secrets, null, 4));
508
+ }
509
+ } catch (e) {
510
+ error(e);
511
+ }
512
+ };
513
+
514
+ // src/commands/defaultCommand.ts
515
+ var defaultCommand_exports = {};
516
+ __export(defaultCommand_exports, {
517
+ builder: () => builder4,
518
+ command: () => command4,
519
+ desc: () => desc4,
520
+ handler: () => handler4
521
+ });
522
+ var import_node_fs3 = __toModule(require("node:fs"));
523
+ var import_node_path3 = __toModule(require("node:path"));
524
+ var import_client_kms4 = __toModule(require("@aws-sdk/client-kms"));
525
+ var import_chalk4 = __toModule(require("chalk"));
526
+ var import_cross_spawn = __toModule(require("cross-spawn"));
527
+ var import_dotenv2 = __toModule(require("dotenv"));
528
+ var command4 = "$0 <command>";
529
+ var desc4 = "Decrypts a .sec file, injects the results into a separate process and runs a command";
530
+ var builder4 = {
531
+ "aws-profile": commonCliOptions.awsProfile,
532
+ "aws-region": commonCliOptions.awsRegion,
533
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
534
+ "sec-file": commonCliOptions.secFile,
535
+ "env-file": commonCliOptions.envFile,
536
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
537
+ verbose: commonCliOptions.verbose,
538
+ command: { string: true, required: true }
539
+ };
540
+ var handleSec = async ({
541
+ secFile,
542
+ credentialsAndOrigin,
543
+ regionAndOrigin,
544
+ awsKeyAlias
545
+ }) => {
546
+ const secSource = import_node_path3.default.resolve(process.cwd(), secFile);
547
+ if (!await fileExists(secSource)) {
548
+ console.error(`Could not open ${(0, import_chalk4.redBright)(secSource)}`);
549
+ return;
550
+ }
551
+ const parsedSec = (0, import_dotenv2.parse)(import_node_fs3.default.readFileSync(secSource, { encoding: "utf8" }));
552
+ const kmsClient = new import_client_kms4.KMSClient({
553
+ credentials: credentialsAndOrigin.value,
554
+ region: regionAndOrigin.value
555
+ });
556
+ const envEntries = await Promise.all(Object.entries(parsedSec).map(async ([key, cipherText]) => {
557
+ const decryptCommand = new import_client_kms4.DecryptCommand({
558
+ KeyId: awsKeyAlias,
559
+ CiphertextBlob: Buffer.from(cipherText, "base64"),
560
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
561
+ });
562
+ const decryptionResult = await kmsClient.send(decryptCommand);
563
+ if (!(decryptionResult == null ? void 0 : decryptionResult.Plaintext)) {
564
+ throw new Error(`No: ${JSON.stringify({
565
+ key,
566
+ cipherText,
567
+ decryptCommand
568
+ })}`);
569
+ }
570
+ const value = Buffer.from(decryptionResult.Plaintext).toString();
571
+ return [key, value];
572
+ }));
573
+ const env = Object.fromEntries(envEntries);
574
+ return env;
575
+ };
576
+ var handler4 = async (argv) => {
577
+ try {
578
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
579
+ argv: __spreadValues({}, argv),
580
+ env: __spreadValues({}, process.env)
581
+ });
582
+ if (argv.verbose) {
583
+ console.log({ credentialsAndOrigin, regionAndOrigin });
584
+ }
585
+ let env;
586
+ if (argv.envFile) {
587
+ console.log("OK");
588
+ env = (0, import_dotenv2.parse)(import_node_fs3.default.readFileSync(argv.envFile, { encoding: "utf8" }));
589
+ } else if (argv.secFile) {
590
+ env = await handleSec({
591
+ secFile: argv.secFile,
592
+ credentialsAndOrigin,
593
+ regionAndOrigin,
594
+ awsKeyAlias: argv.awsKeyAlias
595
+ });
596
+ }
305
597
  const userCommandArgs = process.argv.slice(process.argv.indexOf(argv.command) + 1);
306
598
  if (argv.command) {
307
599
  (0, import_cross_spawn.spawn)(argv.command, [...userCommandArgs], {
@@ -318,67 +610,289 @@ var handler2 = async (argv) => {
318
610
  // src/commands/encryptEnvCommand.ts
319
611
  var encryptEnvCommand_exports = {};
320
612
  __export(encryptEnvCommand_exports, {
321
- builder: () => builder3,
322
- command: () => command3,
323
- desc: () => desc3,
324
- handler: () => handler3
613
+ builder: () => builder5,
614
+ command: () => command5,
615
+ desc: () => desc5,
616
+ handler: () => handler5
325
617
  });
326
- var import_client_kms3 = __toModule(require("@aws-sdk/client-kms"));
327
- var import_chalk4 = __toModule(require("chalk"));
618
+ var import_client_kms5 = __toModule(require("@aws-sdk/client-kms"));
619
+ var import_chalk5 = __toModule(require("chalk"));
328
620
  var import_dotenv3 = __toModule(require("dotenv"));
329
- var import_node_fs3 = __toModule(require("node:fs"));
330
- var import_node_path3 = __toModule(require("node:path"));
331
- var command3 = "encrypt-env";
332
- var desc3 = "Encrypts a dotenv file";
333
- var builder3 = {
334
- "aws-profile": __spreadValues({}, commonCliOptions.awsProfile),
335
- "aws-region": __spreadValues({}, commonCliOptions.awsRegion),
336
- "aws-key-alias": { string: true, default: "alias/top-secret" },
337
- "env-file": {
338
- string: true,
339
- describe: ".env file",
340
- default: ".env"
341
- },
342
- "sec-file": {
343
- string: true,
344
- describe: ".sec file",
345
- default: ".sec"
346
- },
347
- verbose: __spreadValues({}, commonCliOptions.verbose),
348
- yes: __spreadValues({}, commonCliOptions.yes)
621
+ var import_node_fs4 = __toModule(require("node:fs"));
622
+ var import_node_path4 = __toModule(require("node:path"));
623
+ var command5 = "encrypt-env";
624
+ var desc5 = "Encrypts a dotenv file";
625
+ var builder5 = {
626
+ "aws-profile": commonCliOptions.awsProfile,
627
+ "aws-region": commonCliOptions.awsRegion,
628
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
629
+ "env-file": commonCliOptions.envFile,
630
+ "sec-file": commonCliOptions.secFile,
631
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
632
+ verbose: commonCliOptions.verbose
349
633
  };
350
- var handler3 = async (argv) => {
634
+ var handler5 = async (argv) => {
635
+ const { info, error } = getLogger();
351
636
  try {
352
- const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({ argv: __spreadValues({}, argv), env: __spreadValues({}, process.env) });
353
- const envSource = import_node_path3.default.resolve(process.cwd(), argv.envFile);
637
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
638
+ argv: __spreadValues({}, argv),
639
+ env: __spreadValues({}, process.env)
640
+ });
641
+ const envSource = import_node_path4.default.resolve(process.cwd(), argv.envFile);
354
642
  if (!await fileExists(envSource)) {
355
- console.error(`Could not open ${(0, import_chalk4.redBright)(envSource)}`);
643
+ error(`Could not open ${(0, import_chalk5.redBright)(envSource)}`);
356
644
  return;
357
645
  }
358
- const parsedEnv = (0, import_dotenv3.parse)(import_node_fs3.default.readFileSync(envSource, { encoding: "utf8" }));
359
- const kmsClient = new import_client_kms3.KMSClient({
360
- credentials: credentialsAndOrigin.value,
361
- region: regionAndOrigin.value
646
+ const parsedEnv = (0, import_dotenv3.parse)(import_node_fs4.default.readFileSync(envSource, { encoding: "utf8" }));
647
+ const kmsClient = getKMSClient({
648
+ configuration: {
649
+ credentials: credentialsAndOrigin.value,
650
+ region: regionAndOrigin.value
651
+ },
652
+ verbose: argv.verbose
362
653
  });
654
+ if (argv.verbose) {
655
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
656
+ const describeKeyCommand = new import_client_kms5.DescribeKeyCommand({
657
+ KeyId: argv.awsKeyAlias
658
+ });
659
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
660
+ console.log("describeKeyResult", { describeKeyResult });
661
+ }
363
662
  const sec = (await Promise.all(Object.entries(parsedEnv).map(async ([key, value]) => {
364
- const encryptCommand = new import_client_kms3.EncryptCommand({
663
+ const encryptCommand = new import_client_kms5.EncryptCommand({
365
664
  KeyId: argv.awsKeyAlias,
366
665
  Plaintext: Buffer.from(value),
367
666
  EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
368
667
  });
369
668
  const encryptionResult = await kmsClient.send(encryptCommand);
370
669
  if (!encryptionResult.CiphertextBlob) {
371
- throw new Error(`No: ${JSON.stringify({ key, value, encryptCommand })}`);
670
+ throw new Error(`Something bad happened: ${JSON.stringify({
671
+ key,
672
+ value,
673
+ encryptCommand
674
+ })}`);
675
+ }
676
+ if (argv.verbose) {
677
+ info(`Encrypting key ${bold(key)} ${underline("ok")}`);
372
678
  }
373
679
  const cipherText = Buffer.from(encryptionResult.CiphertextBlob).toString("base64");
374
680
  return `${key}="${cipherText}"`;
375
681
  }))).join("\n");
376
- import_node_fs3.default.writeFileSync(import_node_path3.default.resolve(process.cwd(), argv.secFile), sec);
682
+ import_node_fs4.default.writeFileSync(import_node_path4.default.resolve(process.cwd(), argv.secFile), sec);
377
683
  } catch (e) {
378
- console.error(e);
684
+ error(e);
685
+ }
686
+ };
687
+
688
+ // src/commands/encryptSecretsJson.ts
689
+ var encryptSecretsJson_exports = {};
690
+ __export(encryptSecretsJson_exports, {
691
+ builder: () => builder6,
692
+ command: () => command6,
693
+ desc: () => desc6,
694
+ handler: () => handler6
695
+ });
696
+ var import_node_fs5 = __toModule(require("node:fs"));
697
+ var import_node_path5 = __toModule(require("node:path"));
698
+ var import_client_kms6 = __toModule(require("@aws-sdk/client-kms"));
699
+ var import_chalk6 = __toModule(require("chalk"));
700
+ var import_flat2 = __toModule(require("flat"));
701
+ var command6 = "encrypt-secrets-json";
702
+ var desc6 = "Encrypts an unencrypted file";
703
+ var builder6 = {
704
+ "aws-profile": commonCliOptions.awsProfile,
705
+ "aws-region": commonCliOptions.awsRegion,
706
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
707
+ "secrets-file": {
708
+ string: true,
709
+ describe: "filename of json file reading secrets",
710
+ default: "secrets.json"
711
+ },
712
+ "encrypted-secrets-file": {
713
+ string: true,
714
+ describe: "filename of json file for writing encrypted secrets",
715
+ default: "secrets.encrypted.json"
716
+ },
717
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
718
+ verbose: commonCliOptions.verbose,
719
+ yes: __spreadValues({}, commonCliOptions.yes)
720
+ };
721
+ var handler6 = async (argv) => {
722
+ const { info, error } = getLogger();
723
+ try {
724
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
725
+ argv: __spreadValues({}, argv),
726
+ env: __spreadValues({}, process.env)
727
+ });
728
+ const secretsPath = import_node_path5.default.resolve(process.cwd(), argv.secretsFile);
729
+ if (!await fileExists(secretsPath)) {
730
+ error(`Could not open ${(0, import_chalk6.redBright)(secretsPath)}`);
731
+ return;
732
+ }
733
+ const secrets = JSON.parse(import_node_fs5.default.readFileSync(secretsPath, { encoding: "utf8" }));
734
+ if (!secrets.parameters) {
735
+ throw new Error(`Expected 'parameters' property, but got none`);
736
+ }
737
+ const flatParameters = (0, import_flat2.default)(secrets.parameters, { delimiter: "/" });
738
+ if (argv.verbose) {
739
+ console.log(flatParameters);
740
+ }
741
+ const kmsClient = getKMSClient({
742
+ configuration: {
743
+ credentials: credentialsAndOrigin.value,
744
+ region: regionAndOrigin.value
745
+ },
746
+ verbose: argv.verbose
747
+ });
748
+ if (argv.verbose) {
749
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
750
+ const describeKeyCommand = new import_client_kms6.DescribeKeyCommand({
751
+ KeyId: argv.awsKeyAlias
752
+ });
753
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
754
+ console.log("describeKeyResult", { describeKeyResult });
755
+ }
756
+ const encryptedFlatParameters = Object.fromEntries(await Promise.all(Object.entries(flatParameters).map(async ([parameterName, parameter]) => {
757
+ const encryptCommand = new import_client_kms6.EncryptCommand({
758
+ KeyId: argv.awsKeyAlias,
759
+ Plaintext: Buffer.from(parameter),
760
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
761
+ });
762
+ const encryptionResult = await kmsClient.send(encryptCommand);
763
+ if (!encryptionResult.CiphertextBlob) {
764
+ throw new Error(`Something bad happened: ${JSON.stringify({
765
+ key: parameterName,
766
+ value: parameter,
767
+ encryptCommand
768
+ })}`);
769
+ }
770
+ if (argv.verbose) {
771
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
772
+ }
773
+ const cipherText = Buffer.from(encryptionResult.CiphertextBlob).toString("base64");
774
+ return [parameterName, cipherText];
775
+ })));
776
+ const encryptedParameters = import_flat2.default.unflatten(encryptedFlatParameters, { delimiter: "/" });
777
+ const encryptedSecrets = {
778
+ config: secrets.config,
779
+ encryptedParameters
780
+ };
781
+ const encryptedSecretsPath = import_node_path5.default.resolve(process.cwd(), argv.encryptedSecretsFile);
782
+ const overwriteResponse = await promptOverwriteIfFileExists({
783
+ filePath: encryptedSecretsPath,
784
+ skip: argv.yes
785
+ });
786
+ if (overwriteResponse === void 0 || overwriteResponse.overwrite === true) {
787
+ import_node_fs5.default.writeFileSync(encryptedSecretsPath, JSON.stringify(encryptedSecrets, null, 4));
788
+ }
789
+ } catch (e) {
790
+ error(e);
791
+ }
792
+ };
793
+
794
+ // src/commands/offloadToSSMCommand.ts
795
+ var offloadToSSMCommand_exports = {};
796
+ __export(offloadToSSMCommand_exports, {
797
+ builder: () => builder7,
798
+ command: () => command7,
799
+ desc: () => desc7,
800
+ handler: () => handler7
801
+ });
802
+ var import_client_kms7 = __toModule(require("@aws-sdk/client-kms"));
803
+ var import_client_ssm3 = __toModule(require("@aws-sdk/client-ssm"));
804
+ var import_chalk7 = __toModule(require("chalk"));
805
+ var import_flat3 = __toModule(require("flat"));
806
+ var import_node_fs6 = __toModule(require("node:fs"));
807
+ var import_node_path6 = __toModule(require("node:path"));
808
+ var command7 = "offload-secrets-json-to-ssm";
809
+ var desc7 = "Sends decrypted values of secrets.encrypted.json file to SSM parameter store";
810
+ var builder7 = {
811
+ "aws-profile": commonCliOptions.awsProfile,
812
+ "aws-region": commonCliOptions.awsRegion,
813
+ "aws-key-alias": commonCliOptions.awsKeyAlias,
814
+ "encrypted-secrets-file": {
815
+ string: true,
816
+ describe: "filename of json file for reading encrypted secrets",
817
+ default: "secrets.encrypted.json"
818
+ },
819
+ "assume-role-arn": commonCliOptions.awsAssumeRoleArn,
820
+ verbose: commonCliOptions.verbose,
821
+ yes: __spreadValues({}, commonCliOptions.yes)
822
+ };
823
+ var handler7 = async (argv) => {
824
+ const { info, error } = getLogger();
825
+ try {
826
+ const { credentialsAndOrigin, regionAndOrigin } = await handleCredentialsAndRegion({
827
+ argv: __spreadValues({}, argv),
828
+ env: __spreadValues({}, process.env)
829
+ });
830
+ const encryptedSecretsPath = import_node_path6.default.resolve(process.cwd(), argv.encryptedSecretsFile);
831
+ if (!await fileExists(encryptedSecretsPath)) {
832
+ error(`Could not open ${(0, import_chalk7.redBright)(encryptedSecretsPath)}`);
833
+ return;
834
+ }
835
+ const encryptedSecrets = JSON.parse(import_node_fs6.default.readFileSync(encryptedSecretsPath, { encoding: "utf8" }));
836
+ if (!encryptedSecrets.encryptedParameters) {
837
+ throw new Error(`Expected 'encryptedParameters' property, but got none`);
838
+ }
839
+ const flatEncryptedParameters = (0, import_flat3.default)(encryptedSecrets.encryptedParameters, { delimiter: "/" });
840
+ const kmsClient = getKMSClient({
841
+ configuration: {
842
+ credentials: credentialsAndOrigin.value,
843
+ region: regionAndOrigin.value
844
+ },
845
+ verbose: argv.verbose
846
+ });
847
+ if (argv.verbose) {
848
+ info(`Encrypting using key alias ${bold(argv.awsKeyAlias)} in ${bold(await kmsClient.config.region())}`);
849
+ const describeKeyCommand = new import_client_kms7.DescribeKeyCommand({
850
+ KeyId: argv.awsKeyAlias
851
+ });
852
+ const describeKeyResult = await kmsClient.send(describeKeyCommand);
853
+ console.log("describeKeyResult", { describeKeyResult });
854
+ }
855
+ const flatParameters = Object.fromEntries(await Promise.all(Object.entries(flatEncryptedParameters).map(async ([parameterName, encryptedParameter]) => {
856
+ const decryptCommand = new import_client_kms7.DecryptCommand({
857
+ KeyId: argv.awsKeyAlias,
858
+ CiphertextBlob: Buffer.from(encryptedParameter, "base64"),
859
+ EncryptionAlgorithm: "RSAES_OAEP_SHA_256"
860
+ });
861
+ const decryptionResult = await kmsClient.send(decryptCommand);
862
+ if (!decryptionResult.Plaintext) {
863
+ throw new Error(`Something bad happened: ${JSON.stringify({
864
+ key: parameterName,
865
+ cipherText: encryptedParameter,
866
+ decryptCommand
867
+ })}`);
868
+ }
869
+ if (argv.verbose) {
870
+ info(`Encrypting key ${bold(parameterName)} ${underline("ok")}`);
871
+ }
872
+ const value = Buffer.from(decryptionResult.Plaintext).toString();
873
+ return [parameterName, value];
874
+ })));
875
+ const ssmClient = getSSMClient({
876
+ configuration: {
877
+ credentials: credentialsAndOrigin.value,
878
+ region: regionAndOrigin.value
879
+ },
880
+ verbose: argv.verbose
881
+ });
882
+ await Promise.all(Object.entries(flatParameters).map(([parameterName, value]) => {
883
+ const putParameterCommand = new import_client_ssm3.PutParameterCommand({
884
+ Name: `/${parameterName}`,
885
+ Value: value,
886
+ Type: "String",
887
+ Overwrite: true
888
+ });
889
+ return ssmClient.send(putParameterCommand);
890
+ }));
891
+ } catch (e) {
892
+ error(e);
379
893
  }
380
894
  };
381
895
 
382
896
  // src/cli.ts
383
- void (0, import_yargs.default)((0, import_helpers.hideBin)(process.argv)).command(defaultCommand_exports).command(encryptEnvCommand_exports).command(decryptSecCommand_exports).parse();
897
+ void (0, import_yargs.default)((0, import_helpers.hideBin)(process.argv)).command(defaultCommand_exports).command(offloadToSSMCommand_exports).command(debugCommand_exports).command(encryptEnvCommand_exports).command(decryptSecCommand_exports).command(encryptSecretsJson_exports).command(decryptSecretsJson_exports).parse();
384
898
  //# sourceMappingURL=cli.js.map