opal-security 2.1.1 → 2.1.3

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/README.md CHANGED
@@ -22,7 +22,7 @@ $ npm install -g opal-security
22
22
  $ opal COMMAND
23
23
  running command...
24
24
  $ opal (-v|--version|version)
25
- opal-security/2.1.1 darwin-x64 node-v14.16.1
25
+ opal-security/2.1.3 darwin-x64 node-v14.16.1
26
26
  $ opal --help [COMMAND]
27
27
  USAGE
28
28
  $ opal COMMAND
@@ -88,7 +88,7 @@ EXAMPLE
88
88
  opal aws:identity
89
89
  ```
90
90
 
91
- _See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/aws/identity.ts)_
91
+ _See code: [src/commands/aws/identity.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/aws/identity.ts)_
92
92
 
93
93
  ## `opal curl-example`
94
94
 
@@ -102,7 +102,7 @@ OPTIONS
102
102
  -h, --help show CLI help
103
103
  ```
104
104
 
105
- _See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/curl-example.ts)_
105
+ _See code: [src/commands/curl-example.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/curl-example.ts)_
106
106
 
107
107
  ## `opal help [COMMAND]`
108
108
 
@@ -148,7 +148,7 @@ EXAMPLES
148
148
  opal iam-roles:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --profileName "custom-profile"
149
149
  ```
150
150
 
151
- _See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/iam-roles/start.ts)_
151
+ _See code: [src/commands/iam-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/iam-roles/start.ts)_
152
152
 
153
153
  ## `opal kube-roles:start`
154
154
 
@@ -178,7 +178,7 @@ EXAMPLES
178
178
  "arn:aws:iam::712234975475:role/acme-eks-cluster-admin-role"
179
179
  ```
180
180
 
181
- _See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/kube-roles/start.ts)_
181
+ _See code: [src/commands/kube-roles/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/kube-roles/start.ts)_
182
182
 
183
183
  ## `opal login`
184
184
 
@@ -196,7 +196,7 @@ EXAMPLE
196
196
  $ opal login
197
197
  ```
198
198
 
199
- _See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/login.ts)_
199
+ _See code: [src/commands/login.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/login.ts)_
200
200
 
201
201
  ## `opal logout`
202
202
 
@@ -213,7 +213,7 @@ EXAMPLE
213
213
  $ opal logout
214
214
  ```
215
215
 
216
- _See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/logout.ts)_
216
+ _See code: [src/commands/logout.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/logout.ts)_
217
217
 
218
218
  ## `opal postgres-instances:start`
219
219
 
@@ -248,7 +248,7 @@ EXAMPLES
248
248
  opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view
249
249
  ```
250
250
 
251
- _See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/postgres-instances/start.ts)_
251
+ _See code: [src/commands/postgres-instances/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/postgres-instances/start.ts)_
252
252
 
253
253
  ## `opal resources:get`
254
254
 
@@ -266,7 +266,7 @@ EXAMPLE
266
266
  opal resources:get --id 54052a3e-5375-4392-aeaf-0c6c44c131d4
267
267
  ```
268
268
 
269
- _See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/resources/get.ts)_
269
+ _See code: [src/commands/resources/get.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/resources/get.ts)_
270
270
 
271
271
  ## `opal set-custom-header`
272
272
 
@@ -284,7 +284,7 @@ EXAMPLE
284
284
  $ opal set-custom-header --header 'cf-access-token: $TOKEN'
285
285
  ```
286
286
 
287
- _See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/set-custom-header.ts)_
287
+ _See code: [src/commands/set-custom-header.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/set-custom-header.ts)_
288
288
 
289
289
  ## `opal set-token`
290
290
 
@@ -301,7 +301,7 @@ EXAMPLE
301
301
  $ opal set-token
302
302
  ```
303
303
 
304
- _See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/set-token.ts)_
304
+ _See code: [src/commands/set-token.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/set-token.ts)_
305
305
 
306
306
  ## `opal set-url [URL]`
307
307
 
@@ -322,7 +322,7 @@ EXAMPLE
322
322
  $ opal set-url
