@uipath/authz-commands 1.204.0-preview.255 → 1.205.0-preview.256

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 +142 -30
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2206,22 +2206,12 @@ var resolveConfigAsync = async ({
2206
2206
  baseUrl = DEFAULT_BASE_URL;
2207
2207
  }
2208
2208
  baseUrl = normalizeAndValidateBaseUrl(baseUrl);
2209
- let clientId = customClientId;
2210
- if (!clientId && fileAuth.clientId) {
2211
- clientId = fileAuth.clientId;
2212
- }
2213
- if (!clientId) {
2214
- clientId = DEFAULT_CLIENT_ID;
2215
- }
2216
- let clientSecret = customClientSecret;
2217
- if (!clientSecret && fileAuth.clientSecret) {
2218
- clientSecret = fileAuth.clientSecret;
2219
- }
2220
- const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(clientSecret) || Boolean(customClientAssertion));
2209
+ const clientId = customClientId || DEFAULT_CLIENT_ID;
2210
+ const isExternalAppAuth = clientId !== DEFAULT_CLIENT_ID && (Boolean(customClientSecret) || Boolean(customClientAssertion));
2221
2211
  const scopes = resolveScopes(isExternalAppAuth, customScopes, fileAuth.scopes);
2222
2212
  return {
2223
2213
  clientId,
2224
- clientSecret,
2214
+ clientSecret: customClientSecret,
2225
2215
  scopes,
2226
2216
  baseUrl,
2227
2217
  authorizationEndpoint: `${baseUrl}/identity_/connect/authorize`,
@@ -2414,6 +2404,16 @@ class NodeFileSystem {
2414
2404
  async rename(oldPath, newPath) {
2415
2405
  await fs.rename(oldPath, newPath);
2416
2406
  }
2407
+ async isSymbolicLink(filePath) {
2408
+ try {
2409
+ return (await fs.lstat(filePath)).isSymbolicLink();
2410
+ } catch (error) {
2411
+ if (this.isEnoent(error) || this.hasErrnoCode(error, "ENOTDIR")) {
2412
+ return false;
2413
+ }
2414
+ throw error;
2415
+ }
2416
+ }
2417
2417
  async realpath(filePath) {
2418
2418
  try {
2419
2419
  return await fs.realpath(filePath);
@@ -2625,6 +2625,16 @@ var resolveIdentityType = (claims, authFlow, email) => {
2625
2625
  }
2626
2626
  return;
2627
2627
  };
2628
+ var resolveApplicationSubtype = (claims, authFlow) => {
2629
+ switch (asString(claims?.sub_type)) {
2630
+ case "service.external":
2631
+ return "External";
2632
+ case "service.internal":
2633
+ return "Internal";
2634
+ default:
2635
+ return authFlow === "client_credentials" || authFlow === "federated_credentials" ? "External" : undefined;
2636
+ }
2637
+ };
2628
2638
  var looksLikeEmail = (value) => value?.includes("@") ?? false;
2629
2639
  var pickEmail = (claims) => {
2630
2640
  for (const candidate of [claims?.email, claims?.preferred_username]) {
@@ -2666,6 +2676,12 @@ var resolveSessionIdentity = (accessToken, authFlow) => {
2666
2676
  const clientId = asString(claims?.client_id);
2667
2677
  if (clientId)
2668
2678
  identity.clientId = clientId;
2679
+ const subType = asString(claims?.sub_type);
2680
+ if (subType)
2681
+ identity.subType = subType;
2682
+ const applicationSubtype = resolveApplicationSubtype(claims, authFlow);
2683
+ if (applicationSubtype)
2684
+ identity.applicationSubtype = applicationSubtype;
2669
2685
  return identity;
2670
2686
  };
2671
2687
  var readTokenScopes = (accessToken) => accessToken ? pickScopes(decodeClaims(accessToken)) : undefined;
@@ -2958,6 +2974,40 @@ var tryRobotClientFallback = async (options = {}) => {
2958
2974
  }
2959
2975
  };
2960
2976
 
2977
+ // ../../auth/src/tenantSelection.ts
2978
+ var LOGIN_STATUS_HINT = "Run 'uip login status' to see the organization the CLI is signed in to.";
2979
+ var organizationHint = (organizationId) => `The request used '${organizationId}' as the organization. ${LOGIN_STATUS_HINT}`;
2980
+ var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
2981
+ var describeNonJsonResponse = (organizationId, response, parseError) => {
2982
+ if (response.redirected) {
2983
+ 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}`;
2984
+ }
2985
+ const contentType = response.headers.get("content-type") ?? "unknown";
2986
+ return `The organization service returned a '${contentType}' response instead ` + `of JSON: ${parseError.message}. ${organizationHint(organizationId)}`;
2987
+ };
2988
+ var fetchTenantsAndOrganizations = async (baseUrl, accessToken, organizationId, signal) => {
2989
+ const url = `${baseUrl}/${organizationId}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo`;
2990
+ const response = await fetch(url, {
2991
+ headers: {
2992
+ Authorization: `Bearer ${accessToken}`
2993
+ },
2994
+ ...signal ? { signal } : {}
2995
+ });
2996
+ if (!response.ok) {
2997
+ if (response.status === 401) {
2998
+ 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);
2999
+ }
3000
+ const errorText = await response.text();
3001
+ const message = `Failed to get tenants and organizations: ${response.status} ${errorText}`;
3002
+ throw new Error(IDENTIFIER_STATUSES.has(response.status) ? `${message}. ${organizationHint(organizationId)}` : message);
3003
+ }
3004
+ const [parseError, data] = await catchError(response.json());
3005
+ if (parseError) {
3006
+ throw new Error(describeNonJsonResponse(organizationId, response, parseError));
3007
+ }
3008
+ return data;
3009
+ };
3010
+
2961
3011
  // ../../auth/src/tokenRefresh.ts
2962
3012
  var TOKEN_REFRESH_REAUTHENTICATE_MESSAGE = "Token refresh failed. Run 'uip login' to re-authenticate.";
2963
3013
 
@@ -3170,6 +3220,8 @@ var saveEnvFileAsync = async ({
3170
3220
  };
3171
3221
 
3172
3222
  // ../../auth/src/loginStatus.ts
3223
+ var defaultRobotTenantIdCache = new Map;
3224
+ var ROBOT_TENANT_LOOKUP_TIMEOUT_MS = 5000;
3173
3225
  var getLoginStatusAsync = async (options = {}) => {
3174
3226
  return getLoginStatusWithDeps(options);
3175
3227
  };
@@ -3182,12 +3234,20 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
3182
3234
  refreshToken: refreshTokenFn = refreshAccessToken,
3183
3235
  resolveConfig = resolveConfigAsync,
3184
3236
  robotFallback = tryRobotClientFallback,
3237
+ fetchTenantsAndOrgs = fetchTenantsAndOrganizations,
3238
+ robotTenantIdCache = defaultRobotTenantIdCache,
3239
+ robotTenantLookupTimeoutMs = ROBOT_TENANT_LOOKUP_TIMEOUT_MS,
3185
3240
  loadBreaker = loadRefreshBreaker,
3186
3241
  saveBreaker = saveRefreshBreaker,
3187
3242
  clearBreaker = clearRefreshBreaker
3188
3243
  } = deps;
3244
+ const robotDeps = {
3245
+ fetchTenantsAndOrgs,
3246
+ cache: robotTenantIdCache,
3247
+ lookupTimeoutMs: robotTenantLookupTimeoutMs
3248
+ };
3189
3249
  if (isRobotAuthEnforced()) {
3190
- return resolveRobotEnforcedStatus(robotFallback);
3250
+ return resolveRobotEnforcedStatus(robotFallback, robotDeps);
3191
3251
  }
3192
3252
  if (isEnvAuthEnabled()) {
3193
3253
  return readAuthFromEnv();
@@ -3205,7 +3265,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
3205
3265
  hint: `No credentials found for profile "${activeProfile}". Run 'uip login --profile ${activeProfile}' to authenticate this profile.`
3206
3266
  };
3207
3267
  }
3208
- return resolveBorrowedRobotStatus(robotFallback);
3268
+ return resolveBorrowedRobotStatus(robotFallback, robotDeps);
3209
3269
  }
3210
3270
  const loaded = await loadFileCredentials(loadEnvFile, absolutePath);
3211
3271
  if ("status" in loaded) {
@@ -3247,7 +3307,7 @@ var getLoginStatusWithDeps = async (options = {}, deps = {}) => {
3247
3307
  }
3248
3308
  return buildFileStatus(tokens, credentials, globalHint);
3249
3309
  };
3250
- async function resolveRobotEnforcedStatus(robotFallback) {
3310
+ async function resolveRobotEnforcedStatus(robotFallback, deps) {
3251
3311
  if (isEnvAuthEnabled()) {
3252
3312
  throw new EnvAuthConfigError(`${ENV_AUTH_ENABLE_VAR}=true and ${ENFORCE_ROBOT_AUTH_VAR}=true ` + `are mutually exclusive. Unset one of them and re-run.`);
3253
3313
  }
@@ -3258,11 +3318,11 @@ async function resolveRobotEnforcedStatus(robotFallback) {
3258
3318
  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.`
3259
3319
  };
3260
3320
  }
3261
- return buildRobotStatus(robotCreds);
3321
+ return buildRobotStatus(robotCreds, deps);
3262
3322
  }
3263
- async function resolveBorrowedRobotStatus(robotFallback) {
3323
+ async function resolveBorrowedRobotStatus(robotFallback, deps) {
3264
3324
  const robotCreds = await robotFallback();
3265
- return robotCreds ? buildRobotStatus(robotCreds) : { loginStatus: "Not logged in" };
3325
+ return robotCreds ? buildRobotStatus(robotCreds, deps) : { loginStatus: "Not logged in" };
3266
3326
  }
3267
3327
  async function loadFileCredentials(loadEnvFile, absolutePath) {
3268
3328
  let credentials;
@@ -3397,9 +3457,10 @@ function identityFields(accessToken, credentials) {
3397
3457
  ...scopes ? { scopes } : {}
3398
3458
  };
3399
3459
  }
3400
- function buildRobotStatus(robotCreds) {
3460
+ async function buildRobotStatus(robotCreds, deps) {
3401
3461
  const identity = resolveSessionIdentity(robotCreds.accessToken);
3402
3462
  const scopes = readTokenScopes(robotCreds.accessToken);
3463
+ const tenant = robotCreds.tenantId ? { tenantId: robotCreds.tenantId } : await resolveRobotTenantId(robotCreds, deps);
3403
3464
  return {
3404
3465
  loginStatus: "Logged in",
3405
3466
  accessToken: robotCreds.accessToken,
@@ -3407,14 +3468,62 @@ function buildRobotStatus(robotCreds) {
3407
3468
  organizationName: robotCreds.organizationName,
3408
3469
  organizationId: robotCreds.organizationId,
3409
3470
  tenantName: robotCreds.tenantName,
3410
- tenantId: robotCreds.tenantId,
3471
+ tenantId: tenant.tenantId,
3411
3472
  issuer: robotCreds.issuer,
3412
3473
  expiration: getTokenExpiration(robotCreds.accessToken),
3413
3474
  source: "robot" /* Robot */,
3475
+ ...tenant.hint ? { hint: tenant.hint } : {},
3414
3476
  ...identity ? { identity } : {},
3415
3477
  ...scopes ? { scopes } : {}
3416
3478
  };
3417
3479
  }
3480
+ async function resolveRobotTenantId(robotCreds, deps) {
3481
+ const { baseUrl, accessToken, tenantName } = robotCreds;
3482
+ const organization = robotCreds.organizationName ?? robotCreds.organizationId;
3483
+ if (!tenantName || !organization) {
3484
+ return {};
3485
+ }
3486
+ const key = `${baseUrl}|${organization}|${tenantName}|${accessToken}`;
3487
+ let pending = deps.cache.get(key);
3488
+ if (!pending) {
3489
+ pending = catchError(lookupRobotTenantId({ baseUrl, accessToken, organization, tenantName }, deps)).then(([error, resolution]) => {
3490
+ const settled = error ? { hint: tenantLookupFailureHint(tenantName, error.message) } : resolution;
3491
+ if (!settled.tenantId) {
3492
+ deps.cache.delete(key);
3493
+ }
3494
+ return settled;
3495
+ });
3496
+ deps.cache.set(key, pending);
3497
+ }
3498
+ return pending;
3499
+ }
3500
+ async function lookupRobotTenantId(target, deps) {
3501
+ const { baseUrl, accessToken, organization, tenantName } = target;
3502
+ const [error, data] = await catchError(deps.fetchTenantsAndOrgs(baseUrl, accessToken, organization, AbortSignal.timeout(deps.lookupTimeoutMs)));
3503
+ if (error) {
3504
+ const reason = error.name === "TimeoutError" ? `the tenant list did not answer within ${deps.lookupTimeoutMs} ms.` : error.message;
3505
+ return { hint: tenantLookupFailureHint(tenantName, reason) };
3506
+ }
3507
+ const rows = data?.tenants;
3508
+ const tenants = Array.isArray(rows) ? rows.filter((tenant) => typeof tenant?.id === "string" && typeof tenant?.name === "string") : [];
3509
+ const wantedName = decodePathSegment(tenantName);
3510
+ const wanted = wantedName.toLowerCase();
3511
+ const match = tenants.find((tenant) => tenant.name === wantedName) ?? tenants.find((tenant) => tenant.name.toLowerCase() === wanted);
3512
+ if (!match) {
3513
+ const names = tenants.map((tenant) => tenant.name).join(", ");
3514
+ return {
3515
+ 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.`
3516
+ };
3517
+ }
3518
+ return { tenantId: match.id };
3519
+ }
3520
+ function tenantLookupFailureHint(tenantName, reason) {
3521
+ 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.`;
3522
+ }
3523
+ function decodePathSegment(segment) {
3524
+ const [error, decoded] = catchError(() => decodeURIComponent(segment));
3525
+ return error ? segment : decoded;
3526
+ }
3418
3527
  var isFileNotFoundError = (error) => {
3419
3528
  if (!(error instanceof Object))
3420
3529
  return false;
@@ -3683,9 +3792,6 @@ var getAuthContext = async (options = {}) => {
3683
3792
  identity: status.identity
3684
3793
  };
3685
3794
  };
3686
- // ../../auth/src/tenantSelection.ts
3687
- var IDENTIFIER_STATUSES = new Set([400, 403, 404]);
3688
-
3689
3795
  // ../../auth/src/selectTenant.ts
3690
3796
  var TENANT_SELECTION_REQUIRED_CODE = "TENANT_SELECTION_REQUIRED";
3691
3797
  var INVALID_TENANT_CODE = "INVALID_TENANT";
@@ -3782,7 +3888,9 @@ var ErrorDimensions = {
3782
3888
  Result: "Result",
3783
3889
  ErrorCode: "ErrorCode",
3784
3890
  Retry: "Retry",
3785
- ErrorMessage: "ErrorMessage"
3891
+ ErrorMessage: "ErrorMessage",
3892
+ HttpStatus: "HttpStatus",
3893
+ UpstreamErrorCode: "UpstreamErrorCode"
3786
3894
  };
3787
3895
  var AuthDimensions = {
3788
3896
  AuthenticationMethod: "AuthenticationMethod",
@@ -4206,7 +4314,7 @@ var package_default = {
4206
4314
  name: "@uipath/authz-sdk",
4207
4315
  author: "UiPath",
4208
4316
  license: "SEE LICENSE IN LICENSE.txt",
4209
- version: "1.204.0",
4317
+ version: "1.205.0",
4210
4318
  description: "SDK for the UiPath Authorization Service API.",
4211
4319
  repository: {
4212
4320
  type: "git",
@@ -5759,7 +5867,7 @@ function setGlobalLogFilePath(path2) {
5759
5867
  function getGlobalLogFilePath() {
5760
5868
  return logFilePathSlot.get("");
5761
5869
  }
5762
- var DEFAULT_LOG_LEVEL = 3 /* ERROR */;
5870
+ var DEFAULT_LOG_LEVEL = 2 /* WARN */;
5763
5871
 
5764
5872
  class SimpleLogger {
5765
5873
  __brand = "SimpleLogger";
@@ -6861,7 +6969,9 @@ var CLI_ERROR_CODES = [
6861
6969
  "timeout",
6862
6970
  "server_error",
6863
6971
  "method_not_allowed",
6972
+ "not_supported",
6864
6973
  "configuration_error",
6974
+ "execution_failed",
6865
6975
  "unknown_error"
6866
6976
  ];
6867
6977
  var RETRY_HINTS = [
@@ -7818,7 +7928,9 @@ var OutputFormatter;
7818
7928
  [ErrorDimensions.Result]: data.Result,
7819
7929
  [ErrorDimensions.ErrorCode]: data.ErrorCode,
7820
7930
  [ErrorDimensions.Retry]: data.Retry,
7821
- [ErrorDimensions.ErrorMessage]: data.Message
7931
+ [ErrorDimensions.ErrorMessage]: data.Message,
7932
+ [ErrorDimensions.HttpStatus]: data.Context?.httpStatus?.toString(),
7933
+ [ErrorDimensions.UpstreamErrorCode]: data.Context?.errorCode
7822
7934
  });
7823
7935
  }
7824
7936
  logOutput(normalizeOutputKeys(envelope), getOutputFormat());
@@ -8913,7 +9025,7 @@ var package_default2 = {
8913
9025
  name: "@uipath/identity-sdk",
8914
9026
  author: "UiPath",
8915
9027
  license: "SEE LICENSE IN LICENSE.txt",
8916
- version: "1.204.0",
9028
+ version: "1.205.0",
8917
9029
  repository: {
8918
9030
  type: "git",
8919
9031
  url: "https://github.com/UiPath/cli.git",
@@ -11369,4 +11481,4 @@ export {
11369
11481
  registerCommands
11370
11482
  };
11371
11483
 
11372
- //# debugId=8388DA7711B566A064756E2164756E21
11484
+ //# debugId=F2DB86481C2DAC6F64756E2164756E21
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@uipath/authz-commands",
3
3
  "author": "UiPath",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
- "version": "1.204.0-preview.255",
5
+ "version": "1.205.0-preview.256",
6
6
  "description": "Admin CLI commands for the UiPath Authorization service. 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": "63740c6cbb7ff282fa9118cc16a148eb030b245f"
30
30
  }