Skip to content

feat(connector): Databricks create — 4 auth modes with unit + e2e coverage#21

Merged
bradfair merged 9 commits into
mainfrom
feature/databricks-connector-parity
Apr 22, 2026
Merged

feat(connector): Databricks create — 4 auth modes with unit + e2e coverage#21
bradfair merged 9 commits into
mainfrom
feature/databricks-connector-parity

Conversation

@bradfair
Copy link
Copy Markdown
Contributor

@bradfair bradfair commented Apr 22, 2026

Summary

  • Brings Databricks connector creation to Snowflake-parity coverage: four auth-mode leaves (access-token, client-credentials, oauth-sso, oauth-individual) matching the wire shapes captured in api-catalog/POST_connector.create.databricks.*.json.
  • Adds full unit + e2e test coverage; keeps the 100% coverage gate on ./internal/... green.
  • Ships a small prerequisite: cli.DeclareInt (Lookup-guarded fs.IntVar) so the Databricks Group can inherit-declare the shared --port flag.

Pattern applied

One dialect Group with inheritable workspace flags (--name --host --http-path --port --catalog --schema) plus four leaves, each populating a nested databricksAuth one-of variant:

Mode authStrategy databricksAuth variant
access-token service_role pat.token
client-credentials service_role clientCredentials.{clientId, clientSecret}
oauth-sso oauth_sso oauthU2m.{clientId, clientSecret}
oauth-individual per_member_oauth oauthU2m.{clientId, clientSecret}

Wire gotcha captured in types_databricks.go: OAuth modes populate oauthU2m, NOT oauthSso — the server rejects the latter. SSO vs Individual is expressed via envelope-level authStrategy, not the nested one-of.

Summary by CodeRabbit

  • New Features

    • Add Databricks connector creation with four auth modes (access token, client credentials, OAuth SSO, per-member OAuth), workspace flags (name, host, http-path, catalog, schema, port) and clear creation output including OAuth completion hints.
  • Tests

    • Add extensive unit and end-to-end tests for all Databricks flows covering validation, stdin secret handling, JSON output, error propagation, and post-create verification.
  • Other

    • Help text now lists Databricks as a supported dialect.

Group.Flags closures need a Lookup-guarded int wrapper — stdlib
flag.IntVar panics on duplicate declarations, and the existing
DeclareString/DeclareBool helpers already cover string/bool. This
completes the primitive set so dialect Groups can inherit-declare
integer flags (e.g. Databricks --port) without clobbering leaves.
…, OAuth SSO, OAuth individual

Mirrors the Snowflake create structure. One dialect Group with the shared
workspace flags (name, host, http-path, port, catalog, schema) inherited
by every auth-mode leaf via cli.ApplyAncestorFlags; four leaves, one per
auth mode, each populating a nested `databricksAuth` one-of variant:

- `access-token` → `databricksAuth.pat.token` (authStrategy=service_role)
- `client-credentials` → `databricksAuth.clientCredentials.{clientId, clientSecret}` (authStrategy=service_role)
- `oauth-sso` → `databricksAuth.oauthU2m.{clientId, clientSecret}` (authStrategy=oauth_sso); prints the configured endpoint in the success note so self-hosted operators get the right callback URL
- `oauth-individual` → same `oauthU2m` variant with authStrategy=per_member_oauth; prints a per-member-lazy note

Wire label mismatch: OAuth modes populate `oauthU2m`, NOT `oauthSso` — the
server rejects the latter with `databricks.databricks_auth requires pat,
client_credentials, or oauth_u2m`. Captured in the types_databricks.go doc
block so future contributors don't rediscover it.
One _test.go file per leaf, mirroring the Snowflake layout: happy path
(wire shape assertions + omitempty negative assertions), stdin secret
read, empty-stdin usage error, read-error propagation, missing secret,
missing flags, empty-string validation on every required ancestor flag,
JSON bypass, render-write error, bad-flag rejection, Unary error, and
remarshal error. Access-token adds a port-range validation test + a
custom-port happy path; OAuth SSO adds a custom-endpoint echo test that
locks in the self-hosted-endpoint behavior.

Also expands TestCreateGroupHelpMentionsDialects to require `databricks`
so future dialect adds trip the same guard.

Keeps the 100% coverage gate on `./internal/...` green.
One test per auth mode, each env-gated:

- access-token:      ANA_E2E_DBX_TOKEN + workspace env
- client-credentials: ANA_E2E_DBX_CLIENT_{ID,SECRET} + workspace env
- oauth-sso:         ANA_E2E_DBX_OAUTH_CLIENT_{ID,SECRET} + workspace env (asserts the success note references ANA_E2E_ENDPOINT)
- oauth-individual:  same OAuth env (asserts the per-member-lazy note)

