Skip to content

auth: Enrich auth profiles output with validation failure reason#5216

Open
janniklasrose wants to merge 7 commits into
mainfrom
janniklasrose/auth-profile-validate
Open

auth: Enrich auth profiles output with validation failure reason#5216
janniklasrose wants to merge 7 commits into
mainfrom
janniklasrose/auth-profile-validate

Conversation

@janniklasrose

@janniklasrose janniklasrose commented May 8, 2026

Copy link
Copy Markdown
Contributor

Changes

databricks auth profiles now explains why a profile isn't valid, instead of an overloaded valid: false.

  • Text table — the Valid column renders three states: YES (green, validated), NO (red, validation failed for any reason), and ?? (grey, validation skipped via --skip-validate). No extra columns.
  • JSON (--output json) — keeps the boolean valid field (backwards compatible) and adds a valid_reason string that explains a valid: false result: the full underlying error when validation failed, or a skip note under --skip-validate. valid_reason is empty only on success.

Why

A single valid: false was overloaded across very different conditions — expired token, no network, 5xx from the workspace, malformed config, missing host. Users seeing red NO everywhere had no actionable signal. The model here keeps the display dead simple (YES / NO / ??) while valid_reason in JSON carries the full detail for anyone who needs to debug or script against it. Every real error is NO; ?? is reserved for the all-or-nothing --skip-validate, so there's no confusing "NO" on a profile that was never checked.

This PR is intentionally scoped to the output change. A separate follow-up adds a per-profile validation timeout — auth profiles currently stalls for ~5 minutes on a host the SDK retries (connection refused, connect/TLS timeout, retriable 5xx) — with its own regression test.

Tests

  • cmd/auth/profiles_test.go:
    • TestProfileLoadStatusMatrix — via httptest: 401, 403, 500, and InvalidConfig all report valid: false with a non-empty valid_reason; --skip-validate reports valid: false with the skip note.
    • Existing SPOG / no-discovery routing tests assert against Valid / ValidReason.
  • Acceptance test acceptance/cmd/auth/profiles/server-error/ — a 5xx from the validation endpoint produces valid: false with the backend error echoed in valid_reason, exercising the JSON serialization end-to-end.
  • Regenerated affected acceptance outputs (the existing profiles / spog-account test plus auth/login, auth/logout, auth/switch, and auth/host-metadata-cache tests that include auth profiles output).
  • Merged latest origin/main; fixed the InvalidConfig fixture for the SDK bump that replaced the experimental_is_unified_host flag with host-metadata host_type.

This pull request and its description were written by Isaac, an AI coding agent.

