Skip to content

Commit 40be47e

Browse files
feat: engagement pack, Marketplace-ready action, Pyodide playground
- action.yml: add author + branding (check-square/blue) and include-python input - reporters/terminal.py: soft CTA on findings -> rule-request issue form - .github/ISSUE_TEMPLATE/rule-request.yml: structured rule request form - .github/ISSUE_TEMPLATE/config.yml: route usage Qs to Discussions - docs/engagement/: good-first-issues, announcements, discussion draft, Marketplace release guide - docs/blog/sqlfluff-vs-sql-sop.md: honest comparison post - playground/: Pyodide-based in-browser linter scaffold (GH Pages ready) - pyproject.toml: 0.4.0 -> 0.4.1 - CHANGELOG: 0.4.1 entry
1 parent dbc46e3 commit 40be47e

14 files changed

Lines changed: 1451 additions & 11 deletions

File tree

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ contact_links:
33
- name: Security report (rule bypass, false negative, CVE)
44
url: https://github.com/Pawansingh3889/sql-guard/security/advisories/new
55
about: Security issues go through the private advisory channel, not a public issue. See SECURITY.md.
6-
- name: Discussion / question
6+
- name: "Usage question - 'how do I...?'"
7+
url: https://github.com/Pawansingh3889/sql-guard/discussions/categories/q-a
8+
about: Ask in Discussions - lower friction than an issue, often a faster reply.
9+
- name: "Show us how you're using sql-sop"
10+
url: https://github.com/Pawansingh3889/sql-guard/discussions/categories/show-and-tell
11+
about: Share your use case - we feature replies in the README.
12+
- name: General discussion / open-ended question
713
url: https://github.com/Pawansingh3889/sql-guard/discussions
8-
about: Open-ended questions go in Discussions so issues stay actionable.
14+
about: Anything that isn't a bug, rule request, or feature proposal.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Rule request
2+
description: Suggest a new SQL or Python lint rule
3+
title: "rule: <one-line description>"
4+
labels: ["rule-request", "needs-triage"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
Thanks for helping sharpen sql-sop. One rule-per-issue, please.
10+
If you're not sure whether it fits, open it anyway - triage is fast.
11+
12+
- type: textarea
13+
id: what
14+
attributes:
15+
label: What pattern should this rule catch?
16+
description: One sentence. Example - "Warn on UNION when UNION ALL would work."
17+
placeholder: "Warn on ..."
18+
validations:
19+
required: true
20+
21+
- type: textarea
22+
id: fail-example
23+
attributes:
24+
label: SQL (or Python) example that should fail
25+
description: Paste minimal code that should trigger the new rule.
26+
render: sql
27+
placeholder: |
28+
SELECT id FROM orders
29+
UNION
30+
SELECT id FROM archived_orders;
31+
validations:
32+
required: true
33+
34+
- type: textarea
35+
id: pass-example
36+
attributes:
37+
label: SQL (or Python) example that should NOT trigger
38+
description: The boundary case - helps us avoid false positives.
39+
render: sql
40+
placeholder: |
41+
SELECT id FROM orders
42+
UNION ALL
43+
SELECT id FROM archived_orders;
44+
validations:
45+
required: true
46+
47+
- type: dropdown
48+
id: severity
49+
attributes:
50+
label: Proposed severity
51+
options:
52+
- warning (advisory, doesn't block commits)
53+
- error (blocks commits / CI)
54+
- not sure
55+
default: 0
56+
validations:
57+
required: true
58+
59+
- type: input
60+
id: similar
61+
attributes:
62+
label: Similar existing rule (if any)
63+
description: Which rule ID would you model this on? Helps reviewers.
64+
placeholder: "e.g. W003 function-on-column"
65+
66+
- type: textarea
67+
id: why
68+
attributes:
69+
label: Why does this matter in production?
70+
description: A real bug you caught, a code review pattern, a DB outage, etc.
71+
72+
- type: checkboxes
73+
id: scope
74+
attributes:
75+
label: Scope checks (tick what applies)
76+
options:
77+
- label: This is a SQL pattern (regex-based rule in `sql_guard/rules/`)
78+
- label: This needs AST parsing (structural rule, sqlparse-based)
79+
- label: This is a Python scanner rule (libCST, in `sql_guard/rules/python_rules.py`)
80+
- label: I'm willing to open a PR for this myself

CHANGELOG.md

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,46 @@ a deprecation window (see `GOVERNANCE.md` § Scope discipline).
1010

1111
## [Unreleased]
1212

13+
_(nothing yet)_
14+
15+
## [0.4.1] - 2026-04-19
16+
1317
### Added
14-
- **Contributor paperwork**`NOTICE`, `GOVERNANCE.md`, `SECURITY.md`,
15-
`CODE_OF_CONDUCT.md`, `CONTRIBUTING.md` with the "Adding a new rule"
16-
walkthrough. Issue templates for bug reports and feature requests,
17-
PR template with the rule-addition checklist, CODEOWNERS routing
18-
reviews, first-contributor welcome workflow, PR-title validator.
18+
- **GitHub Marketplace listing**`action.yml` now declares `author` and
19+
`branding` (icon: `check-square`, colour: `blue`), plus the previously
20+
CLI-only `--include-python` surfaced as an action input. Ready to
21+
publish via the Release UI's "Publish this Action to the GitHub
22+
Marketplace" toggle.
23+
- **CLI feedback CTA** — when findings are reported, the terminal
24+
reporter prints a single dim line pointing at the rule-request issue
25+
template. Never fires on clean runs. Converts each real lint surface
26+
into a silent engagement ask.
27+
- **Rule-request issue form**`.github/ISSUE_TEMPLATE/rule-request.yml`
28+
captures pattern, fail/pass examples, proposed severity, and whether
29+
the reporter plans to open a PR. Complements the existing
30+
`feature_request.yml` (which stays for non-rule enhancements).
31+
- **Issue-template config**`.github/ISSUE_TEMPLATE/config.yml` now
32+
routes usage questions to `Discussions/Q&A` and use-case posts to
33+
`Discussions/Show-and-tell`, reducing issue-tracker noise.
34+
- **Comparison post**`docs/blog/sqlfluff-vs-sql-sop.md` — honest
35+
side-by-side with sqlfluff, positioning sql-sop as a pre-commit
36+
"smoke detector" alongside sqlfluff's "spell-checker". Includes a
37+
recommended dual-setup example.
38+
- **Hosted playground (scaffold)**`playground/index.html` + deploy
39+
README. Single-file Pyodide-based in-browser linter, ready to serve
40+
from GitHub Pages or Cloudflare Pages. No bundler, no build step.
41+
- **Engagement pack**`docs/engagement/` holds ten
42+
good-first-issue rule drafts (W011-W018, S004, P005 placeholders),
43+
a "Who's using sql-sop?" Discussion draft, multi-channel
44+
announcement post drafts (LinkedIn / Twitter / Reddit / HN), and a
45+
Marketplace release checklist.
46+
47+
### Contributor paperwork (landed in this release as well)
48+
- `NOTICE`, `GOVERNANCE.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`,
49+
`CONTRIBUTING.md` with the "Adding a new rule" walkthrough. Existing
50+
bug-report and feature-request templates, PR template with the
51+
rule-addition checklist, CODEOWNERS routing reviews,
52+
first-contributor welcome workflow, PR-title validator.
1953

2054
### Changed
2155
- **Licence stays MIT, deliberately.** `NOTICE` explains: the package

action.yml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
name: 'sql-sop'
2-
description: 'Fast rule-based SQL linter for pull requests'
2+
description: 'Fast rule-based SQL linter - catches DELETE-without-WHERE, SQL injection, and 20+ other hazards in 0.08 seconds across 200 files.'
3+
author: 'Pawan Singh Kapkoti'
4+
branding:
5+
icon: 'check-square'
6+
color: 'blue'
37
inputs:
48
paths:
59
description: 'Files or directories to check'
@@ -13,6 +17,10 @@ inputs:
1317
description: 'Stop after first error'
1418
required: false
1519
default: 'false'
20+
include-python:
21+
description: 'Also scan .py files for SQL strings in execute() / read_sql() / sqlalchemy.text() calls'
22+
required: false
23+
default: 'false'
1624
runs:
1725
using: 'composite'
1826
steps:
@@ -22,10 +30,16 @@ runs:
2230
python-version: '3.12'
2331
- name: Install sql-sop
2432
shell: bash
25-
run: pip install sql-sop
33+
run: |
34+
if [ "${{ inputs.include-python }}" = "true" ]; then
35+
pip install "sql-sop[python]"
36+
else
37+
pip install sql-sop
38+
fi
2639
- name: Run sql-sop
2740
shell: bash
2841
run: |
2942
sql-sop check ${{ inputs.paths }} \
3043
--severity ${{ inputs.severity }} \
31-
${{ inputs.fail-fast == 'true' && '--fail-fast' || '' }}
44+
${{ inputs.fail-fast == 'true' && '--fail-fast' || '' }} \
45+
${{ inputs.include-python == 'true' && '--include-python' || '' }}

docs/blog/sqlfluff-vs-sql-sop.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# sqlfluff vs sql-sop - when to use which
2+
3+
sqlfluff is the big dog of Python SQL tooling. 800+ rules, dialect-aware,
4+
first-class dbt integration, active maintainer team, and years of
5+
production use across thousands of companies. If you asked me "which
6+
linter should my data team adopt?" my answer is sqlfluff, every time.
7+
8+
So why does sql-sop exist?
9+
10+
Because the two projects aren't solving the same problem, and when I
11+
needed the second shape I couldn't find a good one. This post is a
12+
plain-language comparison so you can pick the right tool for your
13+
situation - or use both.
14+
15+
## The short answer
16+
17+
> Use **sqlfluff** for dialect-aware formatting, dbt integration, and
18+
> comprehensive lint coverage of a SQL codebase.
19+
>
20+
> Use **sql-sop** as a pre-commit hook that catches the "this would
21+
> delete production" class of mistakes in under 0.1 seconds, on
22+
> every commit, zero config.
23+
24+
You can (and probably should) use both. sql-sop runs locally on every
25+
commit; sqlfluff runs in CI once a minute. They don't overlap much in
26+
practice.
27+
28+
## Side-by-side
29+
30+
| | sql-sop | sqlfluff |
31+
|---|---|---|
32+
| Rule count | 23 (focused) | 800+ (comprehensive) |
33+
| Config needed | Zero | `.sqlfluff` with dialect + profile |
34+
| Speed (200 files) | ~0.08s | ~45s |
35+
| Dialect-aware | No (dialect-neutral regex) | Yes (12+ dialects) |
36+
| Formatter (fix mode) | No | Yes |
37+
| dbt integration | No | First-class (`sqlfluff fix models/`) |
38+
| Pre-commit hook | Yes | Yes |
39+
| GitHub Action | Yes (in Marketplace) | Community-maintained |
40+
| Catches DELETE-without-WHERE | Yes | Via custom rules |
41+
| Catches SQL injection in Python | Yes (libCST scanner) | No (SQL-only) |
42+
| Language | Python | Python |
43+
| License | MIT | MIT |
44+
| Maintainer team | Solo (for now) | ~20 active |
45+
| Age | ~1 year | ~5 years |
46+
47+
## The real mental model
48+
49+
The way I think about them:
50+
51+
**sqlfluff is a spell-checker for your entire SQL codebase.** Run it in
52+
CI on every PR. Accept the 45-second build time because you want dialect
53+
awareness, auto-formatting, and 800-rule coverage.
54+
55+
**sql-sop is a smoke detector for the kitchen.** Wire it to your
56+
pre-commit hook. If you write `DELETE FROM orders;` and try to commit,
57+
it fires in under a second. It doesn't know Snowflake from Postgres - it
58+
doesn't need to.
59+
60+
Smoke detectors and spell-checkers serve different purposes. No house
61+
ships only one.
62+
63+
## Where sqlfluff is clearly better
64+
65+
- **Formatting.** sql-sop only lints; sqlfluff fixes and reformats.
66+
- **Dialect accuracy.** sqlfluff's parser knows Snowflake's variant
67+
syntax, BigQuery's wildcards, MS SQL's `TOP`. sql-sop uses regex, so
68+
it makes trade-offs.
69+
- **dbt projects.** sqlfluff is de facto in the dbt ecosystem. Ten
70+
years from now it'll still be the right answer for dbt.
71+
- **Rule depth.** 800 rules vs 23. If you want every edge case covered,
72+
sqlfluff is the only answer.
73+
- **Large codebases.** 10,000+ SQL files? sqlfluff's parser-based
74+
approach scales better than regex on that order of magnitude.
75+
- **Team adoption.** sqlfluff has a mature config file and inherited-
76+
rule system. Teams need that.
77+
78+
## Where sql-sop is useful (and sqlfluff isn't quite the right shape)
79+
80+
- **Pre-commit hook speed.** Developers abandon hooks that take more than
81+
a couple of seconds. 0.08 seconds is imperceptible; 45 seconds is
82+
painful enough that people `--no-verify`. That's the main reason
83+
sql-sop exists.
84+
- **Zero-config starting point.** You can `pip install sql-sop` and get
85+
useful output in the next five seconds. sqlfluff requires picking a
86+
dialect and tuning a profile; that's the right investment for a team
87+
but an overhead for a first commit.
88+
- **Catching SQL injection patterns in Python.** sql-sop's
89+
`--include-python` mode walks your Python source with libCST and
90+
flags f-string interpolation inside `.execute()`, `text()`,
91+
`.read_sql()`, etc. sqlfluff doesn't do this because it's out of
92+
scope for a SQL linter.
93+
- **The "smoke detector" rule count.** 23 rules is small enough to
94+
read in one sitting. Every rule has a dedicated test. The whole
95+
ruleset fits in memory. For the pre-commit shape, that's a feature,
96+
not a limitation.
97+
- **Regex + AST hybrid, small surface.** sqlfluff's parser is brilliant
98+
but it's a lot to embed in a pre-commit hook. sql-sop is ~2000 lines
99+
of Python, most of it regex patterns.
100+
101+
## Honest shortcomings of sql-sop
102+
103+
- **Dialect-neutral means some false positives.** `W001 select-star`
104+
triggers even in a materialized-view definition where `SELECT *` is
105+
intentional. Future plan: `-- noqa: W001` inline disables.
106+
- **Structural rules are shallow.** `S001-S003` use sqlparse, which is
107+
decent for basic AST but not production-grade. Complex nested queries
108+
can defeat the depth check.
109+
- **No fix mode.** You can't run `sql-sop --fix` the way you can with
110+
`sqlfluff fix`.
111+
- **Small community.** One maintainer, ~300 downloads/month. If you
112+
need something in the next 24 hours, sqlfluff's 20-person team will
113+
get to you first.
114+
- **Newer.** A year of production use is not five years of production
115+
use.
116+
117+
## When to use both together
118+
119+
A concrete setup I run in a production data pipeline:
120+
121+
```yaml
122+
# .pre-commit-config.yaml
123+
repos:
124+
- repo: https://github.com/Pawansingh3889/sql-guard
125+
rev: v0.4.1
126+
hooks:
127+
- id: sql-guard
128+
args: [--severity, error] # fast, block on real dangers
129+
```
130+
131+
```yaml
132+
# .github/workflows/ci.yml (excerpt)
133+
jobs:
134+
sqlfluff:
135+
runs-on: ubuntu-latest
136+
steps:
137+
- uses: actions/checkout@v4
138+
- run: |
139+
pip install sqlfluff
140+
sqlfluff lint --dialect postgres .
141+
```
142+
143+
Pre-commit catches the dangerous stuff in under a second; CI runs
144+
sqlfluff at leisure and enforces the style guide. Developers never feel
145+
the cost of either.
146+
147+
## If you're picking one
148+
149+
- **You maintain a dbt project.** Use sqlfluff. Don't look back.
150+
- **You have a SQL-heavy Python backend and want pre-commit safety.**
151+
Use sql-sop. Add sqlfluff later if you expand the SQL codebase.
152+
- **You're a solo dev who just wants a lint in your next commit.**
153+
Use sql-sop for five seconds. Add sqlfluff when it starts paying off.
154+
- **You have a mature data team across multiple dialects.** Use
155+
sqlfluff. Everything else is a distraction.
156+
157+
## Honest footnote
158+
159+
I'm the author of sql-sop, so take the comparison with that bias in
160+
mind. The benchmark number (0.08s vs 45s) was run on my machine
161+
against a 200-file corpus; your mileage varies. sqlfluff's 800 rules
162+
are mostly opt-in - the default rule set is more like 80, which is still
163+
vastly more than sql-sop's 23.
164+
165+
None of this is a zero-sum argument. sqlfluff is excellent. sql-sop
166+
exists because I wanted a smaller, faster shape for the pre-commit
167+
surface, and writing it was cheaper than bending sqlfluff into that
168+
shape. If you end up picking sqlfluff after reading this, that's a
169+
reasonable outcome.
170+
171+
---
172+
173+
*The sql-sop repo and PyPI package are here:*
174+
175+
- *Repo: <https://github.com/Pawansingh3889/sql-guard>*
176+
- *PyPI: `pip install sql-sop`*
177+
178+
*sqlfluff's home:*
179+
180+
- *Repo: <https://github.com/sqlfluff/sqlfluff>*
181+
- *PyPI: `pip install sqlfluff`*

0 commit comments

Comments
 (0)