@govuk-pay/cli 0.0.43 → 0.0.45
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 +1 -1
- package/src/commands/local/subcommands/db.js +13 -7
- package/src/commands/secrets/subcommands/audit.js +30 -0
- package/src/commands/secrets/subcommands/copy.js +35 -0
- package/src/commands/secrets/subcommands/fetch.js +47 -0
- package/src/commands/secrets/subcommands/provision.js +30 -0
- package/src/commands/secrets/utils/preflight.js +47 -0
- package/src/commands/secrets.js +11 -0
package/package.json
CHANGED
|
@@ -19,6 +19,11 @@ const builder = (yargs) => {
|
|
|
19
19
|
type: 'boolean',
|
|
20
20
|
default: false,
|
|
21
21
|
description: 'Launch psql inside the apps database container (no psql history)'
|
|
22
|
+
})
|
|
23
|
+
.option('superuser', {
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
default: false,
|
|
26
|
+
description: 'Connect to the database as the postgres superuser'
|
|
22
27
|
});
|
|
23
28
|
};
|
|
24
29
|
exports.builder = builder;
|
|
@@ -27,6 +32,7 @@ async function dbHandler(argv) {
|
|
|
27
32
|
await (0, standardContent_1.showHeader)();
|
|
28
33
|
const service = argv.app_name;
|
|
29
34
|
const docker = argv.docker;
|
|
35
|
+
const asSuperuser = argv.superuser;
|
|
30
36
|
if (!(service in servicesConfig)) {
|
|
31
37
|
console.error(`The service specified (${service}) was not defined in the service_config.yaml file`);
|
|
32
38
|
return;
|
|
@@ -37,14 +43,14 @@ async function dbHandler(argv) {
|
|
|
37
43
|
return;
|
|
38
44
|
}
|
|
39
45
|
if (docker) {
|
|
40
|
-
launchPsqlInDocker(serviceConfig);
|
|
46
|
+
launchPsqlInDocker(serviceConfig, asSuperuser);
|
|
41
47
|
}
|
|
42
48
|
else if (!psqlAvailable()) {
|
|
43
49
|
console.warn('PSQL installation not found locally.');
|
|
44
|
-
launchPsqlInDocker(serviceConfig);
|
|
50
|
+
launchPsqlInDocker(serviceConfig, asSuperuser);
|
|
45
51
|
}
|
|
46
52
|
else {
|
|
47
|
-
launchPsql(serviceConfig);
|
|
53
|
+
launchPsql(serviceConfig, asSuperuser);
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
exports.default = dbHandler;
|
|
@@ -55,7 +61,7 @@ function psqlAvailable() {
|
|
|
55
61
|
}
|
|
56
62
|
return false;
|
|
57
63
|
}
|
|
58
|
-
function launchPsqlInDocker(serviceConfig) {
|
|
64
|
+
function launchPsqlInDocker(serviceConfig, asSuperuser) {
|
|
59
65
|
console.log('Running psql in running app db container.');
|
|
60
66
|
console.log('Note: This means you wont have a psql history, and one will not survive restarts of pay local');
|
|
61
67
|
(0, node_child_process_1.spawn)('docker', [
|
|
@@ -66,18 +72,18 @@ function launchPsqlInDocker(serviceConfig) {
|
|
|
66
72
|
`${serviceConfig.name}_db`,
|
|
67
73
|
'psql',
|
|
68
74
|
'--host', `${serviceConfig.name}_db`,
|
|
69
|
-
'--user', serviceConfig.name,
|
|
75
|
+
'--user', asSuperuser ? 'postgres' : serviceConfig.name,
|
|
70
76
|
'--dbname', serviceConfig.name
|
|
71
77
|
], { stdio: 'inherit', shell: true });
|
|
72
78
|
}
|
|
73
|
-
function launchPsql(serviceConfig) {
|
|
79
|
+
function launchPsql(serviceConfig, asSuperuser) {
|
|
74
80
|
if (serviceConfig.db_port === undefined) {
|
|
75
81
|
throw new Error(`Service config for ${serviceConfig.name} is missing db_port specification`);
|
|
76
82
|
}
|
|
77
83
|
(0, node_child_process_1.spawn)('psql', [
|
|
78
84
|
'--host', '127.0.0.1',
|
|
79
85
|
'--port', `${serviceConfig.db_port}`,
|
|
80
|
-
'--user', serviceConfig.name,
|
|
86
|
+
'--user', asSuperuser ? 'postgres' : serviceConfig.name,
|
|
81
87
|
'--dbname', serviceConfig.name
|
|
82
88
|
], {
|
|
83
89
|
stdio: 'inherit',
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const preflight_js_1 = __importDefault(require("../utils/preflight.js"));
|
|
9
|
+
exports.command = 'audit <service> <env..>';
|
|
10
|
+
exports.desc = 'Audits secrets for <service> for the given <envs..>';
|
|
11
|
+
const builder = (yargs) => {
|
|
12
|
+
return yargs
|
|
13
|
+
.positional('service', {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The service (e.g. connector) to audit the secret for'
|
|
16
|
+
})
|
|
17
|
+
.positional('env', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The environment (e.g. test-12) to audit the secret for'
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.builder = builder;
|
|
23
|
+
exports.handler = auditHandler;
|
|
24
|
+
async function auditHandler(argv) {
|
|
25
|
+
const service = argv.service;
|
|
26
|
+
const envs = argv.env;
|
|
27
|
+
const preflightInfo = (0, preflight_js_1.default)();
|
|
28
|
+
(0, node_child_process_1.spawnSync)(preflightInfo.rbenvCommand, ['exec', 'bundle', 'exec', 'bin/pay', 'secrets', 'audit', service, ...envs], { shell: true, stdio: 'inherit', cwd: preflightInfo.pathToLegacyRubyCli });
|
|
29
|
+
}
|
|
30
|
+
exports.default = auditHandler;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const preflight_js_1 = __importDefault(require("../utils/preflight.js"));
|
|
9
|
+
exports.command = 'copy <service> <src_env> <dest_env>';
|
|
10
|
+
exports.desc = 'Copies secrets for <service> from <src_env> to <dest_env>';
|
|
11
|
+
const builder = (yargs) => {
|
|
12
|
+
return yargs
|
|
13
|
+
.positional('service', {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The service (e.g. connector) to copy the secrets for'
|
|
16
|
+
})
|
|
17
|
+
.positional('src_env', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The environment (e.g. test-12) to copy the secrets from'
|
|
20
|
+
})
|
|
21
|
+
.positional('dest_env', {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The environment (e.g. test-perf-1) to copy the secrets to'
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
exports.builder = builder;
|
|
27
|
+
exports.handler = copyHandler;
|
|
28
|
+
async function copyHandler(argv) {
|
|
29
|
+
const service = argv.service;
|
|
30
|
+
const srcEnv = argv.src_env;
|
|
31
|
+
const destEnv = argv.dest_env;
|
|
32
|
+
const preflightInfo = (0, preflight_js_1.default)();
|
|
33
|
+
(0, node_child_process_1.spawnSync)(preflightInfo.rbenvCommand, ['exec', 'bundle', 'exec', 'bin/pay', 'secrets', 'copy', service, srcEnv, destEnv], { shell: true, stdio: 'inherit', cwd: preflightInfo.pathToLegacyRubyCli });
|
|
34
|
+
}
|
|
35
|
+
exports.default = copyHandler;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const preflight_js_1 = __importDefault(require("../utils/preflight.js"));
|
|
9
|
+
exports.command = 'fetch <env> <service> <secret_name> [--use-ssm]';
|
|
10
|
+
exports.desc = 'Fetches a <named secret> for <service> for <env>, if use-ssm is set then get the secret from ssm';
|
|
11
|
+
const builder = (yargs) => {
|
|
12
|
+
return yargs
|
|
13
|
+
.positional('env', {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The environment (e.g. test-12) to fetch the secret for'
|
|
16
|
+
})
|
|
17
|
+
.positional('service', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The service (e.g. connector) to fetch the secret for'
|
|
20
|
+
})
|
|
21
|
+
.positional('secret_name', {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'The name of the secret to get'
|
|
24
|
+
})
|
|
25
|
+
.option('use-ssm', {
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
default: false,
|
|
28
|
+
description: 'Query SSM to get the value'
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
exports.builder = builder;
|
|
32
|
+
exports.handler = fetchHandler;
|
|
33
|
+
async function fetchHandler(argv) {
|
|
34
|
+
const service = argv.service;
|
|
35
|
+
const env = argv.env;
|
|
36
|
+
const secretName = argv.secret_name;
|
|
37
|
+
const useSSM = argv.useSsm;
|
|
38
|
+
const preflightInfo = (0, preflight_js_1.default)();
|
|
39
|
+
const rbenvArgs = ['exec', 'bundle', 'exec', 'bin/pay', 'secrets', 'fetch', env, service, secretName];
|
|
40
|
+
if (useSSM) {
|
|
41
|
+
rbenvArgs.push('--use-ssm');
|
|
42
|
+
}
|
|
43
|
+
(0, node_child_process_1.spawnSync)(preflightInfo.rbenvCommand, rbenvArgs, { shell: true, stdio: 'inherit', cwd: preflightInfo.pathToLegacyRubyCli });
|
|
44
|
+
// The fetch command doesn't output a newline which is really annoying, so add one
|
|
45
|
+
console.log();
|
|
46
|
+
}
|
|
47
|
+
exports.default = fetchHandler;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handler = exports.builder = exports.desc = exports.command = void 0;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const preflight_js_1 = __importDefault(require("../utils/preflight.js"));
|
|
9
|
+
exports.command = 'provision <service> <env>';
|
|
10
|
+
exports.desc = 'Provisions secrets from config for <service> in <env>';
|
|
11
|
+
const builder = (yargs) => {
|
|
12
|
+
return yargs
|
|
13
|
+
.positional('service', {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'The service (e.g. connector) to provision secrets for'
|
|
16
|
+
})
|
|
17
|
+
.positional('env', {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The environment (e.g. test-12) to provision the secrets in'
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
exports.builder = builder;
|
|
23
|
+
exports.handler = provisionHandler;
|
|
24
|
+
async function provisionHandler(argv) {
|
|
25
|
+
const service = argv.service;
|
|
26
|
+
const env = argv.env;
|
|
27
|
+
const preflightInfo = (0, preflight_js_1.default)();
|
|
28
|
+
(0, node_child_process_1.spawnSync)(preflightInfo.rbenvCommand, ['exec', 'bundle', 'exec', 'bin/pay', 'secrets', 'provision', service, env], { shell: true, stdio: 'inherit', cwd: preflightInfo.pathToLegacyRubyCli });
|
|
29
|
+
}
|
|
30
|
+
exports.default = provisionHandler;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_child_process_1 = require("node:child_process");
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const constants_1 = require("../../../core/constants");
|
|
9
|
+
function preflightCheck() {
|
|
10
|
+
const pathToLegacyRubyCli = node_path_1.default.join(constants_1.rootDir, 'resources', 'legacy-ruby-cli');
|
|
11
|
+
const rbenvCommand = process.env.PAY_CLI_RBENV_COMMAND ?? 'rbenv';
|
|
12
|
+
console.error('Checking for ruby dependencies prior to launch');
|
|
13
|
+
const whichRbenvResult = (0, node_child_process_1.spawnSync)('command', ['-v', rbenvCommand], { shell: true });
|
|
14
|
+
if (whichRbenvResult.status !== 0) {
|
|
15
|
+
console.error('You need rbenv installed before you can continue.');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
console.error(`Ruby version manager ${rbenvCommand} available`);
|
|
19
|
+
console.error('Checking for bundler');
|
|
20
|
+
const whichBundlerResult = (0, node_child_process_1.spawnSync)(rbenvCommand, ['exec', 'bundle', '--version'], { shell: true, cwd: pathToLegacyRubyCli });
|
|
21
|
+
if (whichBundlerResult.status !== 0) {
|
|
22
|
+
console.error('You need bundler installed and available to rbenv before you can continue. Installing it...');
|
|
23
|
+
const installBundlerResult = (0, node_child_process_1.spawnSync)(rbenvCommand, ['exec', 'gem', 'install', 'bundler'], { shell: true, stdio: 'inherit', cwd: pathToLegacyRubyCli });
|
|
24
|
+
if (installBundlerResult.status !== 0) {
|
|
25
|
+
console.error('Could not install bundler, cannot continue');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
console.error('Bundler available');
|
|
30
|
+
console.error('Checking for bundled dependencies');
|
|
31
|
+
const bundleCheckResult = (0, node_child_process_1.spawnSync)(rbenvCommand, ['exec', 'bundle', 'check'], { shell: true, cwd: pathToLegacyRubyCli });
|
|
32
|
+
if (bundleCheckResult.status !== 0) {
|
|
33
|
+
console.error('Not all bundler dependencies are installed, installing them now.');
|
|
34
|
+
const bundleInstallResult = (0, node_child_process_1.spawnSync)(rbenvCommand, ['exec', 'bundle', 'install'], { shell: true, stdio: 'inherit', cwd: pathToLegacyRubyCli });
|
|
35
|
+
if (bundleInstallResult.status !== 0) {
|
|
36
|
+
console.error('Failed to bundle install, cannot continue');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
console.error('Bundled dependencies installed and available');
|
|
41
|
+
console.error('All ruby dependencies satisfied, executing legacy ruby cli');
|
|
42
|
+
return {
|
|
43
|
+
rbenvCommand,
|
|
44
|
+
pathToLegacyRubyCli
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
exports.default = preflightCheck;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.builder = exports.desc = exports.command = void 0;
|
|
4
|
+
exports.command = 'secrets';
|
|
5
|
+
exports.desc = 'Provision secrets (uses the legacy ruby CLI)';
|
|
6
|
+
const builder = (yargs) => {
|
|
7
|
+
return yargs
|
|
8
|
+
.commandDir('secrets/subcommands')
|
|
9
|
+
.demandCommand();
|
|
10
|
+
};
|
|
11
|
+
exports.builder = builder;
|