[flake8-bandit] Support explicit string concatenations in S310 HTTP detection (#12315)

Closes https://github.com/astral-sh/ruff/issues/12314.
This commit is contained in:
Charlie Marsh 2024-07-14 10:44:08 -04:00 committed by GitHub
parent 7a7c601d5e
commit 18c364d5df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 225 additions and 200 deletions

View file

@ -2,6 +2,7 @@ import urllib.request
urllib.request.urlopen(url='http://www.google.com') urllib.request.urlopen(url='http://www.google.com')
urllib.request.urlopen(url=f'http://www.google.com') urllib.request.urlopen(url=f'http://www.google.com')
urllib.request.urlopen(url='http://' + 'www' + '.google.com')
urllib.request.urlopen(url='http://www.google.com', **kwargs) urllib.request.urlopen(url='http://www.google.com', **kwargs)
urllib.request.urlopen(url=f'http://www.google.com', **kwargs) urllib.request.urlopen(url=f'http://www.google.com', **kwargs)
urllib.request.urlopen('http://www.google.com') urllib.request.urlopen('http://www.google.com')
@ -11,6 +12,7 @@ urllib.request.urlopen(url)
urllib.request.Request(url='http://www.google.com') urllib.request.Request(url='http://www.google.com')
urllib.request.Request(url=f'http://www.google.com') urllib.request.Request(url=f'http://www.google.com')
urllib.request.Request(url='http://' + 'www' + '.google.com')
urllib.request.Request(url='http://www.google.com', **kwargs) urllib.request.Request(url='http://www.google.com', **kwargs)
urllib.request.Request(url=f'http://www.google.com', **kwargs) urllib.request.Request(url=f'http://www.google.com', **kwargs)
urllib.request.Request('http://www.google.com') urllib.request.Request('http://www.google.com')
@ -20,15 +22,18 @@ urllib.request.Request(url)
urllib.request.URLopener().open(fullurl='http://www.google.com') urllib.request.URLopener().open(fullurl='http://www.google.com')
urllib.request.URLopener().open(fullurl=f'http://www.google.com') urllib.request.URLopener().open(fullurl=f'http://www.google.com')
urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs) urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs) urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
urllib.request.URLopener().open('http://www.google.com') urllib.request.URLopener().open('http://www.google.com')
urllib.request.URLopener().open(f'http://www.google.com') urllib.request.URLopener().open(f'http://www.google.com')
urllib.request.URLopener().open('http://' + 'www' + '.google.com')
urllib.request.URLopener().open('file:///foo/bar/baz') urllib.request.URLopener().open('file:///foo/bar/baz')
urllib.request.URLopener().open(url) urllib.request.URLopener().open(url)
urllib.request.urlopen(url=urllib.request.Request('http://www.google.com')) urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'))
urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com')) urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'))
urllib.request.urlopen(url=urllib.request.Request('http://' + 'www' + '.google.com'))
urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs) urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs)
urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs) urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs)
urllib.request.urlopen(urllib.request.Request('http://www.google.com')) urllib.request.urlopen(urllib.request.Request('http://www.google.com'))

View file

@ -1,9 +1,10 @@
//! Check for calls to suspicious functions, or calls into suspicious modules. //! Check for calls to suspicious functions, or calls into suspicious modules.
//! //!
//! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html> //! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html>
use itertools::Either;
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation}; use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
use ruff_macros::{derive_message_formats, violation}; use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Decorator, Expr, ExprCall}; use ruff_python_ast::{self as ast, Decorator, Expr, ExprCall, Operator};
use ruff_text_size::Ranged; use ruff_text_size::Ranged;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -838,6 +839,43 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
true true
} }
/// Returns `true` if the iterator starts with an HTTP or HTTPS prefix.
fn has_http_prefix(chars: impl Iterator<Item = char> + Clone) -> bool {
has_prefix(chars.clone().skip_while(|c| c.is_whitespace()), "http://")
|| has_prefix(chars.skip_while(|c| c.is_whitespace()), "https://")
}
/// Return the leading characters for an expression, if it's a string literal, f-string, or
/// string concatenation.
fn leading_chars(expr: &Expr) -> Option<impl Iterator<Item = char> + Clone + '_> {
match expr {
// Ex) `"foo"`
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
Some(Either::Left(value.chars()))
}
// Ex) f"foo"
Expr::FString(ast::ExprFString { value, .. }) => {
value.elements().next().and_then(|element| {
if let ast::FStringElement::Literal(ast::FStringLiteralElement {
value, ..
}) = element
{
Some(Either::Right(value.chars()))
} else {
None
}
})
}
// Ex) "foo" + "bar"
Expr::BinOp(ast::ExprBinOp {
op: Operator::Add,
left,
..
}) => leading_chars(left),
_ => None,
}
}
let Some(diagnostic_kind) = checker.semantic().resolve_qualified_name(call.func.as_ref()).and_then(|qualified_name| { let Some(diagnostic_kind) = checker.semantic().resolve_qualified_name(call.func.as_ref()).and_then(|qualified_name| {
match qualified_name.segments() { match qualified_name.segments() {
// Pickle // Pickle
@ -864,26 +902,12 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
["django", "utils", "safestring" | "html", "mark_safe"] => Some(SuspiciousMarkSafeUsage.into()), ["django", "utils", "safestring" | "html", "mark_safe"] => Some(SuspiciousMarkSafeUsage.into()),
// URLOpen (`Request`) // URLOpen (`Request`)
["urllib", "request", "Request"] | ["urllib", "request", "Request"] |
["six", "moves", "urllib", "request","Request"] => { ["six", "moves", "urllib", "request", "Request"] => {
// If the `url` argument is a string literal or an f string, allow `http` and `https` schemes. // If the `url` argument is a string literal or an f-string, allow `http` and `https` schemes.
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) { if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
match call.arguments.find_argument("url", 0) { if call.arguments.find_argument("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
// If the `url` argument is a string literal, allow `http` and `https` schemes.
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None; return None;
} }
},
// If the `url` argument is an f-string literal, allow `http` and `https` schemes.
Some(Expr::FString(ast::ExprFString { value, .. })) => {
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None;
}
}
},
_ => {}
}
} }
Some(SuspiciousURLOpenUsage.into()) Some(SuspiciousURLOpenUsage.into())
} }
@ -892,44 +916,20 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" ] => { ["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" ] => {
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) { if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
match call.arguments.find_argument("url", 0) { match call.arguments.find_argument("url", 0) {
// If the `url` argument is a string literal, allow `http` and `https` schemes.
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None;
}
},
// If the `url` argument is an f-string literal, allow `http` and `https` schemes.
Some(Expr::FString(ast::ExprFString { value, .. })) => {
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None;
}
}
},
// If the `url` argument is a `urllib.request.Request` object, allow `http` and `https` schemes. // If the `url` argument is a `urllib.request.Request` object, allow `http` and `https` schemes.
Some(Expr::Call(ExprCall { func, arguments, .. })) => { Some(Expr::Call(ExprCall { func, arguments, .. })) => {
if checker.semantic().resolve_qualified_name(func.as_ref()).is_some_and(|name| name.segments() == ["urllib", "request", "Request"]) { if checker.semantic().resolve_qualified_name(func.as_ref()).is_some_and(|name| name.segments() == ["urllib", "request", "Request"]) {
match arguments.find_argument("url", 0) { if arguments.find_argument("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
// If the `url` argument is a string literal, allow `http` and `https` schemes.
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None; return None;
} }
}
}, },
// If the `url` argument is an f-string literal, allow `http` and `https` schemes. // If the `url` argument is a string literal, allow `http` and `https` schemes.
Some(Expr::FString(ast::ExprFString { value, .. })) => { Some(expr) => {
if let Some(ast::FStringElement::Literal(ast::FStringLiteralElement { value, .. })) = value.elements().next() { if leading_chars(expr).is_some_and(has_http_prefix) {
if has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "http://") || has_prefix(value.chars().skip_while(|c| c.is_whitespace()), "https://") {
return None; return None;
} }
}
},
_ => {}
}
}
}, },
_ => {} _ => {}

