Skip to content

CXH-2166: implement PAT (workspace token) authentication - #54

Open
al-conductorone wants to merge 1 commit into
mainfrom
cxh-2166-baton-databricks-implement-pat-workspace-token
Open

CXH-2166: implement PAT (workspace token) authentication#54
al-conductorone wants to merge 1 commit into
mainfrom
cxh-2166-baton-databricks-implement-pat-workspace-token

Conversation

@al-conductorone

Copy link
Copy Markdown
Contributor

The Databricks connector can again authenticate with per-workspace personal access tokens, matching the setup docs, so customers who use workspace tokens instead of OAuth can connect. Additive change: OAuth stays the default and existing setups are unaffected.

Re-add the personal-access-token auth path removed in e84a1ae so the
connector matches its docs. Workspace tokens authenticate per-workspace
against the Databricks Workspace API and scope the sync to the workspaces
those tokens belong to; OAuth stays the default.

- config: restore workspaces + workspace-tokens fields and the OAuth/token
  constraints; OAuth client id/secret are no longer hard-required
- auth: restore TokenAuth, selecting the token by workspace host prefix so
  Azure dotted deployment names match correctly
- connector: token-aware Validate and prepareClientAuth; thread workspaces
  through to the workspace builder
- workspace builder: build minimal workspace resources from the configured
  list when the Account API is unavailable (token auth)
@al-conductorone
al-conductorone requested a review from a team July 30, 2026 01:31
@linear-code

linear-code Bot commented Jul 30, 2026

Copy link
Copy Markdown

CXH-2166

Comment thread pkg/databricks/auth.go
Comment on lines +39 to +46
func NewTokenAuth(workspaces, tokens []string) *TokenAuth {
tokensMap := make(map[string]string, len(workspaces))
for i, workspace := range workspaces {
tokensMap[workspace] = tokens[i]
}

return &TokenAuth{tokens: tokensMap}
}

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.

🟡 Suggestion (low confidence): NewTokenAuth indexes tokens[i] while ranging over workspaces, so it panics with index-out-of-range if len(tokens) < len(workspaces). In practice ValidateConfig enforces equal lengths before this is reached, so no panic occurs today — but that invariant lives far away in pkg/config. Consider guarding here (e.g. skip when i >= len(tokens)) to make this exported constructor safe on its own.

@github-actions

Copy link
Copy Markdown
Contributor

Connector PR Review: CXH-2166: implement PAT (workspace token) authentication

Blocking Issues: 0 | Suggestions: 2 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base 5aba277cd2a6.
Review mode: full
View review run

Review Summary

Scanned the full PR diff for security and correctness. This PR adds per-workspace personal-access-token auth alongside OAuth: a new TokenAuth that applies the right bearer per request host, config fields (workspaces, workspace-tokens) with field-relationship + length constraints, a token-auth-aware Validate, and a minimal workspace-resource path for when the Account API is unreachable. The design is coherent end-to-end — workspace resource IDs stay as deployment names in both auth modes (no ID-stability break), child builders derive workspaceId from the parent deployment name so TokenAuth.Apply matches, and OAuth remains the default so existing setups are unaffected. TokenAuth.Apply correctly handles dotted Azure deployment names and prefix collisions, and is covered by tests. No blocking issues found.

Security Issues

None found. Tokens are marked WithIsSecret(true), sent only as Bearer headers, and never logged (only account-id is logged).

Correctness Issues

None found.

Suggestions

  • pkg/databricks/auth.go:39-46NewTokenAuth indexes tokens[i] while ranging over workspaces; guarded today by ValidateConfig's equal-length check but would panic if called directly with mismatched lengths.
  • New behavior (config.ValidateConfig, workspace filtering, the minimal-workspace/IsAccountAPIAvailable path) has no unit tests; only TokenAuth.Apply is covered.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/databricks/auth.go`:
- Around line 39-46: `NewTokenAuth(workspaces, tokens []string)` builds its map with
  `tokensMap[workspace] = tokens[i]` while ranging over `workspaces`, which panics with
  index-out-of-range if `len(tokens) < len(workspaces)`. It is guarded today by
  `config.ValidateConfig` (equal-length check) but that invariant lives in another package.
  Harden the constructor itself, e.g. `if i >= len(tokens) { break }` before the assignment,
  or accept paired input, so the exported function is safe independent of the caller.

In `pkg/config/config.go` and `pkg/connector`:
- Add unit tests for the new behavior introduced in this PR: `config.ValidateConfig`
  (equal-length pass/fail), the workspace-filtering branch in `workspaceBuilder.List`
  (configured subset vs. empty set), and the `!IsAccountAPIAvailable()` minimal-workspace
  path that emits `minimalWorkspaceResource` for token auth. Only `TokenAuth.Apply` is
  currently tested.

@github-actions github-actions Bot left a comment

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.

No blocking issues found.

Comment thread pkg/config/config.go
Comment on lines +72 to +83
field.FieldsMutuallyExclusive(
DatabricksClientIdField,
WorkspaceTokensField,
),
field.FieldsRequiredTogether(
DatabricksClientIdField,
DatabricksClientSecretField,
),
field.FieldsDependentOn(
[]field.SchemaField{WorkspaceTokensField},
[]field.SchemaField{WorkspacesField},
),

@johnallers johnallers Jul 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@al-conductorone Would it make sense to use FieldGroups for OAuth and PAT? I think it might simplify these relationships.

Comment thread pkg/config/config.go
WorkspaceTokensField,
BaseURLField,
}
fieldRelationships = []field.SchemaFieldRelationship{

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.

Instead of field relationships we probably want to keep required fields and use different group fields

databricksClientSecret := cfg.DatabricksClientSecret
accountHostname := getAccountHostname(cfg, cfg.Hostname)
if len(cfg.WorkspaceTokens) > 0 {
l.Info("using workspace token auth", zap.String("account-id", cfg.AccountId))

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.

unreachable info log, i don't think it is needed. you can keep it as debug log or remove it entirely

return databricks.NewTokenAuth(cfg.Workspaces, cfg.WorkspaceTokens)
}

l.Info("using oauth", zap.String("account-id", cfg.AccountId))

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.

same here. we should avoid noisy logs as much as we can

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.

3 participants