From 036d8ca37be4f9efeecff973dd0361b532335d24 Mon Sep 17 00:00:00 2001 From: simonfaltum Date: Tue, 9 Jun 2026 22:29:45 +0200 Subject: [PATCH 1/4] auth describe: try both verification endpoints before reporting failure getAuthStatus made exactly one verification call based on the client type MustAnyClient picked (account client -> Workspaces.List, workspace client -> CurrentUser.Me) and reported "Unable to authenticate" when that call failed, even when the credentials were valid. Account console profiles that also carry a workspace_id resolve to a workspace client, and CurrentUser.Me always fails against the accounts host (#5479). If the first verification call fails, build the other client type from the same resolved config (non-interactively, over the same config pointer) and try its verification call before reporting failure. If both fail, report the first error. Success paths still make exactly one call. Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 1 + .../out.test.toml | 3 + .../account-host-with-workspace-id/output.txt | 19 +++ .../account-host-with-workspace-id/script | 15 ++ .../account-host-with-workspace-id/test.toml | 14 ++ cmd/auth/describe.go | 104 ++++++++---- cmd/auth/describe_test.go | 157 ++++++++++++++++++ 7 files changed, 278 insertions(+), 35 deletions(-) create mode 100644 acceptance/cmd/auth/describe/account-host-with-workspace-id/out.test.toml create mode 100644 acceptance/cmd/auth/describe/account-host-with-workspace-id/output.txt create mode 100644 acceptance/cmd/auth/describe/account-host-with-workspace-id/script create mode 100644 acceptance/cmd/auth/describe/account-host-with-workspace-id/test.toml diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index db25ff3c12a..e9b1ef908b6 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,6 +7,7 @@ ### CLI * Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)). +* `databricks auth describe` now verifies credentials against both the workspace and account endpoints before reporting a failure, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)). ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). diff --git a/acceptance/cmd/auth/describe/account-host-with-workspace-id/out.test.toml b/acceptance/cmd/auth/describe/account-host-with-workspace-id/out.test.toml new file mode 100644 index 00000000000..f784a183258 --- /dev/null +++ b/acceptance/cmd/auth/describe/account-host-with-workspace-id/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/cmd/auth/describe/account-host-with-workspace-id/output.txt b/acceptance/cmd/auth/describe/account-host-with-workspace-id/output.txt new file mode 100644 index 00000000000..0cbc7f6a68c --- /dev/null +++ b/acceptance/cmd/auth/describe/account-host-with-workspace-id/output.txt @@ -0,0 +1,19 @@ + +=== Describe falls back to the account endpoint when the workspace check fails + +>>> [CLI] auth describe --profile acct-with-ws +Host: [DATABRICKS_URL] +Account ID: acct-123 +Authenticated with: pat +----- +Current configuration: + ✓ host: [DATABRICKS_URL] (from DATABRICKS_HOST environment variable) + ✓ account_id: acct-123 (from [TEST_TMP_DIR]/home/.databrickscfg config file) + ✓ workspace_id: [NUMID] (from [TEST_TMP_DIR]/home/.databrickscfg config file) + ✓ token: ******** (from DATABRICKS_TOKEN environment variable) + ✓ profile: acct-with-ws (from --profile flag) + ✓ databricks_cli_path: [CLI] + ✓ auth_type: pat + ✓ rate_limit: [NUMID] (from DATABRICKS_RATE_LIMIT environment variable) + ✓ cloud: AWS + ✓ discovery_url: [DATABRICKS_URL]/oidc/.well-known/oauth-authorization-server diff --git a/acceptance/cmd/auth/describe/account-host-with-workspace-id/script b/acceptance/cmd/auth/describe/account-host-with-workspace-id/script new file mode 100644 index 00000000000..5dec6460178 --- /dev/null +++ b/acceptance/cmd/auth/describe/account-host-with-workspace-id/script @@ -0,0 +1,15 @@ +sethome "./home" + +# Older logins wrote account console profiles with both account_id and +# workspace_id, which resolves to a workspace client even though the host only +# serves account APIs (https://github.com/databricks/cli/issues/5479). +cat > "./home/.databrickscfg" < Date: Tue, 9 Jun 2026 22:35:40 +0200 Subject: [PATCH 2/4] auth describe: treat permission-denied as proof of authentication A 403 response means the server authenticated the caller and refused the operation; invalid credentials produce a 401. When both verification endpoints fail but at least one failure is an HTTP 403 API error, report success instead of failure. This makes describe truthful for non-admin users on account hosts, where Workspaces.List is account-admin-only (returns 403) and the account console cannot serve CurrentUser.Me (returns 400), so both checks fail even though the credentials are perfectly valid. Username stays empty in this case; the output template omits it. Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 2 +- .../account-permission-denied/out.test.toml | 3 ++ .../account-permission-denied/output.txt | 19 +++++++ .../describe/account-permission-denied/script | 21 ++++++++ .../account-permission-denied/test.toml | 20 ++++++++ cmd/auth/describe.go | 27 +++++++++- cmd/auth/describe_test.go | 50 +++++++++++++++++++ 7 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 acceptance/cmd/auth/describe/account-permission-denied/out.test.toml create mode 100644 acceptance/cmd/auth/describe/account-permission-denied/output.txt create mode 100644 acceptance/cmd/auth/describe/account-permission-denied/script create mode 100644 acceptance/cmd/auth/describe/account-permission-denied/test.toml diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index e9b1ef908b6..fa20645e1b5 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,7 +7,7 @@ ### CLI * Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)). -* `databricks auth describe` now verifies credentials against both the workspace and account endpoints before reporting a failure, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)). +* `databricks auth describe` now verifies credentials against both the workspace and account endpoints and treats permission-denied responses as proof of successful authentication, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)). ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). diff --git a/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml b/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml new file mode 100644 index 00000000000..f784a183258 --- /dev/null +++ b/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml @@ -0,0 +1,3 @@ +Local = true +Cloud = false +EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/cmd/auth/describe/account-permission-denied/output.txt b/acceptance/cmd/auth/describe/account-permission-denied/output.txt new file mode 100644 index 00000000000..b7febcaf536 --- /dev/null +++ b/acceptance/cmd/auth/describe/account-permission-denied/output.txt @@ -0,0 +1,19 @@ + +=== Permission denied still proves the credentials are valid + +>>> [CLI] auth describe --profile acct-nonadmin +Host: [DATABRICKS_URL] +Account ID: acct-456 +Authenticated with: pat +----- +Current configuration: + ✓ host: [DATABRICKS_URL] (from DATABRICKS_HOST environment variable) + ✓ account_id: acct-456 (from [TEST_TMP_DIR]/home/.databrickscfg config file) + ✓ workspace_id: none (from [TEST_TMP_DIR]/home/.databrickscfg config file) + ✓ token: ******** (from DATABRICKS_TOKEN environment variable) + ✓ profile: acct-nonadmin (from --profile flag) + ✓ databricks_cli_path: [CLI] + ✓ auth_type: pat + ✓ rate_limit: [NUMID] (from DATABRICKS_RATE_LIMIT environment variable) + ✓ cloud: AWS + ✓ discovery_url: [DATABRICKS_URL]/oidc/.well-known/oauth-authorization-server diff --git a/acceptance/cmd/auth/describe/account-permission-denied/script b/acceptance/cmd/auth/describe/account-permission-denied/script new file mode 100644 index 00000000000..c418adc5aac --- /dev/null +++ b/acceptance/cmd/auth/describe/account-permission-denied/script @@ -0,0 +1,21 @@ +sethome "./home" + +# An account profile for a non-admin user: the account verification call is +# admin-only and returns 403, and the account console cannot serve the +# workspace verification call either. A 403 still proves the credentials +# work, so describe must report success. +# +# workspace_id = none (the legacy account-only sentinel) forces the account +# client path; with no workspace_id at all, the testserver's built-in +# /.well-known/databricks-config handler would backfill one and route this +# profile to a workspace client, unlike a real account console host. +cat > "./home/.databrickscfg" < Date: Wed, 10 Jun 2026 11:33:09 +0200 Subject: [PATCH 3/4] auth describe: drop the 403-implies-authenticated heuristic A 403 does not only come from authz denials: network-level gates (IP access lists, private link) also answer 403, and on workspace hosts those can fire before the token is validated, so treating 403 as proof of authentication can report success for invalid credentials. Report the verification failure as-is instead. Non-admin account users are covered by the server-side list-workspaces authz rollout, which already allows non-admins on GCP and AWS public prod. This reverts commit 5d3fa86c81878aff425b4c079ef9add6a537ec59. Co-authored-by: Isaac --- NEXT_CHANGELOG.md | 2 +- .../account-permission-denied/out.test.toml | 3 -- .../account-permission-denied/output.txt | 19 ------- .../describe/account-permission-denied/script | 21 -------- .../account-permission-denied/test.toml | 20 -------- cmd/auth/describe.go | 27 +--------- cmd/auth/describe_test.go | 50 ------------------- 7 files changed, 2 insertions(+), 140 deletions(-) delete mode 100644 acceptance/cmd/auth/describe/account-permission-denied/out.test.toml delete mode 100644 acceptance/cmd/auth/describe/account-permission-denied/output.txt delete mode 100644 acceptance/cmd/auth/describe/account-permission-denied/script delete mode 100644 acceptance/cmd/auth/describe/account-permission-denied/test.toml diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index fa20645e1b5..e9b1ef908b6 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -7,7 +7,7 @@ ### CLI * Added the `databricks quickstart` command, a short introduction to the CLI that prints a human-friendly guide interactively and an agent-oriented version when run non-interactively ([#5464](https://github.com/databricks/cli/pull/5464)). -* `databricks auth describe` now verifies credentials against both the workspace and account endpoints and treats permission-denied responses as proof of successful authentication, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)). +* `databricks auth describe` now verifies credentials against both the workspace and account endpoints before reporting a failure, fixing false "Unable to authenticate" errors for account console profiles ([#5479](https://github.com/databricks/cli/issues/5479)). ### Bundles * Set the default `data_security_mode` to `DATA_SECURITY_MODE_AUTO` in bundle templates ([#5452](https://github.com/databricks/cli/pull/5452)). diff --git a/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml b/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml deleted file mode 100644 index f784a183258..00000000000 --- a/acceptance/cmd/auth/describe/account-permission-denied/out.test.toml +++ /dev/null @@ -1,3 +0,0 @@ -Local = true -Cloud = false -EnvMatrix.DATABRICKS_BUNDLE_ENGINE = ["terraform", "direct"] diff --git a/acceptance/cmd/auth/describe/account-permission-denied/output.txt b/acceptance/cmd/auth/describe/account-permission-denied/output.txt deleted file mode 100644 index b7febcaf536..00000000000 --- a/acceptance/cmd/auth/describe/account-permission-denied/output.txt +++ /dev/null @@ -1,19 +0,0 @@ - -=== Permission denied still proves the credentials are valid - ->>> [CLI] auth describe --profile acct-nonadmin -Host: [DATABRICKS_URL] -Account ID: acct-456 -Authenticated with: pat ------ -Current configuration: - ✓ host: [DATABRICKS_URL] (from DATABRICKS_HOST environment variable) - ✓ account_id: acct-456 (from [TEST_TMP_DIR]/home/.databrickscfg config file) - ✓ workspace_id: none (from [TEST_TMP_DIR]/home/.databrickscfg config file) - ✓ token: ******** (from DATABRICKS_TOKEN environment variable) - ✓ profile: acct-nonadmin (from --profile flag) - ✓ databricks_cli_path: [CLI] - ✓ auth_type: pat - ✓ rate_limit: [NUMID] (from DATABRICKS_RATE_LIMIT environment variable) - ✓ cloud: AWS - ✓ discovery_url: [DATABRICKS_URL]/oidc/.well-known/oauth-authorization-server diff --git a/acceptance/cmd/auth/describe/account-permission-denied/script b/acceptance/cmd/auth/describe/account-permission-denied/script deleted file mode 100644 index c418adc5aac..00000000000 --- a/acceptance/cmd/auth/describe/account-permission-denied/script +++ /dev/null @@ -1,21 +0,0 @@ -sethome "./home" - -# An account profile for a non-admin user: the account verification call is -# admin-only and returns 403, and the account console cannot serve the -# workspace verification call either. A 403 still proves the credentials -# work, so describe must report success. -# -# workspace_id = none (the legacy account-only sentinel) forces the account -# client path; with no workspace_id at all, the testserver's built-in -# /.well-known/databricks-config handler would backfill one and route this -# profile to a workspace client, unlike a real account console host. -cat > "./home/.databrickscfg" < Date: Wed, 10 Jun 2026 11:46:26 +0200 Subject: [PATCH 4/4] auth describe: fold verification fallback tests into a table Review feedback: the five fallback tests repeated the same wiring. One table-driven test now covers both branches; a zero status in describeVerifyServer marks an endpoint that must not be called, which absorbs the no-account-id case. Co-authored-by: Isaac --- cmd/auth/describe_test.go | 203 ++++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 98 deletions(-) diff --git a/cmd/auth/describe_test.go b/cmd/auth/describe_test.go index d76e3154768..3d7bd62a0a1 100644 --- a/cmd/auth/describe_test.go +++ b/cmd/auth/describe_test.go @@ -403,23 +403,28 @@ func TestGetWorkspaceAuthStatus_U2M_PopulatesTokenStorage(t *testing.T) { // describeVerifyServer simulates the host that describe's secondary // verification calls hit: CurrentUser.Me and account Workspaces.List. -// Statuses other than 200 return an error body with that status code. +// Statuses other than 200 return an error body with that status code; a zero +// status marks an endpoint that must not be called at all. func describeVerifyServer(t *testing.T, accountID string, meStatus, listStatus int) *httptest.Server { t.Helper() - respond := func(w http.ResponseWriter, status int, okBody any) { - w.Header().Set("Content-Type", "application/json") - if status != http.StatusOK { - w.WriteHeader(status) - okBody = map[string]any{"error_code": "TEST_ERROR", "message": "secondary check failed"} - } - require.NoError(t, json.NewEncoder(w).Encode(okBody)) - } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + respond := func(status int, okBody any) { + if status == 0 { + t.Errorf("unexpected request to %s", r.URL.Path) + status = http.StatusNotFound + } + w.Header().Set("Content-Type", "application/json") + if status != http.StatusOK { + w.WriteHeader(status) + okBody = map[string]any{"error_code": "TEST_ERROR", "message": "secondary check failed"} + } + require.NoError(t, json.NewEncoder(w).Encode(okBody)) + } switch r.URL.Path { case "/api/2.0/preview/scim/v2/Me": - respond(w, meStatus, map[string]any{"userName": "fallback-user"}) + respond(meStatus, map[string]any{"userName": "fallback-user"}) case "/api/2.0/accounts/" + accountID + "/workspaces": - respond(w, listStatus, []map[string]any{}) + respond(listStatus, []map[string]any{}) default: w.WriteHeader(http.StatusNotFound) } @@ -464,94 +469,96 @@ func resolveCfg(t *testing.T, cfg *config.Config, attrs map[string]string, isAcc } } -func TestGetWorkspaceAuthStatusFallsBackToAccountCheck(t *testing.T) { - server := describeVerifyServer(t, "test-acct", http.StatusNotFound, http.StatusOK) - cfg := &config.Config{} - cmd := newDescribeWorkspaceCmd(t, cfg, &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"}) - - status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, map[string]string{ - "host": server.URL, - "token": "test-token", - "auth_type": "pat", - "account_id": "test-acct", - }, false)) - require.NoError(t, err) - require.Equal(t, "success", status.Status) - assert.Equal(t, "test-acct", status.AccountID) - assert.Empty(t, status.Username) -} - -func TestGetWorkspaceAuthStatusSkipsAccountCheckWithoutAccountID(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - t.Errorf("unexpected request to %s: there is no second endpoint to check without an account ID", r.URL.Path) - w.WriteHeader(http.StatusNotFound) - })) - t.Cleanup(server.Close) - t.Setenv("DATABRICKS_ACCOUNT_ID", "") - - meErr := &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"} - cfg := &config.Config{} - cmd := newDescribeWorkspaceCmd(t, cfg, meErr) - - status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, map[string]string{ - "host": server.URL, - "token": "test-token", - "auth_type": "pat", - }, false)) - require.NoError(t, err) - require.Equal(t, "error", status.Status) - assert.ErrorIs(t, status.Error, meErr) -} - -func TestGetAccountAuthStatusFallsBackToWorkspaceCheck(t *testing.T) { - server := describeVerifyServer(t, "test-acct", http.StatusOK, http.StatusNotFound) - cfg := &config.Config{} - cmd := newDescribeAccountCmd(t, cfg, &apierr.APIError{StatusCode: http.StatusForbidden, Message: "This API is disabled for users without account admin status"}) - - status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, map[string]string{ - "host": server.URL, - "token": "test-token", - "auth_type": "pat", - "account_id": "test-acct", - }, true)) - require.NoError(t, err) - require.Equal(t, "success", status.Status) - assert.Equal(t, "fallback-user", status.Username) - assert.Empty(t, status.AccountID) -} - -func TestGetWorkspaceAuthStatusBothChecksFailReportsFirstError(t *testing.T) { - server := describeVerifyServer(t, "test-acct", http.StatusNotFound, http.StatusUnauthorized) - meErr := &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"} - cfg := &config.Config{} - cmd := newDescribeWorkspaceCmd(t, cfg, meErr) - - status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, map[string]string{ - "host": server.URL, - "token": "test-token", - "auth_type": "pat", - "account_id": "test-acct", - }, false)) - require.NoError(t, err) - require.Equal(t, "error", status.Status) - assert.ErrorIs(t, status.Error, meErr) -} +// TestGetAuthStatusVerificationFallback covers the fallback when the primary +// verification call (mocked client) fails: describe tries the other endpoint +// over HTTP against describeVerifyServer, and only when both fail does it +// report the primary error. Error rows leave wantUsername/wantAccountID empty +// because errorAuthStatus never sets them. +func TestGetAuthStatusVerificationFallback(t *testing.T) { + tests := []struct { + name string + isAccount bool + primaryErr *apierr.APIError + meStatus int + listStatus int + accountID string + wantStatus string + wantUsername string + wantAccountID string + }{ + { + name: "workspace check fails, account check succeeds", + primaryErr: &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"}, + meStatus: http.StatusNotFound, + listStatus: http.StatusOK, + accountID: "test-acct", + wantStatus: "success", + wantAccountID: "test-acct", + }, + { + name: "no second call without an account id", + primaryErr: &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"}, + wantStatus: "error", + }, + { + name: "account check fails, workspace check succeeds", + isAccount: true, + primaryErr: &apierr.APIError{StatusCode: http.StatusForbidden, Message: "This API is disabled for users without account admin status"}, + meStatus: http.StatusOK, + listStatus: http.StatusNotFound, + accountID: "test-acct", + wantStatus: "success", + wantUsername: "fallback-user", + }, + { + name: "workspace branch, both checks fail", + primaryErr: &apierr.APIError{StatusCode: http.StatusBadRequest, Message: "Unable to load OAuth Config"}, + meStatus: http.StatusNotFound, + listStatus: http.StatusUnauthorized, + accountID: "test-acct", + wantStatus: "error", + }, + { + name: "account branch, both checks fail", + isAccount: true, + primaryErr: &apierr.APIError{StatusCode: http.StatusUnauthorized, Message: "credentials expired"}, + meStatus: http.StatusUnauthorized, + listStatus: http.StatusNotFound, + accountID: "test-acct", + wantStatus: "error", + }, + } -func TestGetAccountAuthStatusBothChecksFailReportsFirstError(t *testing.T) { - server := describeVerifyServer(t, "test-acct", http.StatusUnauthorized, http.StatusNotFound) - listErr := &apierr.APIError{StatusCode: http.StatusUnauthorized, Message: "credentials expired"} - cfg := &config.Config{} - cmd := newDescribeAccountCmd(t, cfg, listErr) - - status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, map[string]string{ - "host": server.URL, - "token": "test-token", - "auth_type": "pat", - "account_id": "test-acct", - }, true)) - require.NoError(t, err) - require.Equal(t, "error", status.Status) - assert.ErrorIs(t, status.Error, listErr) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("DATABRICKS_ACCOUNT_ID", "") + server := describeVerifyServer(t, tc.accountID, tc.meStatus, tc.listStatus) + cfg := &config.Config{} + var cmd *cobra.Command + if tc.isAccount { + cmd = newDescribeAccountCmd(t, cfg, tc.primaryErr) + } else { + cmd = newDescribeWorkspaceCmd(t, cfg, tc.primaryErr) + } + attrs := map[string]string{ + "host": server.URL, + "token": "test-token", + "auth_type": "pat", + } + if tc.accountID != "" { + attrs["account_id"] = tc.accountID + } + + status, err := getAuthStatus(cmd, []string{}, false, resolveCfg(t, cfg, attrs, tc.isAccount)) + require.NoError(t, err) + require.Equal(t, tc.wantStatus, status.Status) + assert.Equal(t, tc.wantUsername, status.Username) + assert.Equal(t, tc.wantAccountID, status.AccountID) + if tc.wantStatus == "error" { + assert.ErrorIs(t, status.Error, tc.primaryErr) + } + }) + } } func TestGetWorkspaceAuthStatus_NonU2M_OmitsTokenStorage(t *testing.T) {