You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.9 KiB
Python

import json
import os
import tempfile
import unittest
from subprocess import run, PIPE
from textwrap import dedent
from odoo import tools
from odoo.tests.common import TransactionCase
try:
import pylint
except ImportError:
pylint = None
try:
pylint_bin = tools.which('pylint')
except IOError:
pylint_bin = None
HERE = os.path.dirname(os.path.realpath(__file__))
@unittest.skipUnless(pylint and pylint_bin, "testing lints requires pylint")
class TestSqlLint(TransactionCase):
def check(self, testtext):
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', delete=False) as f:
self.addCleanup(os.remove, f.name)
f.write(dedent(testtext).strip())
result = run(
[pylint_bin,
f'--rcfile={os.devnull}',
'--load-plugins=_odoo_checker_sql_injection',
'--disable=all',
'--enable=sql-injection',
'--output-format=json',
f.name,
],
check=False,
stdout=PIPE, encoding='utf-8',
env={
**os.environ,
'PYTHONPATH': HERE+os.pathsep+os.environ.get('PYTHONPATH', ''),
}
)
return result.returncode, json.loads(result.stdout)
def test_printf(self):
r, [err] = self.check("""
def do_the_thing(cr, name):
cr.execute('select %s from thing' % name)
""")
self.assertTrue(r, "should have noticed the injection")
self.assertEqual(err['line'], 2, err)
r, errs = self.check("""
def do_the_thing(self):
self.env.cr.execute("select thing from %s" % self._table)
""")
self.assertFalse(r, f"underscore-attributes are allowed\n{errs}")
r, errs = self.check("""
def do_the_thing(self):
query = "select thing from %s"
self.env.cr.execute(query % self._table)
""")
self.assertFalse(r, f"underscore-attributes are allowed\n{errs}")
def test_fstring(self):
r, [err] = self.check("""
def do_the_thing(cr, name):
cr.execute(f'select {name} from thing')
""")
self.assertTrue(r, "should have noticed the injection")
self.assertEqual(err['line'], 2, err)
r, errs = self.check("""
def do_the_thing(cr, name):
cr.execute(f'select name from thing')
""")
self.assertFalse(r, f"unnecessary fstring should be innocuous\n{errs}")
r, errs = self.check("""
def do_the_thing(cr, name, value):
cr.execute(f'select {name} from thing where field = %s', [value])
""")
self.assertFalse(r, f"probably has a good reason for the extra arg\n{errs}")
r, errs = self.check("""
def do_the_thing(self):
self.env.cr.execute(f'select name from {self._table}')
""")
self.assertFalse(r, f'underscore-attributes are allowable\n{errs}')