opal-security 2.0.20 → 2.1.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.
@@ -1,22 +1,81 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promptUserForAccessLevels = exports.unexpectedAmountOfAccessLevelsFound = exports.resourcesAreEmpty = void 0;
4
- const cmd_1 = require("./cmd");
3
+ exports.promptUserForAccessLevels = exports.promptUserForResource = exports.filterChoices = exports.DEFAULT_ACCESS_LEVEL = void 0;
5
4
  const handler_1 = require("../handler");
6
5
  const apollo_1 = require("./apollo");
7
6
  const inquirer = require("inquirer");
8
- exports.resourcesAreEmpty = (context, resources) => {
9
- if (resources.length === 0) {
10
- context.log('❗️ Oh no! You don\'t have any resources. Head to Opal to request some.');
11
- return true;
7
+ exports.DEFAULT_ACCESS_LEVEL = {
8
+ accessLevelName: '',
9
+ accessLevelRemoteId: '',
10
+ };
11
+ // Returns a filtered array of items that match the input
12
+ exports.filterChoices = (input, choices) => {
13
+ input = input || '';
14
+ if (input === '') {
15
+ return choices;
12
16
  }
13
- return false;
17
+ return choices.filter(choice => choice.name.toLowerCase().includes(input.toLowerCase()));
14
18
  };
15
- exports.unexpectedAmountOfAccessLevelsFound = (context) => {
16
- context.log('❗️ Oh no! We weren\'t expecting the amount of access levels returned from Opal. Please contact your support engineer.');
19
+ const ListResourcesDocumentTemplate = `
20
+ query ListResources {
21
+ resources(input: {resourceTypes: [RESOURCE_TYPE], onlyMine: true, maxNumEntries: 1000}) {
22
+ __typename
23
+ ... on ResourcesResult {
24
+ resources {
25
+ name
26
+ id
27
+ parentResource {
28
+ name
29
+ }
30
+ connection {
31
+ name
32
+ }
33
+ }
34
+ cursor
35
+ }
36
+ }
37
+ }`;
38
+ exports.promptUserForResource = async (command, resourceType, message) => {
39
+ const listResourcesDocument = ListResourcesDocumentTemplate.replace('RESOURCE_TYPE', resourceType);
40
+ const { resp, error } = await handler_1.runQuery({
41
+ command: command,
42
+ query: listResourcesDocument,
43
+ variables: {},
44
+ });
45
+ if (error) {
46
+ return apollo_1.handleError(command, error, resp);
47
+ }
48
+ const resourceInfos = resp === null || resp === void 0 ? void 0 : resp.data.resources.resources.map((resource) => {
49
+ let name = resource.name;
50
+ if (resource.parentResource) {
51
+ name = `[${resource.parentResource.name}] ${name}`;
52
+ }
53
+ else if (resource.connection) {
54
+ name = `[${resource.connection.name}] ${name}`;
55
+ }
56
+ return {
57
+ id: resource.id,
58
+ name: name,
59
+ };
60
+ });
61
+ if (resourceInfos.length === 0) {
62
+ return apollo_1.handleError(command, 'Oh no! You don\'t have access to any resources. Please go to Opal to request access.');
63
+ }
64
+ const resourceInfoByName = {};
65
+ resourceInfos.forEach(resourceInfo => {
66
+ resourceInfoByName[resourceInfo.name] = resourceInfo;
67
+ });
68
+ inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
69
+ const selectedResourceInfo = await inquirer.prompt([{
70
+ name: 'resource',
71
+ message: message,
72
+ type: 'autocomplete',
73
+ source: (answers, input) => exports.filterChoices(input, resourceInfos),
74
+ }]);
75
+ return resourceInfoByName[selectedResourceInfo.resource];
17
76
  };
18
- const ListAccessRolesForResource = `
19
- query ListAccessRolesForResource($resourceId: ResourceId!) {
77
+ const ListAccessLevelsForResource = `
78
+ query ListAccessLevelsForResource($resourceId: ResourceId!) {
20
79
  accessLevels(input: {resourceId: $resourceId, onlyMine: true}) {
21
80
  __typename
22
81
  ... on ResourceAccessLevelsResult {
@@ -27,23 +86,23 @@ query ListAccessRolesForResource($resourceId: ResourceId!) {
27
86
  }
28
87
  }
29
88
  }`;
30
- exports.promptUserForAccessLevels = async (context, resourceId, instanceType, accessLevelRemoteId) => {
89
+ exports.promptUserForAccessLevels = async (command, resourceId, instanceType, accessLevelRemoteId) => {
31
90
  var _a, _b, _c;
32
- const { resp: accessLevelsResponse, error: accessLevelsError } = await handler_1.runQuery({
33
- command: context,
34
- query: ListAccessRolesForResource,
91
+ const { resp, error } = await handler_1.runQuery({
92
+ command: command,
93
+ query: ListAccessLevelsForResource,
35
94
  variables: { resourceId },
36
95
  });
37
- if (accessLevelsError) {
38
- apollo_1.printRequestOutput(context, accessLevelsResponse, accessLevelsError);
39
- return null;
96
+ if (error) {
97
+ return apollo_1.handleError(command, error, resp);
40
98
  }
41
- const accessLevelInfos = (_c = (_b = (_a = accessLevelsResponse === null || accessLevelsResponse === void 0 ? void 0 : accessLevelsResponse.data) === null || _a === void 0 ? void 0 : _a.accessLevels) === null || _b === void 0 ? void 0 : _b.accessLevels) === null || _c === void 0 ? void 0 : _c.map((resp) => ({ id: resp.accessLevelRemoteId, name: resp.accessLevelName }));
99
+ const accessLevelInfos = (_c = (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.data) === null || _a === void 0 ? void 0 : _a.accessLevels) === null || _b === void 0 ? void 0 : _b.accessLevels) === null || _c === void 0 ? void 0 : _c.map((resp) => ({
100
+ id: resp.accessLevelRemoteId,
101
+ name: resp.accessLevelName,
102
+ }));
42
103
  if (!accessLevelInfos) {
43
- exports.unexpectedAmountOfAccessLevelsFound(context);
44
- return null;
104
+ return apollo_1.handleError(command, 'Oh no! We weren\'t expecting the amount of access levels returned from Opal. Please contact your support engineer.');
45
105
  }
46
- // Prompt user to pick access levels available to them
47
106
  const accessLevelInfoByName = {};
48
107
  const accessLevelInfoByRemoteId = {};
49
108
  accessLevelInfos.forEach(accessLevelInfo => {
@@ -54,13 +113,14 @@ exports.promptUserForAccessLevels = async (context, resourceId, instanceType, ac
54
113
  if (accessLevelRemoteId) {
55
114
  selectedAccessLevel = accessLevelInfoByRemoteId[accessLevelRemoteId];
56
115
  }
116
+ // Prompt user to pick access levels available to them
57
117
  if (!selectedAccessLevel) {
58
118
  inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
59
119
  const selectedAccessLevelInfo = await inquirer.prompt([{
60
120
  name: 'accessLevel',
61
121
  message: `Select an access level to the ${instanceType}`,
62
122
  type: 'autocomplete',
63
- source: (answers, input) => cmd_1.filterChoices(input, accessLevelInfos),
123
+ source: (answers, input) => exports.filterChoices(input, accessLevelInfos),
64
124
  }]);
65
125
  selectedAccessLevel = accessLevelInfoByName[selectedAccessLevelInfo.accessLevel];
66
126
  }
@@ -0,0 +1,4 @@
1
+ import Command from '@oclif/command';
2
+ import { ResourceAccessLevelInput } from '../types';
3
+ export declare const getOrCreateSession: (command: Command, resourceId: string, accessLevel: ResourceAccessLevelInput, sessionId: string | undefined, metadataFragment: string) => Promise<any>;
4
+ export declare const getSessionExpirationMessage: (session: any) => string;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSessionExpirationMessage = exports.getOrCreateSession = void 0;
4
+ const open = require("open");
5
+ const config_1 = require("../lib/config");
6
+ const handler_1 = require("../handler");
7
+ const moment = require("moment");
8
+ const apollo_1 = require("../lib/apollo");
9
+ const common_1 = require("../lib/common");
10
+ const CreateSessionDocument = `
11
+ mutation CreateSession($id: ResourceId!, $accessLevel: ResourceAccessLevelInput!, $sessionId: SessionId) {
12
+ createSession(input: {resourceId: $id, accessLevel: $accessLevel, sessionId: $sessionId}) {
13
+ __typename
14
+ ... on CreateSessionResult {
15
+ session {
16
+ id
17
+ accessLevelRemoteId
18
+ endTime
19
+ metadata {
20
+ METADATA_FRAGMENT
21
+ }
22
+ }
23
+ }
24
+ ... on SessionNotFoundError {
25
+ message
26
+ }
27
+ ... on MfaInvalidError {
28
+ message
29
+ }
30
+ ... on OidcIDTokenNotFoundError {
31
+ message
32
+ }
33
+ ... on ResourceNotFoundError {
34
+ message
35
+ }
36
+ ... on EndSystemAuthorizationError {
37
+ message
38
+ }
39
+ }
40
+ }
41
+ `;
42
+ const ListSessionsDocument = `
43
+ query ListSessions($id: ResourceId!) {
44
+ sessions(input: {resourceId: $id}) {
45
+ __typename
46
+ ... on SessionsResult {
47
+ sessions {
48
+ id
49
+ accessLevelRemoteId
50
+ endTime
51
+ metadata {
52
+ METADATA_FRAGMENT
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+ `;
59
+ const getSession = async (command, resourceId, accessLevelRemoteId, sessionId, metadataFragment) => {
60
+ const { resp, error } = await handler_1.runQuery({
61
+ command: command,
62
+ query: ListSessionsDocument.replace('METADATA_FRAGMENT', metadataFragment),
63
+ variables: {
64
+ id: resourceId,
65
+ },
66
+ });
67
+ if (error) {
68
+ return apollo_1.handleError(command, error);
69
+ }
70
+ switch (resp === null || resp === void 0 ? void 0 : resp.data.sessions.__typename) {
71
+ case 'SessionsResult': {
72
+ const sessions = resp.data.sessions.sessions;
73
+ let selectedSession;
74
+ for (const session of sessions) {
75
+ if (sessionId && session.id !== sessionId) {
76
+ continue;
77
+ }
78
+ if (session.accessLevelRemoteId !== accessLevelRemoteId) {
79
+ continue;
80
+ }
81
+ if (!selectedSession || moment(session.endTime).diff(selectedSession.endTime) > 0) {
82
+ // Select the session with the latest end time
83
+ selectedSession = session;
84
+ }
85
+ }
86
+ return selectedSession;
87
+ }
88
+ default:
89
+ return apollo_1.handleError(command, error, resp);
90
+ }
91
+ };
92
+ const openBrowserAndPollForSession = async (command, message, resourceId, accessLevelRemoteId, sessionId, metadataFragment) => {
93
+ command.log(message);
94
+ const configData = config_1.getOrCreateConfigData(command.config.configDir);
95
+ const url = configData[config_1.urlKey];
96
+ setTimeout(() => {
97
+ open(url + `/resources/${resourceId}?showModal=true`);
98
+ }, 2000); // Wait before opening the browser to give the user time to read the message
99
+ let session;
100
+ while (!session) {
101
+ // eslint-disable-next-line no-await-in-loop
102
+ await common_1.sleep(2000);
103
+ // eslint-disable-next-line no-await-in-loop
104
+ session = await getSession(command, resourceId, accessLevelRemoteId, sessionId, metadataFragment);
105
+ }
106
+ return session;
107
+ };
108
+ const createSession = async (command, resourceId, accessLevel, sessionId, metadataFragment) => {
109
+ const { resp, error } = await handler_1.runMutation({
110
+ command: command,
111
+ query: CreateSessionDocument.replace('METADATA_FRAGMENT', metadataFragment),
112
+ variables: {
113
+ id: resourceId,
114
+ accessLevel: accessLevel,
115
+ sessionId,
116
+ },
117
+ });
118
+ if (error) {
119
+ return apollo_1.handleError(command, error);
120
+ }
121
+ switch (resp === null || resp === void 0 ? void 0 : resp.data.createSession.__typename) {
122
+ case 'CreateSessionResult': {
123
+ return resp.data.createSession.session;
124
+ }
125
+ case 'MfaInvalidError': {
126
+ command.log();
127
+ return openBrowserAndPollForSession(command, '❗ MFA validation needed. Please connect via browser. Opening browser and awaiting validation...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
128
+ }
129
+ case 'OidcIDTokenNotFoundError': {
130
+ command.log();
131
+ return openBrowserAndPollForSession(command, '❗ OIDC authentication needed. Please connect via browser. Opening browser and awaiting authentication...', resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
132
+ }
133
+ default:
134
+ return apollo_1.handleError(command, error, resp);
135
+ }
136
+ };
137
+ exports.getOrCreateSession = async (command, resourceId, accessLevel, sessionId, metadataFragment) => {
138
+ // Use existing session if it exists
139
+ const existingSession = await getSession(command, resourceId, accessLevel.accessLevelRemoteId, sessionId, metadataFragment);
140
+ if (existingSession) {
141
+ return existingSession;
142
+ }
143
+ if (sessionId) {
144
+ return apollo_1.handleError(command, 'Session not found for given id: ' + sessionId);
145
+ }
146
+ // Create new session
147
+ return createSession(command, resourceId, accessLevel, sessionId, metadataFragment);
148
+ };
149
+ exports.getSessionExpirationMessage = (session) => {
150
+ const diff = moment(session.endTime).diff(moment(), 'minutes');
151
+ const hours = Math.floor(diff / 60);
152
+ const minutes = diff % 60;
153
+ return `${hours}h ${minutes}m`;
154
+ };
package/lib/lib/ssh.d.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  import { Command } from '@oclif/command';
2
- import { ResourceInfo } from '../lib/cmd';
3
- export declare const ListSshInstancesDocument = "\nquery ListSSHInstances {\n resources(input: {serviceType: SSH, onlyMine: true, maxNumEntries: 1000}) {\n __typename\n ... on ResourcesResult {\n resources {\n name\n id\n }\n cursor\n }\n }\n}";
4
- export declare const selectComputeInstance: (command: Command, description: string) => Promise<ResourceInfo | undefined>;
2
+ export declare const selectComputeInstance: (command: Command, action: string) => Promise<void | import("./resources").ResourceInfo>;
5
3
  export declare const assertSessionManagerPluginExists: () => Promise<boolean>;
package/lib/lib/ssh.js CHANGED
@@ -1,56 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertSessionManagerPluginExists = exports.selectComputeInstance = exports.ListSshInstancesDocument = void 0;
4
- const handler_1 = require("../handler");
5
- const apollo_1 = require("../lib/apollo");
3
+ exports.assertSessionManagerPluginExists = exports.selectComputeInstance = void 0;
6
4
  const cmd_1 = require("../lib/cmd");
7
- const inquirer = require("inquirer");
8
5
  const resources_1 = require("./resources");
9
- exports.ListSshInstancesDocument = `
10
- query ListSSHInstances {
11
- resources(input: {serviceType: SSH, onlyMine: true, maxNumEntries: 1000}) {
12
- __typename
13
- ... on ResourcesResult {
14
- resources {
15
- name
16
- id
17
- }
18
- cursor
19
- }
20
- }
21
- }`;
22
- exports.selectComputeInstance = async (command, description) => {
23
- const { resp: sshInstancesResp, error } = await handler_1.runQuery({
24
- command: command,
25
- query: exports.ListSshInstancesDocument,
26
- variables: {},
27
- });
28
- if (error) {
29
- apollo_1.printRequestOutput(command, sshInstancesResp, error);
30
- return;
31
- }
32
- const resourceInfos = sshInstancesResp === null || sshInstancesResp === void 0 ? void 0 : sshInstancesResp.data.resources.resources.map((resource) => {
33
- return {
34
- id: resource.id,
35
- name: resource.name,
36
- };
37
- });
38
- const noResourcesFound = resources_1.resourcesAreEmpty(command, resourceInfos);
39
- if (noResourcesFound) {
40
- return;
41
- }
42
- const resourceInfoByName = {};
43
- resourceInfos.forEach(resourceInfo => {
44
- resourceInfoByName[resourceInfo.name] = resourceInfo;
45
- });
46
- inquirer.registerPrompt('autocomplete', require('inquirer-autocomplete-prompt'));
47
- const selectedInstanceInfo = await inquirer.prompt([{
48
- name: 'instance',
49
- message: `Select a compute instance to ${description}`,
50
- type: 'autocomplete',
51
- source: (answers, input) => cmd_1.filterChoices(input, resourceInfos),
52
- }]);
53
- return resourceInfoByName[selectedInstanceInfo.instance];
6
+ exports.selectComputeInstance = async (command, action) => {
7
+ return resources_1.promptUserForResource(command, 'AWS_EC2_INSTANCE', `Select an EC2 instance to ${action}`);
54
8
  };
55
9
  exports.assertSessionManagerPluginExists = async () => {
56
10
  const errorMessage = '❗ AWS session manager plugin is required to use SSH functionality. ' +
package/lib/types.d.ts CHANGED
@@ -4373,6 +4373,7 @@ export declare type Resource = {
4373
4373
  ownerTeam?: Maybe<Group>;
4374
4374
  connectionId: Scalars['ConnectionId'];
4375
4375
  connection?: Maybe<Connection>;
4376
+ parentResource?: Maybe<Resource>;
4376
4377
  folderId?: Maybe<Scalars['ResourceFolderId']>;
4377
4378
  folder?: Maybe<ResourceFolder>;
4378
4379
  resourceUsers: Array<ResourceUser>;
@@ -1 +1 @@
1
- {"version":"2.0.20","commands":{"curl-example":{"id":"curl-example","description":"Prints out an example cURL command containing the parameters the CLI uses to query the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Authenticates you with the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal login"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"logout":{"id":"logout","description":"Clears locally stored Opal server authentication credentials.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal logout"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-custom-header":{"id":"set-custom-header","description":"Sets a custom HTTP header to connect to the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-custom-header --header 'cf-access-token: $TOKEN'"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"header":{"name":"header","type":"option"}},"args":[]},"set-token":{"id":"set-token","description":"Sets an API token to authenticate with the Opal server - alternative auth flow for headless environments.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-token"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-url":{"id":"set-url","description":"Sets the url of the Opal server. Defaults to https://app.opal.dev.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-url"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"custom":{"name":"custom","type":"option"},"allowSelfSignedCerts":{"name":"allowSelfSignedCerts","type":"boolean","allowNo":false},"prod":{"name":"prod","type":"boolean","allowNo":false},"staging":{"name":"staging","type":"boolean","allowNo":false},"demo":{"name":"demo","type":"boolean","allowNo":false},"dev":{"name":"dev","type":"boolean","allowNo":false},"devLocal":{"name":"devLocal","type":"boolean","allowNo":false}},"args":[]},"aws:identity":{"id":"aws:identity","description":"Gets the current caller identity for the \"opal\" AWS profile.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal aws:identity"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"iam-roles:start":{"id":"iam-roles:start","description":"Starts a session to assume an IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal iam-roles:start","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName \"custom-profile\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."},"profileName":{"name":"profileName","type":"option","description":"Uses a custom AWS profile name for the IAM role. Default value is the role's name."}},"args":[]},"kube-roles:start":{"id":"kube-roles:start","description":"Starts a session to assume a Kubernetes cluster IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal kube-roles:start","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the cluster."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"postgres-instances:start":{"id":"postgres-instances:start","description":"Starts a session to query a Postgres database.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal postgres-instances:start","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"fullaccess\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the database."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"resources:get":{"id":"resources:get","description":"Get resource info for a particular resource.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","required":true}},"args":[]},"ssh:copyFrom":{"id":"ssh:copyFrom","description":"Use SCP to copy files from a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyFrom --src instance/dir --dest my/dir","opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:copyTo":{"id":"ssh:copyTo","description":"Use SCP to copy files to a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyTo --src my/dir --dest instance/dir","opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:start":{"id":"ssh:start","description":"Start an SSH session to access a particular compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:start","opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]}}}
1
+ {"version":"2.1.0","commands":{"curl-example":{"id":"curl-example","description":"Prints out an example cURL command containing the parameters the CLI uses to query the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"login":{"id":"login","description":"Authenticates you with the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal login"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"email":{"name":"email","type":"option","description":"Email address to login with."}},"args":[]},"logout":{"id":"logout","description":"Clears locally stored Opal server authentication credentials.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal logout"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-custom-header":{"id":"set-custom-header","description":"Sets a custom HTTP header to connect to the Opal server.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-custom-header --header 'cf-access-token: $TOKEN'"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"header":{"name":"header","type":"option"}},"args":[]},"set-token":{"id":"set-token","description":"Sets an API token to authenticate with the Opal server - alternative auth flow for headless environments.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-token"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"set-url":{"id":"set-url","description":"Sets the url of the Opal server. Defaults to https://app.opal.dev.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["$ opal set-url"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"allowSelfSignedCerts":{"name":"allowSelfSignedCerts","type":"boolean","allowNo":false},"custom":{"name":"custom","type":"option","hidden":true},"prod":{"name":"prod","type":"boolean","hidden":true,"allowNo":false},"demo":{"name":"demo","type":"boolean","hidden":true,"allowNo":false},"dev":{"name":"dev","type":"boolean","hidden":true,"allowNo":false},"devLocal":{"name":"devLocal","type":"boolean","hidden":true,"allowNo":false}},"args":[{"name":"url","description":"URL of the Opal server to use. If unspecified, defaults to https://app.opal.dev","required":false}]},"aws:identity":{"id":"aws:identity","description":"Gets the current caller identity for the \"opal\" AWS profile.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal aws:identity"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"iam-roles:start":{"id":"iam-roles:start","description":"Starts a session to assume an IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal iam-roles:start","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName \"custom-profile\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."},"profileName":{"name":"profileName","type":"option","description":"Uses a custom AWS profile name for the IAM role. Default value is the role's name."}},"args":[]},"kube-roles:start":{"id":"kube-roles:start","description":"Starts a session to assume a Kubernetes cluster IAM role.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal kube-roles:start","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal kube-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal role resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the cluster."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"postgres-instances:start":{"id":"postgres-instances:start","description":"Starts a session to query a Postgres database.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal postgres-instances:start","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId \"fullaccess\""],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","description":"The remote ID of the access level with which to access the database."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"resources:get":{"id":"resources:get","description":"Get resource info for a particular resource.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","required":true}},"args":[]},"ssh:copyFrom":{"id":"ssh:copyFrom","description":"Use SCP to copy files from a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyFrom --src instance/dir --dest my/dir","opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:copyTo":{"id":"ssh:copyTo","description":"Use SCP to copy files to a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:copyTo --src my/dir --dest instance/dir","opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"src":{"name":"src","type":"option","description":"The path of the directory or file you would like to copy over SCP. Note we only support one file or directory at a time.","required":true},"dest":{"name":"dest","type":"option","description":"Pick which directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"Pick which user you want to run SCP over. Keep in mind not all users will have access to each other's home directory.","required":false,"default":"ssm-user"},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]},"ssh:start":{"id":"ssh:start","description":"Starts an SSH session to access a compute instance.","pluginName":"opal-security","pluginType":"core","aliases":[],"examples":["opal ssh:start","opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","description":"The ID of the Opal instance resource."},"sessionId":{"name":"sessionId","type":"option","description":"SessionId of a session that has already been created via the web flow."}},"args":[]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opal-security",
3
3
  "description": "Opal allows you to centrally manage access to all of your sensitive systems.",
4
- "version": "2.0.20",
4
+ "version": "2.1.0",
5
5
  "author": "Stephen Cobbe",
6
6
  "bin": {
7
7
  "opal": "./bin/run"
@@ -81,6 +81,7 @@
81
81
  "url": "https://github.com/opalsecurity/opal-cli.git"
82
82
  },
83
83
  "resolutions": {
84
+ "agent-base": "^6.0.1",
84
85
  "ansi-regex": "5.0.1"
85
86
  },
86
87
  "scripts": {