51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
"""
|
|
Regression tests for ObjectModel._validate_order_by() and its use by
|
|
Credential.get_all() (open_notebook/domain/credential.py), which builds its
|
|
own query instead of delegating to the base get_all() and previously
|
|
interpolated order_by into the SurrealQL unvalidated.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from open_notebook.domain.base import ObjectModel
|
|
from open_notebook.domain.credential import Credential
|
|
from open_notebook.exceptions import InvalidInputError
|
|
|
|
|
|
class TestValidateOrderBy:
|
|
@pytest.mark.parametrize(
|
|
"clause,expected",
|
|
[
|
|
("provider", "provider"),
|
|
("provider, created", "provider, created"),
|
|
("created DESC", "created desc"),
|
|
("provider asc, created desc", "provider asc, created desc"),
|
|
],
|
|
)
|
|
def test_accepts_and_normalizes_valid_clauses(self, clause, expected):
|
|
assert ObjectModel._validate_order_by(clause) == expected
|
|
|
|
@pytest.mark.parametrize(
|
|
"clause",
|
|
[
|
|
"field; DROP TABLE credential",
|
|
"provider, created; REMOVE TABLE credential",
|
|
"provider) FETCH (SELECT * FROM credential",
|
|
"created LIMIT 1",
|
|
"provider desc extra",
|
|
"",
|
|
],
|
|
)
|
|
def test_rejects_injection_and_malformed_clauses(self, clause):
|
|
with pytest.raises(InvalidInputError):
|
|
ObjectModel._validate_order_by(clause)
|
|
|
|
|
|
class TestCredentialGetAllRejectsInjection:
|
|
@pytest.mark.asyncio
|
|
async def test_injection_in_order_by_raises_before_querying(self):
|
|
# Must raise on validation - reaching the database with this string
|
|
# (the pre-fix behavior) would execute the injected statement.
|
|
with pytest.raises(InvalidInputError):
|
|
await Credential.get_all(order_by="provider; DROP TABLE credential")
|