Skip to content

#222: parse type:databricks dbt profile target - #255

Merged
wjduenow merged 9 commits into
devfrom
feature/222-databricks-profile
Jun 25, 2026
Merged

#222: parse type:databricks dbt profile target#255
wjduenow merged 9 commits into
devfrom
feature/222-databricks-profile

Conversation

@wjduenow

@wjduenow wjduenow commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Parse a type: databricks dbt profile target into the unified DbtProfileTarget (single model, discriminated-by-validator — not a union). Per-warehouse twin of the shipped #120 (Snowflake); builds on the #221 skeleton. Closes #222.

Changes

  • 7 new DbtProfileTarget fields: host, http_path, token (repr=False), catalog, client_id, client_secret (repr=False), auth_type; _DATABRICKS_ONLY frozenset.
  • databricks arm in the cross-field validator: auth-conditional required-set (PAT→token; OAuth→client_id+client_secret; auth-validity checked first), bidirectional foreign-field rejection, identifier hygiene. Empty/whitespace credentials count as missing (an unset env_var('…','')"" no longer slips through).
  • Two permissive non-SQL validators validate_databricks_hostname / validate_databricks_http_path (mirror validate_snowflake_account).
  • Shared connection knobs connect_retries/connect_timeout/connect_max_idle added as accepted-but-unused (like threads) so real dbt-databricks profiles parse under extra="forbid".
  • from_profile wires every field (lazy import); drift detector (StrictDatabricksModel + dbt_databricks_drift_v1_x.yml); load_profile e2e fixture + test.
  • Reuses existing error classes (no taxonomy churn). OAuth fields validated now; the OAuth connection is deferred (connector is PAT-only); live connection is Databricks: test harness + gated live e2e + ops docs #226.

Testing

  • uv sync --dev && ruff check && ruff format --check && pyright && pytest — green (4191 passed, 6 skipped; pyright 0 errors). CI green on 3.11/3.12/3.13.
  • Quality Gate: 4 review passes (correctness/security, conventions, tests, edge-cases/dbt-fidelity) → fixed one real bug (empty-string credential bypass) + NITs.

Compounding Update

  • .claude/rules/warehouse-adapters.md § "Databricks arm (issue Databricks: parse 'type: databricks' dbt profile target #222)" — conditional auth-keyed required-set, empty-string-as-missing, shared connection-knob fields.
  • docs/warehouse-adapter-ops.mdtype: databricks parsing + dispatch + error-table row.

Plan: plans/super/222-databricks-profile.md.

Summary by CodeRabbit

  • New Features

    • Added support for Databricks profile parsing and adapter setup, including PAT and OAuth-style connection details.
    • Expanded validation for Databricks host and HTTP path values, plus clearer handling of required and optional connection fields.
    • Added end-to-end coverage for loading Databricks profiles and drift detection for Databricks-shaped configs.
  • Bug Fixes

    • Improved error messages for unsupported profile types and unsupported Databricks auth modes.
    • Prevented secret values from appearing in rendered profile output.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b55b8efd-f9b1-40c4-b8cf-52d641906842

📥 Commits

Reviewing files that changed from the base of the PR and between 9314c3f and 555953b.

📒 Files selected for processing (3)
  • docs/warehouse-adapter-ops.md
  • plans/super/222-databricks-profile.md
  • src/signalforge/warehouse/errors.py
✅ Files skipped from review due to trivial changes (1)
  • plans/super/222-databricks-profile.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/warehouse-adapter-ops.md

📝 Walkthrough

Walkthrough

Adds Databricks profile parsing support across validation, adapter wiring, docs, fixtures, and tests. The changes define Databricks host and HTTP-path validation, Databricks-specific DbtProfileTarget fields and auth checks, from_profile wiring, and new coverage for parsing and drift detection.

Changes

Databricks profile parsing

