diff --git a/src/registry.rs b/src/registry.rs index 515d5f1ba0..f32d196fd7 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -327,23 +327,23 @@ ruff_macros::define_rule_mapping!( // eradicate ERA001 => rules::eradicate::rules::CommentedOutCode, // flake8-bandit - S101 => violations::AssertUsed, - S102 => violations::ExecUsed, - S103 => violations::BadFilePermissions, - S104 => violations::HardcodedBindAllInterfaces, - S105 => violations::HardcodedPasswordString, - S106 => violations::HardcodedPasswordFuncArg, - S107 => violations::HardcodedPasswordDefault, - S108 => violations::HardcodedTempFile, + S101 => rules::flake8_bandit::rules::AssertUsed, + S102 => rules::flake8_bandit::rules::ExecUsed, + S103 => rules::flake8_bandit::rules::BadFilePermissions, + S104 => rules::flake8_bandit::rules::HardcodedBindAllInterfaces, + S105 => rules::flake8_bandit::rules::HardcodedPasswordString, + S106 => rules::flake8_bandit::rules::HardcodedPasswordFuncArg, + S107 => rules::flake8_bandit::rules::HardcodedPasswordDefault, + S108 => rules::flake8_bandit::rules::HardcodedTempFile, S110 => rules::flake8_bandit::rules::TryExceptPass, - S113 => violations::RequestWithoutTimeout, - S324 => violations::HashlibInsecureHashFunction, - S501 => violations::RequestWithNoCertValidation, - S506 => violations::UnsafeYAMLLoad, - S508 => violations::SnmpInsecureVersion, - S509 => violations::SnmpWeakCryptography, + S113 => rules::flake8_bandit::rules::RequestWithoutTimeout, + S324 => rules::flake8_bandit::rules::HashlibInsecureHashFunction, + S501 => rules::flake8_bandit::rules::RequestWithNoCertValidation, + S506 => rules::flake8_bandit::rules::UnsafeYAMLLoad, + S508 => rules::flake8_bandit::rules::SnmpInsecureVersion, + S509 => rules::flake8_bandit::rules::SnmpWeakCryptography, S612 => rules::flake8_bandit::rules::LoggingConfigInsecureListen, - S701 => violations::Jinja2AutoescapeFalse, + S701 => rules::flake8_bandit::rules::Jinja2AutoescapeFalse, // flake8-boolean-trap FBT001 => rules::flake8_boolean_trap::rules::BooleanPositionalArgInFunctionDefinition, FBT002 => rules::flake8_boolean_trap::rules::BooleanDefaultValueInFunctionDefinition, diff --git a/src/rules/flake8_bandit/rules/assert_used.rs b/src/rules/flake8_bandit/rules/assert_used.rs index 6f2a52bcc7..ac333e026a 100644 --- a/src/rules/flake8_bandit/rules/assert_used.rs +++ b/src/rules/flake8_bandit/rules/assert_used.rs @@ -1,13 +1,25 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Located, StmtKind}; use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct AssertUsed; +); +impl Violation for AssertUsed { + #[derive_message_formats] + fn message(&self) -> String { + format!("Use of `assert` detected") + } +} /// S101 pub fn assert_used(stmt: &Located) -> Diagnostic { Diagnostic::new( - violations::AssertUsed, + AssertUsed, Range::new(stmt.location, stmt.location.with_col_offset("assert".len())), ) } diff --git a/src/rules/flake8_bandit/rules/bad_file_permissions.rs b/src/rules/flake8_bandit/rules/bad_file_permissions.rs index bb4cb9ca81..c37b117323 100644 --- a/src/rules/flake8_bandit/rules/bad_file_permissions.rs +++ b/src/rules/flake8_bandit/rules/bad_file_permissions.rs @@ -1,5 +1,8 @@ +use crate::define_violation; +use crate::violation::Violation; use num_traits::ToPrimitive; use once_cell::sync::Lazy; +use ruff_macros::derive_message_formats; use rustc_hash::FxHashMap; use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Operator}; @@ -7,7 +10,19 @@ use crate::ast::helpers::{compose_call_path, SimpleCallArgs}; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct BadFilePermissions { + pub mask: u16, + } +); +impl Violation for BadFilePermissions { + #[derive_message_formats] + fn message(&self) -> String { + let BadFilePermissions { mask } = self; + format!("`os.chmod` setting a permissive mask `{mask:#o}` on file or directory",) + } +} const WRITE_WORLD: u16 = 0o2; const EXECUTE_GROUP: u16 = 0o10; @@ -101,7 +116,7 @@ pub fn bad_file_permissions( if let Some(int_value) = get_int_value(mode_arg) { if (int_value & WRITE_WORLD > 0) || (int_value & EXECUTE_GROUP > 0) { checker.diagnostics.push(Diagnostic::new( - violations::BadFilePermissions { mask: int_value }, + BadFilePermissions { mask: int_value }, Range::from_located(mode_arg), )); } diff --git a/src/rules/flake8_bandit/rules/exec_used.rs b/src/rules/flake8_bandit/rules/exec_used.rs index f1e3297dac..1b8b8b6bea 100644 --- a/src/rules/flake8_bandit/rules/exec_used.rs +++ b/src/rules/flake8_bandit/rules/exec_used.rs @@ -1,8 +1,20 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, ExprKind}; use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct ExecUsed; +); +impl Violation for ExecUsed { + #[derive_message_formats] + fn message(&self) -> String { + format!("Use of `exec` detected") + } +} /// S102 pub fn exec_used(expr: &Expr, func: &Expr) -> Option { @@ -12,8 +24,5 @@ pub fn exec_used(expr: &Expr, func: &Expr) -> Option { if id != "exec" { return None; } - Some(Diagnostic::new( - violations::ExecUsed, - Range::from_located(expr), - )) + Some(Diagnostic::new(ExecUsed, Range::from_located(expr))) } diff --git a/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs b/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs index 23143af711..cdb79b587d 100644 --- a/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs +++ b/src/rules/flake8_bandit/rules/hardcoded_bind_all_interfaces.rs @@ -1,14 +1,24 @@ use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; +use crate::violation::Violation; + +use crate::define_violation; +use ruff_macros::derive_message_formats; + +define_violation!( + pub struct HardcodedBindAllInterfaces; +); +impl Violation for HardcodedBindAllInterfaces { + #[derive_message_formats] + fn message(&self) -> String { + format!("Possible binding to all interfaces") + } +} /// S104 pub fn hardcoded_bind_all_interfaces(value: &str, range: &Range) -> Option { if value == "0.0.0.0" { - Some(Diagnostic::new( - violations::HardcodedBindAllInterfaces, - *range, - )) + Some(Diagnostic::new(HardcodedBindAllInterfaces, *range)) } else { None } diff --git a/src/rules/flake8_bandit/rules/hardcoded_password_default.rs b/src/rules/flake8_bandit/rules/hardcoded_password_default.rs index 3ac5726ce3..5da4207815 100644 --- a/src/rules/flake8_bandit/rules/hardcoded_password_default.rs +++ b/src/rules/flake8_bandit/rules/hardcoded_password_default.rs @@ -1,9 +1,24 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{ArgData, Arguments, Expr, Located}; use super::super::helpers::{matches_password_name, string_literal}; use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct HardcodedPasswordDefault { + pub string: String, + } +); +impl Violation for HardcodedPasswordDefault { + #[derive_message_formats] + fn message(&self) -> String { + let HardcodedPasswordDefault { string } = self; + format!("Possible hardcoded password: \"{}\"", string.escape_debug()) + } +} fn check_password_kwarg(arg: &Located, default: &Expr) -> Option { let string = string_literal(default).filter(|string| !string.is_empty())?; @@ -12,7 +27,7 @@ fn check_password_kwarg(arg: &Located, default: &Expr) -> Option String { + let HardcodedPasswordFuncArg { string } = self; + format!("Possible hardcoded password: \"{}\"", string.escape_debug()) + } +} /// S106 pub fn hardcoded_password_func_arg(keywords: &[Keyword]) -> Vec { @@ -16,7 +31,7 @@ pub fn hardcoded_password_func_arg(keywords: &[Keyword]) -> Vec { return None; } Some(Diagnostic::new( - violations::HardcodedPasswordFuncArg { + HardcodedPasswordFuncArg { string: string.to_string(), }, Range::from_located(keyword), diff --git a/src/rules/flake8_bandit/rules/hardcoded_password_string.rs b/src/rules/flake8_bandit/rules/hardcoded_password_string.rs index 9bed90e327..eeff9eae90 100644 --- a/src/rules/flake8_bandit/rules/hardcoded_password_string.rs +++ b/src/rules/flake8_bandit/rules/hardcoded_password_string.rs @@ -1,9 +1,24 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Constant, Expr, ExprKind}; use super::super::helpers::{matches_password_name, string_literal}; use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct HardcodedPasswordString { + pub string: String, + } +); +impl Violation for HardcodedPasswordString { + #[derive_message_formats] + fn message(&self) -> String { + let HardcodedPasswordString { string } = self; + format!("Possible hardcoded password: \"{}\"", string.escape_debug()) + } +} fn is_password_target(target: &Expr) -> bool { let target_name = match &target.node { @@ -35,7 +50,7 @@ pub fn compare_to_hardcoded_password_string(left: &Expr, comparators: &[Expr]) - return None; } Some(Diagnostic::new( - violations::HardcodedPasswordString { + HardcodedPasswordString { string: string.to_string(), }, Range::from_located(comp), @@ -50,7 +65,7 @@ pub fn assign_hardcoded_password_string(value: &Expr, targets: &[Expr]) -> Optio for target in targets { if is_password_target(target) { return Some(Diagnostic::new( - violations::HardcodedPasswordString { + HardcodedPasswordString { string: string.to_string(), }, Range::from_located(value), diff --git a/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs b/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs index 012eea591f..bcc59a5e27 100644 --- a/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs +++ b/src/rules/flake8_bandit/rules/hardcoded_tmp_directory.rs @@ -1,8 +1,26 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::Expr; use crate::ast::types::Range; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct HardcodedTempFile { + pub string: String, + } +); +impl Violation for HardcodedTempFile { + #[derive_message_formats] + fn message(&self) -> String { + let HardcodedTempFile { string } = self; + format!( + "Probable insecure usage of temporary file or directory: \"{}\"", + string.escape_debug() + ) + } +} /// S108 pub fn hardcoded_tmp_directory( @@ -12,7 +30,7 @@ pub fn hardcoded_tmp_directory( ) -> Option { if prefixes.iter().any(|prefix| value.starts_with(prefix)) { Some(Diagnostic::new( - violations::HardcodedTempFile { + HardcodedTempFile { string: value.to_string(), }, Range::from_located(expr), diff --git a/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs b/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs index a4da820918..97ed4423ef 100644 --- a/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs +++ b/src/rules/flake8_bandit/rules/hashlib_insecure_hash_functions.rs @@ -1,3 +1,6 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Constant, Expr, ExprKind, Keyword}; use super::super::helpers::string_literal; @@ -5,7 +8,22 @@ use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct HashlibInsecureHashFunction { + pub string: String, + } +); +impl Violation for HashlibInsecureHashFunction { + #[derive_message_formats] + fn message(&self) -> String { + let HashlibInsecureHashFunction { string } = self; + format!( + "Probable use of insecure hash functions in `hashlib`: \"{}\"", + string.escape_debug() + ) + } +} const WEAK_HASHES: [&str; 4] = ["md4", "md5", "sha", "sha1"]; @@ -56,7 +74,7 @@ pub fn hashlib_insecure_hash_functions( if let Some(hash_func_name) = string_literal(name_arg) { if WEAK_HASHES.contains(&hash_func_name.to_lowercase().as_str()) { checker.diagnostics.push(Diagnostic::new( - violations::HashlibInsecureHashFunction { + HashlibInsecureHashFunction { string: hash_func_name.to_string(), }, Range::from_located(name_arg), @@ -73,7 +91,7 @@ pub fn hashlib_insecure_hash_functions( } checker.diagnostics.push(Diagnostic::new( - violations::HashlibInsecureHashFunction { + HashlibInsecureHashFunction { string: (*func_name).to_string(), }, Range::from_located(func), diff --git a/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs b/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs index 3197f93f9e..ee968a6b9d 100644 --- a/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs +++ b/src/rules/flake8_bandit/rules/jinja2_autoescape_false.rs @@ -1,3 +1,6 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::Constant; @@ -5,7 +8,29 @@ use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct Jinja2AutoescapeFalse { + pub value: bool, + } +); +impl Violation for Jinja2AutoescapeFalse { + #[derive_message_formats] + fn message(&self) -> String { + let Jinja2AutoescapeFalse { value } = self; + match value { + true => format!( + "Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. \ + Ensure `autoescape=True` or use the `select_autoescape` function." + ), + false => format!( + "By default, jinja2 sets `autoescape` to `False`. Consider using \ + `autoescape=True` or the `select_autoescape` function to mitigate XSS \ + vulnerabilities." + ), + } + } +} /// S701 pub fn jinja2_autoescape_false( @@ -29,20 +54,20 @@ pub fn jinja2_autoescape_false( if let ExprKind::Name { id, .. } = &func.node { if id.as_str() != "select_autoescape" { checker.diagnostics.push(Diagnostic::new( - violations::Jinja2AutoescapeFalse { value: true }, + Jinja2AutoescapeFalse { value: true }, Range::from_located(autoescape_arg), )); } } } _ => checker.diagnostics.push(Diagnostic::new( - violations::Jinja2AutoescapeFalse { value: true }, + Jinja2AutoescapeFalse { value: true }, Range::from_located(autoescape_arg), )), } } else { checker.diagnostics.push(Diagnostic::new( - violations::Jinja2AutoescapeFalse { value: false }, + Jinja2AutoescapeFalse { value: false }, Range::from_located(func), )); } diff --git a/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs b/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs index e08e508068..85af494117 100644 --- a/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs +++ b/src/rules/flake8_bandit/rules/logging_config_insecure_listen.rs @@ -1,6 +1,7 @@ -use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, Keyword}; +use ruff_macros::derive_message_formats; + use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; diff --git a/src/rules/flake8_bandit/rules/mod.rs b/src/rules/flake8_bandit/rules/mod.rs index 6baa4dd9ab..0255462a16 100644 --- a/src/rules/flake8_bandit/rules/mod.rs +++ b/src/rules/flake8_bandit/rules/mod.rs @@ -1,24 +1,30 @@ -pub use assert_used::assert_used; -pub use bad_file_permissions::bad_file_permissions; -pub use exec_used::exec_used; -pub use hardcoded_bind_all_interfaces::hardcoded_bind_all_interfaces; -pub use hardcoded_password_default::hardcoded_password_default; -pub use hardcoded_password_func_arg::hardcoded_password_func_arg; -pub use hardcoded_password_string::{ - assign_hardcoded_password_string, compare_to_hardcoded_password_string, +pub use assert_used::{assert_used, AssertUsed}; +pub use bad_file_permissions::{bad_file_permissions, BadFilePermissions}; +pub use exec_used::{exec_used, ExecUsed}; +pub use hardcoded_bind_all_interfaces::{ + hardcoded_bind_all_interfaces, HardcodedBindAllInterfaces, }; -pub use hardcoded_tmp_directory::hardcoded_tmp_directory; -pub use hashlib_insecure_hash_functions::hashlib_insecure_hash_functions; -pub use jinja2_autoescape_false::jinja2_autoescape_false; +pub use hardcoded_password_default::{hardcoded_password_default, HardcodedPasswordDefault}; +pub use hardcoded_password_func_arg::{hardcoded_password_func_arg, HardcodedPasswordFuncArg}; +pub use hardcoded_password_string::{ + assign_hardcoded_password_string, compare_to_hardcoded_password_string, HardcodedPasswordString, +}; +pub use hardcoded_tmp_directory::{hardcoded_tmp_directory, HardcodedTempFile}; +pub use hashlib_insecure_hash_functions::{ + hashlib_insecure_hash_functions, HashlibInsecureHashFunction, +}; +pub use jinja2_autoescape_false::{jinja2_autoescape_false, Jinja2AutoescapeFalse}; pub use logging_config_insecure_listen::{ logging_config_insecure_listen, LoggingConfigInsecureListen, }; -pub use request_with_no_cert_validation::request_with_no_cert_validation; -pub use request_without_timeout::request_without_timeout; -pub use snmp_insecure_version::snmp_insecure_version; -pub use snmp_weak_cryptography::snmp_weak_cryptography; +pub use request_with_no_cert_validation::{ + request_with_no_cert_validation, RequestWithNoCertValidation, +}; +pub use request_without_timeout::{request_without_timeout, RequestWithoutTimeout}; +pub use snmp_insecure_version::{snmp_insecure_version, SnmpInsecureVersion}; +pub use snmp_weak_cryptography::{snmp_weak_cryptography, SnmpWeakCryptography}; pub use try_except_pass::{try_except_pass, TryExceptPass}; -pub use unsafe_yaml_load::unsafe_yaml_load; +pub use unsafe_yaml_load::{unsafe_yaml_load, UnsafeYAMLLoad}; mod assert_used; mod bad_file_permissions; diff --git a/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs b/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs index 9d7af7674a..26537bd835 100644 --- a/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs +++ b/src/rules/flake8_bandit/rules/request_with_no_cert_validation.rs @@ -1,3 +1,6 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::Constant; @@ -5,7 +8,21 @@ use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct RequestWithNoCertValidation { + pub string: String, + } +); +impl Violation for RequestWithNoCertValidation { + #[derive_message_formats] + fn message(&self) -> String { + let RequestWithNoCertValidation { string } = self; + format!( + "Probable use of `{string}` call with `verify=False` disabling SSL certificate checks" + ) + } +} const REQUESTS_HTTP_VERBS: [&str; 7] = ["get", "options", "head", "post", "put", "patch", "delete"]; const HTTPX_METHODS: [&str; 11] = [ @@ -48,7 +65,7 @@ pub fn request_with_no_cert_validation( } = &verify_arg.node { checker.diagnostics.push(Diagnostic::new( - violations::RequestWithNoCertValidation { + RequestWithNoCertValidation { string: target.to_string(), }, Range::from_located(verify_arg), diff --git a/src/rules/flake8_bandit/rules/request_without_timeout.rs b/src/rules/flake8_bandit/rules/request_without_timeout.rs index 5e9137c85f..29b918fce3 100644 --- a/src/rules/flake8_bandit/rules/request_without_timeout.rs +++ b/src/rules/flake8_bandit/rules/request_without_timeout.rs @@ -1,3 +1,6 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::Constant; @@ -5,7 +8,24 @@ use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct RequestWithoutTimeout { + pub timeout: Option, + } +); +impl Violation for RequestWithoutTimeout { + #[derive_message_formats] + fn message(&self) -> String { + let RequestWithoutTimeout { timeout } = self; + match timeout { + Some(value) => { + format!("Probable use of requests call with timeout set to `{value}`") + } + None => format!("Probable use of requests call without timeout"), + } + } +} const HTTP_VERBS: [&str; 7] = ["get", "options", "head", "post", "put", "patch", "delete"]; @@ -31,7 +51,7 @@ pub fn request_without_timeout( _ => None, } { checker.diagnostics.push(Diagnostic::new( - violations::RequestWithoutTimeout { + RequestWithoutTimeout { timeout: Some(timeout), }, Range::from_located(timeout_arg), @@ -39,7 +59,7 @@ pub fn request_without_timeout( } } else { checker.diagnostics.push(Diagnostic::new( - violations::RequestWithoutTimeout { timeout: None }, + RequestWithoutTimeout { timeout: None }, Range::from_located(func), )); } diff --git a/src/rules/flake8_bandit/rules/snmp_insecure_version.rs b/src/rules/flake8_bandit/rules/snmp_insecure_version.rs index 014d1256f1..11f5b6f4aa 100644 --- a/src/rules/flake8_bandit/rules/snmp_insecure_version.rs +++ b/src/rules/flake8_bandit/rules/snmp_insecure_version.rs @@ -1,4 +1,7 @@ +use crate::define_violation; +use crate::violation::Violation; use num_traits::{One, Zero}; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, ExprKind, Keyword}; use rustpython_parser::ast::Constant; @@ -6,7 +9,16 @@ use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct SnmpInsecureVersion; +); +impl Violation for SnmpInsecureVersion { + #[derive_message_formats] + fn message(&self) -> String { + format!("The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able.") + } +} /// S508 pub fn snmp_insecure_version( @@ -27,7 +39,7 @@ pub fn snmp_insecure_version( { if value.is_zero() || value.is_one() { checker.diagnostics.push(Diagnostic::new( - violations::SnmpInsecureVersion, + SnmpInsecureVersion, Range::from_located(mp_model_arg), )); } diff --git a/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs b/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs index 90c8f7f21d..4181a5f655 100644 --- a/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs +++ b/src/rules/flake8_bandit/rules/snmp_weak_cryptography.rs @@ -1,10 +1,25 @@ +use crate::define_violation; +use crate::violation::Violation; +use ruff_macros::derive_message_formats; use rustpython_ast::{Expr, Keyword}; use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; use crate::registry::Diagnostic; -use crate::violations; + +define_violation!( + pub struct SnmpWeakCryptography; +); +impl Violation for SnmpWeakCryptography { + #[derive_message_formats] + fn message(&self) -> String { + format!( + "You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is \ + insecure." + ) + } +} /// S509 pub fn snmp_weak_cryptography( @@ -19,7 +34,7 @@ pub fn snmp_weak_cryptography( let call_args = SimpleCallArgs::new(args, keywords); if call_args.len() < 3 { checker.diagnostics.push(Diagnostic::new( - violations::SnmpWeakCryptography, + SnmpWeakCryptography, Range::from_located(func), )); } diff --git a/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs b/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs index 293cdf780f..0731aa6168 100644 --- a/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs +++ b/src/rules/flake8_bandit/rules/unsafe_yaml_load.rs @@ -1,10 +1,37 @@ use rustpython_ast::{Expr, ExprKind, Keyword}; +use ruff_macros::derive_message_formats; + use crate::ast::helpers::SimpleCallArgs; use crate::ast::types::Range; use crate::checkers::ast::Checker; +use crate::define_violation; use crate::registry::Diagnostic; -use crate::violations; +use crate::violation::Violation; + +define_violation!( + pub struct UnsafeYAMLLoad { + pub loader: Option, + } +); +impl Violation for UnsafeYAMLLoad { + #[derive_message_formats] + fn message(&self) -> String { + let UnsafeYAMLLoad { loader } = self; + match loader { + Some(name) => { + format!( + "Probable use of unsafe loader `{name}` with `yaml.load`. Allows \ + instantiation of arbitrary objects. Consider `yaml.safe_load`." + ) + } + None => format!( + "Probable use of unsafe `yaml.load`. Allows instantiation of arbitrary objects. \ + Consider `yaml.safe_load`." + ), + } + } +} /// S506 pub fn unsafe_yaml_load(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) { @@ -27,13 +54,13 @@ pub fn unsafe_yaml_load(checker: &mut Checker, func: &Expr, args: &[Expr], keywo _ => None, }; checker.diagnostics.push(Diagnostic::new( - violations::UnsafeYAMLLoad { loader }, + UnsafeYAMLLoad { loader }, Range::from_located(loader_arg), )); } } else { checker.diagnostics.push(Diagnostic::new( - violations::UnsafeYAMLLoad { loader: None }, + UnsafeYAMLLoad { loader: None }, Range::from_located(func), )); } diff --git a/src/violations.rs b/src/violations.rs index c7d90dd61c..981e9ed97f 100644 --- a/src/violations.rs +++ b/src/violations.rs @@ -1054,225 +1054,6 @@ impl Violation for ErrorSuffixOnExceptionName { } } -// flake8-bandit - -define_violation!( - pub struct Jinja2AutoescapeFalse { - pub value: bool, - } -); -impl Violation for Jinja2AutoescapeFalse { - #[derive_message_formats] - fn message(&self) -> String { - let Jinja2AutoescapeFalse { value } = self; - match value { - true => format!( - "Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. \ - Ensure `autoescape=True` or use the `select_autoescape` function." - ), - false => format!( - "By default, jinja2 sets `autoescape` to `False`. Consider using \ - `autoescape=True` or the `select_autoescape` function to mitigate XSS \ - vulnerabilities." - ), - } - } -} - -define_violation!( - pub struct AssertUsed; -); -impl Violation for AssertUsed { - #[derive_message_formats] - fn message(&self) -> String { - format!("Use of `assert` detected") - } -} - -define_violation!( - pub struct ExecUsed; -); -impl Violation for ExecUsed { - #[derive_message_formats] - fn message(&self) -> String { - format!("Use of `exec` detected") - } -} - -define_violation!( - pub struct BadFilePermissions { - pub mask: u16, - } -); -impl Violation for BadFilePermissions { - #[derive_message_formats] - fn message(&self) -> String { - let BadFilePermissions { mask } = self; - format!("`os.chmod` setting a permissive mask `{mask:#o}` on file or directory",) - } -} - -define_violation!( - pub struct HardcodedBindAllInterfaces; -); -impl Violation for HardcodedBindAllInterfaces { - #[derive_message_formats] - fn message(&self) -> String { - format!("Possible binding to all interfaces") - } -} - -define_violation!( - pub struct HardcodedPasswordString { - pub string: String, - } -); -impl Violation for HardcodedPasswordString { - #[derive_message_formats] - fn message(&self) -> String { - let HardcodedPasswordString { string } = self; - format!("Possible hardcoded password: \"{}\"", string.escape_debug()) - } -} - -define_violation!( - pub struct HardcodedPasswordFuncArg { - pub string: String, - } -); -impl Violation for HardcodedPasswordFuncArg { - #[derive_message_formats] - fn message(&self) -> String { - let HardcodedPasswordFuncArg { string } = self; - format!("Possible hardcoded password: \"{}\"", string.escape_debug()) - } -} - -define_violation!( - pub struct HardcodedPasswordDefault { - pub string: String, - } -); -impl Violation for HardcodedPasswordDefault { - #[derive_message_formats] - fn message(&self) -> String { - let HardcodedPasswordDefault { string } = self; - format!("Possible hardcoded password: \"{}\"", string.escape_debug()) - } -} - -define_violation!( - pub struct HardcodedTempFile { - pub string: String, - } -); -impl Violation for HardcodedTempFile { - #[derive_message_formats] - fn message(&self) -> String { - let HardcodedTempFile { string } = self; - format!( - "Probable insecure usage of temporary file or directory: \"{}\"", - string.escape_debug() - ) - } -} - -define_violation!( - pub struct RequestWithoutTimeout { - pub timeout: Option, - } -); -impl Violation for RequestWithoutTimeout { - #[derive_message_formats] - fn message(&self) -> String { - let RequestWithoutTimeout { timeout } = self; - match timeout { - Some(value) => { - format!("Probable use of requests call with timeout set to `{value}`") - } - None => format!("Probable use of requests call without timeout"), - } - } -} - -define_violation!( - pub struct HashlibInsecureHashFunction { - pub string: String, - } -); -impl Violation for HashlibInsecureHashFunction { - #[derive_message_formats] - fn message(&self) -> String { - let HashlibInsecureHashFunction { string } = self; - format!( - "Probable use of insecure hash functions in `hashlib`: \"{}\"", - string.escape_debug() - ) - } -} - -define_violation!( - pub struct RequestWithNoCertValidation { - pub string: String, - } -); -impl Violation for RequestWithNoCertValidation { - #[derive_message_formats] - fn message(&self) -> String { - let RequestWithNoCertValidation { string } = self; - format!( - "Probable use of `{string}` call with `verify=False` disabling SSL certificate checks" - ) - } -} - -define_violation!( - pub struct UnsafeYAMLLoad { - pub loader: Option, - } -); -impl Violation for UnsafeYAMLLoad { - #[derive_message_formats] - fn message(&self) -> String { - let UnsafeYAMLLoad { loader } = self; - match loader { - Some(name) => { - format!( - "Probable use of unsafe loader `{name}` with `yaml.load`. Allows \ - instantiation of arbitrary objects. Consider `yaml.safe_load`." - ) - } - None => format!( - "Probable use of unsafe `yaml.load`. Allows instantiation of arbitrary objects. \ - Consider `yaml.safe_load`." - ), - } - } -} - -define_violation!( - pub struct SnmpInsecureVersion; -); -impl Violation for SnmpInsecureVersion { - #[derive_message_formats] - fn message(&self) -> String { - format!("The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able.") - } -} - -define_violation!( - pub struct SnmpWeakCryptography; -); -impl Violation for SnmpWeakCryptography { - #[derive_message_formats] - fn message(&self) -> String { - format!( - "You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is \ - insecure." - ) - } -} - // flake8-unused-arguments define_violation!(