Conversation
…ipts_not_db.md) Adds a single warn rule to the migration-discipline family that catches the last documented escape hatch from the "no ad-hoc DB writes" memory: direct curl mutations (POST / PATCH / PUT / DELETE) against the Supabase PostgREST endpoint. The neighbor warn-psql-against-supabase-remote already covers the psql / pg_dump / pg_restore vector; warn-curl-mutating-supabase-rest closes the final gap. Match is anchored on the explicit `-X <METHOD>` form and narrowed to `.supabase.co/rest/v1/` so Auth, Storage, and Edge Function endpoints are not flagged. Test fixtures use sanitized hosts (example.supabase.co) — same convention the migration-discipline rules adopted in PR #15 round-2. - 19 rules (was 18) - 93 / 93 tests pass (was 86, +7) - 1.7.0 -> 1.8.0 in package.json, plugin.json, marketplace.json (top-level + nested plugin entry) - README family entry extended with the new rule
|
@greptile review |
Greptile SummaryThis PR adds the
Path to 5/5 Confidence
Confidence Score: 5/5Safe to merge; the rule logic and all 12 tests are correct, and the only gaps are a stale pattern in a design doc and an undocumented false negative for --data-urlencode. The regex correctly catches all the mutation vectors it claims to cover, all 12 tests are well-structured and validate both positive and negative paths, version bumps are consistent, and the bypass marker is properly wired. The two issues found are a documentation artefact (design.md still shows the old pattern) and one undocumented false negative (--data-urlencode implicit POST), neither of which affects runtime behaviour of the deployed rule. openspec/changes/2026-05-hook-curl-mutating-supabase-rest/design.md — the Pattern section is out of date with the implementation.
|
| Filename | Overview |
|---|---|
| hooks/rules/rules.yaml | Adds warn-curl-mutating-supabase-rest rule with a multi-clause pattern covering -XPOST no-space, URL-before-flag ordering, and implicit POST via -d/--data*; --data-urlencode implicit POST is not caught (undocumented gap) |
| hooks/rules/rules.json | Regenerated artifact that mirrors rules.yaml; same pattern gap applies |
| openspec/changes/2026-05-hook-curl-mutating-supabase-rest/design.md | Pattern code block and rationale section still reflect the original single-clause regex from before the Greptile revision rounds; the test list is correct but the Pattern section is stale |
| hooks/rules/README.md | Database/migration discipline family entry extended to include the new rule; description is accurate and consistent with the implementation |
| package.json | Version bumped 1.7.0 → 1.8.0; no other changes |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Bash tool_call: curl command] --> B{Contains supabase.co/rest/v1/?}
B -- No --> ALLOW[Allow: exit 0, no warning]
B -- Yes --> C{Bypass marker present?}
C -- Yes --> ALLOW
C -- No --> D{Vector 1: explicit -X METHOD}
D -- POST/PATCH/PUT/DELETE --> WARN
D -- GET or absent --> E{Vector 2: URL before -X METHOD}
E -- Yes --> WARN
E -- No --> F{Vector 3: implicit POST via -d or --data flags}
F -- Matched --> WARN
F -- No match --> ALLOW
WARN[warn: exit 0 + stderr contains rule id]
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
openspec/changes/2026-05-hook-curl-mutating-supabase-rest/design.md:5-6
**Stale pattern in Design doc**
The "Pattern" code block still shows the original single-clause regex (`curl.*-X[[:space:]]+(POST|PATCH|PUT|DELETE).*\.supabase\.co/rest/v1/`), which is the version from before the Greptile rounds that added the no-space `-XPOST`, URL-before-flag, and implicit-`-d` variants. The rationale text below the box also only describes the `-X METHOD` form and doesn't mention the `-d`/`--data*` implicit-POST vector. Anyone reading `design.md` to understand the rule's scope or to write a follow-up rule gets a materially incomplete picture of what the implementation actually matches.
### Issue 2 of 2
hooks/rules/rules.yaml:1007-1009
**`--data-urlencode` implicit POST not caught**
`curl --data-urlencode 'name=Alice' https://example.supabase.co/rest/v1/profiles` triggers an implicit POST (same as `-d`) but falls through the pattern. The `--data([[:space:]]|=|-raw...|binary...)` alternation requires the character after `--data` to be a space, `=`, `-raw`, or `-binary`; `-urlencode` matches none of those, so the flag is silently skipped. This is in the same class as the `--request` acknowledged false negative, but unlike `--request`, `--data-urlencode` is commonly used for form-style payloads against REST endpoints and isn't called out anywhere in the design doc as a known gap.
Reviews (3): Last reviewed commit: "fix(rules): close round-2 Greptile findi..." | Re-trigger Greptile
…rest 1. Cover the no-space `-XPOST` shorthand: relax `[[:space:]]+` to `[[:space:]]*`. Adds `warns-curl-xpost-no-space` test. 2. Cover URL-before-flag ordering: extend the pattern to a two-clause alternation that matches whether `-X METHOD` precedes or follows the `.supabase.co/rest/v1/` segment. Adds `warns-curl-url-before-flag` test. 3. Rename the four `blocks-*` test names to `warns-*` — the rule action is `warn` (expected_exit 0), so `blocks-*` was misleading. Tests: 93 -> 95 passing (+2 coverage tests).
|
Round 2: addressed all 3 Greptile findings. See commit 5ff4156.
Tests: 93 -> 95 passing. @greptile review |
…abase-rest
1. **Implicit POST via -d/--data is now caught** — extend the pattern
alternation to fire when `-d`, `--data`, `--data-raw`, or
`--data-binary` are present without `-X`. Curl auto-promotes to POST
in that case, so a one-liner like
curl -d '{"id":1}' https://<project>.supabase.co/rest/v1/profiles
would otherwise pass silently. Three new tests cover -d before URL,
--data-raw before URL, and URL before -d.
2. **design.md test list refreshed** — replace the stale `blocks-*`
names with the actual `warns-*` names and list all 12 tests after
rounds 1-2. Drop the old "blocks- naming for symmetry" rationale
that was made obsolete by round 1.
3. **Pattern comment refactored** — document the three vectors the
alternation covers (explicit -X, URL ordering, implicit POST via
data flags).
Tests: 95 -> 98 passing.
|
Round 3: addressed both round-2 findings (implicit POST via @greptile review |
…abase-rest
1. **--data-urlencode now caught** — extend the `--data(...)` alternation
to include `-urlencode[[:space:]]` and `-urlencode=`. Curl
auto-promotes to POST for `--data-urlencode` the same way it does for
`-d`/`--data`/`--data-raw`/`--data-binary`, so a one-liner like
curl --data-urlencode 'name=Alice' https://<project>.supabase.co/rest/v1/profiles
would otherwise pass silently. Adds `warns-curl-implicit-post-via-data-urlencode`
test.
2. **design.md Pattern section refreshed** — replace the original
single-clause regex with the actual 4-clause alternation, documenting
each vector (explicit -X, URL ordering, implicit POST via data flags,
implicit POST via --data-urlencode). The accepted false-negatives
subsection now also mentions `-G` (which overrides auto-promotion).
Tests: 98 -> 99 passing. Greptile already at 5/5 on round 3 commit
ac5b931 — these are belt-and-suspenders fixes for the two nits Greptile
flagged in its 5/5 review.
Summary
Adds a single warn rule to the Database / migration discipline family
that closes the last documented escape hatch from
feedback_scripts_not_db.md:direct mutating
curlcalls against the Supabase PostgREST endpoint.The existing
warn-psql-against-supabase-remoterule covers thepsql/pg_dump/pg_restorevector.warn-curl-mutating-supabase-resthandles the equivalent REST escape hatch.
Why this matters
curl -X POST/PATCH/PUT/DELETE https://<project>.supabase.co/rest/v1/...mutations:
src/services/api/that alreadyencapsulates the same access pattern
The new rule
warn-curl-mutating-supabase-restBashcurl -X (POST|PATCH|PUT|DELETE) ... .supabase.co/rest/v1/.GETis not flagged (read-only). Bypass markercurl-supabase-rest-mutationfor documented hotfixes.The rule is
warn, notblock, mirroring the severity of its neighborwarn-psql-against-supabase-remote. Both warn against the same class ofnudge (ad-hoc DB writes that bypass migrations) and both are escalatable
to
blockin a follow-up PR if usage data shows the warning is ignored.Test count
```
Before: 86 / 86 passed (18 rules)
After: 93 / 93 passed (19 rules, +7 new tests)
```
The 7 new tests cover positive matches (
POST,PATCH,PUT,DELETE),negative matches (
GET, non-Supabase hosts), and bypass-marker behavior.Version bump
`1.7.0 -> 1.8.0`
Per semver, adding a new enforcement rule is a feature add -> minor bump.
Bumped in:
Test plan
Notes for reviewers
same convention as the migration-discipline rules added in PR feat(rules): add 4 migration-discipline PreToolUse rules #15
round-2 (no real project refs in the public toolkit).
is an accepted false negative; the long form is uncommon enough that
authors using it can be expected to know the rule and self-flag.
endpoints are not flagged. Edge Functions are the intended outlet.
OpenSpec: `openspec/changes/2026-05-hook-curl-mutating-supabase-rest/`
(proposal, design, tasks).
This PR is part of a sequential rollout — see the planning thread for
PR-B (Tier 1 anti-foot-shoot blocks) and PR-C (Tier 2 discipline warns)
queued behind it.
Created by Claude Code on behalf of @lapc506
Claude Code