fix(query_builder): added validation to check DocType name (#36878)

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Diptanil Saha 2026-02-09 15:24:58 +05:30 committed by GitHub
parent f622b6f7ad
commit a93b84df3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 13 additions and 14 deletions

View file

@ -134,10 +134,6 @@ TAB_PATTERN = re.compile("^tab")
WORDS_PATTERN = re.compile(r"\w+")
COMMA_PATTERN = re.compile(r",\s*(?![^()]*\))")
# less restrictive version of frappe.core.doctype.doctype.doctype.START_WITH_LETTERS_PATTERN
# to allow table names like __Auth
TABLE_NAME_PATTERN = re.compile(r"^[\w -]*$", flags=re.ASCII)
# Pattern for validating simple field names (alphanumeric + underscore)
SIMPLE_FIELD_PATTERN = re.compile(r"^\w+$", flags=re.ASCII)
@ -272,7 +268,6 @@ class Engine:
self.doctype = get_doctype_name(table.get_sql())
else:
self.doctype = table
self.validate_doctype()
self.table = qb.DocType(table)
if self.apply_permissions:
@ -340,10 +335,6 @@ class Engine:
self.query.immutable = True
return self.query
def validate_doctype(self):
if not TABLE_NAME_PATTERN.match(self.doctype):
frappe.throw(_("Invalid DocType: {0}").format(self.doctype))
def apply_fields(self, fields):
self.fields = self.parse_fields(fields)
@ -1037,11 +1028,6 @@ class Engine:
field_name = groups[3] # This will be the field name (e.g., 'field')
if table_name:
# Table name specified (e.g., `tabX`.`y` or tabX.y or `tabX Y`.`y`)
# Ensure the extracted table name is valid before creating DocType object
if not TABLE_NAME_PATTERN.match(table_name.lstrip("tab")):
frappe.throw(_("Invalid characters in table name: {0}").format(table_name))
doctype_name = table_name[3:] if table_name.startswith("tab") else table_name
table_obj = frappe.qb.DocType(doctype_name)
pypika_field = table_obj[field_name]

View file

@ -1,3 +1,4 @@
import re
import types
import typing
@ -9,6 +10,10 @@ from pypika.terms import Function
from frappe.query_builder.terms import ParameterizedValueWrapper, SQLiteParameterizedValueWrapper
from frappe.utils import get_table_name
# less restrictive version of frappe.core.doctype.doctype.doctype.START_WITH_LETTERS_PATTERN
# to allow table names like __Auth
TABLE_NAME_PATTERN = re.compile(r"^[\w -]*$", flags=re.ASCII)
class Base:
terms = terms
@ -30,6 +35,7 @@ class Base:
@staticmethod
def DocType(table_name: str, *args, **kwargs) -> Table:
Base.validate_doctype(table_name)
table_name = get_table_name(table_name)
return Table(table_name, *args, **kwargs)
@ -45,6 +51,13 @@ class Base:
table = cls.DocType(table)
return super().update(table, *args, **kwargs)
@staticmethod
def validate_doctype(doctype) -> None:
from frappe import _, throw
if not TABLE_NAME_PATTERN.match(doctype):
throw(_("Invalid DocType: {0}").format(doctype))
class MariaDB(Base, MySQLQuery):
Field = terms.Field