Skip to content

feat: dbt-aware rule pack scaffolding + DBT001 model-without-test#57

Merged
Pawansingh3889 merged 10 commits into
mainfrom
feature/dbt-pack-scaffold
May 20, 2026
Merged

feat: dbt-aware rule pack scaffolding + DBT001 model-without-test#57
Pawansingh3889 merged 10 commits into
mainfrom
feature/dbt-pack-scaffold

Conversation

@Pawansingh3889
Copy link
Copy Markdown
Owner

What changed

First slice of the [dbt-aware rule pack ADR]: scaffolding + the simplest of the seven proposed rules (DBT001 model-without-test). The remaining six rules and the Jinja preprocessor are intentionally deferred to follow-up PRs.

New modules:

  • sql_guard/dbt.py — project discovery (find_dbt_project, load_dbt_project, DbtProject, DbtModelEntry). Walks up from a path to find dbt_project.yml, parses model-paths, and reads every schema.yml under those paths. Supports both tests: (dbt ≤1.4) and data_tests: (dbt ≥1.5) spellings. Tolerates malformed schema.yml without crashing the lint run.
  • sql_guard/rules/dbt.pyModelWithoutTest rule class.

Rule API change:

  • New Rule.check_file(file) -> list[Finding] extension point on the base class. Default returns [] so line- and statement-rules pay nothing. File-level rules (e.g. DBT001) override it. Checker runs check_file after the existing line and statement passes.

Wiring:

  • build_dbt_rules(project) registry helper mirrors build_contract_rules(contract).
  • get_rules(..., dbt_project=...) accepts the project and appends DBT rules when set.
  • --dbt CLI flag, auto-discovers dbt_project.yml from the first checked path. Silent without the flag. Surfaces a yellow warning when --dbt is supplied but no project is found.

Related issue

[ADR] dbt-aware rule pack — implementation of DBT001 only; remaining rules are explicitly out of scope for this PR.

If this adds or changes a rule

  • Rule ID is the next unused in its family (DBT001)
  • Rule class registered (via build_dbt_rules rather than ALL_RULES, opt-in pattern)
  • Fixture in tests/fixtures/dbt_project/ (YAML only; no .sql files so existing files_checked counts aren't bumped)
  • "Fires on bad SQL" tests in tests/test_dbt_rules.py
  • "Does NOT fire on safe SQL" tests in tests/test_dbt_rules.py
  • README rule table + Key Numbers count updated — deliberately skipped, see below
  • Rule is not a removal or rename of an existing rule

Why no README update: the README rule table doesn't grow until at least three DBT rules exist, to avoid churning the table on every PR while the pack is still small.

Tests

  • pytest -q passes (280 passed, 1 skipped — up from 254 on main)
  • ruff check . passes
  • New tests: 14 in tests/test_dbt_discovery.py, 12 in tests/test_dbt_rules.py (including end-to-end CLI integration).

Checklist

  • One logical change per commit (9 commits, Conventional Commits style)
  • CHANGELOG.md [Unreleased] entry added

Anything else reviewers should know

Deferred to follow-up PRs (per the ADR):

  • Jinja preprocessor (~1 week of work on its own)
  • DBT002 (direct-table-ref), DBT003 (incremental-without-unique-key), DBT004 (hook-with-ddl), DBT005 (select-star-in-mart), DBT006 (model-without-description), DBT007 (var-injection-risk)

Compatibility:

  • Default behaviour for current users is unchanged — --dbt is opt-in.
  • The new Rule.check_file method has a sensible default; no existing rule needs modification.
  • No new mandatory dependency (PyYAML is already required).

@Pawansingh3889 Pawansingh3889 merged commit 7ee1371 into main May 20, 2026
7 checks passed
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