mirror of
https://github.com/github/codeql.git
synced 2026-04-27 01:35:13 +02:00
Merge remote-tracking branch 'origin/main' into smowton/admin/merge-rc317-into-main
This commit is contained in:
108
python/ql/src/Metrics/Internal/TypeAnnotations.ql
Normal file
108
python/ql/src/Metrics/Internal/TypeAnnotations.ql
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @name Type metrics
|
||||
* @description Counts of various kinds of type annotations in Python code.
|
||||
* @kind table
|
||||
* @id py/type-metrics
|
||||
*/
|
||||
|
||||
import python
|
||||
|
||||
class BuiltinType extends Name {
|
||||
BuiltinType() { this.getId() in ["int", "float", "str", "bool", "bytes", "None"] }
|
||||
}
|
||||
|
||||
newtype TAnnotatable =
|
||||
TAnnotatedFunction(FunctionExpr f) { exists(f.getReturns()) } or
|
||||
TAnnotatedParameter(Parameter p) { exists(p.getAnnotation()) } or
|
||||
TAnnotatedAssignment(AnnAssign a) { exists(a.getAnnotation()) }
|
||||
|
||||
abstract class Annotatable extends TAnnotatable {
|
||||
string toString() { result = "Annotatable" }
|
||||
|
||||
abstract Expr getAnnotation();
|
||||
}
|
||||
|
||||
class AnnotatedFunction extends TAnnotatedFunction, Annotatable {
|
||||
FunctionExpr function;
|
||||
|
||||
AnnotatedFunction() { this = TAnnotatedFunction(function) }
|
||||
|
||||
override Expr getAnnotation() { result = function.getReturns() }
|
||||
}
|
||||
|
||||
class AnnotatedParameter extends TAnnotatedParameter, Annotatable {
|
||||
Parameter parameter;
|
||||
|
||||
AnnotatedParameter() { this = TAnnotatedParameter(parameter) }
|
||||
|
||||
override Expr getAnnotation() { result = parameter.getAnnotation() }
|
||||
}
|
||||
|
||||
class AnnotatedAssignment extends TAnnotatedAssignment, Annotatable {
|
||||
AnnAssign assignment;
|
||||
|
||||
AnnotatedAssignment() { this = TAnnotatedAssignment(assignment) }
|
||||
|
||||
override Expr getAnnotation() { result = assignment.getAnnotation() }
|
||||
}
|
||||
|
||||
/** Holds if `e` is a forward declaration of a type. */
|
||||
predicate is_forward_declaration(Expr e) { e instanceof StringLiteral }
|
||||
|
||||
/** Holds if `e` is a type that may be difficult to analyze. */
|
||||
predicate is_complex_type(Expr e) {
|
||||
e instanceof Subscript and not is_optional_type(e)
|
||||
or
|
||||
e instanceof Tuple
|
||||
or
|
||||
e instanceof List
|
||||
}
|
||||
|
||||
/** Holds if `e` is a type of the form `Optional[...]`. */
|
||||
predicate is_optional_type(Subscript e) { e.getObject().(Name).getId() = "Optional" }
|
||||
|
||||
/** Holds if `e` is a simple type, that is either an identifier (excluding built-in types) or an attribute of a simple type. */
|
||||
predicate is_simple_type(Expr e) {
|
||||
e instanceof Name and not e instanceof BuiltinType
|
||||
or
|
||||
is_simple_type(e.(Attribute).getObject())
|
||||
}
|
||||
|
||||
/** Holds if `e` is a built-in type. */
|
||||
predicate is_builtin_type(Expr e) { e instanceof BuiltinType }
|
||||
|
||||
predicate type_count(
|
||||
string kind, int total, int built_in_count, int forward_declaration_count, int simple_type_count,
|
||||
int complex_type_count, int optional_type_count
|
||||
) {
|
||||
kind = "Parameter annotation" and
|
||||
total = count(AnnotatedParameter p) and
|
||||
built_in_count = count(AnnotatedParameter p | is_builtin_type(p.getAnnotation())) and
|
||||
forward_declaration_count =
|
||||
count(AnnotatedParameter p | is_forward_declaration(p.getAnnotation())) and
|
||||
simple_type_count = count(AnnotatedParameter p | is_simple_type(p.getAnnotation())) and
|
||||
complex_type_count = count(AnnotatedParameter p | is_complex_type(p.getAnnotation())) and
|
||||
optional_type_count = count(AnnotatedParameter p | is_optional_type(p.getAnnotation()))
|
||||
or
|
||||
kind = "Return type annotation" and
|
||||
total = count(AnnotatedFunction f) and
|
||||
built_in_count = count(AnnotatedFunction f | is_builtin_type(f.getAnnotation())) and
|
||||
forward_declaration_count = count(AnnotatedFunction f | is_forward_declaration(f.getAnnotation())) and
|
||||
simple_type_count = count(AnnotatedFunction f | is_simple_type(f.getAnnotation())) and
|
||||
complex_type_count = count(AnnotatedFunction f | is_complex_type(f.getAnnotation())) and
|
||||
optional_type_count = count(AnnotatedFunction f | is_optional_type(f.getAnnotation()))
|
||||
or
|
||||
kind = "Annotated assignment" and
|
||||
total = count(AnnotatedAssignment a) and
|
||||
built_in_count = count(AnnotatedAssignment a | is_builtin_type(a.getAnnotation())) and
|
||||
forward_declaration_count =
|
||||
count(AnnotatedAssignment a | is_forward_declaration(a.getAnnotation())) and
|
||||
simple_type_count = count(AnnotatedAssignment a | is_simple_type(a.getAnnotation())) and
|
||||
complex_type_count = count(AnnotatedAssignment a | is_complex_type(a.getAnnotation())) and
|
||||
optional_type_count = count(AnnotatedAssignment a | is_optional_type(a.getAnnotation()))
|
||||
}
|
||||
|
||||
from
|
||||
string message, int total, int built_in, int forward_decl, int simple, int complex, int optional
|
||||
where type_count(message, total, built_in, forward_decl, simple, complex, optional)
|
||||
select message, total, built_in, forward_decl, simple, complex, optional
|
||||
@@ -5,8 +5,11 @@
|
||||
<recommendation>
|
||||
|
||||
<p>To guard against SSRF attacks you should avoid putting user-provided input directly
|
||||
into a request URL. Instead, either maintain a list of authorized URLs on the server and choose
|
||||
from that list based on the input provided, or perform proper validation of the input.
|
||||
into a request URL. On the application level, maintain a list of authorized URLs on the server and choose
|
||||
from that list based on the input provided. If that is not possible, one should verify the IP address for all user-controlled
|
||||
requests to ensure they are not private. This requires saving the verified IP address of each domain,
|
||||
then utilizing a custom HTTP adapter to ensure that future requests to that domain use the verified IP address.
|
||||
On the network level, you can segment the vulnerable application into its own LAN or block access to specific devices.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
@@ -34,6 +34,14 @@ predicate complex_all(Module m) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate used_in_forward_declaration(Name used, Module mod) {
|
||||
exists(StringLiteral s, Annotation annotation |
|
||||
s.getS() = used.getId() and
|
||||
s.getEnclosingModule() = mod and
|
||||
annotation.getASubExpression*() = s
|
||||
)
|
||||
}
|
||||
|
||||
predicate unused_global(Name unused, GlobalVariable v) {
|
||||
not exists(ImportingStmt is | is.contains(unused)) and
|
||||
forex(DefinitionNode defn | defn.getNode() = unused |
|
||||
@@ -55,7 +63,8 @@ predicate unused_global(Name unused, GlobalVariable v) {
|
||||
unused.defines(v) and
|
||||
not name_acceptable_for_unused_variable(v) and
|
||||
not complex_all(unused.getEnclosingModule())
|
||||
)
|
||||
) and
|
||||
not used_in_forward_declaration(unused, unused.getEnclosingModule())
|
||||
}
|
||||
|
||||
from Name unused, GlobalVariable v
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
|
||||
- The `py/unused-global-variable` now no longer flags variables that are only used in forward references (e.g. the `Foo` in `def bar(x: "Foo"): ...`).
|
||||
@@ -1 +1,5 @@
|
||||
[]
|
||||
- queries: .
|
||||
- include:
|
||||
id:
|
||||
- py/not-named-self
|
||||
- py/not-named-cls
|
||||
|
||||
Reference in New Issue
Block a user