Reuses the Snowflake suite's id-extraction + LIFO cleanup primitives
(extractConnectorID + RegisterConnectorCleanupByName) and gates every
test on a shared ANA_E2E_DBX_{HOST,HTTP_PATH,CATALOG,SCHEMA} env tuple.

README documents every env var; cli-readiness bumps the Databricks row
from Probed to Implemented across all four auth modes.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 629f4550-a566-4474-b010-646e76615445

📥 Commits

Reviewing files that changed from the base of the PR and between 0f50b55 and 36c61ac.

⛔ Files ignored due to path filters (1)
  • e2e/CLAUDE.md is excluded by !**/*.md
📒 Files selected for processing (3)
  • e2e/connector_create_leaves_test.go
  • e2e/connector_databricks_test.go
  • e2e/connector_snowflake_test.go

📝 Walkthrough

Walkthrough

Adds a Databricks dialect to ana connector create with four auth-mode leaves, Databricks types, CLI wiring and validation, extensive unit and e2e tests, a new DeclareInt helper, and an H.Endpoint() accessor on the e2e harness.

Changes

Cohort / File(s) Summary
Databricks CLI group & wiring
internal/connector/create.go, internal/connector/create_databricks.go
Register databricks child group under connector create; declare shared workspace flags and validation helpers (requireDatabricksCommon, requireDatabricksClientID).
Databricks create command leaves
internal/connector/create_databricks_access_token.go, internal/connector/create_databricks_client_credentials.go, internal/connector/create_databricks_oauth_sso.go, internal/connector/create_databricks_oauth_individual.go
Implement four auth-mode leaves that parse flags (including ancestor/shared flags), validate inputs, resolve secrets (supports --*-stdin), construct CreateConnector requests with appropriate AuthStrategy and databricks auth payloads, call unary RPC, and render output.
Databricks request types
internal/connector/types_databricks.go, internal/connector/types.go
Add Databricks spec/auth structs and add optional Databricks field to configEnvelope for request serialization.
Unit / integration tests (Databricks)
internal/connector/create_databricks_*_test.go (4 files)
Comprehensive tests per leaf covering happy paths, stdin secret handling, validation errors, RPC/error propagation, JSON output mode, and response decode/marshal error cases.
E2E tests & harness
e2e/connector_databricks_test.go, e2e/connector_snowflake_test.go, e2e/harness/harness.go, e2e/connector_create_leaves_test.go
Add Databricks e2e smoke tests and helpers (dbxCommonEnv, arg builders); update Snowflake e2e to use shared leaf runner; add H.Endpoint() accessor and connector-create leaf helper (connectorCreateLeaf, extractConnectorID).
CLI helpers & tests
internal/cli/root.go, internal/cli/cli_test.go
Add DeclareInt to guard int flag redeclaration; update/add tests for redeclare-guard behavior and default-retention parse semantics.
Create group help test update
internal/connector/create_postgres_password_test.go
Update help expectation to include new databricks dialect.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as "ana CLI"
  participant Secret as "resolveSecret (stdin)"
  participant Deps as "Deps (Unary client)"
  participant Service as "Connector Service"
  participant Output as "cli.RenderOutput"

  CLI->>Secret: request token/client-secret when --*-stdin used
  Secret-->>CLI: secret or error
  CLI->>Deps: Unary(CreateConnector request with databricks spec)
  Deps->>Service: gRPC/HTTP CreateConnector
  Service-->>Deps: CreateConnector response (connectorId,...)
  Deps-->>CLI: response
  CLI->>Output: render JSON or human output
  Output-->>CLI: write to stdout or return error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I hopped to Databricks with a twitchy nose,
Four tiny doors where authy breezes blow.
Tokens hum from stdin, secrets snug and neat,
RPCs answer, outputs patter—sweet!
Tests munch carrots; the connector is complete.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.72% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding Databricks connector creation with four authentication modes and comprehensive test coverage.
Description check ✅ Passed The description provides a clear summary of what the PR does, includes the required type checkbox, but lacks explicit mention of checklist items (lint, cover, docs).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/databricks-connector-parity

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/connector_databricks_test.go`:
- Around line 122-160: The test TestConnectorCreateDatabricksOAuthSSO
redundantly calls os.Getenv("ANA_E2E_ENDPOINT") and asserts it is set even
though harness.Begin() already validates the env; remove lines that re-read and
assert ANA_E2E_ENDPOINT and instead use the harness to obtain the endpoint
(either call a new getter H.Endpoint() you add to the harness type or reference
an existing accessor) and compare stdout against that value; if you choose the
getter, add func (h *H) Endpoint() string that returns the harness-stored
endpoint and update the comparison to use h.Endpoint() rather than os.Getenv.

In `@internal/cli/cli_test.go`:
- Around line 1044-1085: Update the three tests
(TestDeclareIntGuardsAgainstRedeclare, TestDeclareIntFreshDeclaration,
TestDeclareIntDefault) to invoke the CLI parser helper ParseFlags instead of
calling fs.Parse directly so the ErrUsage chain and CLI behavior are preserved;
replace calls like fs.Parse([]string{"--port","7"}) or fs.Parse(nil) with the
corresponding ParseFlags(fs, []string{...}) or ParseFlags(fs, nil) invocation
and handle the returned error exactly as the tests currently do.

In `@internal/connector/create_databricks_oauth_individual.go`:
- Around line 54-64: Remove the redundant empty-string check for the client ID
in the oauth-individual command: the explicit if c.clientID == "" { ... } block
duplicates validation already performed by cli.RequireFlags in the connector
create databricks oauth-individual flow, so delete that conditional and its
UsageErrf call and rely on cli.RequireFlags (and existing
requireDatabricksCommon) to validate --client-id; locate the check by the symbol
c.clientID and the surrounding function handling the oauth-individual create
path.

In `@internal/connector/create_databricks_oauth_sso.go`:
- Around line 59-69: Remove the redundant empty-string validation for
--client-id: the call to cli.RequireFlags in the connector create databricks
oauth-sso path already enforces presence of "client-id", so delete the block
that checks if c.clientID == "" and returns cli.UsageErrf; ensure
requireDatabricksCommon and other flag checks (requireDatabricksCommon,
cli.RequireFlags) remain unchanged — if you intended to enforce non-empty values
beyond presence, apply the same explicit check to other leaves (e.g.,
client-credentials, oauth-individual) consistently instead of only for
c.clientID.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: da464d12-b7a9-4a27-a1df-deb61a4d9a1a

📥 Commits

Reviewing files that changed from the base of the PR and between cb6219a and 43e1f64.

⛔ Files ignored due to path filters (5)
  • docs/cli-readiness.md is excluded by !**/docs/**, !**/*.md
  • e2e/CLAUDE.md is excluded by !**/*.md
  • e2e/README.md is excluded by !**/*.md
  • internal/cli/CLAUDE.md is excluded by !**/*.md
  • internal/connector/CLAUDE.md is excluded by !**/*.md