Layer / File(s) Summary
Docs and plan
plans/super/222-databricks-profile.md, .claude/rules/warehouse-adapters.md, docs/warehouse-adapter-ops.md, src/signalforge/warehouse/errors.py
The Databricks parsing plan, warehouse docs, and remediation text describe the target contract, supported dispatch types, auth shapes, and updated error wording.
Hostname and path validators
src/signalforge/warehouse/_sql_safety.py, tests/warehouse/test_sql_safety.py
New Databricks hostname and HTTP-path validators are added with positive and negative coverage.
DbtProfileTarget Databricks validation
src/signalforge/warehouse/profiles.py, tests/fixtures/profiles/dbt_databricks_drift_v1_x.yml, tests/warehouse/test_profiles.py
DbtProfileTarget adds Databricks fields, auth-gated required-key checks, foreign-field rejection, secret redaction, drift validation, and load_profile coverage.
Databricks adapter wiring
src/signalforge/warehouse/base.py, tests/fixtures/profiles/databricks_pat.yml, tests/warehouse/test_databricks_stub.py
WarehouseAdapter.from_profile passes parsed Databricks fields into DatabricksAdapter, and dispatch tests use the new Databricks profile fixture.

Sequence Diagram(s)

sequenceDiagram
  participant WarehouseAdapter.from_profile
  participant DbtProfileTarget.model_validate
  participant validate_databricks_hostname
  participant validate_databricks_http_path
  participant DatabricksAdapter

  WarehouseAdapter.from_profile->>DbtProfileTarget.model_validate: validate type: databricks profile
  DbtProfileTarget.model_validate->>validate_databricks_hostname: check host
  DbtProfileTarget.model_validate->>validate_databricks_http_path: check http_path
  DbtProfileTarget.model_validate-->>WarehouseAdapter.from_profile: validated Databricks fields
  WarehouseAdapter.from_profile->>DatabricksAdapter: construct with host, http_path, token, catalog, schema, auth_type, client_id, client_secret
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wjduenow/SignalForge#125 — Extends WarehouseAdapter.from_profile dispatch logic in the same adapter routing path.
  • wjduenow/SignalForge#126 — Touches the same DbtProfileTarget and from_profile validation/wiring flow in profiles.py and base.py.
  • wjduenow/SignalForge#254 — Introduces the earlier Databricks adapter skeleton that this PR’s parsing and wiring now completes.

Poem

🐇 I hopped through profiles, bright and new,
Host and http_path got vetted too.
Tokens tucked away, adapters aligned,
Databricks paths now parse just fine.
Hop, hop, huzzah! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main change: adding Databricks dbt profile target parsing.
Linked Issues check ✅ Passed The changes align with #222: Databricks fields, auth-dependent validation, foreign-field rejection, permissive host/http_path checks, and drift coverage are all present.
Out of Scope Changes check ✅ Passed No clearly unrelated code changes are evident; the docs, plan, tests, and runtime updates all support the Databricks profile parsing work.
Docstring Coverage ✅ Passed Docstring coverage is 92.11% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