View file

@ -1,212 +1,232 @@
--- ---
source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs
--- ---
S310.py:5:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
3 | urllib.request.urlopen(url='http://www.google.com')
4 | urllib.request.urlopen(url=f'http://www.google.com')
5 | urllib.request.urlopen(url='http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
6 | urllib.request.urlopen(url=f'http://www.google.com', **kwargs)
7 | urllib.request.urlopen('http://www.google.com')
|
S310.py:6:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:6:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
4 | urllib.request.urlopen(url=f'http://www.google.com') 4 | urllib.request.urlopen(url=f'http://www.google.com')
5 | urllib.request.urlopen(url='http://www.google.com', **kwargs) 5 | urllib.request.urlopen(url='http://' + 'www' + '.google.com')
6 | urllib.request.urlopen(url=f'http://www.google.com', **kwargs) 6 | urllib.request.urlopen(url='http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
7 | urllib.request.urlopen('http://www.google.com') 7 | urllib.request.urlopen(url=f'http://www.google.com', **kwargs)
8 | urllib.request.urlopen(f'http://www.google.com') 8 | urllib.request.urlopen('http://www.google.com')
| |
S310.py:9:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:7:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
7 | urllib.request.urlopen('http://www.google.com') 5 | urllib.request.urlopen(url='http://' + 'www' + '.google.com')
8 | urllib.request.urlopen(f'http://www.google.com') 6 | urllib.request.urlopen(url='http://www.google.com', **kwargs)
9 | urllib.request.urlopen('file:///foo/bar/baz') 7 | urllib.request.urlopen(url=f'http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
10 | urllib.request.urlopen(url) 8 | urllib.request.urlopen('http://www.google.com')
9 | urllib.request.urlopen(f'http://www.google.com')
| |
S310.py:10:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:10:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
8 | urllib.request.urlopen(f'http://www.google.com') 8 | urllib.request.urlopen('http://www.google.com')
9 | urllib.request.urlopen('file:///foo/bar/baz') 9 | urllib.request.urlopen(f'http://www.google.com')
10 | urllib.request.urlopen(url) 10 | urllib.request.urlopen('file:///foo/bar/baz')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
11 |
12 | urllib.request.Request(url='http://www.google.com')
|
S310.py:14:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
12 | urllib.request.Request(url='http://www.google.com')
13 | urllib.request.Request(url=f'http://www.google.com')
14 | urllib.request.Request(url='http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
15 | urllib.request.Request(url=f'http://www.google.com', **kwargs)
16 | urllib.request.Request('http://www.google.com')
|
S310.py:15:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
13 | urllib.request.Request(url=f'http://www.google.com')
14 | urllib.request.Request(url='http://www.google.com', **kwargs)
15 | urllib.request.Request(url=f'http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
16 | urllib.request.Request('http://www.google.com')
17 | urllib.request.Request(f'http://www.google.com')
|
S310.py:18:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
16 | urllib.request.Request('http://www.google.com')
17 | urllib.request.Request(f'http://www.google.com')
18 | urllib.request.Request('file:///foo/bar/baz')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
19 | urllib.request.Request(url) 11 | urllib.request.urlopen(url)
| |
S310.py:19:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:11:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
17 | urllib.request.Request(f'http://www.google.com') 9 | urllib.request.urlopen(f'http://www.google.com')
18 | urllib.request.Request('file:///foo/bar/baz') 10 | urllib.request.urlopen('file:///foo/bar/baz')
19 | urllib.request.Request(url) 11 | urllib.request.urlopen(url)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
20 | 12 |
21 | urllib.request.URLopener().open(fullurl='http://www.google.com') 13 | urllib.request.Request(url='http://www.google.com')
|
S310.py:16:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
14 | urllib.request.Request(url=f'http://www.google.com')
15 | urllib.request.Request(url='http://' + 'www' + '.google.com')
16 | urllib.request.Request(url='http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
17 | urllib.request.Request(url=f'http://www.google.com', **kwargs)
18 | urllib.request.Request('http://www.google.com')
|
S310.py:17:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
15 | urllib.request.Request(url='http://' + 'www' + '.google.com')
16 | urllib.request.Request(url='http://www.google.com', **kwargs)
17 | urllib.request.Request(url=f'http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
18 | urllib.request.Request('http://www.google.com')
19 | urllib.request.Request(f'http://www.google.com')
|
S310.py:20:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
18 | urllib.request.Request('http://www.google.com')
19 | urllib.request.Request(f'http://www.google.com')
20 | urllib.request.Request('file:///foo/bar/baz')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
21 | urllib.request.Request(url)
| |
S310.py:21:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:21:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
19 | urllib.request.Request(url) 19 | urllib.request.Request(f'http://www.google.com')
20 | 20 | urllib.request.Request('file:///foo/bar/baz')
21 | urllib.request.URLopener().open(fullurl='http://www.google.com') 21 | urllib.request.Request(url)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
22 | urllib.request.URLopener().open(fullurl=f'http://www.google.com') 22 |
23 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs) 23 | urllib.request.URLopener().open(fullurl='http://www.google.com')
|
S310.py:22:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
21 | urllib.request.URLopener().open(fullurl='http://www.google.com')
22 | urllib.request.URLopener().open(fullurl=f'http://www.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
23 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
| |
S310.py:23:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:23:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
21 | urllib.request.URLopener().open(fullurl='http://www.google.com') 21 | urllib.request.Request(url)
22 | urllib.request.URLopener().open(fullurl=f'http://www.google.com') 22 |
23 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs) 23 | urllib.request.URLopener().open(fullurl='http://www.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs) 24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com')
25 | urllib.request.URLopener().open('http://www.google.com') 25 | urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
| |
S310.py:24:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:24:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
22 | urllib.request.URLopener().open(fullurl=f'http://www.google.com') 23 | urllib.request.URLopener().open(fullurl='http://www.google.com')
23 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs) 24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com')
24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
25 | urllib.request.URLopener().open('http://www.google.com') 25 | urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
26 | urllib.request.URLopener().open(f'http://www.google.com') 26 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
| |
S310.py:25:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:25:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
23 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs) 23 | urllib.request.URLopener().open(fullurl='http://www.google.com')
24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs) 24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com')
25 | urllib.request.URLopener().open('http://www.google.com') 25 | urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
26 | urllib.request.URLopener().open(f'http://www.google.com') 26 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
27 | urllib.request.URLopener().open('file:///foo/bar/baz') 27 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
| |
S310.py:26:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:26:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs) 24 | urllib.request.URLopener().open(fullurl=f'http://www.google.com')
25 | urllib.request.URLopener().open('http://www.google.com') 25 | urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
26 | urllib.request.URLopener().open(f'http://www.google.com') 26 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
27 | urllib.request.URLopener().open('file:///foo/bar/baz') 27 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
28 | urllib.request.URLopener().open(url) 28 | urllib.request.URLopener().open('http://www.google.com')
| |
S310.py:27:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:27:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
25 | urllib.request.URLopener().open('http://www.google.com') 25 | urllib.request.URLopener().open(fullurl='http://' + 'www' + '.google.com')
26 | urllib.request.URLopener().open(f'http://www.google.com') 26 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
27 | urllib.request.URLopener().open('file:///foo/bar/baz') 27 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
28 | urllib.request.URLopener().open(url) 28 | urllib.request.URLopener().open('http://www.google.com')
29 | urllib.request.URLopener().open(f'http://www.google.com')
| |
S310.py:28:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:28:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
26 | urllib.request.URLopener().open(f'http://www.google.com') 26 | urllib.request.URLopener().open(fullurl='http://www.google.com', **kwargs)
27 | urllib.request.URLopener().open('file:///foo/bar/baz') 27 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
28 | urllib.request.URLopener().open(url) 28 | urllib.request.URLopener().open('http://www.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
29 | 29 | urllib.request.URLopener().open(f'http://www.google.com')
30 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com')) 30 | urllib.request.URLopener().open('http://' + 'www' + '.google.com')
|
S310.py:29:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
27 | urllib.request.URLopener().open(fullurl=f'http://www.google.com', **kwargs)
28 | urllib.request.URLopener().open('http://www.google.com')
29 | urllib.request.URLopener().open(f'http://www.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
30 | urllib.request.URLopener().open('http://' + 'www' + '.google.com')
31 | urllib.request.URLopener().open('file:///foo/bar/baz')
|
S310.py:30:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
28 | urllib.request.URLopener().open('http://www.google.com')
29 | urllib.request.URLopener().open(f'http://www.google.com')
30 | urllib.request.URLopener().open('http://' + 'www' + '.google.com')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
31 | urllib.request.URLopener().open('file:///foo/bar/baz')
32 | urllib.request.URLopener().open(url)
|
S310.py:31:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
29 | urllib.request.URLopener().open(f'http://www.google.com')
30 | urllib.request.URLopener().open('http://' + 'www' + '.google.com')
31 | urllib.request.URLopener().open('file:///foo/bar/baz')
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
32 | urllib.request.URLopener().open(url)
| |
S310.py:32:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:32:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
30 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com')) 30 | urllib.request.URLopener().open('http://' + 'www' + '.google.com')
31 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com')) 31 | urllib.request.URLopener().open('file:///foo/bar/baz')
32 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs) 32 | urllib.request.URLopener().open(url)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
33 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs) 33 |
34 | urllib.request.urlopen(urllib.request.Request('http://www.google.com')) 34 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'))
|
S310.py:33:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
31 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'))
32 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs)
33 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
34 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
35 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
|
S310.py:36:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
34 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
35 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
36 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
37 | urllib.request.urlopen(urllib.request.Request(url))
|
S310.py:36:24: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
34 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
35 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
36 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
37 | urllib.request.urlopen(urllib.request.Request(url))
| |
S310.py:37:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:37:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
35 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com')) 35 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'))
36 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz')) 36 | urllib.request.urlopen(url=urllib.request.Request('http://' + 'www' + '.google.com'))
37 | urllib.request.urlopen(urllib.request.Request(url)) 37 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
38 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs)
39 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
|
S310.py:38:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
36 | urllib.request.urlopen(url=urllib.request.Request('http://' + 'www' + '.google.com'))
37 | urllib.request.urlopen(url=urllib.request.Request('http://www.google.com'), **kwargs)
38 | urllib.request.urlopen(url=urllib.request.Request(f'http://www.google.com'), **kwargs)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
39 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
40 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
|
S310.py:41:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
39 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
40 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
41 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
42 | urllib.request.urlopen(urllib.request.Request(url))
|
S310.py:41:24: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
39 | urllib.request.urlopen(urllib.request.Request('http://www.google.com'))
40 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
41 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
42 | urllib.request.urlopen(urllib.request.Request(url))
|
S310.py:42:1: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
|
40 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
41 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
42 | urllib.request.urlopen(urllib.request.Request(url))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
| |
S310.py:37:24: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected. S310.py:42:24: S310 Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected.
| |
35 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com')) 40 | urllib.request.urlopen(urllib.request.Request(f'http://www.google.com'))
36 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz')) 41 | urllib.request.urlopen(urllib.request.Request('file:///foo/bar/baz'))
37 | urllib.request.urlopen(urllib.request.Request(url)) 42 | urllib.request.urlopen(urllib.request.Request(url))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ S310
| |

View file

@ -1720,7 +1720,7 @@ impl StringLiteralValue {
} }
/// Returns an iterator over the [`char`]s of each string literal part. /// Returns an iterator over the [`char`]s of each string literal part.
pub fn chars(&self) -> impl Iterator<Item = char> + '_ { pub fn chars(&self) -> impl Iterator<Item = char> + Clone + '_ {
self.iter().flat_map(|part| part.value.chars()) self.iter().flat_map(|part| part.value.chars())
} }