mirror of
https://github.com/github/codeql.git
synced 2025-12-21 11:16:30 +01:00
WIP: Flask View class modeling for restplus
Based on some DBs I had that contained dependencies
This commit is contained in:
@@ -14,6 +14,7 @@ private import semmle.python.ApiGraphs
|
||||
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
|
||||
private import semmle.python.security.dataflow.PathInjectionCustomizations
|
||||
private import semmle.python.dataflow.new.FlowSummary
|
||||
private import semmle.python.frameworks.data.ModelsAsData
|
||||
|
||||
/**
|
||||
* Provides models for the `flask` PyPI package.
|
||||
@@ -39,6 +40,10 @@ module Flask {
|
||||
"MethodView"
|
||||
])
|
||||
.getASubclass*()
|
||||
or
|
||||
result = ModelOutput::getATypeNode("flask.View~Subclass").getASubclass*()
|
||||
or
|
||||
result = ModelOutput::getATypeNode("flask.MethodView~Subclass").getASubclass*()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +57,8 @@ module Flask {
|
||||
API::Node subclassRef() {
|
||||
result =
|
||||
API::moduleImport("flask").getMember("views").getMember("MethodView").getASubclass*()
|
||||
or
|
||||
result = ModelOutput::getATypeNode("flask.MethodView~Subclass").getASubclass*()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,12 @@ extensions:
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: typeModel
|
||||
data: []
|
||||
data:
|
||||
- ["flask.MethodView~Subclass","flask_restplus","Member[api].Member[SwaggerView]"]
|
||||
- ["flask.MethodView~Subclass","flask_restplus","Member[resource].Member[Resource]"]
|
||||
- ["flask.MethodView~Subclass","flask_restplus","Member[api].Member[Resource]"]
|
||||
- ["flask.MethodView~Subclass","flask_restplus","Member[resource].Member[MethodView]"]
|
||||
- ["flask.MethodView~Subclass","flask_restplus","Member[Resource]"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
|
||||
@@ -11,28 +11,17 @@ private import semmle.python.ApiGraphs
|
||||
private import semmle.python.filters.Tests
|
||||
|
||||
// very much inspired by the draft at https://github.com/github/codeql/pull/5632
|
||||
private module NotExposed {
|
||||
module NotExposed {
|
||||
// Instructions:
|
||||
// This needs to be automated better, but for this prototype, here are some rough instructions:
|
||||
// 0) get a database of the library you are about to model
|
||||
// 1) fill out the `getAlreadyModeledClass` body below
|
||||
// 2) quick-eval the `quickEvalMe` predicate below, and copy the output to your modeling predicate
|
||||
class MySpec extends FindSubclassesSpec {
|
||||
MySpec() { this = "MySpec" }
|
||||
|
||||
override API::Node getAlreadyModeledClass() {
|
||||
// FILL ME OUT ! (but don't commit with any changes)
|
||||
none()
|
||||
// for example
|
||||
// result = API::moduleImport("rest_framework").getMember("views").getMember("APIView")
|
||||
}
|
||||
}
|
||||
|
||||
predicate quickEvalMe(string newImport) {
|
||||
newImport =
|
||||
"// imports generated by python/frameworks/internal/SubclassFinder.qll\n" + "this = API::" +
|
||||
concat(string newModelFullyQualified |
|
||||
newModel(any(MySpec spec), newModelFullyQualified, _, _, _)
|
||||
newModel(any(FindSubclassesSpec spec), newModelFullyQualified, _, _, _)
|
||||
|
|
||||
fullyQualifiedToApiGraphPath(newModelFullyQualified), " or this = API::"
|
||||
)
|
||||
@@ -76,6 +65,8 @@ private module NotExposed {
|
||||
bindingset[this]
|
||||
abstract class FindSubclassesSpec extends string {
|
||||
abstract API::Node getAlreadyModeledClass();
|
||||
|
||||
FindSubclassesSpec getSuperClass() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,7 +102,7 @@ private module NotExposed {
|
||||
predicate isNonTestProjectCode(AstNode ast) {
|
||||
not ast.getScope*() instanceof TestScope and
|
||||
not ast.getLocation().getFile().getRelativePath().matches("tests/%") and
|
||||
exists(ast.getLocation().getFile().getRelativePath())
|
||||
not exists(ast.getLocation().getFile().getRelativePath())
|
||||
}
|
||||
|
||||
predicate hasAllStatement(Module mod) {
|
||||
|
||||
44
python/ql/src/meta/ClassHierarchy/Find.ql
Normal file
44
python/ql/src/meta/ClassHierarchy/Find.ql
Normal file
@@ -0,0 +1,44 @@
|
||||
import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.ApiGraphs
|
||||
import semmle.python.frameworks.internal.SubclassFinder::NotExposed
|
||||
private import semmle.python.frameworks.Flask
|
||||
private import semmle.python.frameworks.FastApi
|
||||
private import semmle.python.frameworks.Django
|
||||
import semmle.python.frameworks.data.internal.ApiGraphModelsExtensions as Extensions
|
||||
|
||||
class FlaskViewClasses extends FindSubclassesSpec {
|
||||
FlaskViewClasses() { this = "flask.View~Subclass" }
|
||||
|
||||
override API::Node getAlreadyModeledClass() { result = Flask::Views::View::subclassRef() }
|
||||
}
|
||||
|
||||
class FlaskMethodViewClasses extends FindSubclassesSpec {
|
||||
FlaskMethodViewClasses() { this = "flask.MethodView~Subclass" }
|
||||
|
||||
override API::Node getAlreadyModeledClass() { result = Flask::Views::MethodView::subclassRef() }
|
||||
|
||||
override FlaskViewClasses getSuperClass() { any() }
|
||||
}
|
||||
|
||||
bindingset[fullyQualified]
|
||||
predicate fullyQualifiedToYamlFormat(string fullyQualified, string type2, string path) {
|
||||
exists(int firstDot | firstDot = fullyQualified.indexOf(".", 0, 0) |
|
||||
type2 = fullyQualified.prefix(firstDot) and
|
||||
path =
|
||||
("Member[" + fullyQualified.suffix(firstDot + 1).replaceAll(".", "].Member[") + "]")
|
||||
.replaceAll(".Member[__init__].", "")
|
||||
.replaceAll("Member[__init__].", "")
|
||||
)
|
||||
}
|
||||
|
||||
from FindSubclassesSpec spec, string newModelFullyQualified, string type2, string path, Module mod
|
||||
where
|
||||
newModel(spec, newModelFullyQualified, _, mod, _) and
|
||||
not exists(FindSubclassesSpec subclass | subclass.getSuperClass() = spec |
|
||||
newModel(subclass, newModelFullyQualified, _, mod, _)
|
||||
) and
|
||||
not exists(mod.getLocation().getFile().getRelativePath()) and
|
||||
fullyQualifiedToYamlFormat(newModelFullyQualified, type2, path) and
|
||||
not Extensions::typeModel(spec, type2, path)
|
||||
select spec.(string), type2, path
|
||||
Reference in New Issue
Block a user