323
323
  ```
324
324
 
325
- _See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/set-url.ts)_
325
+ _See code: [src/commands/set-url.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/set-url.ts)_
326
326
 
327
327
  ## `opal ssh:copyFrom`
328
328
 
@@ -354,7 +354,7 @@ EXAMPLES
354
354
  opal ssh:copyFrom --src instance/dir --dest my/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
355
355
  ```
356
356
 
357
- _See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/ssh/copyFrom.ts)_
357
+ _See code: [src/commands/ssh/copyFrom.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/ssh/copyFrom.ts)_
358
358
 
359
359
  ## `opal ssh:copyTo`
360
360
 
@@ -386,7 +386,7 @@ EXAMPLES
386
386
  opal ssh:copyTo --src my/dir --dest instance/dir --id 51f7176b-0464-4a6f-8369-e951e187b398
387
387
  ```
388
388
 
389
- _See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/ssh/copyTo.ts)_
389
+ _See code: [src/commands/ssh/copyTo.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/ssh/copyTo.ts)_
390
390
 
391
391
  ## `opal ssh:start`
392
392
 
@@ -412,5 +412,5 @@ EXAMPLES
412
412
  opal ssh:start --id 51f7176b-0464-4a6f-8369-e951e187b398
413
413
  ```
414
414
 
