Nothing Special   »   [go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] core: add SQL wrapper #134677

Closed
wants to merge 8 commits into from
Closed

Conversation

rco-odoo
Copy link
Member
@rco-odoo rco-odoo commented Sep 7, 2023

We introduce a new class of objects to wrap SQL code together with its parameters. It is designed to be easily composable and to discourage SQL injections. Its API is similar to the methods of module logging: the code is a format string, and the positional parameters are meant to be merged into it using the string formatting operator.

# default and increment are parameters of the SQL code in first argument
term = SQL("COALESCE(value, %s) + %s", default, increment)

# term can safely be injected into another SQL, besides regular parameters
query = SQL("SELECT %s FROM mytable WHERE id = %s", term, id_)

The SQL wrapper can return the final SQL code string as query.code, and the corresponding parameters as query.params (list). The cursor method execute() can now take an SQL object, and execute it just like

cr.execute(query.code, query.params)

It is quite easy to make SQL objects safe against SQL injections: if the code is a string literal, then the SQL object is guaranteed safe, provided the SQL objects within its parameters are themselves safe.

@robodoo
Copy link
Contributor
robodoo commented Sep 7, 2023

Pull request status dashboard

@C3POdoo C3POdoo requested review from a team, xmo-odoo and HydrionBurst and removed request for a team September 7, 2023 12:57
@C3POdoo C3POdoo added the RD research & development, internal work label Sep 7, 2023
Copy link
Member Author
@rco-odoo rco-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal review

addons/sale_project/models/project.py Outdated Show resolved Hide resolved
odoo/addons/base/tests/test_sql.py Outdated Show resolved Hide resolved
odoo/models.py Outdated Show resolved Hide resolved
odoo/models.py Outdated Show resolved Hide resolved
odoo/models.py Outdated Show resolved Hide resolved
odoo/tools/sql.py Outdated Show resolved Hide resolved
def __init__(self, string: str = "", *args):
if isinstance(string, SQL):
string, args = string.__string, string.__args
string % tuple("x" for arg in args)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a shame not to allow post-hoc formatting so we can e.g. create a query, then format arguments in it in a loop. This way the query can be a constant or easier to parameterize.

Here an additional layer has to be added, and I'm not convinced the "intrinsic" formatting is really worth it: in _() it's used because that allows handling of (and falling back in) the case where a translator has broken the source string and added/removed placeholders.

Also makes it harder to support keyword parameterization, despite how useful that is (although keyword parameterization does raise the question of mixing when combining queries, which is a concern with printf-style formatting).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I introduced this enforcement because I was almost unable to debug a SQL object with a missing parameter. The issue is that you generally have a composition of SQL objects, finding which one misses its parameter and where it has been created is really non-trivial.

For this problem, I suggest to add a parameter placeholder, i.e., an object that contains a value which may be updated post-hoc, and implements the SQL adaptation protocol. So you would put that as a parameter anywhere in your SQL objects, and it would simply end up in the sql.params list. If you set its internal value before executing that SQL object, that value will be adapted by psycopg2.

odoo/tools/sql.py Outdated Show resolved Hide resolved
@@ -23,23 +23,108 @@
'SET DEFAULT': 'd',
}


class SQL:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth having this in a more prominent location e.g. odoo.sql? And possibly re-export the more useful of SQL utilities from there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the class SQL, the module sql, or only a subset of the module sql ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly the SQL class. The existing content of tools.sql is a lot more specific (mostly to setup / migration), but if we consider that SQL will get used in every non-static query it would make sense to make it prominent and easily accessible, rather than tuck it into a grab bag of more minor tooling.

odoo/tools/sql.py Outdated Show resolved Hide resolved
odoo/models.py Show resolved Hide resolved
odoo/models.py Outdated Show resolved Hide resolved
@rco-odoo rco-odoo force-pushed the master-sql-rco branch 9 times, most recently from 508acab to 7fa16a2 Compare September 14, 2023 14:11
@C3POdoo C3POdoo requested review from a team September 15, 2023 10:11
@rco-odoo rco-odoo force-pushed the master-sql-rco branch 3 times, most recently from af0de97 to 9fed713 Compare September 16, 2023 09:26
@nhomar
Copy link
Collaborator
nhomar commented Sep 17, 2023

@moylop260 take a look

@rco-odoo rco-odoo force-pushed the master-sql-rco branch 3 times, most recently from 2ea8c7b to 25f3eb6 Compare September 20, 2023 17:18
robodoo pushed a commit that referenced this pull request Sep 27, 2023
We introduce a new class of objects to wrap SQL code together with its
parameters.  It is designed to be easily composable and to discourage
SQL injections.  Its API is similar to the methods of module 'logging':
the code is a format string, and the positional parameters are meant to
be merged into it using the string formatting operator.

    # default and increment are parameters of the SQL code in first argument
    term = SQL("COALESCE(value, %s) + %s", default, increment)

    # term can safely be injected into another SQL, besides regular parameters
    query = SQL("SELECT %s FROM mytable WHERE id = %s", term, id_)

The SQL wrapper can return the final SQL code string as query.code, and
the corresponding parameters as query.params (list).  The cursor method
execute() can now take an SQL object, and execute it just like

    cr.execute(query.code, query.params)

It is quite easy to make SQL objects safe against SQL injections: if the
code is a string literal, then the SQL object is guaranteed safe,
provided the SQL objects within its parameters are themselves safe.

Part-of: #134677
robodoo pushed a commit that referenced this pull request Sep 27, 2023
robodoo pushed a commit that referenced this pull request Sep 27, 2023
robodoo pushed a commit that referenced this pull request Sep 27, 2023
robodoo pushed a commit that referenced this pull request Sep 27, 2023
robodoo pushed a commit that referenced this pull request Sep 27, 2023
robodoo pushed a commit that referenced this pull request Sep 27, 2023
…er_items_query()

closes #134677

Related: odoo/enterprise#47759
Signed-off-by: Raphael Collet <rco@odoo.com>
@robodoo robodoo temporarily deployed to merge September 27, 2023 03:58 Inactive
@robodoo robodoo closed this Sep 27, 2023
@robodoo robodoo added the 16.5 label Sep 27, 2023
@fw-bot fw-bot deleted the master-sql-rco branch October 11, 2023 04:46
@odoo odoo deleted a comment from robodoo Oct 30, 2023
rco-odoo added a commit to odoo/documentation that referenced this pull request Nov 27, 2023
rco-odoo added a commit to odoo/documentation that referenced this pull request Nov 29, 2023
robodoo pushed a commit to odoo/documentation that referenced this pull request Nov 30, 2023
This completes odoo/odoo#134677.

closes #6674

Signed-off-by: Raphael Collet <rco@odoo.com>
fw-bot pushed a commit to odoo/documentation that referenced this pull request Nov 30, 2023
This completes odoo/odoo#134677.

X-original-commit: 2662fa5
robodoo pushed a commit to odoo/documentation that referenced this pull request Dec 1, 2023
This completes odoo/odoo#134677.

closes #6724

X-original-commit: 2662fa5
Signed-off-by: Raphael Collet <rco@odoo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
16.5 RD research & development, internal work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants