neonctl 0.5.4 → 0.7.0

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": "neonctl",
3
- "version": "0.5.4",
3
+ "version": "0.7.0",
4
4
  "description": "CLI tool for NeonDB Cloud management",
5
5
  "main": "index.js",
6
6
  "author": "NeonDB",
@@ -26,6 +26,7 @@
26
26
  "cli-table": "^0.3.11",
27
27
  "open": "^8.4.0",
28
28
  "openid-client": "^5.1.9",
29
+ "yaml": "^2.1.1",
29
30
  "yargs": "^17.5.1"
30
31
  },
31
32
  "publishConfig": {
@@ -39,7 +40,7 @@
39
40
  "build": "npm run clean && tsc && cp src/*.html dist/src/",
40
41
  "clean": "rm -rf dist",
41
42
  "start": "node index.js",
42
- "publizh": "npm run build && npm publish ./dist && git push"
43
+ "publizh": "npm run build && npm publish --ignore-scripts ./dist"
43
44
  },
44
45
  "lint-staged": {
45
46
  "*.ts": [
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getOperation = exports.waitOperationFinalState = void 0;
13
+ const log_1 = require("../log");
14
+ const gateway_1 = require("./gateway");
15
+ function sleep(ms) {
16
+ return new Promise((resolve) => setTimeout(resolve, ms));
17
+ }
18
+ // wait 20 sec max.
19
+ const waitOperationFinalState = (props) => __awaiter(void 0, void 0, void 0, function* () {
20
+ for (let i = 0; i < 20; i++) {
21
+ const operation = yield (0, exports.getOperation)(Object.assign({}, props));
22
+ if (operation.status == 'finished') {
23
+ return;
24
+ }
25
+ log_1.log.info(`Waiting for operation "${props.operation_id}" to finish`);
26
+ yield sleep(1000);
27
+ }
28
+ throw Error(`timeout while waiting for operation ${props.operation_id}`);
29
+ });
30
+ exports.waitOperationFinalState = waitOperationFinalState;
31
+ const getOperation = (props) => (0, gateway_1.apiCall)(Object.assign(Object.assign({}, props), { path: `projects/${props.project_id}/operations/${props.operation_id}`, method: 'GET' }));
32
+ exports.getOperation = getOperation;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.resetPassword = void 0;
13
+ const gateway_1 = require("./gateway");
14
+ const operations_1 = require("./operations");
15
+ const resetPassword = (props) => __awaiter(void 0, void 0, void 0, function* () {
16
+ const response = yield (0, gateway_1.apiCall)(Object.assign(Object.assign({}, props), { path: `projects/${props.project_id}/roles/${props.role_name}/reset_password`, method: 'POST' }));
17
+ yield (0, operations_1.waitOperationFinalState)(Object.assign(Object.assign({}, props), response));
18
+ return response;
19
+ });
20
+ exports.resetPassword = resetPassword;
package/src/auth.js CHANGED
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.auth = exports.refreshToken = void 0;
15
+ exports.auth = exports.refreshToken = exports.defaultClientID = void 0;
16
16
  const openid_client_1 = require("openid-client");
17
17
  const node_http_1 = require("node:http");
18
18
  const node_fs_1 = require("node:fs");
@@ -24,15 +24,15 @@ const SERVER_TIMEOUT = 10000;
24
24
  // where to wait for incoming redirect request from oauth server to arrive
25
25
  const REDIRECT_URI = (port) => `http://127.0.0.1:${port}/callback`;
26
26
  // These scopes cannot be cancelled, they are always needed.
27
- const DEFAULT_SCOPES = [
28
- 'openid',
29
- 'offline',
30
- 'offline_access',
27
+ const ALWAYS_PRESENT_SCOPES = ['openid', 'offline', 'offline_access'];
28
+ const NEONCTL_SCOPES = [
29
+ ...ALWAYS_PRESENT_SCOPES,
31
30
  'urn:neoncloud:projects:create',
32
31
  'urn:neoncloud:projects:read',
33
- 'urn:neoncloud:projects:modify',
32
+ 'urn:neoncloud:projects:update',
34
33
  'urn:neoncloud:projects:delete',
35
34
  ];
35
+ exports.defaultClientID = 'neonctl';
36
36
  openid_client_1.custom.setHttpOptionsDefaults({
37
37
  timeout: SERVER_TIMEOUT,
38
38
  });
@@ -94,8 +94,9 @@ const auth = ({ oauthHost, clientId }) => __awaiter(void 0, void 0, void 0, func
94
94
  //
95
95
  // Open browser to let user authenticate
96
96
  //
97
+ const scopes = clientId == exports.defaultClientID ? NEONCTL_SCOPES : ALWAYS_PRESENT_SCOPES;
97
98
  const authUrl = neonOAuthClient.authorizationUrl({
98
- scope: DEFAULT_SCOPES.join(' '),
99
+ scope: scopes.join(' '),
99
100
  state,
100
101
  code_challenge: codeChallenge,
101
102
  code_challenge_method: 'S256',
@@ -94,7 +94,11 @@ const ensureAuth = (props) => __awaiter(void 0, void 0, void 0, function* () {
94
94
  return;
95
95
  }
96
96
  const token = tokenSet.access_token || 'UNKNOWN';
97
- yield validateToken({ apiHost: props['api-host'], token });
97
+ yield validateToken({
98
+ apiHost: props['api-host'],
99
+ token,
100
+ output: 'json',
101
+ });
98
102
  props.token = token;
99
103
  return;
100
104
  }
@@ -13,7 +13,9 @@ exports.create = exports.list = void 0;
13
13
  const projects_1 = require("../api/projects");
14
14
  const writer_1 = require("../writer");
15
15
  const list = (props) => __awaiter(void 0, void 0, void 0, function* () {
16
- (0, writer_1.writeOut)(props)(yield (0, projects_1.listProjects)(props), { fields: [] });
16
+ (0, writer_1.writeOut)(props)(yield (0, projects_1.listProjects)(props), {
17
+ fields: ['id', 'name', 'region_name', 'created_at'],
18
+ });
17
19
  });
18
20
  exports.list = list;
19
21
  const create = (props) => __awaiter(void 0, void 0, void 0, function* () {
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.resetPwd = void 0;
13
+ const writer_1 = require("../writer");
14
+ const roles_1 = require("../api/roles");
15
+ const resetPwd = (props) => __awaiter(void 0, void 0, void 0, function* () {
16
+ (0, writer_1.writeOut)(props)(yield (0, roles_1.resetPassword)(props), { fields: ['dsn'] });
17
+ });
18
+ exports.resetPwd = resetPwd;
package/src/index.js CHANGED
@@ -41,6 +41,7 @@ const gateway_1 = require("./api/gateway");
41
41
  const auth_1 = require("./commands/auth");
42
42
  const config_1 = require("./config");
43
43
  const log_1 = require("./log");
44
+ const auth_2 = require("./auth");
44
45
  const showHelpMiddleware = (argv) => {
45
46
  if (argv._.length === 1) {
46
47
  yargs.showHelp();
@@ -51,9 +52,11 @@ const builder = yargs
51
52
  .scriptName(package_json_1.default.name)
52
53
  .usage('usage: $0 <cmd> [args]')
53
54
  .help()
54
- .option('json', {
55
- describe: 'Set output format to JSON',
56
- type: 'boolean',
55
+ .option('output', {
56
+ describe: 'Set output format',
57
+ type: 'string',
58
+ choices: ['json', 'yaml', 'table'],
59
+ default: 'table',
57
60
  })
58
61
  .option('api-host', {
59
62
  describe: 'The API host',
@@ -74,7 +77,7 @@ const builder = yargs
74
77
  .option('client-id', {
75
78
  description: 'OAuth client id',
76
79
  type: 'string',
77
- default: 'neonctl',
80
+ default: auth_2.defaultClientID,
78
81
  })
79
82
  .command('auth', 'Authenticate user', (yargs) => yargs, (args) => __awaiter(void 0, void 0, void 0, function* () {
80
83
  (yield Promise.resolve().then(() => __importStar(require('./commands/auth')))).authFlow(args);
@@ -87,18 +90,32 @@ const builder = yargs
87
90
  })
88
91
  .command('me', 'Get user info', (yargs) => yargs.middleware(auth_1.ensureAuth), (args) => __awaiter(void 0, void 0, void 0, function* () {
89
92
  yield (yield Promise.resolve().then(() => __importStar(require('./commands/users')))).me(args);
93
+ }))
94
+ .command('roles', 'Manage roles', (yargs) => __awaiter(void 0, void 0, void 0, function* () {
95
+ yargs
96
+ .usage('usage: $0 roles <cmd> [args]')
97
+ .command('resetpassword', 'Reset password for a role', (yargs) => yargs
98
+ .option('project-id', {
99
+ describe: 'Project ID',
100
+ type: 'string',
101
+ demandOption: true,
102
+ })
103
+ .option('role-name', {
104
+ describe: 'Role name',
105
+ type: 'string',
106
+ demandOption: true,
107
+ }), (args) => __awaiter(void 0, void 0, void 0, function* () {
108
+ yield (yield Promise.resolve().then(() => __importStar(require('./commands/roles')))).resetPwd(Object.assign(Object.assign({}, args), { role_name: args['role-name'], project_id: args['project-id'] }));
109
+ }))
110
+ .middleware(showHelpMiddleware)
111
+ .middleware(auth_1.ensureAuth);
90
112
  }))
91
113
  .command('projects', 'Manage projects', (yargs) => __awaiter(void 0, void 0, void 0, function* () {
92
114
  yargs
93
115
  .usage('usage: $0 projects <cmd> [args]')
94
- // .command(
95
- // 'list',
96
- // 'List projects',
97
- // (yargs) => yargs,
98
- // async (args) => {
99
- // await (await import('./commands/projects')).list(args);
100
- // }
101
- // )
116
+ .command('list', 'List projects', (yargs) => yargs, (args) => __awaiter(void 0, void 0, void 0, function* () {
117
+ yield (yield Promise.resolve().then(() => __importStar(require('./commands/projects')))).list(args);
118
+ }))
102
119
  .command('create', 'Create a project', (yargs) => yargs.option('name', {
103
120
  describe: 'Project name',
104
121
  type: 'string',
package/src/writer.js CHANGED
@@ -4,9 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.writeOut = void 0;
7
+ const yaml_1 = __importDefault(require("yaml"));
7
8
  const cli_table_1 = __importDefault(require("cli-table"));
9
+ // Allow PIPE to finish reading before the end of the output.
10
+ process.stdout.on('error', function (err) {
11
+ if (err.code == 'EPIPE') {
12
+ process.exit(0);
13
+ }
14
+ });
8
15
  const writeOut = (props) => (data, config) => {
9
- if (props.json) {
16
+ if (props.output == 'yaml') {
17
+ process.stdout.write(yaml_1.default.stringify(data, null, 2));
18
+ return;
19
+ }
20
+ if (props.output == 'json') {
10
21
  process.stdout.write(JSON.stringify(data, null, 2));
11
22
  return;
12
23
  }