@govuk-pay/cli 0.0.27 → 0.0.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@govuk-pay/cli",
3
- "version": "0.0.27",
3
+ "version": "0.0.28",
4
4
  "description": "GOV.UK Pay Command Line Interface",
5
5
  "bin": {
6
6
  "pay": "bin/cli.js",
@@ -10,6 +10,7 @@ const client_ecs_1 = require("@aws-sdk/client-ecs");
10
10
  const client_rds_1 = require("@aws-sdk/client-rds");
11
11
  const client_ssm_1 = require("@aws-sdk/client-ssm");
12
12
  const readline_1 = __importDefault(require("readline"));
13
+ const promises_1 = __importDefault(require("node:readline/promises"));
13
14
  const child_process_1 = require("child_process");
14
15
  const constants_js_1 = require("../core/constants.js");
15
16
  let ec2;
@@ -29,6 +30,30 @@ function logTunnelCommands() {
29
30
  pay tunnel help # Describe tunnel command`);
30
31
  }
31
32
  exports.logTunnelCommands = logTunnelCommands;
33
+ async function readInputForReadOrWriteDBAccess() {
34
+ const rl = promises_1.default.createInterface({
35
+ input: process.stdin,
36
+ output: process.stdout
37
+ });
38
+ let answer = await rl.question('Do you require read-only access, or write-access to the database? [R/w]: ');
39
+ rl.close();
40
+ if (answer === undefined || answer === '') {
41
+ answer = 'R';
42
+ console.log('No option entered. Defaulting to read-only');
43
+ }
44
+ if (answer === 'R' || answer === 'r') {
45
+ printGreen('Database read-only access requested');
46
+ return 'read-only';
47
+ }
48
+ else if (answer === 'w') {
49
+ printGreen('Database write access requested');
50
+ return 'write';
51
+ }
52
+ else {
53
+ printError('Invalid option entered. Exiting..');
54
+ process.exit(1);
55
+ }
56
+ }
32
57
  async function tunnelHandler(options) {
33
58
  await (0, standardContent_js_1.showHeader)();
34
59
  const { environment, application } = parseArguments(options);
@@ -39,10 +64,11 @@ async function tunnelHandler(options) {
39
64
  let bastionTask = null;
40
65
  try {
41
66
  printWarningToUser();
67
+ const dbAccessType = await readInputForReadOrWriteDBAccess();
42
68
  const database = await getDatabaseDetails(environment, application);
43
69
  bastionTask = await startBastion(environment);
44
70
  openTunnel(bastionTask, database, environment);
45
- printHowToTunnelText(application, environment, database.EngineVersion);
71
+ await printHowToTunnelText(application, environment, database.EngineVersion, dbAccessType);
46
72
  await waitForExit();
47
73
  await shutdown(environment, bastionTask);
48
74
  }
@@ -345,10 +371,10 @@ async function terminateSession(task, environment) {
345
371
  }
346
372
  }
347
373
  }
348
- function printHowToTunnelText(application, environment, dbEngineVersion) {
349
- const dbUser = getDbUser(application);
350
- const payLowPassDbSecretName = getPayLowPassDbSecretname(environment, dbUser);
351
- const paySecretsPasswordName = getPaySecretsPasswordName();
374
+ async function printHowToTunnelText(application, environment, dbEngineVersion, dbAccessType) {
375
+ const dbUser = await getDbUser(environment, application, dbAccessType);
376
+ const payLowPassDbSecretName = getPayLowPassDbSecretName(environment, dbUser, dbAccessType);
377
+ const paySecretsPasswordName = getPaySecretsPasswordName(dbAccessType);
352
378
  printGreen(`\nConnected tunnel to ${application} RDS database in ${environment} on port 65432\n`);
353
379
  printGreen('Copy DB credentials to clipboard (in another window) using pay-low-pass:');
354
380
  printGreen(` pay-low-pass ${payLowPassDbSecretName} | pbcopy`);
@@ -361,15 +387,42 @@ function printHowToTunnelText(application, environment, dbEngineVersion) {
361
387
  printGreen('Or even more conveniently connect using a docker container and set the password automatically using pay-low-pass:');
362
388
  printGreen(` docker run -e "PGPASSWORD=$(pay-low-pass ${payLowPassDbSecretName})" --rm -ti postgres:${dbEngineVersion}-alpine psql --host docker.for.mac.localhost --port 65432 --user ${dbUser} --dbname ${application}\n`);
363
389
  }
364
- // TODO: add a write flag. Default to readonly.
365
- function getDbUser(application) {
366
- return `${application}_support_readonly`;
390
+ async function getDbUser(environment, application, dbAccessType) {
391
+ let paramName;
392
+ if (dbAccessType === 'write') {
393
+ paramName = `${environment}_${application}.db_user`;
394
+ }
395
+ else {
396
+ paramName = `${environment}_${application}.db_support_user_readonly`;
397
+ }
398
+ const ssmClient = new client_ssm_1.SSMClient();
399
+ const input = { Names: [paramName], WithDecryption: true };
400
+ const command = new client_ssm_1.GetParametersCommand(input);
401
+ const response = await ssmClient.send(command);
402
+ if (response?.Parameters?.length !== undefined && response?.Parameters?.length > 0 &&
403
+ response?.Parameters[0]?.Value !== undefined) {
404
+ return response.Parameters[0].Value;
405
+ }
406
+ else {
407
+ printError('Unable to get database username from Parameter Store');
408
+ return '';
409
+ }
367
410
  }
368
- function getPayLowPassDbSecretname(environment, user) {
369
- return `aws/rds/support_readonly_users/${environment.split('-')[0]}/${user}`;
411
+ function getPayLowPassDbSecretName(environment, user, dbAccessType) {
412
+ if (dbAccessType === 'write') {
413
+ return `aws/rds/application_users/${environment.split('-')[0]}/${user}`;
414
+ }
415
+ else {
416
+ return `aws/rds/support_readonly_users/${environment.split('-')[0]}/${user}`;
417
+ }
370
418
  }
371
- function getPaySecretsPasswordName() {
372
- return 'DB_SUPPORT_PASSWORD_READONLY';
419
+ function getPaySecretsPasswordName(dbAccessType) {
420
+ if (dbAccessType === 'write') {
421
+ return 'DB_PASSWORD';
422
+ }
423
+ else {
424
+ return 'DB_SUPPORT_PASSWORD_READONLY';
425
+ }
373
426
  }
374
427
  function printWarningToUser() {
375
428
  console.log(FORMAT.yellow, '⚠️ WARNING: When using SSM, any and all activity you perform may be getting logged for security auditing purposes (think PCI).', FORMAT.reset);