Python: Add inline test of MaD sinks

This enables us to keep the framework modeling tests under `/frameworks`
folder

I had hoped to use `mad-sink[<kind>]` syntax, but that was not allowed
:(

Maybe it oculd be allowed in the future, but for now I'll stick with the
more ugly solution of `mad-sink__<kind>`
This commit is contained in:
Rasmus Wriedt Larsen
2022-05-05 13:11:43 +02:00
parent 6ae5ef9f3b
commit 0a589bed4e
4 changed files with 79 additions and 27 deletions

View File

@@ -0,0 +1,50 @@
import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.PrintNode
private import semmle.python.frameworks.data.ModelsAsData
// need to import Frameworks to get the actual modeling imported
private import semmle.python.Frameworks
// this improt needs to be public to get the query predicates propagated to the actual test files
import TestUtilities.InlineExpectationsTest
class MadSinkTest extends InlineExpectationsTest {
MadSinkTest() { this = "MadSinkTest" }
override string getARelevantTag() {
exists(string kind | exists(ModelOutput::getASinkNode(kind)) |
result = "mad-sink__" + kind
)
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(DataFlow::Node sink, string kind |
sink = ModelOutput::getASinkNode(kind).getARhs() and
location = sink.getLocation() and
element = sink.toString() and
value = prettyNodeForInlineTest(sink) and
tag = "mad-sink__" + kind
)
}
}
class MadSourceTest extends InlineExpectationsTest {
MadSourceTest() { this = "MadSourceTest" }
override string getARelevantTag() {
exists(string kind | exists(ModelOutput::getASourceNode(kind)) |
result = "mad-source__" + kind
)
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(DataFlow::Node source, string kind |
source = ModelOutput::getASourceNode(kind).getAnImmediateUse() and
location = source.getLocation() and
element = source.toString() and
value = prettyNodeForInlineTest(source) and
tag = "mad-source__" + kind
)
}
}

View File

@@ -0,0 +1,2 @@
import python
import experimental.meta.MaDTest

View File

@@ -7,17 +7,17 @@ async def test_connection():
try:
# The file-like object is passed in as a keyword-only argument.
# See https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.Connection.copy_from_query
await conn.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
await conn.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__file-access="filepath" getAPathArgument="filepath"
await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__file-access="filepath" getAPathArgument="filepath"
await conn.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath"
await conn.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath"
await conn.copy_from_table("table", output="filepath") # $ mad-sink__file-access="filepath" getAPathArgument="filepath"
await conn.copy_to_table("table", source="filepath") # $ mad-sink__file-access="filepath" getAPathArgument="filepath"
await conn.execute("sql") # $ getSql="sql"
await conn.executemany("sql") # $ getSql="sql"
await conn.fetch("sql") # $ getSql="sql"
await conn.fetchrow("sql") # $ getSql="sql"
await conn.fetchval("sql") # $ getSql="sql"
await conn.execute("sql") # $ mad-sink__sql-injection="sql"
await conn.executemany("sql") # $ mad-sink__sql-injection="sql"
await conn.fetch("sql") # $ mad-sink__sql-injection="sql"
await conn.fetchrow("sql") # $ mad-sink__sql-injection="sql"
await conn.fetchval("sql") # $ mad-sink__sql-injection="sql"
finally:
await conn.close()
@@ -27,9 +27,9 @@ async def test_prepared_statement():
conn = await asyncpg.connect()
try:
pstmt = await conn.prepare("psql") # $ getSql="psql"
pstmt.executemany()
pstmt.fetch()
pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql"
pstmt.executemany()
pstmt.fetch()
pstmt.fetchrow()
pstmt.fetchval()
@@ -46,7 +46,7 @@ async def test_cursor():
cursor = await conn.cursor("sql") # $ getSql="sql" constructedSql="sql"
await cursor.fetch()
pstmt = await conn.prepare("psql") # $ getSql="psql"
pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql"
pcursor = await pstmt.cursor() # $ getSql="psql"
await pcursor.fetch()
@@ -69,23 +69,23 @@ async def test_connection_pool():
pool = await asyncpg.create_pool()
try:
await pool.copy_from_query("sql", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ getSql="sql" getAPathArgument="filepath"
await pool.copy_from_table("table", output="filepath") # $ getAPathArgument="filepath"
await pool.copy_to_table("table", source="filepath") # $ getAPathArgument="filepath"
await pool.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__file-access="filepath" getAPathArgument="filepath"
await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__file-access="filepath" getAPathArgument="filepath"
await pool.copy_from_table("table", output="filepath") # $ mad-sink__file-access="filepath" getAPathArgument="filepath"
await pool.copy_to_table("table", source="filepath") # $ mad-sink__file-access="filepath" getAPathArgument="filepath"
await pool.execute("sql") # $ getSql="sql"
await pool.executemany("sql") # $ getSql="sql"
await pool.fetch("sql") # $ getSql="sql"
await pool.fetchrow("sql") # $ getSql="sql"
await pool.fetchval("sql") # $ getSql="sql"
await pool.execute("sql") # $ mad-sink__sql-injection="sql"
await pool.executemany("sql") # $ mad-sink__sql-injection="sql"
await pool.fetch("sql") # $ mad-sink__sql-injection="sql"
await pool.fetchrow("sql") # $ mad-sink__sql-injection="sql"
await pool.fetchval("sql") # $ mad-sink__sql-injection="sql"
async with pool.acquire() as conn:
await conn.execute("sql") # $ getSql="sql"
await conn.execute("sql") # $ mad-sink__sql-injection="sql"
conn = await pool.acquire()
try:
await conn.fetch("sql") # $ getSql="sql"
await conn.fetch("sql") # $ mad-sink__sql-injection="sql"
finally:
await pool.release(conn)
@@ -93,13 +93,13 @@ async def test_connection_pool():
await pool.close()
async with asyncpg.create_pool() as pool:
await pool.execute("sql") # $ getSql="sql"
await pool.execute("sql") # $ mad-sink__sql-injection="sql"
async with pool.acquire() as conn:
await conn.execute("sql") # $ getSql="sql"
await conn.execute("sql") # $ mad-sink__sql-injection="sql"
conn = await pool.acquire()
try:
await conn.fetch("sql") # $ getSql="sql"
await conn.fetch("sql") # $ mad-sink__sql-injection="sql"
finally:
await pool.release(conn)