📒 Files selected for processing (16)
  • e2e/connector_databricks_test.go
  • internal/cli/cli_test.go
  • internal/cli/root.go
  • internal/connector/create.go
  • internal/connector/create_databricks.go
  • internal/connector/create_databricks_access_token.go
  • internal/connector/create_databricks_access_token_test.go
  • internal/connector/create_databricks_client_credentials.go
  • internal/connector/create_databricks_client_credentials_test.go
  • internal/connector/create_databricks_oauth_individual.go
  • internal/connector/create_databricks_oauth_individual_test.go
  • internal/connector/create_databricks_oauth_sso.go
  • internal/connector/create_databricks_oauth_sso_test.go
  • internal/connector/create_postgres_password_test.go
  • internal/connector/types.go
  • internal/connector/types_databricks.go

Comment thread e2e/connector_databricks_test.go
Comment thread internal/cli/cli_test.go
Comment thread internal/connector/create_databricks_oauth_individual.go
Comment thread internal/connector/create_databricks_oauth_sso.go
cli.RequireFlags only asserts explicit presence, so '--client-id ""'
slips through — every Databricks leaf that takes --client-id needs an
extra empty-string guard. Extract the inline check into a shared
requireDatabricksClientID helper so the three leaves (client-credentials,
oauth-sso, oauth-individual) apply identical validation and the intent
is documented in one place.
The OAuth-SSO smoke tests in both the Snowflake and Databricks suites
were re-fetching ANA_E2E_ENDPOINT via os.Getenv and asserting non-empty,
but harness.Begin already validates the var and skips the test if it's
unset. Add a thin H.Endpoint() accessor so tests that need the endpoint
(to match it against CLI stdout) pull it from the harness rather than
re-reading the environment.
stdlib flag.Parse re-wraps Set errors with %v, so the ErrUsage chain
that callers rely on only survives when parsing goes through
cli.ParseFlags. The six Declare{String,Bool,Int}* tests were calling
fs.Parse directly, bypassing the production path. Route them through
ParseFlags to match the rule already enforced in flags_test.go.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/connector_databricks_test.go`:
- Around line 159-192: Update TestConnectorCreateDatabricksOAuthIndividual to
perform the same post-create "connector get" verification as the other tests:
after calling extractConnectorID(t, stdout) and h.RegisterConnectorCleanup(id)
(and only if not h.DryRun()), run the CLI "connector get <id>" via h.Run (or
h.RunStdin if needed), check for errors, and assert the returned stdout contains
"connectorType: DATABRICKS" and the "lazily at first query" per-member-lazy
note; reuse the same helpers (extractConnectorID, h.Run/h.RunStdin) and mirror
the existing assertion text used earlier in the test for consistency.
- Around line 91-120: Add a post-create verification call to run "connector get"
for the created connector ID in TestConnectorCreateDatabricksClientCredentials:
after calling extractConnectorID(t, stdout) and h.RegisterConnectorCleanup(id),
invoke the harness to execute the equivalent of "connector get <id>" (using the
harness Run/RunStdin helper like h.Run or h.RunStdin) and assert the returned
stdout contains "connectorType: DATABRICKS" (same check used earlier in the
access-token test), failing the test if the verification fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4428356f-fc9a-4b61-a9f1-85e58ddb63d0

📥 Commits

Reviewing files that changed from the base of the PR and between 43e1f64 and 5d14d5c.

📒 Files selected for processing (8)
  • e2e/connector_databricks_test.go
  • e2e/connector_snowflake_test.go
  • e2e/harness/harness.go
  • internal/cli/cli_test.go
  • internal/connector/create_databricks.go
  • internal/connector/create_databricks_client_credentials.go
  • internal/connector/create_databricks_oauth_individual.go
  • internal/connector/create_databricks_oauth_sso.go

Comment thread e2e/connector_databricks_test.go
Comment thread e2e/connector_databricks_test.go
Databricks client-credentials and oauth-individual were missing the
post-create `connector get` verification that access-token already had.
Same drift had crept into Snowflake keypair/oauth-sso/oauth-individual.
Add the get round-trip to every create-leaf smoke so the server read-back
is uniformly asserted.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@e2e/connector_databricks_test.go`:
- Around line 61-201: Tests TestConnectorCreateDatabricksAccessToken,
TestConnectorCreateDatabricksClientCredentials,
TestConnectorCreateDatabricksOAuthSSO and
TestConnectorCreateDatabricksOAuthIndividual duplicate the
create/run/dry-run/id/cleanup/get pattern; extract a helper (e.g.,
createAndVerifyDatabricksConnector) that accepts the harness, command args (or
leaf name), stdin content, expected stdout fragments and returns the created id
(or error), reusing databricksCommonArgs and extractConnectorID; replace each
test body to build args, call the helper, register cleanup by name before helper
if needed, and assert leaf-specific stdout fragments (like "connectorType:
DATABRICKS" or "complete OAuth at "+h.Endpoint()) outside or via expected
fragments passed into the helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c3bbd1d3-7ce0-4b85-90e0-b41bdc9e647d

📥 Commits

Reviewing files that changed from the base of the PR and between 5d14d5c and 0f50b55.

📒 Files selected for processing (2)
  • e2e/connector_databricks_test.go
  • e2e/connector_snowflake_test.go

Comment thread e2e/connector_databricks_test.go
… + Databricks

The create/dry-run/id/cleanup/connectorType/get round-trip was copy-pasted
across all 8 Snowflake + Databricks create-leaf smokes, and the parity gap
that motivated 0f50b55 (missing `connector get` on 5 of 8 leaves) could
only recur because each test hand-rolled the sequence.

Hoist the pattern into connectorCreateLeaf{Name,Args,Stdin,ConnectorType,
Extra}.Run — the only way to skip the `get` round-trip now is to bypass
the helper on purpose. Also moves extractConnectorID (and its shared
regex) into the new dialect-neutral helpers file so it no longer lives
awkwardly next to Snowflake-only code.

Leaf-specific stdout assertions (OAuth endpoint note, per-member-lazy
note) ride along on the `Extra` hook so each test stays a single
declarative block.
@bradfair bradfair added this pull request to the merge queue Apr 22, 2026
Merged via the queue into main with commit ba9159d Apr 22, 2026
10 checks passed
@bradfair bradfair deleted the feature/databricks-connector-parity branch April 22, 2026 19:28
@hpt-bot hpt-bot Bot mentioned this pull request Apr 22, 2026
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