Skip to content

fix(auth): clearer U2M errors for missing profiles and modern CLI detection#184

Draft
parthban-db wants to merge 1 commit into
mainfrom
parthban-db/stack/bugbash-bug8-u2m-errors
Draft

fix(auth): clearer U2M errors for missing profiles and modern CLI detection#184
parthban-db wants to merge 1 commit into
mainfrom
parthban-db/stack/bugbash-bug8-u2m-errors

Conversation

@parthban-db
Copy link
Copy Markdown
Contributor

@parthban-db parthban-db commented Jun 3, 2026

🥞 Stacked PR

Use this link to review incremental changes.


Summary

Makes the U2M (Databricks CLI) credential provider fail with clear, accurate errors: a mistyped profile is reported up front instead of as a misleading host error, CLI stderr no longer renders a doubled Error: prefix, and modern CLI wrappers/shims are no longer misflagged as the legacy Python CLI.

Why

newU2mCredentials shells out to the databricks CLI, and two error paths misled developers. An unknown profile made databricks auth token fail with a host-configuration error (already prefixed with Error:, which the SDK then doubled), so a simple typo told the user to specify a host. Separately, CLI modernity was inferred purely from binary size, rejecting legitimate small wrappers, shims, and launcher symlinks as legacy.

What changed

  • Adds a PROFILE_NOT_FOUND code to U2mCredentialsErrorCode; the provider now pre-checks the profile via resolve from @databricks/sdk-core/profiles and fails fast naming the missing profile, instead of running the CLI.
  • Strips a leading Error: prefix from CLI stderr before wrapping, so messages no longer read Error: Error: ....
  • Determines modern-CLI status by running databricks version and requiring >= 0.100.0; the 1 MB binary-size check is kept only as a fallback when the version cannot be obtained or parsed.
  • Refactors validateCliPath onto new isModernCli/cliVersion/isAtLeastMinVersion helpers and adds ensureProfileExists/stripErrorPrefix.
  • Go divergence: the Go SDK uses a persistent OAuth flow rather than a CLI shell-out, so this CLI-detection logic is intentionally TypeScript-only.

Validated: npm run build, npm test (14-case u2m suite), npm run typecheck, and npm run lint pass for @databricks/sdk-auth.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Please ensure that the NEXT_CHANGELOG.md file is updated with any relevant changes.
If this is not necessary for your PR, please include the following in your PR description:
NO_CHANGELOG=true
and rerun the job.

1 similar comment
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Please ensure that the NEXT_CHANGELOG.md file is updated with any relevant changes.
If this is not necessary for your PR, please include the following in your PR description:
NO_CHANGELOG=true
and rerun the job.

…ection

## Summary

Fixes two misleading failure modes in the Databricks CLI ("U2M") credential provider: a non-existent profile no longer surfaces a confusing host error with a doubled `Error:` prefix, and modern CLI wrappers/shims smaller than 1 MB are no longer misclassified as the legacy Python CLI.

## Why

`newU2mCredentials` shells out to the `databricks` CLI to obtain access tokens, and two of its error paths produced output that pointed developers in the wrong direction.

First, when the requested profile does not exist, `databricks auth token --profile X` treats the unknown profile as "no profile configured" and fails with a host-related message such as `Error: cannot configure default credentials, please check ... or specify --host`. The provider passed that stderr through verbatim and wrapped it as `cannot get access token: <stderr>`. Because the CLI already prefixes its stderr with `Error:`, the rendered result read `cannot get access token: Error: ...`, and once the surrounding `U2mCredentialsError` is logged the prefix doubled again. A developer who simply mistyped a profile name was told to specify a host, with a stutter of `Error:` labels.

Second, the provider distinguished the modern Go-based CLI (>= 0.100.0) from the legacy Python CLI purely by binary size: any file under 1 MB was reported as `LEGACY_CLI_DETECTED`. That heuristic flags legitimate setups where `databricks` is a small wrapper, shim, or symlink-resolving launcher rather than the full statically linked binary, blocking auth even when a perfectly modern CLI is installed.

## What changed

### Interface changes

- **`U2mCredentialsErrorCode`** gains a `'PROFILE_NOT_FOUND'` member. `newU2mCredentials` now rejects with this code (and the message `profile "<name>" was not found in the Databricks config file`) when the requested profile is absent.

### Behavioral changes

- A request for a non-existent profile now fails fast with `PROFILE_NOT_FOUND` naming the missing profile, instead of running the CLI and surfacing its host error. The profile is pre-checked via `resolve` from `@databricks/sdk-core/profiles`, which already reports `PROFILE_NOT_FOUND` for an explicitly requested-but-missing profile; any other resolution error is rethrown unchanged.
- CLI stderr that is already prefixed with `Error:` has that prefix stripped before the SDK wraps it, so the message no longer doubles the label.
- CLI modernity is now determined by running `databricks version` and parsing its `Databricks CLI v<semver>` banner, requiring `>= 0.100.0`. The 1 MB binary-size check is kept only as a fallback for when the version command cannot be run or its output cannot be parsed. Wrappers and shims that report a modern version are accepted.

### Internal changes

- `validateCliPath` delegates the legacy-vs-modern decision to a new `isModernCli(path, size)` helper, backed by `cliVersion` (runs `<path> version`, parses the semver) and `isAtLeastMinVersion` (compares against `MIN_CLI_VERSION`).
- Added `ensureProfileExists` and `stripErrorPrefix` helpers in `u2m.ts`.
- The `u2m` test suite mocks `@databricks/sdk-core/profiles` so the profile pre-check is deterministic and does not read the developer's `~/.databrickscfg`. The CLI exec mock now routes by sub-command (`version` vs `auth token`) so the version probe and the token request can be stubbed independently. New cases cover the profile pre-check, the `Error:`-prefix stripping, a pre-0.100.0 reported version, and the size fallback when the version cannot be read.

### Go-parity note

The Go reference SDK in this checkout implements U2M via a persistent OAuth flow rather than a CLI shell-out, so there is no Go counterpart for this provider's CLI detection. The `databricks version` parsing here follows the Databricks CLI's own version banner (`Databricks CLI v<semver>`); the legacy Python launcher does not emit that banner, so it falls through to the size heuristic. This is a deliberate, TypeScript-only divergence rather than a port of a specific Go function.

## How is this tested?

`npm run build`, `npm test`, `npm run typecheck`, and `npm run lint` for `@databricks/sdk-auth` (built on top of `@databricks/sdk-core`) all pass. The 14-case `u2m` suite covers the new `PROFILE_NOT_FOUND` path, `Error:`-prefix de-duplication, version-based modern-CLI detection, and the binary-size fallback.

Co-authored-by: Isaac
@parthban-db parthban-db force-pushed the parthban-db/stack/bugbash-bug8-u2m-errors branch from 1e04012 to 9bfd9a5 Compare June 4, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant