fix: Resolve unused import and variable warnings

This commit is contained in:
Rodrigo Rodriguez 2026-02-19 11:48:17 +00:00
parent 3b21ab5ef9
commit d7211a6c19
9 changed files with 90 additions and 64 deletions

View file

@ -75,13 +75,13 @@ pub fn convert_mail_line_with_substitution(line: &str) -> String {
pub fn convert_mail_block(recipient: &str, lines: &[String]) -> String { pub fn convert_mail_block(recipient: &str, lines: &[String]) -> String {
let mut subject = String::new(); let mut subject = String::new();
let mut body_lines: Vec<String> = Vec::new(); let mut body_lines: Vec<String> = Vec::new();
let mut in_subject = true; // let mut in_subject = true; // Removed unused variable
let mut skip_blank = true; let mut skip_blank = true;
for line in lines.iter() { for line in lines.iter() {
if line.to_uppercase().starts_with("SUBJECT:") { if line.to_uppercase().starts_with("SUBJECT:") {
subject = line[8..].trim().to_string(); subject = line[8..].trim().to_string();
in_subject = false; // in_subject = false; // Removed unused assignment
skip_blank = true; skip_blank = true;
continue; continue;
} }

View file

@ -4,8 +4,8 @@ use crate::basic::keywords::table_definition::process_table_definitions;
use crate::basic::keywords::webhook::execute_webhook_registration; use crate::basic::keywords::webhook::execute_webhook_registration;
use crate::core::shared::models::TriggerKind; use crate::core::shared::models::TriggerKind;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use diesel::{QueryableByName, sql_query}; use diesel::QueryableByName;
use diesel::sql_types::Text; // use diesel::sql_types::Text; // Removed unused import
use diesel::ExpressionMethods; use diesel::ExpressionMethods;
use diesel::QueryDsl; use diesel::QueryDsl;
use diesel::RunQueryDsl; use diesel::RunQueryDsl;
@ -771,7 +771,7 @@ impl BasicCompiler {
table_name: &str, table_name: &str,
bot_id: uuid::Uuid, bot_id: uuid::Uuid,
) -> Result<Vec<String>, Box<dyn Error + Send + Sync>> { ) -> Result<Vec<String>, Box<dyn Error + Send + Sync>> {
use std::path::Path; // use std::path::Path;
// Find the tables.bas file in the bot's data directory // Find the tables.bas file in the bot's data directory
let bot_name = self.get_bot_name_by_id(bot_id)?; let bot_name = self.get_bot_name_by_id(bot_id)?;

View file

@ -6,7 +6,8 @@ use crate::core::shared::sanitize_identifier;
use crate::core::urls::ApiUrls; use crate::core::urls::ApiUrls;
use crate::security::error_sanitizer::log_and_sanitize; use crate::security::error_sanitizer::log_and_sanitize;
use crate::security::sql_guard::{ use crate::security::sql_guard::{
build_safe_count_query, build_safe_select_query, is_table_allowed_with_conn, validate_table_name, build_safe_count_query, build_safe_select_by_id_query, build_safe_select_query,
is_table_allowed_with_conn, validate_table_name,
}; };
use axum::{ use axum::{
extract::{Path, Query, State}, extract::{Path, Query, State},
@ -257,10 +258,21 @@ pub async fn get_record_handler(
} }
}; };
let query = format!( let query = match build_safe_select_by_id_query(&table_name) {
"SELECT row_to_json(t.*) as data FROM {} t WHERE id = $1", Ok(q) => q,
table_name Err(e) => {
); warn!("Failed to build safe query for {}: {}", table_name, e);
return (
StatusCode::BAD_REQUEST,
Json(RecordResponse {
success: false,
data: None,
message: Some("Invalid table name".to_string()),
}),
)
.into_response();
}
};
let row: Result<Option<JsonRow>, _> = sql_query(&query) let row: Result<Option<JsonRow>, _> = sql_query(&query)
.bind::<diesel::sql_types::Uuid, _>(record_id) .bind::<diesel::sql_types::Uuid, _>(record_id)
@ -700,7 +712,17 @@ pub async fn count_records_handler(
return (StatusCode::FORBIDDEN, Json(json!({ "error": e }))).into_response(); return (StatusCode::FORBIDDEN, Json(json!({ "error": e }))).into_response();
} }
let query = format!("SELECT COUNT(*) as count FROM {}", table_name); let query = match build_safe_count_query(&table_name) {
Ok(q) => q,
Err(e) => {
warn!("Failed to build count query: {}", e);
return (
StatusCode::BAD_REQUEST,
Json(json!({ "error": "Invalid table name" })),
)
.into_response();
}
};
let result: Result<CountResult, _> = sql_query(&query).get_result(&mut conn); let result: Result<CountResult, _> = sql_query(&query).get_result(&mut conn);
match result { match result {
@ -747,14 +769,18 @@ pub async fn search_records_handler(
} }
}; };
let safe_search = search_term.replace('%', "\\%").replace('_', "\\_");
let query = format!( let query = format!(
"SELECT row_to_json(t.*) as data FROM {} t WHERE "SELECT row_to_json(t.*) as data FROM {} t WHERE
COALESCE(t.title::text, '') || ' ' || COALESCE(t.name::text, '') || ' ' || COALESCE(t.description::text, '') COALESCE(t.title::text, '') || ' ' || COALESCE(t.name::text, '') || ' ' || COALESCE(t.description::text, '')
ILIKE '%{}%' LIMIT {}", ILIKE '%' || $1 || '%' LIMIT {}",
table_name, search_term, limit table_name, limit
); );
let rows: Result<Vec<JsonRow>, _> = sql_query(&query).get_results(&mut conn); let rows: Result<Vec<JsonRow>, _> = sql_query(&query)
.bind::<diesel::sql_types::Text, _>(&safe_search)
.get_results(&mut conn);
match rows { match rows {
Ok(data) => { Ok(data) => {

View file

@ -7,7 +7,7 @@ use crate::core::shared::sanitize_identifier;
use crate::core::shared::state::AppState; use crate::core::shared::state::AppState;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::sql_query; use diesel::sql_query;
use diesel::sql_types::{Text, Nullable}; use diesel::sql_types::Text;
use log::{error, info, warn}; use log::{error, info, warn};
use std::error::Error; use std::error::Error;
use std::sync::Arc; use std::sync::Arc;

View file

@ -912,14 +912,14 @@ impl ScriptService {
fn convert_mail_block(recipient: &str, lines: &[String]) -> String { fn convert_mail_block(recipient: &str, lines: &[String]) -> String {
let mut subject = String::new(); let mut subject = String::new();
let mut body_lines: Vec<String> = Vec::new(); let mut body_lines: Vec<String> = Vec::new();
let mut in_subject = true; // let mut in_subject = true; // Removed unused variable
let mut skip_blank = true; let mut skip_blank = true;
for (i, line) in lines.iter().enumerate() { for line in lines.iter() {
// Check if this line is a subject line // Check if this line is a subject line
if line.to_uppercase().starts_with("SUBJECT:") { if line.to_uppercase().starts_with("SUBJECT:") {
subject = line[8..].trim().to_string(); subject = line[8..].trim().to_string();
in_subject = false; // in_subject = false; // Removed unused assignment
skip_blank = true; skip_blank = true;
continue; continue;
} }
@ -1203,7 +1203,7 @@ impl ScriptService {
// Split into multiple TALK statements to avoid expression complexity limit // Split into multiple TALK statements to avoid expression complexity limit
// Use chunks of 5 lines per TALK statement // Use chunks of 5 lines per TALK statement
let chunk_size = 5; let chunk_size = 5;
for (chunk_idx, chunk) in talk_block_lines.chunks(chunk_size).enumerate() { for chunk in talk_block_lines.chunks(chunk_size) {
// Convert all talk lines in this chunk to a single TALK statement // Convert all talk lines in this chunk to a single TALK statement
let mut combined_talk = String::new(); let mut combined_talk = String::new();
for (i, talk_line) in chunk.iter().enumerate() { for (i, talk_line) in chunk.iter().enumerate() {
@ -1415,7 +1415,7 @@ impl ScriptService {
/// to avoid creating local variables that shadow outer scope variables. /// to avoid creating local variables that shadow outer scope variables.
pub fn convert_select_case_syntax(script: &str) -> String { pub fn convert_select_case_syntax(script: &str) -> String {
let mut result = String::new(); let mut result = String::new();
let mut lines: Vec<&str> = script.lines().collect(); let lines: Vec<&str> = script.lines().collect();
let mut i = 0; let mut i = 0;
log::info!("[TOOL] Converting SELECT/CASE syntax to if-else chains"); log::info!("[TOOL] Converting SELECT/CASE syntax to if-else chains");
@ -1479,7 +1479,7 @@ impl ScriptService {
// Close the last case arm (no else if, so we need the closing brace) // Close the last case arm (no else if, so we need the closing brace)
result.push_str(" }\n"); result.push_str(" }\n");
current_case_body.clear(); current_case_body.clear();
in_case = false; //in_case = false; // Removed unused assignment
} }
// No extra closing brace needed - the last } else if ... { already closed the chain // No extra closing brace needed - the last } else if ... { already closed the chain
i += 1; i += 1;
@ -1502,7 +1502,7 @@ impl ScriptService {
// Close the current case arm (no else if, so we need the closing brace) // Close the current case arm (no else if, so we need the closing brace)
result.push_str(" }\n"); result.push_str(" }\n");
current_case_body.clear(); current_case_body.clear();
in_case = false; //in_case = false; // Removed unused assignment
} }
// No extra closing brace needed // No extra closing brace needed
break; break;

View file

@ -2,7 +2,7 @@
/// Works across all LLM providers (GLM, OpenAI, Claude, etc.) /// Works across all LLM providers (GLM, OpenAI, Claude, etc.)
use log::{error, info, warn}; use log::{error, info, warn};
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap; // use std::collections::HashMap;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;

View file

@ -74,6 +74,8 @@ static ALLOWED_COMMANDS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
"systemctl", "systemctl",
"sudo", "sudo",
"visudo", "visudo",
"id",
"netsh",
]) ])
}); });

View file

@ -1,7 +1,6 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::process::Command;
use tracing::{error, info, warn}; use tracing::{error, info, warn};
use crate::security::command_guard::SafeCommand; use crate::security::command_guard::SafeCommand;
@ -84,12 +83,12 @@ impl ProtectionInstaller {
#[cfg(windows)] #[cfg(windows)]
pub fn check_admin() -> bool { pub fn check_admin() -> bool {
let result = Command::new("powershell") let result = SafeCommand::new("powershell")
.args([ .and_then(|cmd| cmd.args(&[
"-Command", "-Command",
"([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)" "([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"
]) ]))
.output(); .and_then(|cmd| cmd.execute());
match result { match result {
Ok(output) => { Ok(output) => {
@ -102,9 +101,9 @@ impl ProtectionInstaller {
#[cfg(not(windows))] #[cfg(not(windows))]
pub fn check_root() -> bool { pub fn check_root() -> bool {
Command::new("id") SafeCommand::new("id")
.arg("-u") .and_then(|cmd| cmd.arg("-u"))
.output() .and_then(|cmd| cmd.execute())
.map(|o| String::from_utf8_lossy(&o.stdout).trim() == "0") .map(|o| String::from_utf8_lossy(&o.stdout).trim() == "0")
.unwrap_or(false) .unwrap_or(false)
} }
@ -268,26 +267,23 @@ impl ProtectionInstaller {
fn configure_windows_security(&self) -> Result<()> { fn configure_windows_security(&self) -> Result<()> {
info!("Configuring Windows security settings..."); info!("Configuring Windows security settings...");
// Enable Windows Defender real-time protection let _ = SafeCommand::new("powershell")
let _ = Command::new("powershell") .and_then(|cmd| cmd.args(&[
.args([
"-Command", "-Command",
"Set-MpPreference -DisableRealtimeMonitoring $false; Set-MpPreference -DisableIOAVProtection $false; Set-MpPreference -DisableScriptScanning $false" "Set-MpPreference -DisableRealtimeMonitoring $false; Set-MpPreference -DisableIOAVProtection $false; Set-MpPreference -DisableScriptScanning $false"
]) ]))
.output(); .and_then(|cmd| cmd.execute());
// Enable Windows Firewall let _ = SafeCommand::new("netsh")
let _ = Command::new("netsh") .and_then(|cmd| cmd.args(&["advfirewall", "set", "allprofiles", "state", "on"]))
.args(["advfirewall", "set", "allprofiles", "state", "on"]) .and_then(|cmd| cmd.execute());
.output();
// Enable Windows Defender scanning for mapped drives let _ = SafeCommand::new("powershell")
let _ = Command::new("powershell") .and_then(|cmd| cmd.args(&[
.args([
"-Command", "-Command",
"Set-MpPreference -DisableRemovableDriveScanning $false -DisableScanningMappedNetworkDrivesForFullScan $false" "Set-MpPreference -DisableRemovableDriveScanning $false -DisableScanningMappedNetworkDrivesForFullScan $false"
]) ]))
.output(); .and_then(|cmd| cmd.execute());
info!("Windows security configuration completed"); info!("Windows security configuration completed");
Ok(()) Ok(())
@ -313,12 +309,11 @@ impl ProtectionInstaller {
Ok(()) Ok(())
} }
#[cfg(not(windows))]
#[cfg(not(windows))] #[cfg(not(windows))]
fn validate_sudoers(&self) -> Result<()> { fn validate_sudoers(&self) -> Result<()> {
let output = std::process::Command::new("visudo") let output = SafeCommand::new("visudo")
.args(["-c", "-f", SUDOERS_FILE]) .and_then(|cmd| cmd.args(&["-c", "-f", SUDOERS_FILE]))
.output() .and_then(|cmd| cmd.execute())
.context("Failed to run visudo validation")?; .context("Failed to run visudo validation")?;
if !output.status.success() { if !output.status.success() {
@ -330,7 +325,6 @@ impl ProtectionInstaller {
Ok(()) Ok(())
} }
#[cfg(not(windows))]
#[cfg(not(windows))] #[cfg(not(windows))]
fn install_lmd(&self) -> Result<bool> { fn install_lmd(&self) -> Result<bool> {
let maldet_path = Path::new("/usr/local/sbin/maldet"); let maldet_path = Path::new("/usr/local/sbin/maldet");
@ -398,7 +392,6 @@ impl ProtectionInstaller {
Ok(true) Ok(true)
} }
#[cfg(not(windows))]
#[cfg(not(windows))] #[cfg(not(windows))]
fn update_databases(&self) -> Result<()> { fn update_databases(&self) -> Result<()> {
info!("Updating security tool databases..."); info!("Updating security tool databases...");
@ -442,12 +435,12 @@ impl ProtectionInstaller {
fn update_windows_signatures(&self) -> Result<()> { fn update_windows_signatures(&self) -> Result<()> {
info!("Updating Windows Defender signatures..."); info!("Updating Windows Defender signatures...");
let result = Command::new("powershell") let result = SafeCommand::new("powershell")
.args([ .and_then(|cmd| cmd.args(&[
"-Command", "-Command",
"Update-MpSignature; Write-Host 'Windows Defender signatures updated'", "Update-MpSignature; Write-Host 'Windows Defender signatures updated'",
]) ]))
.output(); .and_then(|cmd| cmd.execute());
match result { match result {
Ok(output) => { Ok(output) => {
@ -571,13 +564,9 @@ impl ProtectionInstaller {
#[cfg(windows)] #[cfg(windows)]
{ {
for (tool_name, tool_cmd) in WINDOWS_TOOLS { for (tool_name, tool_cmd) in WINDOWS_TOOLS {
let check = Command::new(tool_cmd) let check = SafeCommand::new(tool_cmd)
.arg("--version") .and_then(|cmd| cmd.arg("--version"))
.or_else(|_| { .and_then(|cmd| cmd.execute());
Command::new("powershell")
.args(["-Command", &format!("Get-Command {}", tool_cmd)])
})
.output();
let installed = check.map(|o| o.status.success()).unwrap_or(false); let installed = check.map(|o| o.status.success()).unwrap_or(false);
result.tools.push(ToolVerification { result.tools.push(ToolVerification {

View file

@ -68,11 +68,20 @@ pub struct CombinedRateLimiter {
impl CombinedRateLimiter { impl CombinedRateLimiter {
pub fn new(http_config: HttpRateLimitConfig, system_limits: SystemLimits) -> Self { pub fn new(http_config: HttpRateLimitConfig, system_limits: SystemLimits) -> Self {
const DEFAULT_RPS: NonZeroU32 = match NonZeroU32::new(100) {
Some(v) => v,
None => unreachable!(),
};
const DEFAULT_BURST: NonZeroU32 = match NonZeroU32::new(200) {
Some(v) => v,
None => unreachable!(),
};
let quota = Quota::per_second( let quota = Quota::per_second(
NonZeroU32::new(http_config.requests_per_second).unwrap_or(NonZeroU32::new(100).expect("100 is non-zero")), NonZeroU32::new(http_config.requests_per_second).unwrap_or(DEFAULT_RPS),
) )
.allow_burst( .allow_burst(
NonZeroU32::new(http_config.burst_size).unwrap_or(NonZeroU32::new(200).expect("200 is non-zero")), NonZeroU32::new(http_config.burst_size).unwrap_or(DEFAULT_BURST),
); );
Self { Self {