Skip to content

Commit 5cfc433

Browse files
committed
Python: Refactor PEP249 to encapsulate in module
So global namespace doesn't contain `Connection` whenever `PEP249.qll` is imported
1 parent c476c89 commit 5cfc433

File tree

10 files changed

+154
-104
lines changed

10 files changed

+154
-104
lines changed

python/ql/src/semmle/python/frameworks/Aioch.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
private import python
99
private import semmle.python.Concepts
1010
private import semmle.python.ApiGraphs
11-
private import semmle.python.frameworks.PEP249
1211
private import semmle.python.frameworks.ClickhouseDriver
1312

1413
/**

python/ql/src/semmle/python/frameworks/ClickhouseDriver.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module ClickhouseDriver {
2323
* `clickhouse_driver` implements PEP249,
2424
* providing ways to execute SQL statements against a database.
2525
*/
26-
class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
26+
class ClickHouseDriverPEP249 extends PEP249::PEP249ModuleApiNode {
2727
ClickHouseDriverPEP249() { this = API::moduleImport("clickhouse_driver") }
2828
}
2929

python/ql/src/semmle/python/frameworks/Django.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ private module PrivateDjango {
313313
/**
314314
* `django.db` implements PEP249, providing ways to execute SQL statements against a database.
315315
*/
316-
private class DjangoDb extends PEP249ModuleApiNode {
316+
private class DjangoDb extends PEP249::PEP249ModuleApiNode {
317317
DjangoDb() { this = API::moduleImport("django").getMember("db") }
318318
}
319319

@@ -322,7 +322,7 @@ private module PrivateDjango {
322322
/** Gets a reference to the `django.db.connection` object. */
323323
API::Node connection() { result = db().getMember("connection") }
324324

325-
class DjangoDbConnection extends Connection::InstanceSource {
325+
class DjangoDbConnection extends PEP249::Connection::InstanceSource {
326326
DjangoDbConnection() { this = connection().getAUse() }
327327
}
328328

python/ql/src/semmle/python/frameworks/MySQLdb.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private module MySQLdb {
2525
// MySQLdb
2626
// ---------------------------------------------------------------------------
2727
/** MySQLdb implements PEP 249, providing ways to execute SQL statements against a database. */
28-
class MySQLdb extends PEP249ModuleApiNode {
28+
class MySQLdb extends PEP249::PEP249ModuleApiNode {
2929
MySQLdb() { this = API::moduleImport("MySQLdb") }
3030
}
3131
}

python/ql/src/semmle/python/frameworks/Mysql.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ private module Mysql {
3030
* The mysql.connector module
3131
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
3232
*/
33-
class MysqlConnector extends PEP249ModuleApiNode {
33+
class MysqlConnector extends PEP249::PEP249ModuleApiNode {
3434
MysqlConnector() { this = API::moduleImport("mysql").getMember("connector") }
3535
}
3636
}

python/ql/src/semmle/python/frameworks/PEP249.qll

Lines changed: 12 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -8,119 +8,36 @@ private import semmle.python.dataflow.new.DataFlow
88
private import semmle.python.dataflow.new.RemoteFlowSources
99
private import semmle.python.Concepts
1010
private import semmle.python.ApiGraphs
11+
import semmle.python.frameworks.internal.PEP249Impl
1112

1213
/**
1314
* A module implementing PEP 249. Extend this class for implementations.
1415
*
15-
* DEPRECATED: Extend `PEP249ModuleApiNode` instead.
16+
* DEPRECATED: Extend `PEP249::PEP249ModuleApiNode` instead.
1617
*/
1718
abstract deprecated class PEP249Module extends DataFlow::Node { }
1819

1920
/**
20-
* An abstract class encompassing API graph nodes that implement PEP 249.
21-
* Extend this class for implementations.
21+
* DEPRECATED: Use `PEP249::PEP249ModuleApiNode` instead.
2222
*/
23-
abstract class PEP249ModuleApiNode extends API::Node {
24-
/** Gets a string representation of this element. */
25-
override string toString() { result = this.(API::Node).toString() }
26-
}
27-
28-
/** Gets a reference to a connect call. */
29-
DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
23+
deprecated class PEP249ModuleApiNode = PEP249::PEP249ModuleApiNode;
3024

3125
/**
32-
* Provides models for the `db.Connection` class
33-
*
34-
* See https://www.python.org/dev/peps/pep-0249/#connection-objects.
26+
* DEPRECATED: Use `PEP249::Connection` instead.
3527
*/
36-
module Connection {
37-
/**
38-
* A source of instances of `db.Connection`, extend this class to model new instances.
39-
*
40-
* This can include instantiations of the class, return values from function
41-
* calls, or a special parameter that will be set when functions are called by external
42-
* libraries.
43-
*
44-
* Use the predicate `Connection::instance()` to get references to instances of `db.Connection`.
45-
*
46-
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
47-
* a connection than going through `connect`.
48-
*/
49-
abstract class InstanceSource extends DataFlow::Node { }
50-
51-
/** A direct instantiation of `db.Connection`. */
52-
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
53-
ClassInstantiation() { this.getFunction() = connect() }
54-
}
55-
56-
/** Gets a reference to an instance of `db.Connection`. */
57-
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
58-
t.start() and
59-
result instanceof InstanceSource
60-
or
61-
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
62-
}
63-
64-
/** Gets a reference to an instance of `db.Connection`. */
65-
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
66-
}
28+
deprecated module Connection = PEP249::Connection;
6729

6830
/**
69-
* Provides models for the `cursor` method on a connection.
70-
* See https://www.python.org/dev/peps/pep-0249/#cursor.
31+
* DEPRECATED: Use `PEP249::cursor` instead.
7132
*/
72-
module cursor {
73-
/** Gets a reference to the `cursor` method on a connection. */
74-
private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
75-
t.startInAttr("cursor") and
76-
result = Connection::instance()
77-
or
78-
exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
79-
}
80-
81-
/** Gets a reference to the `cursor` method on a connection. */
82-
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
83-
84-
/** Gets a reference to a result of calling the `cursor` method on a connection. */
85-
private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
86-
t.start() and
87-
result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
88-
or
89-
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
90-
}
91-
92-
/** Gets a reference to a result of calling the `cursor` method on a connection. */
93-
DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
94-
}
33+
deprecated module cursor = PEP249::cursor;
9534

9635
/**
97-
* Gets a reference to the `execute` method on a cursor (or on a connection).
98-
*
99-
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
100-
* recognize it as an alias for constructing a cursor and calling `execute` on it.
101-
*
102-
* See https://www.python.org/dev/peps/pep-0249/#id15.
36+
* DEPRECATED: Use `PEP249::execute` instead.
10337
*/
104-
private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
105-
t.startInAttr("execute") and
106-
result in [cursor::methodResult(), Connection::instance()]
107-
or
108-
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
109-
}
38+
deprecated predicate execute = PEP249::execute/0;
11039

11140
/**
112-
* Gets a reference to the `execute` method on a cursor (or on a connection).
113-
*
114-
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
115-
* recognize it as an alias for constructing a cursor and calling `execute` on it.
116-
*
117-
* See https://www.python.org/dev/peps/pep-0249/#id15.
41+
* DEPRECATED: Use `PEP249::connect` instead.
11842
*/
119-
DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
120-
121-
/** A call to the `execute` method on a cursor (or on a connection). */
122-
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
123-
ExecuteCall() { this.getFunction() = execute() }
124-
125-
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
126-
}
43+
deprecated predicate connect = PEP249::connect/0;

