mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Python: Rewrite ClickHouse SQL lib modeling
This did turn into a few changes, that maybe could have been split into
separate PRs 🤷
* Rename `ClickHouseDriver` => `ClickhouseDriver`, to better follow
import name in `.qll` name
* Rewrote modeling to use API graphs
* Split modeling of `aioch` into separate `.qll` file, which does re-use
the `getExecuteMethodName` predicate. I feel that sharing code between
the modeling like this was the best approach, and stuck the
`INTERNAL: Do not use.` labels on both modules.
* I also added handling of keyword arguments (see change in .py files)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `aioch` PyPI package (an
|
||||
* async-io version of the `clickhouse-driver` PyPI package).
|
||||
*
|
||||
* See https://pypi.org/project/aioch/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.PEP249
|
||||
private import experimental.semmle.python.frameworks.ClickhouseDriver
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides models for `aioch` PyPI package (an async-io version of the
|
||||
* `clickhouse-driver` PyPI package).
|
||||
*
|
||||
* See https://pypi.org/project/aioch/
|
||||
*/
|
||||
module Aioch {
|
||||
/** Provides models for `aioch.Client` class and subclasses. */
|
||||
module Client {
|
||||
/** Gets a reference to the `aioch.Client` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result = API::moduleImport("aioch").getMember("Client").getASubclass*()
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `clickhouse_driver.Client` or any subclass. */
|
||||
API::Node instance() { result = subclassRef().getReturn() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to any of the the execute methods on a `aioch.Client`, which are just async
|
||||
* versions of the methods in the `clickhouse-driver` PyPI package.
|
||||
*
|
||||
* See
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_iter
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_with_progress
|
||||
*/
|
||||
class ClientExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
|
||||
ClientExecuteCall() {
|
||||
exists(string methodName | methodName = ClickhouseDriver::getExecuteMethodName() |
|
||||
this = Client::instance().getMember(methodName).getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("query")] }
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of `clickhouse-driver` and `aioch` PyPI packages.
|
||||
* See
|
||||
* - https://pypi.org/project/clickhouse-driver/
|
||||
* - https://pypi.org/project/aioch/
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.PEP249
|
||||
|
||||
/**
|
||||
* Provides models for `clickhouse-driver` and `aioch` PyPI packages.
|
||||
* See
|
||||
* - https://pypi.org/project/clickhouse-driver/
|
||||
* - https://pypi.org/project/aioch/
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/
|
||||
*/
|
||||
module ClickHouseDriver {
|
||||
/** Gets a reference to the `clickhouse_driver` module. */
|
||||
API::Node clickhouse_driver() { result = API::moduleImport("clickhouse_driver") }
|
||||
|
||||
/** Gets a reference to the `aioch` module. This module allows to make async db queries. */
|
||||
API::Node aioch() { result = API::moduleImport("aioch") }
|
||||
|
||||
/**
|
||||
* `clickhouse_driver` implements PEP249,
|
||||
* providing ways to execute SQL statements against a database.
|
||||
*/
|
||||
class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
|
||||
ClickHouseDriverPEP249() { this = clickhouse_driver() }
|
||||
}
|
||||
|
||||
module Client {
|
||||
/** Gets a reference to a Client call. */
|
||||
private DataFlow::Node client_ref() {
|
||||
result = clickhouse_driver().getMember("Client").getASubclass*().getAUse()
|
||||
or
|
||||
result = aioch().getMember("Client").getASubclass*().getAUse()
|
||||
}
|
||||
|
||||
/** A direct instantiation of `clickhouse_driver.Client`. */
|
||||
private class ClientInstantiation extends DataFlow::CallCfgNode {
|
||||
ClientInstantiation() { this.getFunction() = client_ref() }
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `clickhouse_driver.Client`. */
|
||||
private DataFlow::LocalSourceNode instance(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof ClientInstantiation
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `clickhouse_driver.Client`. */
|
||||
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
|
||||
}
|
||||
|
||||
/** clickhouse_driver.Client execute methods */
|
||||
private string execute_function() {
|
||||
result in ["execute_with_progress", "execute", "execute_iter"]
|
||||
}
|
||||
|
||||
/** Gets a reference to the `clickhouse_driver.Client.execute` method */
|
||||
private DataFlow::LocalSourceNode clickhouse_execute(DataFlow::TypeTracker t) {
|
||||
t.startInAttr(execute_function()) and
|
||||
result = Client::instance()
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = clickhouse_execute(t2).track(t2, t))
|
||||
}
|
||||
|
||||
/** Gets a reference to the `clickhouse_driver.Client.execute` method */
|
||||
DataFlow::Node clickhouse_execute() {
|
||||
clickhouse_execute(DataFlow::TypeTracker::end()).flowsTo(result)
|
||||
}
|
||||
|
||||
/** A call to the `clickhouse_driver.Client.execute` method */
|
||||
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
|
||||
ExecuteCall() { this.getFunction() = clickhouse_execute() }
|
||||
|
||||
override DataFlow::Node getSql() { result.asCfgNode() = node.getArg(0) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `clickhouse-driver` PyPI package.
|
||||
* See
|
||||
* - https://pypi.org/project/clickhouse-driver/
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.PEP249
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Provides models for `clickhouse-driver` PyPI package (imported as `clickhouse_driver`).
|
||||
* See
|
||||
* - https://pypi.org/project/clickhouse-driver/
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/
|
||||
*/
|
||||
module ClickhouseDriver {
|
||||
/**
|
||||
* `clickhouse_driver` implements PEP249,
|
||||
* providing ways to execute SQL statements against a database.
|
||||
*/
|
||||
class ClickHouseDriverPEP249 extends PEP249ModuleApiNode {
|
||||
ClickHouseDriverPEP249() { this = API::moduleImport("clickhouse_driver") }
|
||||
}
|
||||
|
||||
/** Provides models for `clickhouse_driver.Client` class and subclasses. */
|
||||
module Client {
|
||||
/** Gets a reference to the `clickhouse_driver.Client` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
exists(API::Node classRef |
|
||||
// canonical definition
|
||||
classRef = API::moduleImport("clickhouse_driver").getMember("client").getMember("Client")
|
||||
or
|
||||
// commonly used alias
|
||||
classRef = API::moduleImport("clickhouse_driver").getMember("Client")
|
||||
|
|
||||
result = classRef.getASubclass*()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `clickhouse_driver.Client` or any subclass. */
|
||||
API::Node instance() { result = subclassRef().getReturn() }
|
||||
}
|
||||
|
||||
/** `clickhouse_driver.Client` execute method names */
|
||||
string getExecuteMethodName() { result in ["execute_with_progress", "execute", "execute_iter"] }
|
||||
|
||||
/**
|
||||
* A call to any of the the execute methods on a `clickhouse_driver.Client` method
|
||||
*
|
||||
* See
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_iter
|
||||
* - https://clickhouse-driver.readthedocs.io/en/latest/api.html#clickhouse_driver.Client.execute_with_progress
|
||||
*/
|
||||
class ClientExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
|
||||
ClientExecuteCall() { this = Client::instance().getMember(getExecuteMethodName()).getACall() }
|
||||
|
||||
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("query")] }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user