415
- _See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.1/src/commands/ssh/start.ts)_
415
+ _See code: [src/commands/ssh/start.ts](https://github.com/opalsecurity/opal-cli/blob/v2.1.3/src/commands/ssh/start.ts)_
416
416
  <!-- commandsstop -->
@@ -55,6 +55,9 @@ class StartIAMRoleSession extends command_1.Command {
55
55
  roleName = flags.profileName;
56
56
  }
57
57
  const session = await sessions_1.getOrCreateSession(this, roleId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, IamSessionMetadataFragment, flags.refresh);
58
+ if (!session) {
59
+ return;
60
+ }
58
61
  const metadata = session.metadata;
59
62
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
60
63
  case 'AwsIamFederatedRoleSession': {
@@ -37,6 +37,9 @@ class StartKubeIAMRoleSession extends command_1.Command {
37
37
  return;
38
38
  }
39
39
  const session = await sessions_1.getOrCreateSession(this, clusterId, accessLevel, sessionId, EksSessionMetadataFragment, flags.refresh);
40
+ if (!session) {
41
+ return;
42
+ }
40
43
  const metadata = session.metadata;
41
44
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
42
45
  case 'AwsIamFederatedEksSession': {
@@ -1,4 +1,5 @@
1
1
  import { Command, flags } from '@oclif/command';
2
+ export declare const CLISignInMethodName = "CLISignInMethod";
2
3
  export declare const CLIAuthSessionCheckName = "CLIAuthSessionCheck";
3
4
  export declare const CLIAuthSessionCheckDocument = "\nquery CLIAuthSessionCheck {\n organizationSettings {\n ... on OrganizationSettingsResult {\n settings {\n id\n }\n }\n }\n}\n";
4
5
  export default class Login extends Command {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CLIAuthSessionCheckDocument = exports.CLIAuthSessionCheckName = void 0;
3
+ exports.CLIAuthSessionCheckDocument = exports.CLIAuthSessionCheckName = exports.CLISignInMethodName = void 0;
4
4
  const command_1 = require("@oclif/command");
5
5
  const keytar = require("keytar");
6
6
  const open = require("open");
@@ -17,6 +17,19 @@ const ISSUER_DEV = 'https://authdev.opal.dev';
17
17
  const GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
18
18
  const CLIENT_ID_PROD = '42rm6E5v7o67LBpRfjdT9KhnjrQHr9UF';
19
19
  const CLIENT_ID_DEV = 'XYV8qoAvZG7dHnhRp2g5XMJ1zX9fBP6s';
20
+ const CLISignInMethodDocumentLegacy = `
21
+ query CLISignInMethod($input: SignInMethodInput!) {
22
+ signInMethod(input: $input) {
23
+ __typename
24
+ ... on SignInMethodResult {
25
+ signInOrganizations {
26
+ organizationId
27
+ organizationName
28
+ }
29
+ }
30
+ }
31
+ }`;
32
+ exports.CLISignInMethodName = 'CLISignInMethod';
20
33
  const CLISignInMethodDocument = `
21
34
  query CLISignInMethod($input: SignInMethodInput!) {
22
35
  signInMethod(input: $input) {
@@ -25,6 +38,7 @@ query CLISignInMethod($input: SignInMethodInput!) {
25
38
  signInOrganizations {
26
39
  organizationId
27
40
  organizationName
41
+ cliClientId
28
42
  }
29
43
  }
30
44
  }
@@ -43,7 +57,7 @@ query CLIAuthSessionCheck {
43
57
  `;
44
58
  class Login extends command_1.Command {
45
59
  async run() {
46
- var _a, _b, _c, _d, _e;
60
+ var _a, _b, _c, _d, _e, _f, _g;
47
61
  try {
48
62
  await apollo_1.initClient(this);
49
63
  const { flags } = this.parse(Login);
@@ -51,11 +65,13 @@ class Login extends command_1.Command {
51
65
  const configData = config_1.getOrCreateConfigData(configDir);
52
66
  let email = flags.email;
53
67
  let organizationID;
68
+ let clientIdCandidate;
54
69
  if (await credentials_1.cred.accessToken) {
55
70
  // Only use the previous email + organizationID if email isn't explicitly specified.
56
71
  if (!email) {
57
72
  email = await credentials_1.cred.email;
58
73
  organizationID = await credentials_1.cred.organizationID;
74
+ clientIdCandidate = await credentials_1.cred.clientIdCandidate;
59
75
  }
60
76
  await credentials_1.cred.removeCredentials(-1);
61
77
  }
@@ -75,31 +91,48 @@ class Login extends command_1.Command {
75
91
  email = promptEmail;
76
92
  }
77
93
  if (!organizationID) {
94
+ let signInOrganizationsLegacyResponse;
78
95
  const { resp: signInOrganizationsResponse, error } = await handler_1.runQuery({
79
96
  command: this,
80
97
  query: CLISignInMethodDocument,
81
98
  variables: { input: { email } },
82
99
  });
83
100
  if (error) {
84
- this.log(''); // Intentional newline
85
- return apollo_1.handleError(this, 'Could not connect to Opal. Did you set the right URL? (`opal set-url --help`)');
101
+ if ('statusCode' in error.networkError && error.networkError.statusCode === 422) {
102
+ const { resp, error: legacyError } = await handler_1.runQuery({
103
+ command: this,
104
+ query: CLISignInMethodDocumentLegacy,
105
+ variables: { input: { email } },
106
+ });
107
+ signInOrganizationsLegacyResponse = resp;
108
+ if (legacyError) {
109
+ this.log(''); // Intentional newline
110
+ return apollo_1.handleError(this, 'Could not connect to Opal. Did you set the right URL? (`opal set-url --help`)');
111
+ }
112
+ }
113
+ else {
114
+ this.log(''); // Intentional newline
115
+ return apollo_1.handleError(this, 'Could not connect to Opal. Did you set the right URL? (`opal set-url --help`)');
116
+ }
86
117
  }
87
- const signInOrganizations = (_b = (_a = signInOrganizationsResponse === null || signInOrganizationsResponse === void 0 ? void 0 : signInOrganizationsResponse.data) === null || _a === void 0 ? void 0 : _a.signInMethod) === null || _b === void 0 ? void 0 : _b.signInOrganizations;
118
+ const signInOrganizations = signInOrganizationsResponse ? (_b = (_a = signInOrganizationsResponse === null || signInOrganizationsResponse === void 0 ? void 0 : signInOrganizationsResponse.data) === null || _a === void 0 ? void 0 : _a.signInMethod) === null || _b === void 0 ? void 0 : _b.signInOrganizations : (_d = (_c = signInOrganizationsLegacyResponse === null || signInOrganizationsLegacyResponse === void 0 ? void 0 : signInOrganizationsLegacyResponse.data) === null || _c === void 0 ? void 0 : _c.signInMethod) === null || _d === void 0 ? void 0 : _d.signInOrganizations;
88
119
  if (signInOrganizations && signInOrganizations.length > 0) {
89
120
  if (signInOrganizations.length === 1) {
90
121
  organizationID = signInOrganizations[0].organizationId;
122
+ clientIdCandidate = signInOrganizations[0].cliClientId;
91
123
  }
92
124
  else {
93
125
  const responses = await inquirer.prompt([{
94
- name: 'organizationID',
126
+ name: 'signInOrganization',
95
127
  message: 'Select an organization:',
96
128
  type: 'list',
97
129
  choices: signInOrganizations.map(signInOrganization => ({
98
130
  name: signInOrganization.organizationName,
99
- value: signInOrganization.organizationId,
131
+ value: signInOrganization,
100
132
  })),
101
133
  }]);
102
- organizationID = responses.organizationID;
134
+ organizationID = responses.signInOrganization.organizationId;
135
+ clientIdCandidate = responses.signInOrganization.cliClientId;
103
136
  }
104
137
  }
105
138
  else {
@@ -108,13 +141,20 @@ class Login extends command_1.Command {
108
141
  }
109
142
  }
110
143
  let issuer;
111
- let clientId;
112
144
  if (config_1.isProduction(this.config.configDir)) {
113
145
  issuer = await openid_client_1.Issuer.discover(ISSUER_PROD);
114
- clientId = CLIENT_ID_PROD;
115
146
  }
116
147
  else {
117
148
  issuer = await openid_client_1.Issuer.discover(ISSUER_DEV);
149
+ }
150
+ let clientId;
151
+ if (clientIdCandidate) {
152
+ clientId = clientIdCandidate;
153
+ }
154
+ else if (config_1.isProduction(this.config.configDir)) {
155
+ clientId = CLIENT_ID_PROD;
156
+ }
157
+ else {
118
158
  clientId = CLIENT_ID_DEV;
119
159
  }
120
160
  /* eslint-disable camelcase */
@@ -139,14 +179,19 @@ class Login extends command_1.Command {
139
179
  await open(handle.verification_uri_complete, { wait: false });
140
180
  const tokenSet = await handle.poll();
141
181
  const userInfo = await client.userinfo(tokenSet);
142
- await keytar.setPassword(credentials_1.OPAL_CREDS_KEY, (userInfo.email || 'unset-email') + '|' + organizationID, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || '');
182
+ let account = (userInfo.email || 'unset-email') + '|' + organizationID;
183
+ if (clientIdCandidate) {
184
+ // Save the clientIdCandidate only when SAML is set up for the org.
185
+ account = account + '|' + clientIdCandidate;
186
+ }
187
+ await keytar.setPassword(credentials_1.OPAL_CREDS_KEY, account, (tokenSet === null || tokenSet === void 0 ? void 0 : tokenSet.access_token) || '');
143
188
  // "Representative" authenticated call to check the log-in worked as expected.
144
189
  const { resp: authCheckResp, error: authCheckErr } = await handler_1.runQuery({
145
190
  command: this,
146
191
  query: exports.CLIAuthSessionCheckDocument,
147
192
  variables: {},
148
193
  });
149
- if (authCheckErr || !((_e = (_d = (_c = authCheckResp === null || authCheckResp === void 0 ? void 0 : authCheckResp.data) === null || _c === void 0 ? void 0 : _c.organizationSettings) === null || _d === void 0 ? void 0 : _d.settings) === null || _e === void 0 ? void 0 : _e.id)) {
194
+ if (authCheckErr || !((_g = (_f = (_e = authCheckResp === null || authCheckResp === void 0 ? void 0 : authCheckResp.data) === null || _e === void 0 ? void 0 : _e.organizationSettings) === null || _f === void 0 ? void 0 : _f.settings) === null || _g === void 0 ? void 0 : _g.id)) {
150
195
  this.log('Error verifying log in. Authenticated commands may fail. Please double check your URL and use `opal logout; opal login` to try again.\n');
151
196
  await credentials_1.cred.removeCredentials(-1);
152
197
  apollo_1.handleError(this, authCheckErr);
@@ -54,6 +54,9 @@ class StartPostgresInstanceSession extends command_1.Command {
54
54
  return;
55
55
  }
56
56
  const session = await sessions_1.getOrCreateSession(this, instanceId, accessLevel, sessionId, RdsSessionMetadataFragment, flags.refresh);
57
+ if (!session) {
58
+ return;
59
+ }
57
60
  const metadata = session.metadata;
58
61
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
59
62
  case 'AwsIamFederatedRdsSession': {
@@ -28,6 +28,9 @@ class StartSCPSession extends command_1.Command {
28
28
  instanceName = selectedInstance.name;
29
29
  }
30
30
  const session = await sessions_1.getOrCreateSession(this, instanceId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, start_1.Ec2SessionMetadataFragment);
31
+ if (!session) {
32
+ return;
33
+ }
31
34
  const metadata = session.metadata;
32
35
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
33
36
  case 'AwsIamFederatedSSMSession': {
@@ -28,6 +28,9 @@ class StartSCPSession extends command_1.Command {
28
28
  instanceName = selectedInstance.name;
29
29
  }
30
30
  const session = await sessions_1.getOrCreateSession(this, instanceId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, start_1.Ec2SessionMetadataFragment);
31
+ if (!session) {
32
+ return;
33
+ }
31
34
  const metadata = session.metadata;
32
35
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
33
36
  case 'AwsIamFederatedSSMSession': {
@@ -61,6 +61,9 @@ class StartSSHSession extends command_1.Command {
61
61
  (resp === null || resp === void 0 ? void 0 : resp.data.resource.resource.name) || 'ssh-instance';
62
62
  }
63
63
  const session = await sessions_1.getOrCreateSession(this, instanceId, resources_1.DEFAULT_ACCESS_LEVEL, sessionId, exports.Ec2SessionMetadataFragment, flags.refresh);
64
+ if (!session) {
65
+ return;
66
+ }
64
67
  const metadata = session.metadata;
65
68
  switch (metadata === null || metadata === void 0 ? void 0 : metadata.__typename) {
66
69
  case 'AwsIamFederatedSSMSession': {
package/lib/lib/apollo.js CHANGED
@@ -131,6 +131,11 @@ exports.initClient = async (command) => {
131
131
  // to the login screen again.
132
132
  return;
133
133
  }
134
+ if (operation.operationName === login_1.CLISignInMethodName) {
135
+ // We have special handling for this operation due to the fact that the backend version
136
+ // can be out of date and not include the new cliClientId field.
137
+ return;
138
+ }
134
139
  if (networkError && 'statusCode' in networkError) {
135
140
  let errorMessage = null;
136
141
  if ('result' in networkError) {
package/lib/lib/aws.js CHANGED
@@ -2,18 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAwsEnvVarMessage = exports.getAwsConfigUpdateCmd = void 0;
4
4
  const opalProfileKey = 'opal';
5
- const kebabCase = (str) => {
6
- return str.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[\s_]+/g, '-').toLowerCase();
7
- };
8
5
  const sanitize = (str) => {
9
- // remove non standard characters
10
- let sanitizedStr = str.replace(/[^A-Za-z0-9- ]/g, '');
11
- // de-dupe spaces
6
+ // Remove non standard characters.
7
+ // Note: AWS supports profile names containing alphanumeric characters, symbols, and white spaces
8
+ // from the ASCII character set.
9
+ let sanitizedStr = str.replace(/[^A-Za-z0-9-_ ]/g, '');
10
+ // De-dupe spaces
12
11
  sanitizedStr = sanitizedStr.replace(/\s+/g, ' ');
13
- // map remaining spaces to '-;
12
+ // Map remaining spaces to '-'
14
13
  sanitizedStr = sanitizedStr.replace(/ /g, '-');
15
- // convert to kebab case
16
- sanitizedStr = kebabCase(sanitizedStr);
17
14
  return sanitizedStr;
18
15
  };
19
16
  exports.getAwsConfigUpdateCmd = (itemName, awsAccessKeyId, awsSecretAccessKey, awsSessionToken) => {
@@ -3,6 +3,7 @@ export declare const cred: {
3
3
  removeCredentials(after: number): Promise<void>;
4
4
  readonly accountId: Promise<string | undefined>;
5
5
  readonly organizationID: Promise<string | undefined>;
6
+ readonly clientIdCandidate: Promise<string | undefined>;
6
7
  readonly email: Promise<string | undefined>;
7
8
  readonly accessToken: Promise<string | undefined>;
8
9
  };
@@ -32,6 +32,20 @@ exports.cred = {
32
32
  if (!parts || parts.length <= 1) {
33
33
  return undefined;
34
34
  }
35
+ return parts[1];
36
+ })();
37
+ },
38
+ get clientIdCandidate() {
39
+ return (async () => {
40
+ const keyContents = await keytar.findCredentials(exports.OPAL_CREDS_KEY);
41
+ if (!keyContents[0]) {
42
+ return undefined;
43
+ }
44
+ const { account } = keyContents[0];
45
+ const parts = account.split('|');
46
+ if (!parts || parts.length <= 2) {
47
+ return undefined;
48
+ }
35
49
  return parts.pop();
36
50
  })();
37
51
  },
package/lib/types.d.ts CHANGED
@@ -4892,6 +4892,7 @@ export declare type SignInOrganization = {
4892
4892
  organizationName: Scalars['String'];
4893
4893
  enableSocialSignIn: Scalars['Boolean'];
4894
4894
  enableSAMLSignIn: Scalars['Boolean'];
4895
+ cliClientId?: Maybe<Scalars['String']>;
4895
4896
  };
4896
4897
  export declare type SignInOutput = SignInResult;
4897
4898
  export declare type SignInResult = {
@@ -1 +1 @@
1
- {"version":"2.1.1","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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false},"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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","char":"a","description":"The remote ID of the access level with which to access the resource."},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false}},"args":[]},"postgres-instances:start":{"id":"postgres-instances:start","description":"Starts a session to connect to 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","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","char":"a","description":"The remote ID of the access level with which to access the resource."},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false},"action":{"name":"action","type":"option","description":"Method of connecting to the database.\n- open: Open external database app\n- psql: Start psql session in shell\n- view: View connection configuration details","options":["open","psql","view"]}},"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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"}},"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 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":"The directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"The 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was 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 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":"The directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"The 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false}},"args":[]}}}
1
+ {"version":"2.1.3","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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false},"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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","char":"a","description":"The remote ID of the access level with which to access the resource."},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false}},"args":[]},"postgres-instances:start":{"id":"postgres-instances:start","description":"Starts a session to connect to 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","opal postgres-instances:start --id 51f7176b-0464-4a6f-8369-e951e187b398 --accessLevelRemoteId fullaccess --action view"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"id":{"name":"id","type":"option","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"accessLevelRemoteId":{"name":"accessLevelRemoteId","type":"option","char":"a","description":"The remote ID of the access level with which to access the resource."},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false},"action":{"name":"action","type":"option","description":"Method of connecting to the database.\n- open: Open external database app\n- psql: Start psql session in shell\n- view: View connection configuration details","options":["open","psql","view"]}},"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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"}},"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 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":"The directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"The 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was 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 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":"The directory you want your files to be copied to.","required":false,"default":"."},"user":{"name":"user","type":"option","description":"The 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was 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","char":"i","description":"The Opal ID of the resource. You can find this from the URL, e.g. https://opal.dev/resources/[ID]"},"sessionId":{"name":"sessionId","type":"option","char":"s","description":"The Opal ID of the session to connect to. Uses an existing session that was created via the web flow."},"refresh":{"name":"refresh","type":"boolean","char":"r","description":"Starts a new session even if one already exists. Useful if a session is about to expire.","allowNo":false}},"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.1.1",
4
+ "version": "2.1.3",
5
5
  "author": "Stephen Cobbe",
6
6
  "bin": {
7
7
  "opal": "./bin/run"