@uipath/identity-commands 1.204.0 → 1.205.0-preview.258

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.
Files changed (2) hide show
  1. package/dist/index.js +141 -29
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2277,6 +2277,16 @@ class NodeFileSystem {
2277
2277
  async rename(oldPath, newPath) {
2278
2278
  await fs.rename(oldPath, newPath);
2279
2279
  }
2280
+ async isSymbolicLink(filePath) {
2281
+ try {
2282
+ return (await fs.lstat(filePath)).isSymbolicLink();
2283
+ } catch (error) {
2284
+ if (this.isEnoent(error) || this.hasErrnoCode(error, "ENOTDIR")) {
2285
+ return false;
2286
+ }
2287
+ throw error;
2288
+ }
2289
+ }
2280
2290
  async realpath(filePath) {
2281
2291
  try {
2282
2292
  return await fs.realpath(filePath);
@@ -3312,7 +3322,7 @@ function setGlobalLogFilePath(path2) {
3312
3322
  function getGlobalLogFilePath() {
3313
3323
  return logFilePathSlot.get("");
3314
3324
  }
3315
- var DEFAULT_LOG_LEVEL = 3 /* ERROR */;
3325
+ var DEFAULT_LOG_LEVEL = 2 /* WARN */;
3316
3326
 
3317
3327
  class SimpleLogger {
3318
3328
  __brand = "SimpleLogger";
@@ -3579,7 +3589,9 @@ var ErrorDimensions = {
3579
3589
  Result: "Result",
3580
3590
  ErrorCode: "ErrorCode",
3581
3591
  Retry: "Retry",
3582
- ErrorMessage: "ErrorMessage"
3592
+ ErrorMessage: "ErrorMessage",
3593
+ HttpStatus: "HttpStatus",
3594
+ UpstreamErrorCode: "UpstreamErrorCode"
3583
3595
  };
3584
3596
  var AuthDimensions = {
3585
3597
  AuthenticationMethod: "AuthenticationMethod",
@@ -4567,7 +4579,9 @@ var CLI_ERROR_CODES = [
4567
4579
  "timeout",
4568
4580
  "server_error",
4569
4581
  "method_not_allowed",
4582
+ "not_supported",
4570
4583
  "configuration_error",
4584
+ "execution_failed",
4571
4585
  "unknown_error"
4572
4586
  ];
4573
4587
  var RETRY_HINTS = [
@@ -5524,7 +5538,9 @@ var OutputFormatter;
5524
5538
  [ErrorDimensions.Result]: data.Result,
5525
5539
  [ErrorDimensions.ErrorCode]: data.ErrorCode,
5526
5540
  [ErrorDimensions.Retry]: data.Retry,
5527
- [ErrorDimensions.ErrorMessage]: data.Message
5541
+ [ErrorDimensions.ErrorMessage]: data.Message,
5542
+ [ErrorDimensions.HttpStatus]: data.Context?.httpStatus?.toString(),
5543
+ [ErrorDimensions.UpstreamErrorCode]: data.Context?.errorCode
5528
5544
  });
5529
5545
  }
5530
5546
  logOutput(normalizeOutputKeys(envelope), getOutputFormat());
@@ -6710,7 +6726,7 @@ var package_default = {
6710
6726
  name: "@uipath/identity-sdk",
6711
6727
  author: "UiPath",
6712
6728
  license: "SEE LICENSE IN LICENSE.txt",
6713
- version: "1.204.0",
6729
+ version: "1.205.0",
6714
6730
  repository: {
6715
6731
  type: "git",
6716
6732
  url: "https://github.com/UiPath/cli.git",
@@ -9375,22 +9391,12 @@ var resolveConfigAsync = async ({
9375
9391
  baseUrl = DEFAULT_BASE_URL;
9376
9392
  }
9377
9393
  baseUrl = normalizeAndValidateBaseUrl(baseUrl);
9378
- let clientId = customClientId;
9379
- if (!clientId && fileAuth.clientId) {
9380
- clientId = fileAuth.clientId;
9381
- }
9382
- if (!clientId) {
9383
- clientId = DEFAULT_CLIENT_ID;
9384
- }
9385
- let clientSecret = customClientSecret;
9386
- if (!clientSecret && fileAuth.clientSecret) {
9387
- clientSecret = fileAuth.clientSecret;
9388
- }
9389
- const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
9394
+ const clientId = customClientId || DEFAULT_CLIENT_ID;
9395
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
9390
9396
  const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
9391
9397
  return {
9392
9398
  clientId,
9393
- clientSecret,
9399
+ clientSecret: customClientSecret,
9394
9400
  scopes,
9395
9401
  baseUrl,
9396
9402
  authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
@@ -9564,6 +9570,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
9564
9570
  }
9565
9571
  return;
9566
9572
  };
9573
+ var resolveApplicationSubtype = (claims, authFlow) => {
9574
+ switch (asString(claims?.sub_type)) {
9575
+ case "service.external":
9576
+ return "External";
9577
+ case "service.internal":
9578
+ return "Internal";
9579
+ default:
9580
+ return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
9581
+ }
9582
+ };
9567
9583
  var looksLikeEmail = (value) => value?.includes("@") ?? false;
9568
9584
  var pickEmail = (claims) => {
9569
9585
  for (const candidate of [claims?.email, claims?.preferred_username]) {
@@ -9605,6 +9621,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
9605
9621
  const clientId = asString(claims?.client_id);
9606
9622
  if (clientId)
9607
9623
  identity.clientId = clientId;
9624
+ const subType = asString(claims?.sub_type);
9625
+ if (subType)
9626
+ identity.subType = subType;
9627
+ const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
9628
+ if (applicationSubtype)
9629
+ identity.applicationSubtype = applicationSubtype;
9608
9630
  return identity;
9609
9631
  };
9610
9632
  var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
@@ -9897,6 +9919,40 @@ var tryRobotClientFallback = async (options = {}) => {
9897
9919
  }
9898
9920
  };
9899
9921
 
9922
+ // ../../auth/src/tenantSelection.ts
9923
+ var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
9924
+ var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
9925
+ var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
9926
+ var describeNonJsonResponse = (organizationId, response, parseError) => {
9927
+ if (response.redirected) {
9928
+ return `Could not find organization '${organizationId}': the request was ` + `redirected to a sign-in page instead of the organization's tenant ` + `list. ${LOGIN_STATUS_HINT}`;
9929
+ }
9930
+ const contentType = response.headers.get("content-type") ?? "unknown";
9931
+ return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
9932
+ };
9933
+ var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
9934
+ const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
9935
+ const response = await fetch(url, {
9936
+ headers: {
9937
+ Authorization: `Bearer ${accessToken}`
9938
+ },
9939
+ ...signal ? { signal } : {}
9940
+ });
9941
+ if (!response.ok) {
9942
+ if (response.status === 401) {
9943
+ throw new Error(`Unauthorized: the access token was rejected, it was not ` + `issued for organization '${organizationId}', or ` + `'${organizationId}' was not accepted as an organization ` + `URL segment in this environment. ` + LOGIN_STATUS_HINT);
9944
+ }
9945
+ const errorText = await response.text();
9946
+ const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
9947
+ throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
9948
+ }
9949
+ const [parseError, data] = await catchError2(response.json());
9950
+ if (parseError) {
9951
+ throw new Error(describeNonJsonResponse(organizationId, response, parseError));
9952
+ }
9953
+ return data;
9954
+ };
9955
+
9900
9956
  // ../../auth/src/tokenRefresh.ts
9901
9957
  var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
9902
9958
 
@@ -10109,6 +10165,8 @@ var saveEnvFileAsync = async ({
10109
10165
  };
10110
10166
 
10111
10167
  // ../../auth/src/loginStatus.ts
10168
+ var defaultRobotTenantIdCache = new Map;
10169
+ var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
10112
10170
  var getLoginStatusAsync = async (options = {}) => {
10113
10171
  return getLoginStatusWithDeps(options);
10114
10172
  };
@@ -10121,12 +10179,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
10121
10179
  refreshToken: refreshTokenFn = refreshAccessToken,
10122
10180
  resolveConfig = resolveConfigAsync,
10123
10181
  robotFallback = tryRobotClientFallback,
10182
+ fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
10183
+ robotTenantIdCache = defaultRobotTenantIdCache,
10184
+ robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
10124
10185
  loadBreaker = loadRefreshBreaker,
10125
10186
  saveBreaker = saveRefreshBreaker,
10126
10187
  clearBreaker = clearRefreshBreaker
10127
10188
  } = deps;
10189
+ const robotDeps = {
10190
+ fetchTenantsAndOrgs,
10191
+ cache: robotTenantIdCache,
10192
+ lookupTimeoutMs: robotTenantLookupTimeoutMs
10193
+ };
10128
10194
  if (isRobotAuthEnforced()) {
10129
- return resolveRobotEnforcedStatus(robotFallback);
10195
+ return resolveRobotEnforcedStatus(robotFallback, robotDeps);
10130
10196
  }
10131
10197
  if (isEnvAuthEnabled()) {
10132
10198
  return readAuthFromEnv();
@@ -10144,7 +10210,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
10144
10210
  hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
10145
10211
  };
10146
10212
  }
10147
- return resolveBorrowedRobotStatus(robotFallback);
10213
+ return resolveBorrowedRobotStatus(robotFallback, robotDeps);
10148
10214
  }
10149
10215
  const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
10150
10216
  if ("status" in loaded) {
@@ -10186,7 +10252,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
10186
10252
  }
10187
10253
  return buildFileStatus(tokens, credentials, globalHint);
10188
10254
  };
10189
- async function resolveRobotEnforcedStatus(robotFallback) {
10255
+ async function resolveRobotEnforcedStatus(robotFallback, deps) {
10190
10256
  if (isEnvAuthEnabled()) {
10191
10257
  throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
10192
10258
  }
@@ -10197,11 +10263,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
10197
10263
  hint: `${ENFORCE_ROBOT_AUTH_VAR}=true but the UiPath Robot ` + `session is unavailable. Start and sign in to the Assistant, ` + `or unset ${ENFORCE_ROBOT_AUTH_VAR} to fall back to file or ` + `env-var authentication.`
10198
10264
  };
10199
10265
  }
10200
- return buildRobotStatus(robotCreds);
10266
+ return buildRobotStatus(robotCreds, deps);
10201
10267
  }
10202
- async function resolveBorrowedRobotStatus(robotFallback) {
10268
+ async function resolveBorrowedRobotStatus(robotFallback, deps) {
10203
10269
  const robotCreds = await robotFallback();
10204
- return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
10270
+ return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
10205
10271
  }
10206
10272
  async function loadFileCredentials(loadEnvFile, absolutePath) {
10207
10273
  let credentials;
@@ -10336,9 +10402,10 @@ function identityFields(accessToken, credentials) {
10336
10402
  ...scopes ? { scopes } : {}
10337
10403
  };
10338
10404
  }
10339
- function buildRobotStatus(robotCreds) {
10405
+ async function buildRobotStatus(robotCreds, deps) {
10340
10406
  const identity = resolveSessionIdentity(robotCreds.accessToken);
10341
10407
  const scopes = readTokenScopes(robotCreds.accessToken);
10408
+ const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
10342
10409
  return {
10343
10410
  loginStatus: "Logged in",
10344
10411
  accessToken: robotCreds.accessToken,
@@ -10346,14 +10413,62 @@ function buildRobotStatus(robotCreds) {
10346
10413
  organizationName: robotCreds.organizationName,
10347
10414
  organizationId: robotCreds.organizationId,
10348
10415
  tenantName: robotCreds.tenantName,
10349
- tenantId: robotCreds.tenantId,
10416
+ tenantId: tenant.tenantId,
10350
10417
  issuer: robotCreds.issuer,
10351
10418
  expiration: getTokenExpiration(robotCreds.accessToken),
10352
10419
  source: "robot" /* Robot */,
10420
+ ...tenant.hint ? { hint: tenant.hint } : {},
10353
10421
  ...identity ? { identity } : {},
10354
10422
  ...scopes ? { scopes } : {}
10355
10423
  };
10356
10424
  }
10425
+ async function resolveRobotTenantId(robotCreds, deps) {
10426
+ const { baseUrl, accessToken, tenantName } = robotCreds;
10427
+ const organization = robotCreds.organizationName ?? robotCreds.organizationId;
10428
+ if (!tenantName || !organization) {
10429
+ return {};
10430
+ }
10431
+ const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
10432
+ let pending = deps.cache.get(key);
10433
+ if (!pending) {
10434
+ pending = catchError2(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
10435
+ const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
10436
+ if (!settled.tenantId) {
10437
+ deps.cache.delete(key);
10438
+ }
10439
+ return settled;
10440
+ });
10441
+ deps.cache.set(key, pending);
10442
+ }
10443
+ return pending;
10444
+ }
10445
+ async function lookupRobotTenantId(target, deps) {
10446
+ const { baseUrl, accessToken, organization, tenantName } = target;
10447
+ const [error, data] = await catchError2(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
10448
+ if (error) {
10449
+ const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
10450
+ return { hint: tenantLookupFailureHint(tenantName, reason) };
10451
+ }
10452
+ const rows = data?.tenants;
10453
+ const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
10454
+ const wantedName = decodePathSegment(tenantName);
10455
+ const wanted = wantedName.toLowerCase();
10456
+ const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
10457
+ if (!match) {
10458
+ const names = tenants.map((tenant) => tenant.name).join(", ");
10459
+ return {
10460
+ hint: `The Robot session targets tenant '${tenantName}', but ` + `organization '${organization}' lists no tenant of that name` + `${names ? ` (available: ${names})` : ""}. Commands that need ` + `the tenant id will fail until it can be resolved.`
10461
+ };
10462
+ }
10463
+ return { tenantId: match.id };
10464
+ }
10465
+ function tenantLookupFailureHint(tenantName, reason) {
10466
+ return `Could not resolve the id of tenant '${tenantName}' from the ` + `Robot session: ${reason} Commands that need the tenant id will ` + `fail until it can be resolved.`;
10467
+ }
10468
+ function decodePathSegment(segment) {
10469
+ const [error, decoded] = catchError2(() => decodeURIComponent(segment));
10470
+ return error ? segment : decoded;
10471
+ }
10357
10472
  var isFileNotFoundError = (error) => {
10358
10473
  if (!(error instanceof Object))
10359
10474
  return false;
@@ -10622,9 +10737,6 @@ var getAuthContext = async (options = {}) => {
10622
10737
  identity: status.identity
10623
10738
  };
10624
10739
  };
10625
- // ../../auth/src/tenantSelection.ts
10626
- var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
10627
-
10628
10740
  // ../../auth/src/selectTenant.ts
10629
10741
  var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
10630
10742
  var INVALID_TENANT_CODE = "INVALID_TENANT";
@@ -13008,4 +13120,4 @@ export {
13008
13120
  registerCommands
13009
13121
  };
13010
13122
 
13011
- //# debugId=25FA4B6CAC582C8964756E2164756E21
13123
+ //# debugId=2614B63C0A818C8964756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/identity-commands",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.204.0",
5
+ "version": "1.205.0-preview.258",
6
6
  "description": "Admin CLI commands for Identity Server users, groups, robot accounts, and external apps. Library composed by admin-tool, not a standalone CLI tool.",
7
7
  "private": false,
8
8
  "repository": {
@@ -26,5 +26,5 @@
26
26
  "files": [
27
27
  "dist"
28
28
  ],
29
- "gitHead": "699c58dabb59414557755a8933bcbe40aa420df3"
29
+ "gitHead": "8f629ee9fa89abf94f197436a60cb3b9620f8b27"
30
30
  }