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

8 months ago
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}')