mirror of
https://github.com/github/codeql.git
synced 2026-07-02 18:15:33 +02:00
Merge branch 'main' into mad-write-through-model
This commit is contained in:
@@ -1,3 +1,16 @@
|
||||
## 7.2.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results.
|
||||
* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged.
|
||||
* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts.
|
||||
|
||||
## 7.1.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `Flask::FlaskApp::instance()` will now also return instances of subclasses defined in the source tree. Previously, these were filtered out. `Flask::FlaskApp::classRef()` has been deprecated in favor of `Flask::FlaskApp::subclassRef()` since it already returned some subclasses.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results.
|
||||
12
python/ql/lib/change-notes/released/7.2.0.md
Normal file
12
python/ql/lib/change-notes/released/7.2.0.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## 7.2.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The `Function.getAReturnValueFlowNode()` predicate has been deprecated. Bind a `Return` node explicitly instead — `exists(Return ret | ret.getScope() = f and n.getNode() = ret.getValue())`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
* The `AstNode.getAFlowNode()` predicate has been deprecated. Use `ControlFlowNode.getNode()` from the other direction instead: replace `e.getAFlowNode() = n` with `n.getNode() = e`. This is a preparatory step towards migrating the dataflow library off the legacy CFG; it has no semantic effect.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Python type tracking now follows values stored in instance attributes such as `self.attr` across instance methods, including across a class hierarchy (for example, a value stored on `self.attr` in a base class and read in a subclass, or vice versa). As a result, analysis is more likely to recognize user-defined objects that are stored on `self` and used later in other methods, which may produce additional results.
|
||||
* Simplified the internal predicates that detect `@staticmethod`, `@classmethod` and `@property` decorators to match the decorator's AST `Name` directly, rather than going through the CFG and requiring the name to resolve globally. Code that shadows these three builtin decorators at the module-scope will now be classified by the decorator name alone; in practice, shadowing these names is extremely rare and the call-graph results are unchanged.
|
||||
* Python taint tracking is now more precise for values flowing through container contents, such as list, set, tuple, and dictionary elements. This may remove some false positive alerts.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 7.1.2
|
||||
lastReleaseVersion: 7.2.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-all
|
||||
version: 7.1.3-dev
|
||||
version: 7.2.1-dev
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
|
||||
@@ -71,14 +71,21 @@ module Flask {
|
||||
* See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.
|
||||
*/
|
||||
module FlaskApp {
|
||||
/** Gets a reference to the `flask.Flask` class. */
|
||||
API::Node classRef() {
|
||||
result = API::moduleImport("flask").getMember("Flask") or
|
||||
/**
|
||||
* Gets a reference to the `flask.Flask` class or any subclass.
|
||||
*
|
||||
* Deprecated: Use `subclassRef()` instead, this predicate always returned some subclasses.
|
||||
*/
|
||||
deprecated API::Node classRef() { result = subclassRef() }
|
||||
|
||||
/** Gets a reference to the `flask.Flask` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result = API::moduleImport("flask").getMember("Flask").getASubclass*() or
|
||||
result = ModelOutput::getATypeNode("flask.Flask~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
/** Gets a reference to an instance of `flask.Flask` (a flask application). */
|
||||
API::Node instance() { result = classRef().getReturn() }
|
||||
API::Node instance() { result = subclassRef().getReturn() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +139,7 @@ module Flask {
|
||||
API::Node classRef() {
|
||||
result = API::moduleImport("flask").getMember("Response")
|
||||
or
|
||||
result = [FlaskApp::classRef(), FlaskApp::instance()].getMember("response_class")
|
||||
result = [FlaskApp::subclassRef(), FlaskApp::instance()].getMember("response_class")
|
||||
or
|
||||
result = ModelOutput::getATypeNode("flask.Response~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 1.8.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `py/modification-of-locals` query no longer flags modifications of a `locals()` dictionary that has been passed out of the scope in which `locals()` was called (for example, by passing it to another function or storing it in an instance attribute). In such cases the dictionary is used as an ordinary mapping and modifying it is meaningful, so these were false positives. The "modification has no effect" claim only applies within the scope that called `locals()`, which is now the only case reported.
|
||||
|
||||
## 1.8.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 1.8.5
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `py/modification-of-locals` query no longer flags modifications of a `locals()` dictionary that has been passed out of the scope in which `locals()` was called (for example, by passing it to another function or storing it in an instance attribute). In such cases the dictionary is used as an ordinary mapping and modifying it is meaningful, so these were false positives. The "modification has no effect" claim only applies within the scope that called `locals()`, which is now the only case reported.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.8.4
|
||||
lastReleaseVersion: 1.8.5
|
||||
|
||||
@@ -351,7 +351,7 @@ class DjangoHttpRequest extends FindSubclassesSpec {
|
||||
class FlaskClass extends FindSubclassesSpec {
|
||||
FlaskClass() { this = "flask.Flask~Subclass" }
|
||||
|
||||
override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::classRef() }
|
||||
override API::Node getAlreadyModeledClass() { result = Flask::FlaskApp::subclassRef() }
|
||||
}
|
||||
|
||||
class FlaskBlueprint extends FindSubclassesSpec {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-queries
|
||||
version: 1.8.5-dev
|
||||
version: 1.8.6-dev
|
||||
groups:
|
||||
- python
|
||||
- queries
|
||||
|
||||
29
python/ql/test/experimental/meta/InlineInstanceTest.qll
Normal file
29
python/ql/test/experimental/meta/InlineInstanceTest.qll
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Defines an InlineExpectationsTest for class instances, that is,
|
||||
* for any API::Node that is an instance of a class (e.g. `Flask`).
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.ApiGraphs
|
||||
import utils.test.InlineExpectationsTest
|
||||
private import semmle.python.dataflow.new.internal.PrintNode
|
||||
|
||||
signature API::Node getInstanceSig();
|
||||
|
||||
module MakeInlineInstanceTest<getInstanceSig/0 getInstance> {
|
||||
private module InlineInstanceTest implements TestSig {
|
||||
string getARelevantTag() { result = "instance" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(location.getFile().getRelativePath()) and
|
||||
exists(API::Node instance | instance = getInstance() |
|
||||
location = instance.getLocation() and
|
||||
element = prettyNode(instance.asSource()) and
|
||||
value = "" and
|
||||
tag = "instance"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<InlineInstanceTest>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import python
|
||||
import semmle.python.frameworks.Flask
|
||||
import semmle.python.ApiGraphs
|
||||
import experimental.meta.InlineInstanceTest
|
||||
|
||||
API::Node getInstance() { result = Flask::FlaskApp::instance() }
|
||||
|
||||
import MakeInlineInstanceTest<getInstance/0>
|
||||
@@ -0,0 +1,14 @@
|
||||
from flask import Flask
|
||||
|
||||
|
||||
class Sub(Flask):
|
||||
def __init__(self, *args, **kwargs):
|
||||
Flask.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
app = Sub(__name__) # $ instance
|
||||
|
||||
|
||||
@app.route("/") # $ routeSetup="/"
|
||||
def hello(): # $ requestHandler
|
||||
return "world" # $ HttpResponse
|
||||
@@ -1,7 +1,7 @@
|
||||
import flask
|
||||
|
||||
from flask import Flask, request, make_response
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
@app.route("/") # $ routeSetup="/"
|
||||
def hello_world(): # $ requestHandler
|
||||
|
||||
@@ -3,7 +3,7 @@ import json
|
||||
from flask import Flask, make_response, jsonify, Response, request, redirect
|
||||
from werkzeug.datastructures import Headers
|
||||
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
|
||||
@app.route("/html1") # $ routeSetup="/html1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import flask
|
||||
|
||||
from flask import Flask, make_response
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
|
||||
SOME_ROUTE = "/some/route"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
@app.route("/save-uploaded-file") # $ routeSetup="/save-uploaded-file"
|
||||
def test_taint(): # $ requestHandler
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from flask import Flask, request, render_template_string, stream_template_string
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
@app.route("/test_taint/<name>/<int:number>") # $ routeSetup="/test_taint/<name>/<int:number>"
|
||||
def test_taint(name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from flask import Flask, Response, stream_with_context, render_template_string, stream_template_string
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__) # $ instance
|
||||
|
||||
@app.route("/a") # $ routeSetup="/a"
|
||||
def a(): # $ requestHandler
|
||||
|
||||
Reference in New Issue
Block a user