wjduenow added 7 commits June 24, 2026 17:46
…leTarget (US-002, #222)

Teach the unified DbtProfileTarget to parse a `type: databricks` dbt profile,
mirroring the Snowflake per-type validator arm (#120):

- 7 new Optional fields: host, http_path, catalog, client_id, auth_type plus
  the secret material token + client_secret (repr=False, like Snowflake
  password). `dataset` (schema alias) + `threads` stay shared; catalog is its
  own new field (the analogue of project / database).
- _DATABRICKS_ONLY frozenset + _DATABRICKS_REQUIRED (host, http_path always)
  + _DATABRICKS_SUPPORTED_AUTH ({pat, oauth}, None = default PAT).
- databricks arm in _validate_type_field_coherence: unsupported auth_type ->
  UnsupportedAuthMethodError FIRST (a bad method changes which keys are
  required); auth-conditional required-key collect-all (PAT needs token;
  oauth needs client_id + client_secret) -> IncompleteProfileError; foreign
  _BIGQUERY_ONLY | _SNOWFLAKE_ONLY rejection (plain ValueError); identifier
  hygiene on catalog/schema (strict) + host/http_path (permissive US-001
  validators).
- bigquery + snowflake arms extended to also reject _DATABRICKS_ONLY fields.
- _DATABRICKS_DEFERRED_AUTH_REMEDIATION in errors.py (imported by name, not
  exported in __all__, mirroring _SNOWFLAKE_DEFERRED_AUTH_REMEDIATION).

Tests: full PAT + OAuth parse, missing http_path / PAT token / oauth client
creds, unknown auth_type, foreign-field rejection both directions
(bq<->databricks, snowflake<->databricks), bad catalog/schema/host/http_path,
secret repr redaction.

The two #221 from_profile dispatch stub tests fed a project/schema-only
databricks profile (now correctly rejected — project is BigQuery-only);
updated to a valid full target. base.py's catalog<-profile.project mapping is
left for US-003 to rewire, so _catalog stays None for now (asserted, flips in
US-003).
…etector + load_profile e2e (US-003, #222)

Rewire WarehouseAdapter.from_profile's databricks branch to pass the real
parsed DbtProfileTarget fields (host / http_path / token / catalog + the
OAuth-M2M auth fields), replacing the #221 placeholder catalog<-project
mapping. Add the mandatory drift detector (StrictDatabricksModel +
dbt_databricks_drift_v1_x.yml fixture) and a load_profile end-to-end
fixture + test, mirroring the shipped Snowflake #120 work. Flip the
transitional from_profile dispatch assertion left by US-002 to reflect the
now-correct field wiring.
…pass + add connection-knob passthrough fields + test hardening

- profiles.py: required-key check treats empty/whitespace as missing (token/client_id/client_secret could bypass via is-None-only check; realistic trigger is an unset env_var('...','') rendering to '')
- profiles.py: add connect_retries/connect_timeout/connect_max_idle as accepted-but-unused shared fields (mirrors the threads precedent) so a real dbt-databricks profile parses under extra=forbid
- _sql_safety.py: fix off-by-one in http_path length comment (1-511 after slash)
- test_profiles.py: drop vacuous 'or host'/'or http_path' assertion fallback; add explicit auth_type=pat, short-catalog 'main', empty-credential rejection, and connection-knob acceptance tests
…cks profile arm

- warehouse-adapters.md: new 'Databricks arm (issue #222)' subsection under Unified DbtProfileTarget (conditional auth-keyed required-set, empty-string-as-missing credential check, shared connection-knob passthrough fields); update the #221 skeleton deferral note to point at the landed work
- warehouse-adapter-ops.md: document type:databricks profile parsing in the from_profile dispatch section + UnsupportedProfileTypeError row
@wjduenow
wjduenow marked this pull request as ready for review June 25, 2026 02:47
@wjduenow
wjduenow requested a review from Copilot June 25, 2026 02:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds Databricks (type: databricks) support to the unified DbtProfileTarget profile parser, including permissive non-SQL validation for connection fields, auth-conditional required-key logic, and drift-detection fixtures/tests—then wires the parsed fields through WarehouseAdapter.from_profile to the existing Databricks skeleton adapter.

Changes:

  • Extend DbtProfileTarget with Databricks connection/auth fields and a databricks arm in the cross-field validator (including symmetric foreign-field rejection).
  • Add permissive validators for Databricks host and http_path, plus unit tests and end-to-end load_profile coverage.
  • Add a Databricks drift detector fixture + strict mirror model, and update docs/rules/plan to reflect the new parsing behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/signalforge/warehouse/_sql_safety.py Adds permissive Databricks hostname/http_path validators (non-SQL hygiene).
src/signalforge/warehouse/profiles.py Adds Databricks fields, auth-conditional required set, and foreign-field rejection in the model validator.
src/signalforge/warehouse/errors.py Adds Databricks deferred-auth remediation string for UnsupportedAuthMethodError.
src/signalforge/warehouse/base.py Wires parsed Databricks fields through WarehouseAdapter.from_profile into DatabricksAdapter.
tests/warehouse/test_sql_safety.py Unit tests for the new Databricks host/http_path validators (valid + garbage + error rendering).
tests/warehouse/test_profiles.py Databricks parsing tests (PAT + OAuth), foreign-field rejection, drift detector, and load_profile e2e test.
tests/warehouse/test_databricks_stub.py Updates/extends factory dispatch test to assert real Databricks fields are passed through.
tests/fixtures/profiles/dbt_databricks_drift_v1_x.yml Adds Databricks drift-detector fixture for strict mirror validation.
tests/fixtures/profiles/databricks_pat.yml Adds minimal Databricks PAT profiles.yml fixture for load_profile e2e test.
docs/warehouse-adapter-ops.md Documents Databricks profile parsing and updates supported profile types.
.claude/rules/warehouse-adapters.md Records the new Databricks arm conventions/patterns for future work.
plans/super/222-databricks-profile.md Adds the super plan describing scope/decisions/tests for #222.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/warehouse-adapter-ops.md Outdated
Comment thread plans/super/222-databricks-profile.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/signalforge/warehouse/profiles.py (1)

279-293: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Empty-string auth_type is treated as unsupported, not as default PAT.

The required-key block deliberately normalizes empty/whitespace credentials to "missing" to handle an unset env_var(..., '') render. An auth_type rendered to "" from the same templating pattern instead hits Line 279 ("" is not None and "" not in _DATABRICKS_SUPPORTED_AUTH) and raises UnsupportedAuthMethodError(method="") rather than defaulting to PAT. The error is still loud and lists the supported set, so this isn't a correctness bug — just an asymmetry with the credential handling you explicitly cared about. Consider normalizing a blank auth_type to None for consistency.

♻️ Optional normalization
-            if self.auth_type is not None and self.auth_type not in _DATABRICKS_SUPPORTED_AUTH:
+            auth_type = (self.auth_type or "").strip() or None
+            if auth_type is not None and auth_type not in _DATABRICKS_SUPPORTED_AUTH:
                 raise UnsupportedAuthMethodError(
-                    method=self.auth_type,
+                    method=self.auth_type,
                     remediation=_DATABRICKS_DEFERRED_AUTH_REMEDIATION,
                 )

(Use the normalized value in the == "oauth" branch below too.)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/signalforge/warehouse/profiles.py` around lines 279 - 293, The auth_type
handling in the Databricks profile validation treats an empty string as
unsupported instead of falling back to default PAT like the credential fields
do. Normalize blank or whitespace-only auth_type to None before the
_DATABRICKS_SUPPORTED_AUTH check in profiles.py, and use that normalized value
in the subsequent oauth vs PAT required-key branch so the behavior is consistent
with the empty-string handling for token/client fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/warehouse-adapter-ops.md`:
- Line 800: The docs row and UnsupportedProfileTypeError.default_remediation are
out of sync about supported profile types. Update the runtime remediation text
in UnsupportedProfileTypeError (or revise the warehouse docs table) so the
supported/unsupported dbt profile types match exactly, using the existing
UnsupportedProfileTypeError symbol in src/signalforge/warehouse/errors.py as the
source of truth.
- Around line 68-75: The WarehouseAdapter documentation overstates the
Databricks skeleton contract in the section describing
WarehouseAdapter.from_profile and the databricks adapter. Update the wording so
it is precise: only sample_rows, column_stats, and run_test_sql still raise
NotImplementedError for Databricks, while the other warehouse methods already
inherit typed *NotSupportedError defaults from the ABC. Keep the
dispatch/remediation description for profile.type accurate and align the adapter
behavior summary with the actual Databricks methods.

In `@plans/super/222-databricks-profile.md`:
- Line 34: The Databricks profile contract is inconsistent because the
documentation marks schema as required while the validator/tests still treat it
as the shared dataset alias. Update the docs to remove schema from the
required-key list, or if schema must be mandatory, align the implementation by
updating _DATABRICKS_REQUIRED and the related missing-key tests so the contract
matches the code.

---

Nitpick comments:
In `@src/signalforge/warehouse/profiles.py`:
- Around line 279-293: The auth_type handling in the Databricks profile
validation treats an empty string as unsupported instead of falling back to
default PAT like the credential fields do. Normalize blank or whitespace-only
auth_type to None before the _DATABRICKS_SUPPORTED_AUTH check in profiles.py,
and use that normalized value in the subsequent oauth vs PAT required-key branch
so the behavior is consistent with the empty-string handling for token/client
fields.
🪄 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: CHILL

Plan: Pro

Run ID: 43cdfe85-64fe-4d0c-a73d-5719744a25ea

📥 Commits

Reviewing files that changed from the base of the PR and between 314ffc8 and 9314c3f.

📒 Files selected for processing (12)
  • .claude/rules/warehouse-adapters.md
  • docs/warehouse-adapter-ops.md
  • plans/super/222-databricks-profile.md
  • src/signalforge/warehouse/_sql_safety.py
  • src/signalforge/warehouse/base.py
  • src/signalforge/warehouse/errors.py
  • src/signalforge/warehouse/profiles.py
  • tests/fixtures/profiles/databricks_pat.yml
  • tests/fixtures/profiles/dbt_databricks_drift_v1_x.yml
  • tests/warehouse/test_databricks_stub.py
  • tests/warehouse/test_profiles.py
  • tests/warehouse/test_sql_safety.py

Comment thread docs/warehouse-adapter-ops.md
Comment thread docs/warehouse-adapter-ops.md Outdated
Comment thread plans/super/222-databricks-profile.md Outdated
@wjduenow wjduenow changed the title #222: parse type:databricks dbt profile target (plan) #222: parse type:databricks dbt profile target Jun 25, 2026
- errors.py: UnsupportedProfileTypeError docstring + default_remediation now name postgres/snowflake/databricks with correct version tracks (was stale 'bigquery only … v0.2'); source of truth for the docs row
- warehouse-adapter-ops.md: precise NotImplementedError-vs-*NotSupportedError scope for the Databricks skeleton; error-table row synced to the runtime remediation with correct v0.2/v0.x labels
- plan: clarify dbt-requires-schema vs SignalForge's narrower required-VALIDATED set (schema/catalog are parse-optional, not in _DATABRICKS_REQUIRED)
@wjduenow

Copy link
Copy Markdown
Owner Author

PR Review Summary

All five review threads addressed (fixed in 555953b / PR metadata). No false positives — every comment was a legitimate accuracy/consistency issue.

Fixed (5 items)

File Issue Resolution
src/signalforge/warehouse/errors.py UnsupportedProfileTypeError.default_remediation was stale (bigquery only … v0.2), out of sync with the docs row (CodeRabbit) Rewrote docstring + remediation to name postgres (v0.2 stub) / snowflake (v0.2) / databricks (v0.x skeleton) — now the source of truth the docs row mirrors
docs/warehouse-adapter-ops.md (row ~800) docs listed databricks supported but runtime remediation didn't (CodeRabbit); "v0.x" applied to postgres/snowflake too (Copilot) Synced the row to the runtime remediation with correct per-adapter version tracks
docs/warehouse-adapter-ops.md (§ from_profile) overstated that all Databricks warehouse methods raise NotImplementedError (CodeRabbit) Now precise: only sample_rows/column_stats/run_test_sql raise; the rest inherit the ABC's typed *NotSupportedError
plans/super/222-databricks-profile.md (l.34) dbt-reference note marked schema required, but it's the optional shared dataset alias in SignalForge's contract (CodeRabbit) Clarified dbt-requires-schema vs SignalForge's narrower required-VALIDATED set (schema/catalog are parse-optional, not in _DATABRICKS_REQUIRED)
PR title/body + plans/…:12 phase PR body said "detailing (awaiting approval)" while the plan phase is "devolved" (Copilot) Dropped the (plan) title suffix and rewrote the PR body to the shipped/in-review state

False Positives (0 items)

All threads resolved.

@wjduenow
wjduenow merged commit c1b638c into dev Jun 25, 2026
7 checks passed
@wjduenow
wjduenow deleted the feature/222-databricks-profile branch June 25, 2026 03:46
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