9deca7f346
PARAMETER VALIDATION FIXES (6 functions):
1. lib/common-functions.sh:219 - format_duration()
2. lib/php-detector.sh:277 - get_fpm_process_count()
3. lib/user-manager.sh:263 - get_plesk_user_domains()
4. modules/performance/hardware-health-check.sh:44 - add_finding()
5. modules/performance/hardware-health-check.sh:55 - command_exists()
6. modules/performance/network-bandwidth-analyzer.sh:45 - add_finding()
7. modules/performance/network-bandwidth-analyzer.sh:56 - command_exists()
All functions now validate required parameters with:
- [ -z "$1" ] && return 1 (single param)
- [ -z "$1" ] || [ -z "$2" ] && return 1 (multiple params)
QA SCRIPT IMPROVEMENTS:
- tools/toolkit-qa-check.sh: Skip $@ / $* passthrough functions
- Added filter for echo/printf functions using only $@ or $*
- Example: cecho() { echo -e "$@" }
- These don't need validation as they passthrough all args
PROGRESS:
- HIGH issues remain at 10 (different ones now)
- Eliminated more false positives
- Next: Fix remaining issues in bot-analyzer.sh
1063 lines
41 KiB
Bash
Executable File
1063 lines
41 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Server Toolkit QA Checker - Optimized for AI Assistant Development
|
|
# Designed to help Claude track bugs during development with minimal computation
|
|
#
|
|
# Features:
|
|
# - Structured output (easy to parse)
|
|
# - Fixed subshell counter bug
|
|
# - Groups by severity
|
|
# - Concise summaries
|
|
# - Quick file:line references
|
|
#
|
|
|
|
TOOLKIT_PATH="${1:-/root/server-toolkit}"
|
|
|
|
if [ ! -d "$TOOLKIT_PATH" ]; then
|
|
echo "ERROR: $TOOLKIT_PATH not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Output file for easy review
|
|
REPORT="/tmp/qa-report.txt"
|
|
> "$REPORT"
|
|
|
|
# Counters (will use temp file to avoid subshell issues)
|
|
TEMP_COUNTS="/tmp/qa-counts.$$"
|
|
echo "0 0 0 0" > "$TEMP_COUNTS"
|
|
|
|
# Helper to increment counters (avoids subshell issue)
|
|
count_issue() {
|
|
local severity="$1"
|
|
read crit high med low < "$TEMP_COUNTS"
|
|
case "$severity" in
|
|
CRITICAL) ((crit++)) ;;
|
|
HIGH) ((high++)) ;;
|
|
MEDIUM) ((med++)) ;;
|
|
LOW) ((low++)) ;;
|
|
esac
|
|
echo "$crit $high $med $low" > "$TEMP_COUNTS"
|
|
}
|
|
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "SERVER TOOLKIT QA SCAN"
|
|
echo "Path: $TOOLKIT_PATH"
|
|
echo "Date: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# Create structured output file
|
|
{
|
|
echo "QA SCAN REPORT"
|
|
echo "=============="
|
|
echo "Timestamp: $(date)"
|
|
echo "Path: $TOOLKIT_PATH"
|
|
echo ""
|
|
} > "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 1: grep -F with regex anchors (CRITICAL - causes wrong results)
|
|
#==============================================================================
|
|
echo "[1/30] Checking: grep -F with regex anchors..."
|
|
{
|
|
echo "## CHECK 1: grep -F with regex anchors"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: -F disables regex, \$ and ^ match literally"
|
|
echo ""
|
|
|
|
# Use process substitution to avoid subshell
|
|
while IFS=: read -r file line_num line_content; do
|
|
if echo "$line_content" | grep -qE '"\$|".*\^|\\\$'; then
|
|
echo "CRITICAL|$file|$line_num|grep -F with regex anchor"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
done < <(grep -rn 'grep -F' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 2: SCRIPT_DIR collisions (HIGH - causes path errors)
|
|
#==============================================================================
|
|
echo "[2/30] Checking: SCRIPT_DIR variable collisions..."
|
|
{
|
|
echo "## CHECK 2: SCRIPT_DIR variable collisions"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Multiple files redefining same path variable"
|
|
echo ""
|
|
|
|
script_dir_count=$(grep -l "^SCRIPT_DIR=" "$TOOLKIT_PATH"/**/*.sh 2>/dev/null | wc -l)
|
|
if [ "$script_dir_count" -gt 1 ]; then
|
|
files=$(grep -l "^SCRIPT_DIR=" "$TOOLKIT_PATH"/**/*.sh 2>/dev/null | tr '\n' ' ')
|
|
echo "HIGH|Multiple files|N/A|SCRIPT_DIR in $script_dir_count files: $files"
|
|
count_issue "HIGH"
|
|
fi
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 3: SYS_* variable resets (CRITICAL - breaks system detection)
|
|
#==============================================================================
|
|
echo "[3/30] Checking: SYS_* variable resets..."
|
|
{
|
|
echo "## CHECK 3: SYS_* variable resets without protection"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: Re-sourcing wipes all system detection variables"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
if grep -q '^[[:space:]]*export SYS_.*=""' "$file" && ! grep -q "SYS_DETECTION_COMPLETE" "$file"; then
|
|
line_num=$(grep -n '^[[:space:]]*export SYS_.*=""' "$file" | head -1 | cut -d: -f1)
|
|
echo "CRITICAL|$file|$line_num|SYS reset without guard"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH/lib" -name "*.sh" 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 4: Missing function exports (HIGH - functions unavailable)
|
|
#==============================================================================
|
|
echo "[4/30] Checking: Missing function exports..."
|
|
{
|
|
echo "## CHECK 4: Missing function exports in libraries"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Functions not exported = unavailable in nested calls"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
func_count=$(grep -cE "^[a-zA-Z_][a-zA-Z0-9_]*\(\)" "$file" 2>/dev/null || echo "0")
|
|
func_count=${func_count//[$'\n\r']/} # Remove newlines
|
|
export_count=$(grep -c "export -f" "$file" 2>/dev/null || echo "0")
|
|
export_count=${export_count//[$'\n\r']/} # Remove newlines
|
|
|
|
if [ -n "$func_count" ] && [ -n "$export_count" ] && [ "$func_count" -gt 0 ] && [ "$export_count" -eq 0 ]; then
|
|
echo "HIGH|$file|N/A|$func_count functions, 0 exports"
|
|
count_issue "HIGH"
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH/lib" -name "*.sh" 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 5: Integer comparisons without empty checks (HIGH - causes errors)
|
|
#==============================================================================
|
|
echo "[5/30] Checking: Unsafe integer comparisons (top 10)..."
|
|
{
|
|
echo "## CHECK 5: Integer comparisons without empty checks"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Empty vars cause 'integer expression expected' errors"
|
|
echo "Note: Showing first 10 instances"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
var=$(echo "$line_content" | grep -oE '\$[a-zA-Z_][a-zA-Z0-9_]*' | head -1)
|
|
echo "HIGH|$file|$line_num|Integer comparison: $var"
|
|
count_issue "HIGH"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
done < <(grep -rn '\[ \$[a-zA-Z_][a-zA-Z0-9_]* -\(lt\|gt\|le\|ge\|eq\|ne\) [0-9]' "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null)
|
|
|
|
total=$(grep -r '\[ \$[a-zA-Z_][a-zA-Z0-9_]* -\(lt\|gt\|le\|ge\|eq\|ne\) [0-9]' "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null | wc -l)
|
|
echo "Total found: $total (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 6: Missing common-functions.sh (HIGH - command not found)
|
|
#==============================================================================
|
|
echo "[6/30] Checking: Missing common-functions.sh..."
|
|
{
|
|
echo "## CHECK 6: Missing common-functions.sh sourcing"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Uses functions without sourcing = command not found"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
if ! grep -q "source.*common-functions.sh" "$file"; then
|
|
echo "HIGH|$file|N/A|Uses common functions without sourcing"
|
|
count_issue "HIGH"
|
|
fi
|
|
done < <(grep -l 'cecho\|print_info\|print_warning\|print_error' "$TOOLKIT_PATH"/modules/**/*.sh 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 7: exit in libraries (HIGH - terminates parent script)
|
|
#==============================================================================
|
|
echo "[7/30] Checking: exit in library files..."
|
|
{
|
|
echo "## CHECK 7: exit in sourced libraries"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Should use 'return' not 'exit'"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
while IFS=: read -r line_num line_content; do
|
|
# Skip comments
|
|
if ! echo "$line_content" | grep -q "^[[:space:]]*#"; then
|
|
if echo "$line_content" | grep -qE '(^|[[:space:]])exit[[:space:]]'; then
|
|
echo "HIGH|$file|$line_num|Library uses exit"
|
|
count_issue "HIGH"
|
|
fi
|
|
fi
|
|
done < <(grep -n '\<exit\>' "$file" 2>/dev/null | grep -v "^[[:space:]]*#" | head -5)
|
|
done < <(find "$TOOLKIT_PATH/lib" -name "*.sh" 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 8: bc command usage (LOW - external dependency)
|
|
#==============================================================================
|
|
echo "[8/30] Checking: bc command usage..."
|
|
{
|
|
echo "## CHECK 8: bc command usage"
|
|
echo "Severity: LOW"
|
|
echo "Issue: Requires bc package - not installed on all systems"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Skip comments
|
|
if ! echo "$line_content" | grep -q "^[[:space:]]*#"; then
|
|
echo "LOW|$file|$line_num|Uses bc command"
|
|
count_issue "LOW"
|
|
fi
|
|
done < <(grep -rn ' bc\b' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
total_bc=$(grep -r ' bc\b' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | wc -l)
|
|
echo "Total found: $total_bc (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 9: Hardcoded /var/cpanel paths (MEDIUM - breaks multi-panel)
|
|
#==============================================================================
|
|
echo "[9/30] Checking: Hardcoded /var/cpanel paths..."
|
|
{
|
|
echo "## CHECK 9: Hardcoded /var/cpanel paths"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Hardcoded paths break on non-cPanel systems"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Skip if using $SYS variables OR if it's a fallback value in ${VAR:-/var/cpanel}
|
|
if ! echo "$line_content" | grep -qE '(\$SYS|:-/var/cpanel)'; then
|
|
# Skip comments
|
|
if ! echo "$line_content" | grep -q "^[[:space:]]*#"; then
|
|
echo "MEDIUM|$file|$line_num|Hardcoded /var/cpanel path"
|
|
count_issue "MEDIUM"
|
|
fi
|
|
fi
|
|
done < <(grep -rn '/var/cpanel' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
total_cpanel=$(grep -r '/var/cpanel' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | grep -vE '(\$SYS|:-/var/cpanel)' | grep -v '^[[:space:]]*#' | wc -l)
|
|
echo "Total found: $total_cpanel (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 10: Undefined color variables (LOW - cosmetic issue)
|
|
#==============================================================================
|
|
echo "[10/30] Checking: Undefined color variables..."
|
|
{
|
|
echo "## CHECK 10: Undefined color variables"
|
|
echo "Severity: LOW"
|
|
echo "Issue: Uses color variables without defining them"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
# Skip if sources common-functions, defines colors, OR is common-functions.sh itself
|
|
if [[ "$file" != *"common-functions.sh" ]] && ! grep -q "source.*common-functions" "$file" && ! grep -q "^RED=" "$file"; then
|
|
# Check if uses color variables
|
|
if grep -q '\${RED}\|\${GREEN}\|\${BLUE}\|\${YELLOW}\|\${CYAN}\|\${MAGENTA}\|\${NC}' "$file"; then
|
|
line_num=$(grep -n '\${RED}\|\${GREEN}' "$file" | head -1 | cut -d: -f1)
|
|
echo "LOW|$file|$line_num|Uses color vars without definition"
|
|
count_issue "LOW"
|
|
fi
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -type f 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 11: Bash syntax validation (CRITICAL - prevents execution)
|
|
#==============================================================================
|
|
echo "[11/30] Checking: Bash syntax errors..."
|
|
{
|
|
echo "## CHECK 11: Bash syntax validation"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: Syntax errors prevent script from running"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
if ! bash -n "$file" 2>/dev/null; then
|
|
errors=$(bash -n "$file" 2>&1 | head -1)
|
|
echo "CRITICAL|$file|N/A|Syntax: $errors"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" 2>/dev/null)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 12: Dangerous rm commands (CRITICAL - data loss risk)
|
|
#==============================================================================
|
|
echo "[12/30] Checking: Dangerous rm commands..."
|
|
{
|
|
echo "## CHECK 12: Dangerous rm commands"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: rm -rf with potentially empty variables = catastrophic data loss"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Skip if it's in an echo/comment (documentation, not execution)
|
|
if echo "$line_content" | grep -qE '^\s*(echo|#)'; then
|
|
continue
|
|
fi
|
|
|
|
# Check for rm -rf $var patterns where var might be empty
|
|
if echo "$line_content" | grep -qE 'rm\s+-[a-z]*r[a-z]*f.*\$[A-Z_]+[^/]|rm\s+-[a-z]*r[a-z]*f\s+/?\$'; then
|
|
# Skip if it has proper validation ([ -n "$var" ] && rm ...)
|
|
if ! echo "$line_content" | grep -q '\[\s*-[nz]'; then
|
|
echo "CRITICAL|$file|$line_num|Dangerous rm -rf with unvalidated variable"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
fi
|
|
done < <(grep -rn 'rm\s\+-[a-z]*r' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 13: Unquoted variable expansions (HIGH - word splitting/globbing risks)
|
|
#==============================================================================
|
|
echo "[13/30] Checking: Unquoted variables in dangerous contexts..."
|
|
{
|
|
echo "## CHECK 13: Unquoted variable expansions"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Unquoted \$var in rm/cp/mv can cause unintended file operations"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for dangerous commands with unquoted variables
|
|
if echo "$line_content" | grep -qE '(rm|cp|mv|chmod|chown)\s+[^"'"'"']*\$[A-Z_a-z]+[^"]'; then
|
|
# Skip comments and quoted contexts
|
|
if ! echo "$line_content" | grep -qE '^\s*#|".*\$.*"|'"'"'.*\$.*'"'"''; then
|
|
echo "HIGH|$file|$line_num|Unquoted variable in dangerous command"
|
|
count_issue "HIGH"
|
|
fi
|
|
fi
|
|
done < <(grep -rnE '(rm|cp|mv|chmod|chown)\s+.*\$' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 14: Command injection via eval (CRITICAL - arbitrary code execution)
|
|
#==============================================================================
|
|
echo "[14/30] Checking: Command injection risks..."
|
|
{
|
|
echo "## CHECK 14: Command injection via eval"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: eval with user-controlled input = remote code execution risk"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for eval usage - always risky
|
|
if ! echo "$line_content" | grep -q '^\s*#'; then
|
|
echo "CRITICAL|$file|$line_num|Uses eval command (code injection risk)"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
done < <(grep -rn '\beval\s' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -5)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 15: Temp file security (MEDIUM - race conditions/predictable names)
|
|
#==============================================================================
|
|
echo "[15/30] Checking: Temp file security..."
|
|
{
|
|
echo "## CHECK 15: Insecure temp file creation"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Predictable temp file names = race condition attacks"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for /tmp usage without mktemp
|
|
if echo "$line_content" | grep -qE '/tmp/[a-zA-Z_-]+\.(txt|tmp|log|dat)'; then
|
|
if ! echo "$line_content" | grep -qE 'mktemp|TEMP_DIR'; then
|
|
echo "MEDIUM|$file|$line_num|Hardcoded /tmp path (use mktemp)"
|
|
count_issue "MEDIUM"
|
|
fi
|
|
fi
|
|
done < <(grep -rn '/tmp/' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 16: TODO/FIXME/HACK markers (LOW - technical debt tracking)
|
|
#==============================================================================
|
|
echo "[16/30] Checking: Technical debt markers..."
|
|
{
|
|
echo "## CHECK 16: TODO/FIXME/HACK comments"
|
|
echo "Severity: LOW"
|
|
echo "Issue: Tracks incomplete features and known issues"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
marker=$(echo "$line_content" | grep -oE 'TODO|FIXME|HACK|XXX' | head -1)
|
|
echo "LOW|$file|$line_num|Technical debt: $marker"
|
|
count_issue "LOW"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
done < <(grep -rnE '\b(TODO|FIXME|HACK|XXX)\b' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
total_debt=$(grep -rE '\b(TODO|FIXME|HACK|XXX)\b' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | wc -l)
|
|
echo "Total found: $total_debt (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 17: Duplicate function definitions (MEDIUM - causes conflicts)
|
|
#==============================================================================
|
|
echo "[17/30] Checking: Duplicate function definitions..."
|
|
{
|
|
echo "## CHECK 17: Duplicate function definitions"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Same function in multiple files causes unpredictable behavior"
|
|
echo ""
|
|
|
|
# Extract all function names and find duplicates
|
|
declare -A func_files
|
|
while IFS=: read -r file func_name; do
|
|
if [ -n "${func_files[$func_name]}" ]; then
|
|
echo "MEDIUM|$file|N/A|Duplicate function '$func_name' (also in ${func_files[$func_name]})"
|
|
count_issue "MEDIUM"
|
|
else
|
|
func_files[$func_name]="$file"
|
|
fi
|
|
done < <(grep -rh '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*()' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | \
|
|
sed 's/^\s*//; s/(.*$//' | sort | uniq -d | \
|
|
while read func; do grep -rl "^[[:space:]]*$func()" "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | sed "s|$|:$func|"; done)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 18: Missing input validation (HIGH - security/reliability risk)
|
|
#==============================================================================
|
|
echo "[18/30] Checking: Missing input validation..."
|
|
{
|
|
echo "## CHECK 18: Functions without parameter validation"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Functions accepting parameters without validation"
|
|
echo ""
|
|
|
|
count=0
|
|
while read -r file; do
|
|
# Find functions that use $1, $2 etc but don't validate them
|
|
while IFS=: read -r line_num func_line; do
|
|
# Get function name
|
|
func_name=$(echo "$func_line" | sed 's/^\s*//; s/(.*$//')
|
|
|
|
# Check if function uses parameters (exclude AWK/sed field references)
|
|
# Get function body and filter out awk/sed commands before checking for $1-9
|
|
func_body=$(grep -A 20 "^[[:space:]]*$func_name()" "$file" 2>/dev/null | grep -v 'awk\|sed' || true)
|
|
|
|
# Skip functions that only use $@ or $* (passthrough/wrapper functions)
|
|
if echo "$func_body" | grep -E '^\s*(echo|printf).*\$[@*]' | grep -qv '\$[1-9]'; then
|
|
continue
|
|
fi
|
|
|
|
if echo "$func_body" | grep -q '\$[1-9]'; then
|
|
# Skip if uses safe default pattern: ${1:-default}
|
|
if grep -A 5 "^[[:space:]]*$func_name()" "$file" 2>/dev/null | grep -qE '\$\{[1-9]:-'; then
|
|
continue
|
|
fi
|
|
|
|
# Skip if function doesn't actually use positional params (only uses local vars)
|
|
# Check first 10 lines of function - if all $1-9 are in local declarations only, skip
|
|
if ! echo "$func_body" | grep -v "local.*=" | grep -q '\$[1-9]'; then
|
|
continue
|
|
fi
|
|
|
|
# Skip simple echo/print wrapper functions (validation not needed for display)
|
|
# If function only uses params in echo/print statements, it's safe
|
|
if echo "$func_body" | grep -E "^\s*(echo|printf|print)" | grep -q '\$[1-9]'; then
|
|
if ! echo "$func_body" | grep -v -E "^\s*(echo|printf|print|local|#)" | grep -q '\$[1-9]'; then
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
# Check if it validates them (accepts both $1 and variable name patterns)
|
|
# Pattern 1: [ -z "$1" ] or [ -n "$1" ]
|
|
# Pattern 2: [ -z "$var_name" ] where var_name was assigned from $1
|
|
# Pattern 3: [ $# -lt 1 ] or similar
|
|
# Pattern 4: if [ ! -f "$1" ] - file existence checks count as validation
|
|
if ! grep -A 5 "^[[:space:]]*$func_name()" "$file" 2>/dev/null | grep -qE '\[\s*-[nzf]\s*"\$([1-9]|[a-zA-Z_][a-zA-Z0-9_]*)"\s*\]|\[\s*!\s*-[nzf]\s*|\[\s*\$#\s*-'; then
|
|
echo "HIGH|$file|$line_num|Function '$func_name' uses parameters without validation"
|
|
count_issue "HIGH"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break 2
|
|
fi
|
|
fi
|
|
done < <(grep -n '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*()' "$file" 2>/dev/null)
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -not -name "toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count issues (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 19: Long functions (MEDIUM - maintainability issue)
|
|
#==============================================================================
|
|
echo "[19/30] Checking: Overly long functions..."
|
|
{
|
|
echo "## CHECK 19: Long functions (>100 lines)"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Long functions are hard to maintain and test"
|
|
echo ""
|
|
|
|
count=0
|
|
while read -r file; do
|
|
# Find function definitions and count lines until closing brace
|
|
awk '
|
|
/^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]*\(\)/ {
|
|
func_name = $0
|
|
gsub(/[[:space:]]*\(\).*/, "", func_name)
|
|
gsub(/^[[:space:]]*/, "", func_name)
|
|
func_line = NR
|
|
brace_count = 0
|
|
line_count = 0
|
|
in_function = 1
|
|
next
|
|
}
|
|
in_function {
|
|
line_count++
|
|
if (/\{/) brace_count += gsub(/\{/, "{")
|
|
if (/\}/) brace_count -= gsub(/\}/, "}")
|
|
if (brace_count == 0 && line_count > 100) {
|
|
print FILENAME ":" func_line ":Function '\''" func_name "'\'' is " line_count " lines"
|
|
in_function = 0
|
|
}
|
|
if (brace_count == 0) in_function = 0
|
|
}
|
|
' "$file" 2>/dev/null
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -not -name "toolkit-qa-check.sh" 2>/dev/null) | while IFS=: read -r file line_num message; do
|
|
echo "MEDIUM|$file|$line_num|$message"
|
|
count_issue "MEDIUM"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
done
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 20: ShellCheck integration (if available)
|
|
#==============================================================================
|
|
echo "[20/30] Checking: ShellCheck warnings (if available)..."
|
|
{
|
|
echo "## CHECK 20: ShellCheck static analysis"
|
|
echo "Severity: VARIES"
|
|
echo "Issue: ShellCheck finds many common bash pitfalls"
|
|
echo ""
|
|
|
|
if command -v shellcheck >/dev/null 2>&1; then
|
|
count=0
|
|
while read -r file; do
|
|
# Run shellcheck and capture warnings
|
|
shellcheck_output=$(shellcheck -f gcc "$file" 2>/dev/null | head -5)
|
|
if [ -n "$shellcheck_output" ]; then
|
|
echo "$shellcheck_output" | while IFS=: read -r f line col severity message; do
|
|
case "$severity" in
|
|
*error*) echo "HIGH|$f|$line|ShellCheck: $message"; count_issue "HIGH" ;;
|
|
*warning*) echo "MEDIUM|$f|$line|ShellCheck: $message"; count_issue "MEDIUM" ;;
|
|
*info*|*style*) echo "LOW|$f|$line|ShellCheck: $message"; count_issue "LOW" ;;
|
|
esac
|
|
((count++))
|
|
[ "$count" -ge 20 ] && break 2
|
|
done
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -not -name "toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
echo "Note: Ran ShellCheck on first 10 files (showing first 20 issues)"
|
|
else
|
|
echo "INFO: ShellCheck not installed - skipping advanced checks"
|
|
echo "Install with: dnf install ShellCheck (or: apt install shellcheck)"
|
|
fi
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 21: Using [ ] instead of [[ ]] (MEDIUM - less safe)
|
|
#==============================================================================
|
|
echo "[21/30] Checking: Single bracket conditionals..."
|
|
{
|
|
echo "## CHECK 21: Using [ ] instead of [[ ]]"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Single brackets don't handle empty vars/special chars safely"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for [ with string comparisons or variable tests
|
|
if echo "$line_content" | grep -qE '\[\s+[^]]*(\$[a-zA-Z_]|==|!=)[^]]*\]'; then
|
|
# Skip if it's already [[ ]] or a comment
|
|
if ! echo "$line_content" | grep -qE '^\s*#|\[\['; then
|
|
echo "MEDIUM|$file|$line_num|Using [ ] instead of safer [[ ]]"
|
|
count_issue "MEDIUM"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
fi
|
|
fi
|
|
done < <(grep -rn '\[\s' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count issues (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 22: Looping over ls output (HIGH - fatally flawed pattern)
|
|
#==============================================================================
|
|
echo "[22/30] Checking: Loops over ls output..."
|
|
{
|
|
echo "## CHECK 22: Looping over ls output"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: for f in \$(ls) breaks with spaces/special chars"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
if ! echo "$line_content" | grep -q '^\s*#'; then
|
|
echo "HIGH|$file|$line_num|Looping over ls output (use glob or find -print0)"
|
|
count_issue "HIGH"
|
|
fi
|
|
done < <(grep -rnE 'for\s+\w+\s+in\s+\$\(ls' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 23: Missing set -euo pipefail (MEDIUM - silent failures)
|
|
#==============================================================================
|
|
echo "[23/30] Checking: Missing error handling flags..."
|
|
{
|
|
echo "## CHECK 23: Missing set -euo pipefail"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Scripts continue after errors, unset vars expand to empty"
|
|
echo ""
|
|
|
|
count=0
|
|
while read -r file; do
|
|
# Skip library files (they're sourced, not executed)
|
|
if [[ "$file" == */lib/* ]]; then
|
|
continue
|
|
fi
|
|
|
|
# Check for shebang (executable script)
|
|
if head -1 "$file" 2>/dev/null | grep -q '^#!/bin/bash'; then
|
|
# Check if it has any error handling
|
|
if ! grep -q 'set -[euo]' "$file" 2>/dev/null; then
|
|
echo "MEDIUM|$file|N/A|Missing set -e/-u/-o pipefail (consider 'set -euo pipefail')"
|
|
count_issue "MEDIUM"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
fi
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH/modules" "$TOOLKIT_PATH/tools" -name "*.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count scripts without error handling"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 24: Unused variables (LOW - dead code)
|
|
#==============================================================================
|
|
echo "[24/30] Checking: Unused variables..."
|
|
{
|
|
echo "## CHECK 24: Unused variables"
|
|
echo "Severity: LOW"
|
|
echo "Issue: Variables declared but never used (AI code smell)"
|
|
echo ""
|
|
|
|
count=0
|
|
while read -r file; do
|
|
# Find all variable assignments
|
|
while IFS=: read -r line_num var_line; do
|
|
var_name=$(echo "$var_line" | grep -oE '^[[:space:]]*(local[[:space:]]+)?([a-zA-Z_][a-zA-Z0-9_]*)=' | sed 's/local //; s/=//')
|
|
if [ -n "$var_name" ]; then
|
|
# Check if variable is used anywhere after declaration
|
|
if ! grep -q "\$$var_name\b" "$file" 2>/dev/null; then
|
|
echo "LOW|$file|$line_num|Unused variable: $var_name"
|
|
count_issue "LOW"
|
|
((count++))
|
|
[ "$count" -ge 15 ] && break 2
|
|
fi
|
|
fi
|
|
done < <(grep -n '^\s*\(local \)\?[a-zA-Z_][a-zA-Z0-9_]*=' "$file" 2>/dev/null | head -20)
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -not -name "toolkit-qa-check.sh" 2>/dev/null | head -5)
|
|
|
|
echo "Note: Checked first 5 files, showing first 15 issues"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 25: Backticks instead of $() (LOW - deprecated syntax)
|
|
#==============================================================================
|
|
echo "[25/30] Checking: Deprecated backticks..."
|
|
{
|
|
echo "## CHECK 25: Using backticks instead of \$()"
|
|
echo "Severity: LOW"
|
|
echo "Issue: Backticks are deprecated, harder to nest"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
if ! echo "$line_content" | grep -q '^\s*#'; then
|
|
echo "LOW|$file|$line_num|Uses backticks (use \$(...) instead)"
|
|
count_issue "LOW"
|
|
fi
|
|
done < <(grep -rn '`[^`]*`' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 26: Missing or wrong shebang (HIGH - execution issues)
|
|
#==============================================================================
|
|
echo "[26/30] Checking: Shebang issues..."
|
|
{
|
|
echo "## CHECK 26: Missing or incorrect shebang"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: Script won't execute correctly without proper shebang"
|
|
echo ""
|
|
|
|
while read -r file; do
|
|
# Skip library files (sourced, not executed)
|
|
if [[ "$file" == */lib/* ]]; then
|
|
continue
|
|
fi
|
|
|
|
first_line=$(head -1 "$file" 2>/dev/null)
|
|
|
|
# Check if missing shebang
|
|
if [ ! "$first_line" = "#!/bin/bash" ] && [ ! "$first_line" = "#!/usr/bin/env bash" ]; then
|
|
if [ "${first_line:0:2}" != "#!" ]; then
|
|
echo "HIGH|$file|1|Missing shebang (add #!/bin/bash)"
|
|
count_issue "HIGH"
|
|
else
|
|
echo "MEDIUM|$file|1|Non-standard shebang: $first_line"
|
|
count_issue "MEDIUM"
|
|
fi
|
|
fi
|
|
done < <(find "$TOOLKIT_PATH/modules" "$TOOLKIT_PATH/tools" -name "*.sh" 2>/dev/null | head -20)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 27: Not checking command exit status (MEDIUM - silent failures)
|
|
#==============================================================================
|
|
echo "[27/30] Checking: Unchecked critical commands..."
|
|
{
|
|
echo "## CHECK 27: Critical commands without exit status checks"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Commands that can fail should be checked"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for critical commands without || or && or if checks
|
|
if echo "$line_content" | grep -qE '^\s*(curl|wget|rsync|mysql|ssh|git)\s' && \
|
|
! echo "$line_content" | grep -qE '(\|\||&&|if\s)'; then
|
|
# Skip comments
|
|
if ! echo "$line_content" | grep -q '^\s*#'; then
|
|
cmd=$(echo "$line_content" | awk '{print $1}')
|
|
echo "MEDIUM|$file|$line_num|$cmd command without exit status check"
|
|
count_issue "MEDIUM"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
fi
|
|
fi
|
|
done < <(grep -rnE '^\s*(curl|wget|rsync|mysql|ssh|git)\s' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count unchecked commands (showing first 10)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 28: Incorrect string/number comparison (HIGH - type confusion)
|
|
#==============================================================================
|
|
echo "[28/30] Checking: Type confusion in comparisons..."
|
|
{
|
|
echo "## CHECK 28: Using wrong comparison operators"
|
|
echo "Severity: HIGH"
|
|
echo "Issue: -eq for strings or = for numbers causes bugs"
|
|
echo ""
|
|
|
|
count=0
|
|
# Check for -eq with likely string variables
|
|
while IFS=: read -r file line_num line_content; do
|
|
if echo "$line_content" | grep -qE '\$[A-Z_]*[a-z][A-Za-z_]*(name|user|status|type|mode|method)\s+-eq\s'; then
|
|
echo "HIGH|$file|$line_num|Using -eq for likely string comparison (use = or ==)"
|
|
count_issue "HIGH"
|
|
((count++))
|
|
[ "$count" -ge 5 ] && break
|
|
fi
|
|
done < <(grep -rnE '\-eq\s' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count type confusion issues (showing first 5)"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 29: Unsafe array iteration (MEDIUM - word splitting)
|
|
#==============================================================================
|
|
echo "[29/30] Checking: Unsafe array expansions..."
|
|
{
|
|
echo "## CHECK 29: Array iteration without quotes"
|
|
echo "Severity: MEDIUM"
|
|
echo "Issue: Use \"\${array[@]}\" not \${array[@]} or \$array"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Check for unquoted array expansions
|
|
if echo "$line_content" | grep -qE 'for\s+\w+\s+in\s+\$\{[^}]+\[@\]\}' && \
|
|
! echo "$line_content" | grep -q '"\${'; then
|
|
echo "MEDIUM|$file|$line_num|Unquoted array expansion (causes word splitting)"
|
|
count_issue "MEDIUM"
|
|
((count++))
|
|
[ "$count" -ge 10 ] && break
|
|
fi
|
|
done < <(grep -rnE 'for\s+\w+\s+in\s+\$\{.*\[@\]' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null)
|
|
|
|
echo "Found: $count unsafe array iterations"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# CHECK 30: Hardcoded credentials or secrets (CRITICAL - security)
|
|
#==============================================================================
|
|
echo "[30/30] Checking: Hardcoded credentials..."
|
|
{
|
|
echo "## CHECK 30: Hardcoded passwords/API keys"
|
|
echo "Severity: CRITICAL"
|
|
echo "Issue: Credentials in code = major security vulnerability"
|
|
echo ""
|
|
|
|
while IFS=: read -r file line_num line_content; do
|
|
# Look for suspicious patterns
|
|
if echo "$line_content" | grep -qiE '(password|passwd|pwd|api_key|apikey|secret|token|auth)=["'"'"'][^"'"'"']+["'"'"']' && \
|
|
! echo "$line_content" | grep -qE '^\s*#|<password>|REDACTED|YOUR_|ENTER_|example'; then
|
|
echo "CRITICAL|$file|$line_num|Possible hardcoded credential detected"
|
|
count_issue "CRITICAL"
|
|
fi
|
|
done < <(grep -rniE '(password|passwd|api_key|apikey|secret|token)=' "$TOOLKIT_PATH" --include="*.sh" --exclude="toolkit-qa-check.sh" 2>/dev/null | head -10)
|
|
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# PERFORMANCE CHECKS (INFO level - not counted as issues)
|
|
#==============================================================================
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "PERFORMANCE & OPTIMIZATION CHECKS (Informational)"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
{
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "PERFORMANCE ANALYSIS"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
# PERF 1: cat file | grep (inefficient)
|
|
echo "[PERF-1] Inefficient cat | grep patterns..."
|
|
{
|
|
echo "## PERF-1: Inefficient pipe usage"
|
|
echo "Severity: INFO"
|
|
echo "Pattern: cat file | grep (should be: grep '' file)"
|
|
echo ""
|
|
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
echo "INFO|$file|$line_num|cat | grep pattern"
|
|
((count++))
|
|
[ "$count" -ge 5 ] && break
|
|
done < <(grep -rn 'cat.*|.*grep' "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null)
|
|
|
|
total=$(grep -r 'cat.*|.*grep' "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null | wc -l)
|
|
echo "Found: $total instances (showing first 5)"
|
|
echo "Optimization: Replace 'cat file | grep pattern' with 'grep pattern file'"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
# PERF 2: Repeated file reads
|
|
echo "[PERF-2] Multiple zcat on same file..."
|
|
{
|
|
echo "## PERF-2: Repeated decompression"
|
|
echo "Severity: INFO"
|
|
echo "Pattern: Multiple zcat/gunzip calls (expensive)"
|
|
echo ""
|
|
|
|
zcat_files=$(grep -rh 'zcat [^|]*' "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null | \
|
|
grep -oE 'zcat [^ ]+' | sort | uniq -c | sort -rn | head -3)
|
|
|
|
if [ -n "$zcat_files" ]; then
|
|
echo "$zcat_files"
|
|
echo ""
|
|
echo "Optimization: Decompress once, store in variable or temp file"
|
|
else
|
|
echo "None found"
|
|
fi
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
# PERF 3: Subshells in loops (expensive)
|
|
echo "[PERF-3] Expensive patterns in loops..."
|
|
{
|
|
echo "## PERF-3: Subshells in loops"
|
|
echo "Severity: INFO"
|
|
echo "Pattern: \$(...) or \`...\` inside while/for loops"
|
|
echo ""
|
|
|
|
# Find loops with subshells (sample only)
|
|
count=0
|
|
while read -r file; do
|
|
# Get line numbers of loops
|
|
grep -n 'while.*do\|for.*do' "$file" 2>/dev/null | while IFS=: read -r loop_line rest; do
|
|
# Check next 10 lines for subshells
|
|
start=$loop_line
|
|
end=$((loop_line + 10))
|
|
if sed -n "${start},${end}p" "$file" 2>/dev/null | grep -q '\$(\|`'; then
|
|
echo "INFO|$file|$loop_line|Subshell in loop (potential slowdown)"
|
|
((count++))
|
|
[ "$count" -ge 5 ] && break 2
|
|
fi
|
|
done
|
|
done < <(find "$TOOLKIT_PATH" -name "*.sh" -type f 2>/dev/null | head -20)
|
|
|
|
echo "Note: Review loops for expensive nested operations"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
# PERF 4: Inefficient string operations
|
|
echo "[PERF-4] String operations that could use bash builtins..."
|
|
{
|
|
echo "## PERF-4: Inefficient string operations"
|
|
echo "Severity: INFO"
|
|
echo "Pattern: sed/awk/cut when bash builtins work"
|
|
echo ""
|
|
|
|
# Sample sed replacements
|
|
count=0
|
|
while IFS=: read -r file line_num line_content; do
|
|
if echo "$line_content" | grep -q "sed 's/"; then
|
|
echo "INFO|$file|$line_num|sed replacement (consider \${var//pattern/replacement})"
|
|
((count++))
|
|
[ "$count" -ge 5 ] && break
|
|
fi
|
|
done < <(grep -rn "sed 's/" "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null)
|
|
|
|
total_sed=$(grep -r "sed 's/" "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null | wc -l)
|
|
echo "Found: $total_sed sed substitutions"
|
|
echo "Note: Many are justified, but consider bash builtins for simple cases"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
# PERF 5: Multiple grep on same large file
|
|
echo "[PERF-5] File read optimization opportunities..."
|
|
{
|
|
echo "## PERF-5: Repeated file access"
|
|
echo "Severity: INFO"
|
|
echo "Pattern: Same file accessed multiple times"
|
|
echo ""
|
|
|
|
# Check for common heavy files
|
|
echo "Common files that might benefit from caching:"
|
|
for common_file in "/etc/csf/csf.conf" "/var/log/messages" "/etc/passwd"; do
|
|
count=$(grep -r "$common_file" "$TOOLKIT_PATH" --include="*.sh" 2>/dev/null | wc -l)
|
|
if [ "$count" -gt 5 ]; then
|
|
echo " $common_file: $count references (consider caching)"
|
|
fi
|
|
done
|
|
echo ""
|
|
echo "Optimization: Cache frequently-read files in variables"
|
|
echo ""
|
|
} >> "$REPORT"
|
|
|
|
#==============================================================================
|
|
# SUMMARY
|
|
#==============================================================================
|
|
read crit high med low < "$TEMP_COUNTS"
|
|
total=$((crit + high + med + low))
|
|
|
|
{
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "SUMMARY"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
echo "Total Issues: $total"
|
|
echo " CRITICAL: $crit"
|
|
echo " HIGH: $high"
|
|
echo " MEDIUM: $med"
|
|
echo " LOW: $low"
|
|
echo ""
|
|
echo "Files Scanned: $(find "$TOOLKIT_PATH" -name "*.sh" 2>/dev/null | wc -l)"
|
|
echo "Report: $REPORT"
|
|
echo "═══════════════════════════════════════════════════════════════"
|
|
} | tee -a "$REPORT"
|
|
|
|
echo ""
|
|
echo "DETAILED BREAKDOWN BY SEVERITY:"
|
|
echo ""
|
|
|
|
# Group and display by severity
|
|
echo "CRITICAL ISSUES ($crit):"
|
|
grep "^CRITICAL|" "$REPORT" | while IFS='|' read -r sev file line issue; do
|
|
printf " %s:%s - %s\n" "$file" "$line" "$issue"
|
|
done
|
|
echo ""
|
|
|
|
echo "HIGH ISSUES ($high):"
|
|
grep "^HIGH|" "$REPORT" | head -15 | while IFS='|' read -r sev file line issue; do
|
|
printf " %s:%s - %s\n" "$file" "$line" "$issue"
|
|
done
|
|
if [ "$high" -gt 15 ]; then
|
|
echo " ... and $((high - 15)) more (see $REPORT)"
|
|
fi
|
|
echo ""
|
|
|
|
echo "MEDIUM ISSUES ($med):"
|
|
grep "^MEDIUM|" "$REPORT" | while IFS='|' read -r sev file line issue; do
|
|
printf " %s:%s - %s\n" "$file" "$line" "$issue"
|
|
done
|
|
echo ""
|
|
|
|
echo "LOW ISSUES ($low):"
|
|
grep "^LOW|" "$REPORT" | while IFS='|' read -r sev file line issue; do
|
|
printf " %s:%s - %s\n" "$file" "$line" "$issue"
|
|
done
|
|
|
|
# Cleanup
|
|
rm -f "$TEMP_COUNTS"
|
|
|
|
echo ""
|
|
echo "Full report saved to: $REPORT"
|
|
echo "Exit code: $total"
|
|
|
|
exit $total
|