…th profiles`

Replace the binary `valid: true|false` with a three-state `status` (valid /
invalid / unknown) plus an optional `error` description, so users can tell
an expired token apart from a network blip. The legacy `valid` field is now
a `*bool`: emitted only when the result is conclusive, omitted for transient
errors that previously misreported as `valid: false`. Adds a 10s per-profile
validation timeout (also bounding `EnsureResolved`'s host-metadata fetch via
`HTTPTimeoutSeconds`/`RetryTimeoutSeconds`) so a single dead host no longer
stalls the whole listing.

Co-authored-by: Isaac
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Approval status: pending

/cmd/auth/ - needs approval

Files: cmd/auth/profiles.go, cmd/auth/profiles_test.go
Suggested: @simonfaltum
Also eligible: @mihaimitrea-db, @tanmay-db, @renaudhartert-db, @tejaskochar-db, @hectorcast-db, @parthban-db, @Divyansh-db, @chrisst, @rauchy

General files (require maintainer)

7 files changed
Based on git history:

  • @simonfaltum -- recent work in cmd/auth/, acceptance/cmd/auth/profiles/, acceptance/cmd/auth/switch/nominal/

Any maintainer (@andrewnester, @anton-107, @denik, @pietern, @shreyas-goenka, @simonfaltum, @renaudhartert-db, @lennartkats-db) can approve all areas.
See OWNERS for ownership rules.

@janniklasrose
janniklasrose requested a review from simonfaltum May 8, 2026 11:15
@janniklasrose
janniklasrose marked this pull request as draft May 8, 2026 18:16
@janniklasrose janniklasrose changed the title auth: distinguish "validation failed" from "couldn't validate" in auth profiles [WIP] auth: distinguish "validation failed" from "couldn't validate" in auth profiles Jun 4, 2026
…ofile-validate

# Conflicts:
#	NEXT_CHANGELOG.md
#	acceptance/auth/host-metadata-cache/output.txt
#	cmd/auth/profiles.go
Collapse the profile validation display to three states in the Valid
column: YES (validated), NO (any validation error), and ?? (validation
skipped via --skip-validate). Drop the separate Reason column from the
text table — every real error becomes NO, and ?? is reserved for
skip-validate, so the table stays scannable with no per-error curation.

JSON output keeps the boolean `valid` field and carries the full
underlying error (or a skip note) in `valid_reason`; it is empty only on
success. This removes the earlier classifyValidationError/networkErrorReason
machinery and the status/error JSON fields in favor of the simpler model.

Co-authored-by: Isaac
Keep this PR focused on the YES/NO/?? + valid_reason output change. The
per-profile validation timeout (HTTPTimeoutSeconds/RetryTimeoutSeconds +
context.WithTimeout) is a separate fix for a real stall — a host the SDK
retries (connection refused, connect/TLS timeout, retriable 5xx) blocks
`auth profiles` for ~5 minutes — and will land in its own PR with a
regression test. Remove it here along with the network-down test case,
which is the only one that depends on the bound to avoid hanging.

Co-authored-by: Isaac
Under the simplified YES/NO/?? model, a 401 and a 5xx produce the identical
outcome (valid:false + the backend error echoed in valid_reason), so the
expired-token test no longer exercises a distinct path from server-error.
Keep server-error as the single end-to-end check that valid_reason renders
in --output json; remove expired-token.

Co-authored-by: Isaac
The comment described the old four-state model (500 -> "unknown" vs
"invalid"). Update it to the current model: any validation error is
valid=false with the backend error echoed in valid_reason.

Co-authored-by: Isaac
Comment thread cmd/auth/profiles.go Outdated
Comment thread .nextchanges/cli/auth-profiles-validate.md Outdated
- Handle InvalidConfig in its own switch case instead of an early-return
  if before the switch (per review).
- Shorten the changelog fragment and link the PR.

Co-authored-by: Isaac
@janniklasrose janniklasrose changed the title [WIP] auth: distinguish "validation failed" from "couldn't validate" in auth profiles auth: Enrich auth profiles output with validation failure reason Jul 15, 2026
@janniklasrose
janniklasrose marked this pull request as ready for review July 15, 2026 11:24
Comment thread cmd/auth/profiles.go
Comment on lines +43 to +47
// Valid is true only when validation conclusively succeeded. ValidReason
// explains a false result: the full underlying error when validation failed,
// or a "skipped" note under --skip-validate. It is empty only on success.
// The text table shows only YES/NO/?? (via StatusDisplay); the reason detail
// is reserved for --output json.

@renaudhartert-db renaudhartert-db Jul 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional] I understand this is out of scope for this PR but it would be great to explicit about what "Valid" means. E.g. is it about the schema? The ability to authenticate? Whether a token is in the cache?

IIUC, a profile is valid if it is possible to make a valid API call. I wonder if this creates a double standard:

  • Everything except U2M: the profile is correct and works in its environment.
  • U2M: whether there is a token in the cache for that profile. That is, we do not actually validate the profile beyond checking that it exists.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see also my other reply. Valid YES/true currently means "able to use the profile for other authenticated calls as-is".

I don't know if that is how customers actually interpret it, but that's the only thing our views let them reasonably infer.

Adding ValidReason to the table view seemed really clunky UX (or requires custom logic to handle all sorts of errors and show them nicely) hence it's only in json output where we can dump the error.

Comment thread cmd/auth/profiles.go
Comment on lines +64 to +68
func (c *profileMetadata) setStatus(ctx context.Context, status profileStatus, reason string) {
c.Valid = status == profileStatusValid
c.ValidReason = reason
c.StatusDisplay = renderStatusCell(ctx, status)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[optional] It feels like we're increasingly mixing data model and rendering concerns. For example, Valid and StatusDisplay seem to be "views" over the status.

I don't think we need to act on this as part of this PR. Though, we will have to decouple this as part of centralizing the profile read/write logic in a single package.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 - working with what we have right now, we currently only expose the boolean status to customers ("Am I able to use this profile?"). Initially this PR was prompted by intermittent/cryptic failures where I didn't know why I saw "Valid? NO".

Would be great if the centralised logic could differentiate

  • expired, requiring re-auth
  • bad config, requiring fix/doctor
  • intermittent issues (can't reach host, etc)

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.

2 participants