@govuk-pay/cli 0.0.53 → 0.0.55

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.53",
3
+ "version": "0.0.55",
4
4
  "description": "GOV.UK Pay Command Line Interface",
5
5
  "bin": {
6
6
  "pay": "bin/cli.js",
package/readme.md CHANGED
@@ -23,9 +23,10 @@ once it's installed you can run it using `pay [arguments]` or `payx [arguments]`
23
23
  If you'd rather not install it globally you can run it using `npx @govuk-pay/cli`.
24
24
 
25
25
  We're in the process of porting the existing Ruby CLI into typescript, we've tried to make that process
26
- transparent to the users of the CLI. Most of the commands rely on the existing ruby implementation therefore
27
- you'll need `rbenv` installed with `bundler` installed into it. When handing over to ruby we use `zsh` by default,
28
- if you want a different shell or `rbenv` you can set the following environment variables:
26
+ transparent to the users of the CLI. None of the commands now rely on the ruby implementation, but you can
27
+ (for now) still execute the ruby versions by using `pay legacy`. You'll need `rbenv` installed with `bundler
28
+ installed into it. When handing over to ruby we use `zsh` by default, if you want a different shell or `rbenv`
29
+ you can set the following environment variables:
29
30
 
30
31
  - `PAY_CLI_RBENV_COMMAND` - defaults to `rbenv`
31
32
  - `PAY_CLI_SHELL_COMMAND` - defaults to `zsh`
@@ -144,11 +144,13 @@ selfservice:
144
144
  type: node
145
145
  proxy: true
146
146
  naxsi: true
147
+ is_bundled: true
147
148
  db: false
148
149
  port: 9400
149
150
  debug_port: 9401
150
151
  healthcheck: true
151
152
  proxy_port: 39000
153
+ entrypoint_override_local: 'sh -c "npm ci && npm run dev"'
152
154
  clusters:
153
155
  - admin
154
156
  - endtoend
@@ -138,7 +138,11 @@ services:
138
138
  test: ["CMD", "wget", "-Y", "off", "-O", "/dev/null", "http://{{name}}:{{port}}/healthcheck"]
139
139
  interval: 10s
140
140
  timeout: 5s
141
+ {{#ifBoth isBundled localBuild}}
142
+ retries: 20
143
+ {{else}}
141
144
  retries: 12
145
+ {{/ifBoth}}
142
146
  env_file:
143
147
  - {{../defaultServiceConfigsPath}}/services/{{name}}.env
144
148
  {{#ifFileExists environmentOverrideFilePath}}
@@ -147,9 +151,12 @@ services:
147
151
  {{#ifBoth ../mountLocalNodeApps localBuild}}
148
152
  volumes:
149
153
  - "$WORKSPACE/pay-{{../name}}:/app"
150
- {{#if ../../mountPayJSCommons}}
154
+ {{#if ../isBundled}}
155
+ - {{../name}}_node_modules:/app/node_modules
156
+ {{/if}}
157
+ {{#if ../../mountPayJSCommons}}
151
158
  - "$WORKSPACE/pay-js-commons:/pay-js-commons"
152
- {{/if}}
159
+ {{/if}}
153
160
  {{/ifBoth}}
154
161
  environment:
155
162
  - BIND_HOST=0.0.0.0
@@ -281,5 +288,10 @@ networks:
281
288
 
282
289
  volumes:
283
290
  {{#each dbServices}}
284
- {{name}}:
291
+ {{name}}:
292
+ {{/each}}
293
+ {{#each nodeApps}}
294
+ {{#if isBundled}}
295
+ {{name}}_node_modules:
296
+ {{/if}}
285
297
  {{/each}}
@@ -180,7 +180,8 @@ function payServiceFromPayServiceConfig(config, upOptions, environmentOverridesP
180
180
  imageTag: localBuild ? 'local' : 'latest-master',
181
181
  requiresLocalStack: sqsQueues.length > 0 || snsTopics.length > 0,
182
182
  entrypointOverrideLocal: config.entrypoint_override_local,
183
- environmentOverrideFilePath: node_path_1.default.join(environmentOverridesPath, `${config.name}.env`)
183
+ environmentOverrideFilePath: node_path_1.default.join(environmentOverridesPath, `${config.name}.env`),
184
+ isBundled: config.is_bundled
184
185
  };
185
186
  }
186
187
  function dbServiceFromPayServiceConfig(config) {
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SERVICE_NAMES = exports.ENVIRONMENT_NAMES = exports.SECRET_SOURCES = void 0;
4
- exports.SECRET_SOURCES = ['ssm', 'pay-low-pass', 'value'];
4
+ exports.SECRET_SOURCES = [
5
+ 'bitwarden-cli',
6
+ 'pay-low-pass',
7
+ 'ssm',
8
+ 'value'
9
+ ];
5
10
  exports.ENVIRONMENT_NAMES = [
6
11
  'deploy',
7
12
  'deploy-7',
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BITWARDEN_CLI_CONFIG = void 0;
4
+ exports.BITWARDEN_CLI_CONFIG = {};
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSecretConfig = exports.configuredSecretsForServiceInEnv = exports.SECRET_SOURCE_PRECEDENCE = exports.SECRETS = void 0;
4
+ const bitwarden_cli_1 = require("./secrets/bitwarden_cli");
4
5
  const pay_low_pass_1 = require("./secrets/pay_low_pass");
5
6
  const config_types_1 = require("./config.types");
6
7
  const service_secrets_1 = require("./service_secrets");
7
8
  const ssm_1 = require("./secrets/ssm");
8
9
  const value_1 = require("./secrets/value");
9
10
  exports.SECRETS = {
11
+ 'bitwarden-cli': bitwarden_cli_1.BITWARDEN_CLI_CONFIG,
10
12
  ssm: ssm_1.SSM_CONFIG,
11
13
  'pay-low-pass': pay_low_pass_1.PAY_LOW_PASS_CONFIG,
12
14
  value: value_1.VALUE_CONFIG
@@ -17,6 +19,7 @@ exports.SECRETS = {
17
19
  */
18
20
  exports.SECRET_SOURCE_PRECEDENCE = [
19
21
  'value',
22
+ 'bitwarden-cli',
20
23
  'pay-low-pass',
21
24
  'ssm'
22
25
  ];
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BitwardenCLIProvider = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const providers_types_1 = require("./providers.types");
6
+ class BitwardenCLIProvider extends providers_types_1.AbstractSecretProvider {
7
+ bitwardenUnlockToken;
8
+ constructor(env, secretSource) {
9
+ super(env, secretSource);
10
+ this.bitwardenUnlockToken = checkBitwardenStatus();
11
+ }
12
+ async get(secretConfig) {
13
+ const env = {
14
+ ...process.env
15
+ };
16
+ if (this.bitwardenUnlockToken !== undefined) {
17
+ env.BW_SESSION = this.bitwardenUnlockToken;
18
+ }
19
+ const bwGetPasswordResult = (0, child_process_1.spawnSync)('bw', ['get', 'password', secretConfig.secretSourceValue], {
20
+ env
21
+ });
22
+ if (bwGetPasswordResult.status !== 0) {
23
+ if (bwGetPasswordResult.stderr.toString().includes('Not found.')) {
24
+ console.error(`Secret ${secretConfig.secretSourceValue} not found in bitwarden. This can either be because it doesn't exist, or you don't have access`);
25
+ return undefined;
26
+ }
27
+ console.error('Unknown error when trying to get the password from bitwarden, output from the get follows:');
28
+ console.error(bwGetPasswordResult.output.toString());
29
+ process.exit(1);
30
+ }
31
+ return bwGetPasswordResult.stdout.toString();
32
+ }
33
+ }
34
+ exports.BitwardenCLIProvider = BitwardenCLIProvider;
35
+ function checkBitwardenStatus() {
36
+ const bwAvailableResult = (0, child_process_1.spawnSync)('command', ['-v', 'bw'], { shell: true });
37
+ if (bwAvailableResult.status !== 0) {
38
+ console.error('You need to install the bitwarden CLI before you can source secrets from it: `brew install bitwarden-cli`');
39
+ process.exit(1);
40
+ }
41
+ const bwStatusResult = (0, child_process_1.spawnSync)('bw', ['status']);
42
+ if (bwStatusResult.status !== 0) {
43
+ console.error('Could not check the login status of the bitwarden cli with command `bw status`. Output from the command follows:');
44
+ console.error(bwStatusResult.output.toString());
45
+ process.exit(1);
46
+ }
47
+ let bwStatusJson;
48
+ try {
49
+ bwStatusJson = JSON.parse(bwStatusResult.stdout.toString());
50
+ }
51
+ catch (e) {
52
+ console.error('An error occured when trying to parse the JSON output of `bw status`. The output of that command follows:');
53
+ console.error(bwStatusResult.output.toString());
54
+ process.exit(1);
55
+ }
56
+ if (!('status' in bwStatusJson)) {
57
+ console.error('The JSON output of `bw status` did not contain a \'status\' key. The output of that command follows:');
58
+ console.error(bwStatusResult.output.toString());
59
+ process.exit(1);
60
+ }
61
+ if (bwStatusJson.status === 'unauthenticated') {
62
+ console.error('Error: You are not authenticated in the bitwarden cli, you need to run `bw login` and login');
63
+ process.exit(1);
64
+ }
65
+ else if (bwStatusJson.status === 'locked') {
66
+ console.warn('Your bitwarden cli is logged in, but locked. Executing `bw unlock`, please enter your master password when prompted');
67
+ return unlockBitWarden();
68
+ }
69
+ else if (bwStatusJson.status === 'unlocked') {
70
+ return undefined;
71
+ }
72
+ }
73
+ function unlockBitWarden() {
74
+ const bwUnlockResult = (0, child_process_1.spawnSync)('bw', ['unlock'], {
75
+ shell: true,
76
+ stdio: ['inherit', 'pipe', 'inherit']
77
+ });
78
+ if (bwUnlockResult.status !== 0) {
79
+ console.error('Failed to unlock your bitwarden vault.');
80
+ process.exit(1);
81
+ }
82
+ const lineWithToken = bwUnlockResult.stdout.toString().split('\n').find((line) => {
83
+ return line.startsWith('$ export BW_SESSION=');
84
+ });
85
+ if (lineWithToken === undefined) {
86
+ console.error('Could not find the BW_SESSION token in the `bw unlock` output. Looking for a line that starts with `$ export BW_SESSION=`. Got:');
87
+ console.error(bwUnlockResult.output.toString());
88
+ process.exit(1);
89
+ }
90
+ const sessionToken = lineWithToken.substring(lineWithToken.indexOf('"') + 1, lineWithToken.lastIndexOf('"'));
91
+ if (sessionToken.length === 0 || sessionToken.startsWith('$ export BW_SESSION=') || sessionToken.includes('"')) {
92
+ console.error('The session token we read from `bw unlock` does not look correct. Output from the command follows');
93
+ console.error(bwUnlockResult.output.toString());
94
+ process.exit(1);
95
+ }
96
+ console.warn('Bitwarden unlocked');
97
+ return sessionToken;
98
+ }
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.providerFor = void 0;
4
+ const bitwarden_cli_1 = require("./bitwarden_cli");
4
5
  const pass_repo_1 = require("./pass_repo");
5
6
  const ssm_1 = require("./ssm");
6
7
  const value_1 = require("./value");
7
8
  const providers = {
8
- ssm: {},
9
+ 'bitwarden-cli': {},
9
10
  'pay-low-pass': {},
11
+ ssm: {},
10
12
  value: {}
11
13
  };
12
14
  function providerFor(secretConfig) {
@@ -25,6 +27,10 @@ function providerFor(secretConfig) {
25
27
  memoisedProvider = new ssm_1.SSMProvider(secretConfig.environment, secretConfig.source);
26
28
  break;
27
29
  }
30
+ case 'bitwarden-cli': {
31
+ memoisedProvider = new bitwarden_cli_1.BitwardenCLIProvider(secretConfig.environment, secretConfig.source);
32
+ break;
33
+ }
28
34
  }
29
35
  providers[secretConfig.source][secretConfig.environment] = memoisedProvider;
30
36
  }