diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S102.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S102.py index e945b224c568f7..85ca1539589f72 100644 --- a/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S102.py +++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S102.py @@ -13,3 +13,12 @@ def _(): def _(): from builtin import exec exec('') # No error + +# https://github.com/astral-sh/ruff/issues/28011 +list(map(exec, ["hi"])) # Preview: Error +foo = exec # Preview: Error + +def _(): + def exec(): ... + + list(map(exec, [])) # Shadowed -- No error diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index d30f5911b2bad5..716bec9c1fd74d 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -287,6 +287,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) { Rule::SuspiciousInsecureCipherModeUsage, Rule::SuspiciousMktempUsage, Rule::SuspiciousEvalUsage, + Rule::ExecBuiltin, Rule::SuspiciousMarkSafeUsage, Rule::SuspiciousURLOpenUsage, Rule::SuspiciousNonCryptographicRandomUsage, @@ -410,6 +411,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) { Rule::SuspiciousInsecureCipherModeUsage, Rule::SuspiciousMktempUsage, Rule::SuspiciousEvalUsage, + Rule::ExecBuiltin, Rule::SuspiciousMarkSafeUsage, Rule::SuspiciousURLOpenUsage, Rule::SuspiciousNonCryptographicRandomUsage, diff --git a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs index 2cb386c4a6c028..fa6e45eebc4312 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/mod.rs @@ -98,6 +98,7 @@ mod tests { } #[test_case(Rule::BadFilePermissions, Path::new("S103.py"))] + #[test_case(Rule::ExecBuiltin, Path::new("S102.py"))] #[test_case(Rule::SuspiciousPickleUsage, Path::new("S301.py"))] #[test_case(Rule::SuspiciousEvalUsage, Path::new("S307.py"))] #[test_case(Rule::SuspiciousMarkSafeUsage, Path::new("S308.py"))] diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/exec_used.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/exec_used.rs index 4fb9f77dea1c2c..2e3f5c29f72ba4 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/exec_used.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/exec_used.rs @@ -1,11 +1,10 @@ -use ruff_python_ast::Expr; - use ruff_macros::{ViolationMetadata, derive_message_formats}; -use ruff_text_size::Ranged; +use ruff_python_ast::Expr; use crate::Violation; use crate::checkers::ast::Checker; use crate::codes::Category; +use crate::rules::flake8_bandit::rules::suspicious_function_call_target; /// ## What it does /// Checks for uses of the builtin `exec` function. @@ -35,7 +34,5 @@ impl Violation for ExecBuiltin { /// S102 pub(crate) fn exec_used(checker: &Checker, func: &Expr) { - if checker.semantic().match_builtin_expr(func, "exec") { - checker.report_diagnostic(ExecBuiltin, func.range()); - } + suspicious_function_call_target(checker, func); } diff --git a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs index f7b85ee623069d..919e309d5b09f5 100644 --- a/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs +++ b/crates/ruff_linter/src/rules/flake8_bandit/rules/suspicious_function_call.rs @@ -12,6 +12,7 @@ use crate::Violation; use crate::checkers::ast::Checker; use crate::codes::Category; use crate::preview::is_suspicious_function_reference_enabled; +use crate::rules::flake8_bandit::rules::ExecBuiltin; /// ## What it does /// Checks for calls to `pickle` functions or modules that wrap them. @@ -982,6 +983,10 @@ pub(crate) fn suspicious_function_call(checker: &Checker, call: &ExprCall) { ); } +pub(crate) fn suspicious_function_call_target(checker: &Checker, func: &Expr) { + suspicious_function(checker, func, None, func.range()); +} + pub(crate) fn suspicious_function_reference(checker: &Checker, func: &Expr) { if !is_suspicious_function_reference_enabled(checker.settings()) { return; @@ -1014,7 +1019,7 @@ pub(crate) fn suspicious_function_reference(checker: &Checker, func: &Expr) { suspicious_function(checker, func, None, func.range()); } -/// S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323 +/// S102, S301, S302, S303, S304, S305, S306, S307, S308, S310, S311, S312, S313, S314, S315, S316, S317, S318, S319, S320, S321, S323 fn suspicious_function( checker: &Checker, func: &Expr, @@ -1162,6 +1167,11 @@ fn suspicious_function( checker.report_diagnostic_if_enabled(SuspiciousEvalUsage, range) } + // Exec + ["" | "builtins", "exec"] => { + checker.report_diagnostic_if_enabled(ExecBuiltin, func.range()) + } + // MarkSafe ["django", "utils", "safestring" | "html", "mark_safe"] => { if let Some(arguments) = arguments { diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__S102_S102.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__S102_S102.py.snap new file mode 100644 index 00000000000000..6268c014a2b225 --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__S102_S102.py.snap @@ -0,0 +1,33 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +assertion_line: 116 +--- +--- Linter settings --- +-linter.preview = disabled ++linter.preview = enabled + +--- Summary --- +Removed: 0 +Added: 2 + +--- Added --- +S102 Use of `exec` detected + --> S102.py:18:10 + | +17 | # https://github.com/astral-sh/ruff/issues/28011 +18 | list(map(exec, ["hi"])) # Preview: Error + | ^^^^ +19 | foo = exec # Preview: Error + | + + +S102 Use of `exec` detected + --> S102.py:19:7 + | +17 | # https://github.com/astral-sh/ruff/issues/28011 +18 | list(map(exec, ["hi"])) # Preview: Error +19 | foo = exec # Preview: Error + | ^^^^ +20 | +21 | def _(): + | diff --git a/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__exec-builtin_S102.py.snap b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__exec-builtin_S102.py.snap new file mode 100644 index 00000000000000..148342f85f819d --- /dev/null +++ b/crates/ruff_linter/src/rules/flake8_bandit/snapshots/ruff_linter__rules__flake8_bandit__tests__preview__exec-builtin_S102.py.snap @@ -0,0 +1,33 @@ +--- +source: crates/ruff_linter/src/rules/flake8_bandit/mod.rs +assertion_line: 112 +--- +--- Linter settings --- +-linter.preview = disabled ++linter.preview = enabled + +--- Summary --- +Removed: 0 +Added: 2 + +--- Added --- +S102 Use of `exec` detected + --> S102.py:18:10 + | +17 | # https://github.com/astral-sh/ruff/issues/28011 +18 | list(map(exec, ["hi"])) # Preview: Error + | ^^^^ +19 | foo = exec # Preview: Error + | + + +S102 Use of `exec` detected + --> S102.py:19:7 + | +17 | # https://github.com/astral-sh/ruff/issues/28011 +18 | list(map(exec, ["hi"])) # Preview: Error +19 | foo = exec # Preview: Error + | ^^^^ +20 | +21 | def _(): + |