@govuk-pay/cli 0.0.27 → 0.0.29

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.29",
4
4
  "description": "GOV.UK Pay Command Line Interface",
5
5
  "bin": {
6
6
  "pay": "bin/cli.js",
@@ -65,6 +65,7 @@ pay-low-pass:
65
65
  master_db_password: aws/rds/superuser/deploy-tooling/pact-broker/password # pragma: allowlist secret
66
66
  db_user: aws/rds/application_users/deploy/pact_broker_db_username
67
67
  db_password: aws/rds/application_users/deploy/pact_broker_db_password # pragma: allowlist secret
68
+ DB_SUPPORT_PASSWORD_READONLY: aws/rds/support_readonly_users/deploy/pact_broker_support_readonly # pragma: allowlist secret
68
69
  stubs:
69
70
  smartpay-expected-password: pay-stubs/smartpay/expected-password
70
71
  smartpay-expected-user: pay-stubs/smartpay/expected-user
@@ -498,6 +499,9 @@ value:
498
499
  LEDGER_RDS_PASSWORD: "/" # pragma: allowlist secret
499
500
  PRODUCTS_RDS_PASSWORD: "/" # pragma: allowlist secret
500
501
  PUBLICAUTH_RDS_PASSWORD: "/" # pragma: allowlist secret
502
+ deploy-tooling:
503
+ pact-broker:
504
+ DB_SUPPORT_USER_READONLY: "pact_broker_support_readonly"
501
505
  test-12:
502
506
  adminusers:
503
507
  DB_USER: "adminusers1"
@@ -41,6 +41,8 @@ pact-broker:
41
41
  - master_db_password
42
42
  - db_user
43
43
  - db_password
44
+ - DB_SUPPORT_USER_READONLY
45
+ - DB_SUPPORT_PASSWORD_READONLY
44
46
  pact-broker-auth:
45
47
  - pact-broker-basic-auth-password
46
48
  - pact-broker-basic-auth-username
@@ -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);