Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 571fc3e

Browse files
committed
Revert "deprecate SqlConstruction"
This reverts commit c0eca0d.
1 parent 1062aae commit 571fc3e

15 files changed

Lines changed: 85 additions & 49 deletions

File tree

python/ql/lib/change-notes/2022-05-02-deprecate-sqlconstruction.md

Lines changed: 0 additions & 4 deletions
This file was deleted.

python/ql/lib/semmle/python/Concepts.qll

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,19 +308,36 @@ module CodeExecution {
308308
}
309309
}
310310

311-
/** DEPRECATED: Use `SqlExecution` instead. */
312-
deprecated class SqlConstruction extends DataFlow::Node instanceof SqlConstruction::Range {
311+
/**
312+
* A data-flow node that constructs an SQL statement.
313+
*
314+
* Often, it is worthy of an alert if an SQL statement is constructed such that
315+
* executing it would be a security risk.
316+
*
317+
* If it is important that the SQL statement is indeed executed, then use `SQLExecution`.
318+
*
319+
* Extend this class to refine existing API models. If you want to model new APIs,
320+
* extend `SqlConstruction::Range` instead.
321+
*/
322+
class SqlConstruction extends DataFlow::Node instanceof SqlConstruction::Range {
313323
/** Gets the argument that specifies the SQL statements to be constructed. */
314324
DataFlow::Node getSql() { result = super.getSql() }
315325
}
316326

317-
/**
318-
* DEPRECATED: Use `SqlExecution` instead.
319-
* Provides a class for modeling new SQL execution APIs.
320-
*/
321-
deprecated module SqlConstruction {
322-
/** DEPRECATED: Use `SqlExecution::Range` instead. */
323-
abstract deprecated class Range extends DataFlow::Node {
327+
/** Provides a class for modeling new SQL execution APIs. */
328+
module SqlConstruction {
329+
/**
330+
* A data-flow node that constructs an SQL statement.
331+
*
332+
* Often, it is worthy of an alert if an SQL statement is constructed such that
333+
* executing it would be a security risk.
334+
*
335+
* If it is important that the SQL statement is indeed executed, then use `SQLExecution`.
336+
*
337+
* Extend this class to model new APIs. If you want to refine existing API models,
338+
* extend `SqlConstruction` instead.
339+
*/
340+
abstract class Range extends DataFlow::Node {
324341
/** Gets the argument that specifies the SQL statements to be constructed. */
325342
abstract DataFlow::Node getSql();
326343
}
@@ -329,6 +346,9 @@ deprecated module SqlConstruction {
329346
/**
330347
* A data-flow node that executes SQL statements.
331348
*
349+
* If the context of interest is such that merely constructing an SQL statement
350+
* would be valuabe to report, then consider using `SqlConstruction`.
351+
*
332352
* Extend this class to refine existing API models. If you want to model new APIs,
333353
* extend `SqlExecution::Range` instead.
334354
*/
@@ -342,6 +362,9 @@ module SqlExecution {
342362
/**
343363
* A data-flow node that executes SQL statements.
344364
*
365+
* If the context of interest is such that merely constructing an SQL statement
366+
* would be valuabe to report, then consider using `SqlConstruction`.
367+
*
345368
* Extend this class to model new APIs. If you want to refine existing API models,
346369
* extend `SqlExecution` instead.
347370
*/

python/ql/lib/semmle/python/frameworks/Aiomysql.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private module Aiomysql {
5050
* A query. Calling `execute` on a `Cursor` constructs a query.
5151
* See https://aiomysql.readthedocs.io/en/stable/cursors.html#Cursor.execute
5252
*/
53-
class CursorExecuteCall extends SqlExecution::Range, API::CallNode {
53+
class CursorExecuteCall extends SqlConstruction::Range, API::CallNode {
5454
CursorExecuteCall() { this = cursor().getMember("execute").getACall() }
5555

5656
override DataFlow::Node getSql() { result = this.getParameter(0, "operation").getARhs() }
@@ -91,7 +91,7 @@ private module Aiomysql {
9191
* A query. Calling `execute` on a `SAConnection` constructs a query.
9292
* See https://aiomysql.readthedocs.io/en/stable/sa.html#aiomysql.sa.SAConnection.execute
9393
*/
94-
class SAConnectionExecuteCall extends SqlExecution::Range, API::CallNode {
94+
class SAConnectionExecuteCall extends SqlConstruction::Range, API::CallNode {
9595
SAConnectionExecuteCall() { this = saConnection().getMember("execute").getACall() }
9696

9797
override DataFlow::Node getSql() { result = this.getParameter(0, "query").getARhs() }

python/ql/lib/semmle/python/frameworks/Aiopg.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ private module Aiopg {
5050
* A query. Calling `execute` on a `Cursor` constructs a query.
5151
* See https://aiopg.readthedocs.io/en/stable/core.html#aiopg.Cursor.execute
5252
*/
53-
class CursorExecuteCall extends SqlExecution::Range, API::CallNode {
53+
class CursorExecuteCall extends SqlConstruction::Range, API::CallNode {
5454
CursorExecuteCall() { this = cursor().getMember("execute").getACall() }
5555

5656
override DataFlow::Node getSql() { result = this.getParameter(0, "operation").getARhs() }
@@ -87,7 +87,7 @@ private module Aiopg {
8787
* A query. Calling `execute` on a `SAConnection` constructs a query.
8888
* See https://aiopg.readthedocs.io/en/stable/sa.html#aiopg.sa.SAConnection.execute
8989
*/
90-
class SAConnectionExecuteCall extends SqlExecution::Range, API::CallNode {
90+
class SAConnectionExecuteCall extends SqlConstruction::Range, API::CallNode {
9191
SAConnectionExecuteCall() { this = saConnection().getMember("execute").getACall() }
9292

9393
override DataFlow::Node getSql() { result = this.getParameter(0, "query").getARhs() }

python/ql/lib/semmle/python/frameworks/Asyncpg.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private module Asyncpg {
5656
* The creation of the `Cursor` executes the query.
5757
*/
5858
module Cursor {
59-
class CursorConstruction extends SqlExecution::Range, API::CallNode {
59+
class CursorConstruction extends SqlConstruction::Range, API::CallNode {
6060
CursorConstruction() {
6161
this = ModelOutput::getATypeNode("asyncpg", "Connection").getMember("cursor").getACall()
6262
}

python/ql/lib/semmle/python/frameworks/SqlAlchemy.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ module SqlAlchemy {
323323
* A construction of a `sqlalchemy.sql.expression.TextClause`, which represents a
324324
* textual SQL string directly.
325325
*/
326-
abstract class TextClauseConstruction extends SqlExecution::Range, DataFlow::CallCfgNode {
326+
abstract class TextClauseConstruction extends SqlConstruction::Range, DataFlow::CallCfgNode {
327327
/** Gets the argument that specifies the SQL text. */
328328
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("text")] }
329329
}

python/ql/lib/semmle/python/security/dataflow/SqlInjectionCustomizations.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ module SqlInjection {
4343
class RemoteFlowSourceAsSource extends Source, RemoteFlowSource { }
4444

4545
/**
46-
* DEPRECATED: Use `SqlExecutionAsSink` instead.
4746
* A SQL statement of a SQL construction, considered as a flow sink.
4847
*/
49-
deprecated class SqlConstructionAsSink extends Sink {
48+
class SqlConstructionAsSink extends Sink {
5049
SqlConstructionAsSink() { this = any(SqlConstruction c).getSql() }
5150
}
5251

python/ql/test/experimental/meta/ConceptsTest.qll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,24 @@ class CodeExecutionTest extends InlineExpectationsTest {
128128
}
129129
}
130130

131+
class SqlConstructionTest extends InlineExpectationsTest {
132+
SqlConstructionTest() { this = "SqlConstructionTest" }
133+
134+
override string getARelevantTag() { result = "constructedSql" }
135+
136+
override predicate hasActualResult(Location location, string element, string tag, string value) {
137+
exists(location.getFile().getRelativePath()) and
138+
exists(SqlConstruction e, DataFlow::Node sql |
139+
exists(location.getFile().getRelativePath()) and
140+
sql = e.getSql() and
141+
location = e.getLocation() and
142+
element = sql.toString() and
143+
value = prettyNodeForInlineTest(sql) and
144+
tag = "constructedSql"
145+
)
146+
}
147+
}
148+
131149
class SqlExecutionTest extends InlineExpectationsTest {
132150
SqlExecutionTest() { this = "SqlExecutionTest" }
133151

python/ql/test/library-tests/frameworks/aiomysql/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ async def test_cursor():
55
# Create connection directly
66
conn = await aiomysql.connect()
77
cur = await conn.cursor()
8-
await cur.execute("sql") # $ getSql="sql"
8+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
99

1010
# Create connection via pool
1111
async with aiomysql.create_pool() as pool:
1212
# Create Cursor via Connection
1313
async with pool.acquire() as conn:
1414
async with conn.cursor() as cur:
15-
await cur.execute("sql") # $ getSql="sql"
15+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
1616

1717
# Create Cursor directly
1818
async with pool.cursor() as cur:
19-
await cur.execute("sql") # $ getSql="sql"
19+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
2020

2121
# variants using as few `async with` as possible
2222
pool = await aiomysql.create_pool()
2323
conn = await pool.acquire()
2424
cur = await conn.cursor()
25-
await cur.execute("sql") # $ getSql="sql"
25+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
2626

2727
# Test SQLAlchemy integration
2828
from aiomysql.sa import create_engine
2929

3030
async def test_engine():
3131
engine = await create_engine()
3232
conn = await engine.acquire()
33-
await conn.execute("sql") # $ getSql="sql"
33+
await conn.execute("sql") # $ getSql="sql" constructedSql="sql"

python/ql/test/library-tests/frameworks/aiopg/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ async def test_cursor():
55
# Create connection directly
66
conn = await aiopg.connect()
77
cur = await conn.cursor()
8-
await cur.execute("sql") # $ getSql="sql"
8+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
99

1010
# Create connection via pool
1111
async with aiopg.create_pool() as pool:
1212
# Create Cursor via Connection
1313
async with pool.acquire() as conn:
1414
async with conn.cursor() as cur:
15-
await cur.execute("sql") # $ getSql="sql"
15+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
1616

1717
# Create Cursor directly
1818
async with pool.cursor() as cur:
19-
await cur.execute("sql") # $ getSql="sql"
19+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
2020

2121
# variants using as few `async with` as possible
2222
pool = await aiopg.create_pool()
2323
conn = await pool.acquire()
2424
cur = await conn.cursor()
25-
await cur.execute("sql") # $ getSql="sql"
25+
await cur.execute("sql") # $ getSql="sql" constructedSql="sql"
2626

2727
# Test SQLAlchemy integration
2828
from aiopg.sa import create_engine
2929

3030
async def test_engine():
3131
engine = await create_engine()
3232
conn = await engine.acquire()
33-
await conn.execute("sql") # $ getSql="sql"
33+
await conn.execute("sql") # $ getSql="sql" constructedSql="sql"

0 commit comments

Comments
 (0)