hasura / hasura/graphql-engine

Prevent running SQL with COMMIT statement via run_sql

Open
#9,221 0 comments 1 reaction 0 assignees View on GitHub
k/enhancement t/product-platform
Dominant language
TypeScript
Stars
32.1k
Forks
3k
PR merge metrics
PR metrics pending

Description

### Is your proposal related to a problem?

The `run_sql` api allows users to run arbitrary sql, and is, amongst other things, used to run migrations.

SQL executed via this api is wrapped like so:
```sql
BEGIN ISOLATION LEVEL READ COMMITTED READ ONLY;
SET LOCAL "hasura.tracecontext" = '{"span_id":"8e8f1409160a4489","trace_id":"95deafe2b16486ac75b7f1185730d0aa"}';
SET LOCAL "hasura.user" = '{"x-hasura-role":"admin"}';

-- BEGIN USER SQL

-- END USER SQL

COMMIT;
```
This ensures all SQL executed via this api is run in a transaction.
The issue is users can execute a `COMMIT` statement of their own.

If they do so, projects break if they have event triggers.

Given the following user migration:

```sql
SELECT 1;
COMMIT;
INSERT INTO notifications(message) VALUES ('this is a message');
```

The SQL executed will look like this:

```sql
BEGIN ISOLATION LEVEL READ COMMITTED READ ONLY;
SET LOCAL "hasura.tracecontext" = '{"span_id":"8e8f1409160a4489","trace_id":"95deafe2b16486ac75b7f1185730d0aa"}';
SET LOCAL "hasura.user" = '{"x-hasura-role":"admin"}';

SELECT 1;
COMMIT;
INSERT INTO notifications(message) VALUES ('this is a message');

COMMIT;
```

The issue is, the first `COMMIT` will result in the local settings `hasura.tracecontext` and `hasura.user` [going out of scope](https://www.postgresql.org/docs/current/sql-set.html):
> Specifies that the command takes effect for only the current transaction. After COMMIT or ROLLBACK, the session-level setting takes effect again. Issuing this outside of a transaction block emits a warning and otherwise has no effect.

This conflicts with our postgres function `hdb_catalog.insert_event_log` which is used by events.
The [function](https://github.com/hasura/graphql-engine/blob/525361d3d256f2432f6da2eefe8dbf17ab047e19/server/src-rsr/migrations/43_to_42.sql#L758-L759) expects the settings `hasura.user` and `hasura.tracecontext` to be valid JSON values, or be unset such that the value will be null.

But when a local variable goes out of scope, it is reset to the default value of an empty string, so `current_setting('hasura.user', 't')` will return an empty string instead of a valid json value or null.

### Describe the solution you'd like

For the reasons described above, and others, using `COMMIT` in `run_sql` can be problematic and should be prevented.

Furthermore, the exact behavior of `run_sql` should be documented.

Contributor guide

Open the contributing guide

Research direction

Start from the run_sql API implementation and its PostgreSQL transaction handling, then inspect existing tests and documentation for run_sql behavior. Add coverage showing that user-supplied COMMIT statements are rejected or handled safely, and document the resulting transaction behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, sql
Domain
api, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.