python/ql/src/semmle/python/frameworks/Psycopg2.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ private module Psycopg2 {
2323
// Psycopg
2424
// ---------------------------------------------------------------------------
2525
/** psycopg2 implements PEP 249, providing ways to execute SQL statements against a database. */
26-
class Psycopg2 extends PEP249ModuleApiNode {
26+
class Psycopg2 extends PEP249::PEP249ModuleApiNode {
2727
Psycopg2() { this = API::moduleImport("psycopg2") }
2828
}
2929
}

python/ql/src/semmle/python/frameworks/PyMySQL.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ private import semmle.python.frameworks.PEP249
1616
*/
1717
private module PyMySQL {
1818
/** PyMySQL implements PEP 249, providing ways to execute SQL statements against a database. */
19-
class PyMySQLPEP249 extends PEP249ModuleApiNode {
19+
class PyMySQLPEP249 extends PEP249::PEP249ModuleApiNode {
2020
PyMySQLPEP249() { this = API::moduleImport("pymysql") }
2121
}
2222
}

python/ql/src/semmle/python/frameworks/Stdlib.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ private module Stdlib {
885885
*
886886
* See https://devdocs.io/python~3.9/library/sqlite3
887887
*/
888-
class Sqlite3 extends PEP249ModuleApiNode {
888+
class Sqlite3 extends PEP249::PEP249ModuleApiNode {
889889
Sqlite3() { this = API::moduleImport("sqlite3") }
890890
}
891891

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* INTERNAL: Do not use.
3+
*
4+
* Provides internal implementation of PEP249. This currently resides in a different
5+
* file than `python/ql/src/semmle/python/frameworks/PEP249.qll`, since we used to
6+
* export everything without being encapsulated in a module, and shadowing rules means
7+
* that we can't just add the module directly to that file :(
8+
*
9+
* So once we can remove those deprecated things (Start of July 2022), we can also move
10+
* the core implementation into its' proper place.
11+
*
12+
* Provides classes modeling PEP 249.
13+
* See https://www.python.org/dev/peps/pep-0249/.
14+
*/
15+
16+
private import python
17+
private import semmle.python.dataflow.new.DataFlow
18+
private import semmle.python.dataflow.new.RemoteFlowSources
19+
private import semmle.python.Concepts
20+
private import semmle.python.ApiGraphs
21+
22+
/**
23+
* Provides classes modeling PEP 249.
24+
*/
25+
module PEP249 {
26+
/**
27+
* An abstract class encompassing API graph nodes that implement PEP 249.
28+
* Extend this class for implementations.
29+
*/
30+
abstract class PEP249ModuleApiNode extends API::Node {
31+
/** Gets a string representation of this element. */
32+
override string toString() { result = this.(API::Node).toString() }
33+
}
34+
35+
/** Gets a reference to a connect call. */
36+
DataFlow::Node connect() { result = any(PEP249ModuleApiNode a).getMember("connect").getAUse() }
37+
38+
/**
39+
* Provides models for the `db.Connection` class
40+
*
41+
* See https://www.python.org/dev/peps/pep-0249/#connection-objects.
42+
*/
43+
module Connection {
44+
/**
45+
* A source of instances of `db.Connection`, extend this class to model new instances.
46+
*
47+
* This can include instantiations of the class, return values from function
48+
* calls, or a special parameter that will be set when functions are called by external
49+
* libraries.
50+
*
51+
* Use the predicate `Connection::instance()` to get references to instances of `db.Connection`.
52+
*
53+
* Extend this class if the module implementing PEP 249 offers more direct ways to obtain
54+
* a connection than going through `connect`.
55+
*/
56+
abstract class InstanceSource extends DataFlow::Node { }
57+
58+
/** A direct instantiation of `db.Connection`. */
59+
private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode {
60+
ClassInstantiation() { this.getFunction() = connect() }
61+
}
62+
63+
/** Gets a reference to an instance of `db.Connection`. */
64+
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
65+
t.start() and
66+
result instanceof InstanceSource
67+
or
68+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
69+
}
70+
71+
/** Gets a reference to an instance of `db.Connection`. */
72+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
73+
}
74+
75+
/**
76+
* Provides models for the `cursor` method on a connection.
77+
* See https://www.python.org/dev/peps/pep-0249/#cursor.
78+
*/
79+
module cursor {
80+
/** Gets a reference to the `cursor` method on a connection. */
81+
private DataFlow::LocalSourceNode methodRef(DataFlow::TypeTracker t) {
82+
t.startInAttr("cursor") and
83+
result = Connection::instance()
84+
or
85+
exists(DataFlow::TypeTracker t2 | result = methodRef(t2).track(t2, t))
86+
}
87+
88+
/** Gets a reference to the `cursor` method on a connection. */
89+
DataFlow::Node methodRef() { methodRef(DataFlow::TypeTracker::end()).flowsTo(result) }
90+
91+
/** Gets a reference to a result of calling the `cursor` method on a connection. */
92+
private DataFlow::LocalSourceNode methodResult(DataFlow::TypeTracker t) {
93+
t.start() and
94+
result.asCfgNode().(CallNode).getFunction() = methodRef().asCfgNode()
95+
or
96+
exists(DataFlow::TypeTracker t2 | result = methodResult(t2).track(t2, t))
97+
}
98+
99+
/** Gets a reference to a result of calling the `cursor` method on a connection. */
100+
DataFlow::Node methodResult() { methodResult(DataFlow::TypeTracker::end()).flowsTo(result) }
101+
}
102+
103+
/**
104+
* Gets a reference to the `execute` method on a cursor (or on a connection).
105+
*
106+
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
107+
* recognize it as an alias for constructing a cursor and calling `execute` on it.
108+
*
109+
* See https://www.python.org/dev/peps/pep-0249/#id15.
110+
*/
111+
private DataFlow::LocalSourceNode execute(DataFlow::TypeTracker t) {
112+
t.startInAttr("execute") and
113+
result in [cursor::methodResult(), Connection::instance()]
114+
or
115+
exists(DataFlow::TypeTracker t2 | result = execute(t2).track(t2, t))
116+
}
117+
118+
/**
119+
* Gets a reference to the `execute` method on a cursor (or on a connection).
120+
*
121+
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
122+
* recognize it as an alias for constructing a cursor and calling `execute` on it.
123+
*
124+
* See https://www.python.org/dev/peps/pep-0249/#id15.
125+
*/
126+
DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
127+
128+
/** A call to the `execute` method on a cursor (or on a connection). */
129+
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
130+
ExecuteCall() { this.getFunction() = execute() }
131+
132+
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
133+
}
134+
}

0 commit comments

Comments
 (0)