Skip to content

Commit 97571e0

Browse files
committed
Python: Add modeling of peewee
1 parent 1317ae2 commit 97571e0

File tree

5 files changed

+200
-4
lines changed

5 files changed

+200
-4
lines changed

docs/codeql/support/reusables/frameworks.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ Python built-in support
174174
MySQL-python, Database
175175
psycopg2, Database
176176
sqlite3, Database
177+
peewee, Database ORM
177178
cryptography, Cryptography library
178179
pycryptodome, Cryptography library
179180
pycryptodomex, Cryptography library
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added modeling of raw SQL execution from the PyPI package `peewee`.

python/ql/src/semmle/python/Frameworks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ private import semmle.python.frameworks.Rsa
2525
private import semmle.python.frameworks.Simplejson
2626
private import semmle.python.frameworks.Stdlib
2727
private import semmle.python.frameworks.Tornado
28+
private import semmle.python.frameworks.Peewee
2829
private import semmle.python.frameworks.Twisted
2930
private import semmle.python.frameworks.Ujson
3031
private import semmle.python.frameworks.Yaml
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `peewee` PyPI package.
3+
* See
4+
* - https://pypi.org/project/peewee/
5+
* - https://docs.peewee-orm.com/en/latest/index.html
6+
*/
7+
8+
private import python
9+
private import semmle.python.dataflow.new.DataFlow
10+
private import semmle.python.dataflow.new.TaintTracking
11+
private import semmle.python.Concepts
12+
private import semmle.python.ApiGraphs
13+
private import semmle.python.frameworks.PEP249
14+
15+
/**
16+
* Provides models for the `peewee` PyPI package.
17+
* See
18+
* - https://pypi.org/project/peewee/
19+
* - https://docs.peewee-orm.com/en/latest/index.html
20+
*/
21+
private module Peewee {
22+
/** Provides models for the `peewee.Database` class and subclasses. */
23+
module Database {
24+
/** Gets a reference to the `peewee.Database` class or any subclass. */
25+
API::Node subclassRef() {
26+
result = API::moduleImport("peewee").getMember("Database").getASubclass*()
27+
or
28+
// known subclasses
29+
result =
30+
API::moduleImport("peewee")
31+
.getMember(["SqliteDatabase", "MySQLDatabase", "PostgresqlDatabase"])
32+
.getASubclass*()
33+
or
34+
// Ohter known subclasses, semi auto generated by using
35+
// ```codeql
36+
// class DBClass extends Class, SelfRefMixin {
37+
// DBClass() {
38+
// exists(this.getLocation().getFile().getRelativePath()) and
39+
// this.getName().matches("%Database") and
40+
// this.getABase().(Name).getId().matches("%Database")
41+
// }
42+
// }
43+
//
44+
// from DBClass dbClass, Module mod
45+
// where
46+
// dbClass.getScope() = mod
47+
// select mod.getName()+ "." + dbClass.getName()
48+
// ```
49+
result =
50+
API::moduleImport("playhouse")
51+
.getMember("apsw_ext")
52+
.getMember("APSWDatabase")
53+
.getASubclass*()
54+
or
55+
result =
56+
API::moduleImport("playhouse")
57+
.getMember("cockroachdb")
58+
.getMember("CockroachDatabase")
59+
.getASubclass*()
60+
or
61+
result =
62+
API::moduleImport("playhouse")
63+
.getMember("cockroachdb")
64+
.getMember("PooledCockroachDatabase")
65+
.getASubclass*()
66+
or
67+
result =
68+
API::moduleImport("playhouse")
69+
.getMember("mysql_ext")
70+
.getMember("MySQLConnectorDatabase")
71+
.getASubclass*()
72+
or
73+
result =
74+
API::moduleImport("playhouse")
75+
.getMember("pool")
76+
.getMember("PooledCSqliteExtDatabase")
77+
.getASubclass*()
78+
or
79+
result =
80+
API::moduleImport("playhouse")
81+
.getMember("pool")
82+
.getMember("PooledMySQLDatabase")
83+
.getASubclass*()
84+
or
85+
result =
86+
API::moduleImport("playhouse")
87+
.getMember("pool")
88+
.getMember("PooledPostgresqlDatabase")
89+
.getASubclass*()
90+
or
91+
result =
92+
API::moduleImport("playhouse")
93+
.getMember("pool")
94+
.getMember("PooledPostgresqlExtDatabase")
95+
.getASubclass*()
96+
or
97+
result =
98+
API::moduleImport("playhouse")
99+
.getMember("pool")
100+
.getMember("PooledSqliteDatabase")
101+
.getASubclass*()
102+
or
103+
result =
104+
API::moduleImport("playhouse")
105+
.getMember("pool")
106+
.getMember("PooledSqliteExtDatabase")
107+
.getASubclass*()
108+
or
109+
result =
110+
API::moduleImport("playhouse")
111+
.getMember("pool")
112+
.getMember("_PooledPostgresqlDatabase")
113+
.getASubclass*()
114+
or
115+
result =
116+
API::moduleImport("playhouse")
117+
.getMember("pool")
118+
.getMember("_PooledSqliteDatabase")
119+
.getASubclass*()
120+
or
121+
result =
122+
API::moduleImport("playhouse")
123+
.getMember("postgres_ext")
124+
.getMember("PostgresqlExtDatabase")
125+
.getASubclass*()
126+
or
127+
result =
128+
API::moduleImport("playhouse")
129+
.getMember("sqlcipher_ext")
130+
.getMember("SqlCipherDatabase")
131+
.getASubclass*()
132+
or
133+
result =
134+
API::moduleImport("playhouse")
135+
.getMember("sqlcipher_ext")
136+
.getMember("SqlCipherExtDatabase")
137+
.getASubclass*()
138+
or
139+
result =
140+
API::moduleImport("playhouse")
141+
.getMember("sqlite_ext")
142+
.getMember("CSqliteExtDatabase")
143+
.getASubclass*()
144+
or
145+
result =
146+
API::moduleImport("playhouse")
147+
.getMember("sqlite_ext")
148+
.getMember("SqliteExtDatabase")
149+
.getASubclass*()
150+
or
151+
result =
152+
API::moduleImport("playhouse")
153+
.getMember("sqliteq")
154+
.getMember("SqliteQueueDatabase")
155+
.getASubclass*()
156+
}
157+
158+
/** Gets a reference to an instance of `peewee.Database` or any subclass. */
159+
API::Node instance() { result = subclassRef().getReturn() }
160+
}
161+
162+
/**
163+
* A call to the `connection` method on a `peewee.Database` instance.
164+
* https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.connection.
165+
*/
166+
class PeeweeDatabaseConnectionCall extends PEP249::Connection::InstanceSource,
167+
DataFlow::CallCfgNode {
168+
PeeweeDatabaseConnectionCall() {
169+
this = Database::instance().getMember("connection").getACall()
170+
}
171+
}
172+
173+
/**
174+
* A call to the `cursor` method on a `peewee.Database` instance.
175+
* https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.cursor.
176+
*/
177+
class PeeweeDatabaseCursorCall extends PEP249::Cursor::InstanceSource, DataFlow::CallCfgNode {
178+
PeeweeDatabaseCursorCall() { this = Database::instance().getMember("cursor").getACall() }
179+
}
180+
181+
/**
182+
* A call to the `execute_sql` method on a `peewee.Database` instance.
183+
* See https://docs.peewee-orm.com/en/latest/peewee/api.html#Database.execute_sql.
184+
*/
185+
class PeeweeDatabaseExecuteSqlCall extends SqlExecution::Range, DataFlow::CallCfgNode {
186+
PeeweeDatabaseExecuteSqlCall() {
187+
this = Database::instance().getMember("execute_sql").getACall()
188+
}
189+
190+
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
191+
}
192+
}

python/ql/test/library-tests/frameworks/peewee/sql_execution.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77

88
conn = db.connection()
99
cursor = conn.cursor()
10-
cursor.execute("sql") # $ MISSING: getSql="sql"
10+
cursor.execute("sql") # $ getSql="sql"
1111

1212
cursor = db.cursor()
13-
cursor.execute("sql") # $ MISSING: getSql="sql"
13+
cursor.execute("sql") # $ getSql="sql"
1414

15-
db.execute_sql("sql") # $ MISSING: getSql="sql"
15+
db.execute_sql("sql") # $ getSql="sql"
1616

1717
# Pool extension
1818
pool = playhouse.pool.PooledMySQLDatabase(...)
19-
pool.execute_sql("sql") # $ MISSING: getSql="sql"
19+
pool.execute_sql("sql") # $ getSql="sql"

0 commit comments

Comments
 (0)