diff --git a/tools/toolkit-qa-check.sh b/tools/toolkit-qa-check.sh index 8cf5acb..9a8698d 100755 --- a/tools/toolkit-qa-check.sh +++ b/tools/toolkit-qa-check.sh @@ -58,7 +58,7 @@ echo "" #============================================================================== # CHECK 1: grep -F with regex anchors (CRITICAL - causes wrong results) #============================================================================== -echo "[1/8] Checking: grep -F with regex anchors..." +echo "[1/20] Checking: grep -F with regex anchors..." { echo "## CHECK 1: grep -F with regex anchors" echo "Severity: CRITICAL" @@ -79,7 +79,7 @@ echo "" #============================================================================== # CHECK 2: SCRIPT_DIR collisions (HIGH - causes path errors) #============================================================================== -echo "[2/8] Checking: SCRIPT_DIR variable collisions..." +echo "[2/20] Checking: SCRIPT_DIR variable collisions..." { echo "## CHECK 2: SCRIPT_DIR variable collisions" echo "Severity: HIGH" @@ -99,7 +99,7 @@ echo "" #============================================================================== # CHECK 3: SYS_* variable resets (CRITICAL - breaks system detection) #============================================================================== -echo "[3/8] Checking: SYS_* variable resets..." +echo "[3/20] Checking: SYS_* variable resets..." { echo "## CHECK 3: SYS_* variable resets without protection" echo "Severity: CRITICAL" @@ -120,7 +120,7 @@ echo "" #============================================================================== # CHECK 4: Missing function exports (HIGH - functions unavailable) #============================================================================== -echo "[4/8] Checking: Missing function exports..." +echo "[4/20] Checking: Missing function exports..." { echo "## CHECK 4: Missing function exports in libraries" echo "Severity: HIGH" @@ -145,7 +145,7 @@ echo "" #============================================================================== # CHECK 5: Integer comparisons without empty checks (HIGH - causes errors) #============================================================================== -echo "[5/8] Checking: Unsafe integer comparisons (top 10)..." +echo "[5/20] Checking: Unsafe integer comparisons (top 10)..." { echo "## CHECK 5: Integer comparisons without empty checks" echo "Severity: HIGH" @@ -170,7 +170,7 @@ echo "" #============================================================================== # CHECK 6: Missing common-functions.sh (HIGH - command not found) #============================================================================== -echo "[6/8] Checking: Missing common-functions.sh..." +echo "[6/20] Checking: Missing common-functions.sh..." { echo "## CHECK 6: Missing common-functions.sh sourcing" echo "Severity: HIGH" @@ -190,7 +190,7 @@ echo "" #============================================================================== # CHECK 7: exit in libraries (HIGH - terminates parent script) #============================================================================== -echo "[7/8] Checking: exit in library files..." +echo "[7/20] Checking: exit in library files..." { echo "## CHECK 7: exit in sourced libraries" echo "Severity: HIGH" @@ -215,7 +215,7 @@ echo "" #============================================================================== # CHECK 8: bc command usage (LOW - external dependency) #============================================================================== -echo "[8/11] Checking: bc command usage..." +echo "[8/20] Checking: bc command usage..." { echo "## CHECK 8: bc command usage" echo "Severity: LOW" @@ -238,7 +238,7 @@ echo "" #============================================================================== # CHECK 9: Hardcoded /var/cpanel paths (MEDIUM - breaks multi-panel) #============================================================================== -echo "[9/11] Checking: Hardcoded /var/cpanel paths..." +echo "[9/20] Checking: Hardcoded /var/cpanel paths..." { echo "## CHECK 9: Hardcoded /var/cpanel paths" echo "Severity: MEDIUM" @@ -264,7 +264,7 @@ echo "" #============================================================================== # CHECK 10: Undefined color variables (LOW - cosmetic issue) #============================================================================== -echo "[10/11] Checking: Undefined color variables..." +echo "[10/20] Checking: Undefined color variables..." { echo "## CHECK 10: Undefined color variables" echo "Severity: LOW" @@ -289,7 +289,7 @@ echo "" #============================================================================== # CHECK 11: Bash syntax validation (CRITICAL - prevents execution) #============================================================================== -echo "[11/11] Checking: Bash syntax errors..." +echo "[11/20] Checking: Bash syntax errors..." { echo "## CHECK 11: Bash syntax validation" echo "Severity: CRITICAL" @@ -307,6 +307,263 @@ done < <(find "$TOOLKIT_PATH" -name "*.sh" 2>/dev/null) echo "" } >> "$REPORT" +#============================================================================== +# CHECK 12: Dangerous rm commands (CRITICAL - data loss risk) +#============================================================================== +echo "[12/20] 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 + # 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/20] 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/20] 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/20] 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/20] 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/20] 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/20] 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 + if grep -A 20 "^[[:space:]]*$func_name()" "$file" 2>/dev/null | grep -q '\$[1-9]'; then + # Check if it validates them + if ! grep -A 5 "^[[:space:]]*$func_name()" "$file" 2>/dev/null | grep -qE '\[\s*-[nz]\s*"\$[1-9]"|\[\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/20] 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/20] 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" + #============================================================================== # PERFORMANCE CHECKS (INFO level - not counted as issues) #==============================================================================