Merge remote-tracking branch 'origin/main' into smowton/admin/merge-rc317-into-main

This commit is contained in:
Chris Smowton
2025-03-19 16:01:29 +00:00
2476 changed files with 45571 additions and 29067 deletions

View 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

View File

@@ -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>

View File

@@ -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

View File

@@ -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"): ...`).

View File

@@ -1 +1,5 @@
[]
- queries: .
- include:
id:
- py/not-named-self
- py/not-named-cls