-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(rules): implement flake8-bandit
S201
(flask_debug_true
)
#7503
Changes from 1 commit
2d23862
c074458
46355ee
7ed0354
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from flask import Flask | ||
|
||
app = Flask(__name__) | ||
|
||
@app.route('/') | ||
def main(): | ||
raise | ||
|
||
#bad | ||
app.run(debug=True) | ||
|
||
#okay | ||
app.run() | ||
app.run(debug=False) | ||
|
||
#unrelated | ||
run() | ||
run(debug=True) | ||
run(debug) | ||
foo.run(debug=True) | ||
app = 1 | ||
app.run(debug=True) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -573,6 +573,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> { | |
(Flake8Bandit, "110") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::TryExceptPass), | ||
(Flake8Bandit, "112") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::TryExceptContinue), | ||
(Flake8Bandit, "113") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::RequestWithoutTimeout), | ||
(Flake8Bandit, "201") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::FlaskDebugTrue), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're now in the habit of adding new rules under |
||
(Flake8Bandit, "301") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::SuspiciousPickleUsage), | ||
(Flake8Bandit, "302") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::SuspiciousMarshalUsage), | ||
(Flake8Bandit, "303") => (RuleGroup::Unspecified, rules::flake8_bandit::rules::SuspiciousInsecureHashUsage), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
use ruff_diagnostics::{Diagnostic, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
use ruff_python_ast::helpers::is_const_true; | ||
use ruff_python_ast::{Expr, ExprAttribute, ExprCall, Stmt, StmtAssign}; | ||
use ruff_text_size::Ranged; | ||
|
||
use crate::checkers::ast::Checker; | ||
|
||
/// ## What it does | ||
/// Checks for uses of `debug=True` in Flask. | ||
/// | ||
/// ## Why is this bad? | ||
/// Enabling debug mode shows an interactive debugger in the browser if an error occurs, and allows | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's annoying, but we manually format these to fit 80 characters, since they sometimes get printed to the terminal. |
||
/// running arbitrary Python code from the browser. This could leak sensitive information, or allow | ||
/// an attacker to run arbitrary code. | ||
/// | ||
/// ## Example | ||
/// ```python | ||
/// import flask | ||
/// | ||
/// app = Flask() | ||
/// | ||
/// app.run(debug=True) | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```python | ||
/// import flask | ||
/// | ||
/// app = Flask() | ||
/// | ||
/// app.run(debug=os.environ["ENV"] == "dev") | ||
/// ``` | ||
/// | ||
/// ## References | ||
/// - [Flask documentation: Debug Mode](https://flask.palletsprojects.com/en/latest/quickstart/#debug-mode) | ||
#[violation] | ||
pub struct FlaskDebugTrue; | ||
|
||
impl Violation for FlaskDebugTrue { | ||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
format!("Use of `debug=True` in Flask app detected") | ||
} | ||
} | ||
|
||
/// S201 | ||
pub(crate) fn flask_debug_true(checker: &mut Checker, call: &ExprCall) { | ||
let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else { | ||
return; | ||
}; | ||
|
||
if attr.as_str() != "run" { | ||
return; | ||
} | ||
|
||
if let Some(debug_argument) = call.arguments.find_keyword("debug") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can reduce one level of indentation by doing:
|
||
if !is_const_true(&debug_argument.value) { | ||
return; | ||
} | ||
|
||
if let Expr::Name(name) = value.as_ref() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here: can use |
||
checker | ||
.semantic() | ||
.resolve_name(name) | ||
.map_or((), |binding_id| { | ||
if let Some(Stmt::Assign(StmtAssign { value, .. })) = checker | ||
.semantic() | ||
.binding(binding_id) | ||
.statement(checker.semantic()) | ||
{ | ||
if let Expr::Call(ExprCall { func, .. }) = value.as_ref() { | ||
if checker | ||
.semantic() | ||
.resolve_call_path(func) | ||
.is_some_and(|call_path| { | ||
matches!(call_path.as_slice(), ["flask", "Flask"]) | ||
}) | ||
{ | ||
checker | ||
.diagnostics | ||
.push(Diagnostic::new(FlaskDebugTrue, debug_argument.range())); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
source: crates/ruff/src/rules/flake8_bandit/mod.rs | ||
--- | ||
S201.py:10:9: S201 Use of `debug=True` in Flask app detected | ||
| | ||
9 | #bad | ||
10 | app.run(debug=True) | ||
| ^^^^^^^^^^ S201 | ||
11 | | ||
12 | #okay | ||
| | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For whatever reason, the comment we typically use here is
# Errors
and then# OK
(instead of#okay
).