@govuk-pay/cli 0.0.37 → 0.0.39

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.37",
3
+ "version": "0.0.39",
4
4
  "description": "GOV.UK Pay Command Line Interface",
5
5
  "bin": {
6
6
  "pay": "bin/cli.js",
@@ -30,7 +30,6 @@ const builder = (yargs) => {
30
30
  exports.builder = builder;
31
31
  exports.handler = browseHandler;
32
32
  async function browseHandler(argv) {
33
- console.log(argv);
34
33
  await (0, standardContent_js_1.showHeader)();
35
34
  const location = argv.location;
36
35
  const requestedItem = requestableItems.get(location);
@@ -7,12 +7,12 @@ exports.handler = exports.builder = exports.desc = exports.command = void 0;
7
7
  const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
8
8
  const standardContent_1 = require("../../../core/standardContent");
9
9
  exports.command = 'account';
10
- exports.desc = 'Create a local gateway account';
10
+ exports.desc = 'Create a local gateway account, and optionally a new service';
11
11
  const builder = (yargs) => {
12
12
  return yargs.usage(`$0 local account [--service-id <SERVICE_ID>]\n\n${exports.desc}`)
13
13
  .option('service-id', {
14
14
  type: 'string',
15
- description: 'ID of an existing service'
15
+ description: 'External ID of an existing service, if not provided a new service will be created'
16
16
  });
17
17
  };
18
18
  exports.builder = builder;
@@ -9,18 +9,18 @@ const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
9
9
  const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
10
10
  const standardContent_1 = require("../../../core/standardContent");
11
11
  exports.command = 'browse <service>';
12
- exports.desc = 'Browse to local service';
12
+ exports.desc = 'Open a local service in your web browser';
13
13
  const builder = (yargs) => {
14
14
  return yargs
15
15
  .usage(`$0 local browse <service> [--proxy]\n\n${exports.desc}`)
16
16
  .positional('service', {
17
17
  type: 'string',
18
- description: 'service'
18
+ description: 'Name of the service to open in your browser'
19
19
  })
20
20
  .option('proxy', {
21
21
  type: 'boolean',
22
22
  default: false,
23
- description: 'Opens the service via the local proxy for the service'
23
+ description: 'Opens the service via the reverse proxy for the service'
24
24
  });
25
25
  };
26
26
  exports.builder = builder;
@@ -4,14 +4,16 @@ exports.handler = exports.builder = exports.desc = exports.command = void 0;
4
4
  const node_child_process_1 = require("node:child_process");
5
5
  const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
6
6
  const standardContent_1 = require("../../../core/standardContent");
7
+ const servicesConfig = (0, pay_local_cluster_js_1.loadServicesConfig)();
7
8
  exports.command = 'db <app_name>';
8
- exports.desc = 'Connect to <app_name> database';
9
+ exports.desc = 'Open psql connected to <app_name> database';
9
10
  const builder = (yargs) => {
10
11
  return yargs
11
12
  .usage(`$0 local db <app_name> [--docker]\n\n${exports.desc}`)
12
13
  .positional('app_name', {
13
14
  type: 'string',
14
- description: 'service'
15
+ choices: Object.values(servicesConfig).filter(service => service.db).map(service => service.name).sort(),
16
+ description: 'The name of the app whose database you wish to connect to'
15
17
  })
16
18
  .option('docker', {
17
19
  type: 'boolean',
@@ -25,7 +27,6 @@ async function dbHandler(argv) {
25
27
  await (0, standardContent_1.showHeader)();
26
28
  const service = argv.app_name;
27
29
  const docker = argv.docker;
28
- const servicesConfig = (0, pay_local_cluster_js_1.loadServicesConfig)();
29
30
  if (!(service in servicesConfig)) {
30
31
  console.error(`The service specified (${service}) was not defined in the service_config.yaml file`);
31
32
  return;
@@ -15,13 +15,13 @@ exports.DOCKER_COMPOSE_RENDERED_TEMPALTES_PATH = node_path_1.default.join('local
15
15
  exports.DOCKER_COMPOSE_SERVICES_CONFIG_PATH = node_path_1.default.join('local', 'docker-compose', 'default-configs-DO-NOT-EDIT');
16
16
  exports.ENVIRONMENT_OVERRIDES_PATH = node_path_1.default.join('local', 'environment-overrides');
17
17
  exports.command = 'down';
18
- exports.desc = 'Bring down a cluster';
18
+ exports.desc = 'Shut down the local cluster';
19
19
  const builder = (yargs) => {
20
20
  return yargs
21
21
  .usage(`$0 local down [--cluster <cluster>]\n\n${exports.desc}`)
22
22
  .option('cluster', {
23
23
  type: 'string',
24
- description: 'Cluster to bring down',
24
+ description: 'Cluster to bring down, if not specified it will be the last cluster that was launched',
25
25
  choices: pay_local_cluster_js_1.CLUSTERS
26
26
  });
27
27
  };
@@ -12,7 +12,7 @@ exports.DOCKER_COMPOSE_RENDERED_TEMPALTES_PATH = node_path_1.default.join('local
12
12
  exports.DOCKER_COMPOSE_SERVICES_CONFIG_PATH = node_path_1.default.join('local', 'docker-compose', 'default-configs-DO-NOT-EDIT');
13
13
  exports.ENVIRONMENT_OVERRIDES_PATH = node_path_1.default.join('local', 'environment-overrides');
14
14
  exports.command = 'nuke';
15
- exports.desc = 'Kill and completely destroy all containers previously started by pay local';
15
+ exports.desc = 'Kill and completely destroy all containers that can be launched by pay local';
16
16
  exports.handler = nukeHandler;
17
17
  async function nukeHandler(argv) {
18
18
  await (0, standardContent_1.showHeader)();
@@ -5,11 +5,11 @@ const node_child_process_1 = require("node:child_process");
5
5
  const totp_generator_1 = require("totp-generator");
6
6
  const standardContent_1 = require("../../../core/standardContent");
7
7
  exports.command = 'otp <key>';
8
- exports.desc = 'Create otp code';
8
+ exports.desc = 'Generate an otp code';
9
9
  const builder = (yargs) => {
10
10
  return yargs.positional('key', {
11
11
  type: 'string',
12
- description: 'otp key'
12
+ description: 'TOTP secret key for which to generated a code'
13
13
  });
14
14
  };
15
15
  exports.builder = builder;
@@ -14,7 +14,7 @@ const builder = (yargs) => {
14
14
  .usage(`$0 local payment [--api-key <api-key>] [--email-collection-mode <email-collection-mode>]\n\n${exports.desc}`)
15
15
  .option('api-key', {
16
16
  type: 'string',
17
- description: 'API Key'
17
+ description: 'API Key to use to create the payment. If not set a new service and gateway account will also be created'
18
18
  }).option('email-collection-mode', {
19
19
  type: 'string',
20
20
  default: 'MANDATORY',
@@ -8,14 +8,14 @@ const node_child_process_1 = __importDefault(require("node:child_process"));
8
8
  const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
9
9
  const standardContent_1 = require("../../../core/standardContent");
10
10
  exports.command = 'paymentlink';
11
- exports.desc = 'Create a payment link';
11
+ exports.desc = 'Create a payment link in gateway account id 1';
12
12
  const builder = (yargs) => {
13
13
  return yargs
14
14
  .usage(`$0 local paymentlink --api-key <api-key>\n\n${exports.desc}`)
15
15
  .option('api-key', {
16
16
  demandOption: true,
17
17
  type: 'string',
18
- description: 'API Key'
18
+ description: 'API Key for the payment link to use to create payments'
19
19
  });
20
20
  };
21
21
  exports.builder = builder;
@@ -11,13 +11,13 @@ const docker_compose_controller_js_1 = __importDefault(require("../docker_compos
11
11
  const standardContent_1 = require("../../../core/standardContent");
12
12
  exports.DOCKER_COMPOSE_RENDERED_TEMPLATES_PATH = node_path_1.default.join('local', 'docker-compose', 'rendered-templates');
13
13
  exports.command = 'restart <app>';
14
- exports.desc = 'Restart a container and waits for it to be healthy';
14
+ exports.desc = 'Restart a container and wait for it to be healthy';
15
15
  const builder = (yargs) => {
16
16
  return yargs
17
17
  .usage(`$0 local restart <app>\n\n${exports.desc}`)
18
18
  .positional('app', {
19
19
  type: 'string',
20
- description: 'App to restart'
20
+ description: 'Container to restart'
21
21
  });
22
22
  };
23
23
  exports.builder = builder;
@@ -8,13 +8,13 @@ const node_child_process_1 = require("node:child_process");
8
8
  const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
9
9
  const standardContent_1 = require("../../../core/standardContent");
10
10
  exports.command = 'token';
11
- exports.desc = 'Create a token';
11
+ exports.desc = 'Create an API token';
12
12
  const builder = (yargs) => {
13
13
  return yargs
14
14
  .usage(`$0 local token [--gateway-account-id <gateway-account-id>]\n\n${exports.desc}`)
15
15
  .option('gateway-account-id', {
16
16
  type: 'string',
17
- description: 'ID of the gateway account'
17
+ description: 'ID of the gateway account, if not specified a service and gateway account will also be created'
18
18
  });
19
19
  };
20
20
  exports.builder = builder;
@@ -24,42 +24,42 @@ const builder = (yargs) => {
24
24
  type: 'string',
25
25
  choices: pay_local_cluster_js_1.CLUSTERS,
26
26
  default: 'all',
27
- description: 'cluster'
27
+ description: 'Cluster of services to launch'
28
28
  })
29
29
  .option('apps', {
30
30
  type: 'array',
31
31
  default: [],
32
- description: ''
32
+ description: 'Launch only these listed apps within the specified cluster'
33
33
  })
34
34
  .option('local', {
35
35
  type: 'array',
36
36
  default: [],
37
- description: ''
37
+ description: 'Use local versions of the docker images from the checkouts in your WORKSPACE'
38
38
  })
39
39
  .option('proxy', {
40
40
  type: 'boolean',
41
41
  default: false,
42
- description: ''
42
+ description: 'Launch reverse proxies with naxsi configured in front of the public-facing apps'
43
43
  })
44
44
  .option('with-egress-proxy', {
45
45
  type: 'boolean',
46
46
  default: false,
47
- description: ''
47
+ description: 'Launch the cluster with the egress proxy and configure connector and frontend to use it'
48
48
  })
49
49
  .option('rebuild', {
50
50
  type: 'boolean',
51
51
  default: true,
52
- description: ''
52
+ description: 'When running with --local, force the local containers to be rebuilt from your WORKSPACE'
53
53
  })
54
54
  .option('pull', {
55
55
  type: 'boolean',
56
56
  default: true,
57
- description: ''
57
+ description: 'Pull the latest versions of all containers prior to launching the cluster'
58
58
  })
59
59
  .option('mount-local-node-apps', {
60
60
  type: 'boolean',
61
61
  default: false,
62
- description: ''
62
+ description: 'Mount your local project directory (in WORKSPACE/pay-<app>) into the running node container'
63
63
  })
64
64
  .option('mount-pay-js-commons', {
65
65
  type: 'boolean',
@@ -13,11 +13,11 @@ exports.desc = 'Copy base URL of local service to clipboard';
13
13
  const builder = (yargs) => {
14
14
  return yargs.positional('service', {
15
15
  type: 'string',
16
- description: 'service'
16
+ description: 'The service you wish to generate the URL of'
17
17
  }).option('proxy', {
18
18
  type: 'boolean',
19
19
  default: false,
20
- description: 'Something about proxy'
20
+ description: 'Generate the url for the reverse proxy of the <service> specified'
21
21
  });
22
22
  };
23
23
  exports.builder = builder;
@@ -9,14 +9,14 @@ const totp_generator_1 = require("totp-generator");
9
9
  const node_child_process_1 = require("node:child_process");
10
10
  const standardContent_1 = require("../../../core/standardContent");
11
11
  exports.command = 'user';
12
- exports.desc = 'Create a local user';
12
+ exports.desc = 'Create a selfservice user with a new service and gateway account';
13
13
  const builder = (yargs) => {
14
14
  return yargs
15
15
  .usage(`$0 local user [--create-payments]\n\n${exports.desc}`)
16
16
  .option('create-payments', {
17
17
  type: 'boolean',
18
- default: false,
19
- description: 'Create payments'
18
+ default: true,
19
+ description: 'Create 10 payments in the gateway account'
20
20
  });
21
21
  };
22
22
  exports.builder = builder;
@@ -48,7 +48,7 @@ async function userHandler(argv) {
48
48
  console.error('Failed to create an API token');
49
49
  return;
50
50
  }
51
- if (createPayments !== undefined && createPayments) {
51
+ if (createPayments) {
52
52
  console.warn('💸 Creating 10 payments in card sandbox gateway account (each . is a success, each ! is a failure)');
53
53
  let createPaymentResult;
54
54
  for (let i = 0; i < 10; i++) {
@@ -60,6 +60,7 @@ async function userHandler(argv) {
60
60
  process.stderr.write('.');
61
61
  }
62
62
  }
63
+ console.warn('');
63
64
  }
64
65
  console.warn('🤓 Creating admin user for service');
65
66
  const user = await app_client_js_1.default.createUser([account.gateway_account_id], 'admin');
@@ -82,14 +83,18 @@ async function userHandler(argv) {
82
83
  console.log(`🎫 Card API token: ${apiToken}`);
83
84
  console.log();
84
85
  let selfserviceUrl;
86
+ copyToClipboard(user.email);
87
+ console.log(`📋 “${user.email}” copied to clipboard`);
85
88
  if (await app_client_js_1.default.isProxyHealthy('selfservice')) {
86
89
  selfserviceUrl = app_client_js_1.default.externalUrlFor('selfservice', '/', true);
87
90
  }
88
- else {
91
+ else if (await app_client_js_1.default.isHealthy('selfservice')) {
89
92
  selfserviceUrl = app_client_js_1.default.externalUrlFor('selfservice', '/', false);
90
93
  }
91
- copyToClipboard(user.email);
92
- console.log(`📋 “${user.email}” copied to clipboard`);
94
+ else {
95
+ console.error('The selfservice service is unhealthy, so it is not being opened in a web browser');
96
+ return;
97
+ }
93
98
  console.log(`🌎 Opening selfservice (${selfserviceUrl}) browser`);
94
99
  console.log();
95
100
  (0, node_child_process_1.spawn)('open', [selfserviceUrl]);
@@ -16,6 +16,7 @@ const constants_js_1 = require("../core/constants.js");
16
16
  let ec2;
17
17
  let ecs;
18
18
  let ssm;
19
+ let rds;
19
20
  const FORMAT = {
20
21
  red: '\x1b[31m',
21
22
  green: '\x1b[32m',
@@ -76,9 +77,10 @@ async function tunnelHandler(argv) {
76
77
  }
77
78
  }
78
79
  const warnTime = maximumDuration * 0.75;
79
- ec2 = new client_ec2_1.EC2Client();
80
- ecs = new client_ecs_1.ECSClient();
81
- ssm = new client_ssm_1.SSMClient();
80
+ ec2 = new client_ec2_1.EC2Client({ region: 'eu-west-1' });
81
+ ecs = new client_ecs_1.ECSClient({ region: 'eu-west-1' });
82
+ ssm = new client_ssm_1.SSMClient({ region: 'eu-west-1' });
83
+ rds = new client_rds_1.RDSClient({ region: 'eu-west-1' });
82
84
  let bastionTask = null;
83
85
  try {
84
86
  printWarningToUser();
@@ -295,7 +297,6 @@ async function stopBastion(task, environment) {
295
297
  }
296
298
  async function getDatabaseDetails(environment, application) {
297
299
  const describeDbCommand = new client_rds_1.DescribeDBInstancesCommand({});
298
- const rds = new client_rds_1.RDSClient();
299
300
  const describeDbCommandResponse = await rds.send(describeDbCommand);
300
301
  if (describeDbCommandResponse.DBInstances == null || describeDbCommandResponse.DBInstances.length < 1) {
301
302
  throw new Error(`Failed to find the database for ${application} in ${environment}`);
@@ -420,10 +421,9 @@ async function getDbUser(environment, application, dbAccessType) {
420
421
  else {
421
422
  paramName = `${environment}_${application}.db_support_user_readonly`;
422
423
  }
423
- const ssmClient = new client_ssm_1.SSMClient();
424
424
  const input = { Names: [paramName], WithDecryption: true };
425
425
  const command = new client_ssm_1.GetParametersCommand(input);
426
- const response = await ssmClient.send(command);
426
+ const response = await ssm.send(command);
427
427
  if (response?.Parameters?.length !== undefined && response?.Parameters?.length > 0 &&
428
428
  response?.Parameters[0]?.Value !== undefined) {
429
429
  return response.Parameters[0].Value;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handler = exports.desc = exports.command = void 0;
4
+ const standardContent_js_1 = require("../core/standardContent.js");
5
+ const node_child_process_1 = require("node:child_process");
6
+ const commandRouter_js_1 = require("../core/commandRouter.js");
7
+ exports.command = 'update';
8
+ exports.desc = 'Update the pay cli by running `npm install -g @govuk-pay/cli` on your behalf';
9
+ exports.handler = updateHandler;
10
+ async function updateHandler(_argv) {
11
+ await (0, standardContent_js_1.showHeader)();
12
+ if (await (0, commandRouter_js_1.isLatestVersion)()) {
13
+ console.error('Pay cli is already the latest version available in npm');
14
+ return;
15
+ }
16
+ console.log('Running `npm install -g @govuk-pay/cli');
17
+ (0, node_child_process_1.spawnSync)('npm', ['install', '-g', '@govuk-pay/cli'], { shell: true, stdio: 'inherit' });
18
+ }
19
+ exports.default = updateHandler;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.isLatestVersion = void 0;
6
7
  const package_json_1 = __importDefault(require("../../package.json"));
7
8
  const semver_1 = __importDefault(require("semver"));
8
9
  const yargs_1 = __importDefault(require("yargs/yargs"));
@@ -22,16 +23,24 @@ async function runCommand() {
22
23
  exports.default = runCommand;
23
24
  async function checkVersion() {
24
25
  try {
25
- const { version: currentVersion, engines: { node: requiredNodeVersion } } = package_json_1.default;
26
+ const { engines: { node: requiredNodeVersion } } = package_json_1.default;
26
27
  if (!semver_1.default.satisfies(process.version, requiredNodeVersion)) {
27
28
  console.log(`Required Node.js version is ${requiredNodeVersion}, you are running ${process.version}. Please upgrade before continuing.`);
28
29
  }
29
- const { version: remoteVersion } = await fetch('https://registry.npmjs.org/@govuk-pay/cli/latest')
30
- .then(async (r) => await r.json());
31
- if (currentVersion !== remoteVersion) {
32
- console.log(`You are running pay-cli version ${currentVersion}, the latest version is ${remoteVersion}.`);
33
- console.log('Run `npm install -g @govuk-pay/cli` to upgrade.');
30
+ if (!await isLatestVersion()) {
31
+ console.log('Run `pay update` or `npm install -g @govuk-pay/cli` to upgrade.');
34
32
  }
35
33
  }
36
34
  catch { }
37
35
  }
36
+ async function isLatestVersion() {
37
+ const { version: currentVersion } = package_json_1.default;
38
+ const { version: remoteVersion } = await fetch('https://registry.npmjs.org/@govuk-pay/cli/latest')
39
+ .then(async (r) => await r.json());
40
+ if (currentVersion !== remoteVersion) {
41
+ console.log(`You are running pay-cli version ${currentVersion}, the latest version is ${remoteVersion}.`);
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ exports.isLatestVersion = isLatestVersion;