Add CHECK 31 to QA script: detect 'local' outside functions
Issue:
- User encountered "local: can only be used in a function" error
in analyze-historical-attacks.sh (lines 190, 203)
- The script used 'local' keyword in a code block redirected to a file
- This is a CRITICAL runtime error that prevents script execution
- QA script didn't catch this issue
Solution:
Added CHECK 31 to toolkit-qa-check.sh:
- Detects 'local' keyword used outside function context
- Tracks function boundaries using brace depth counting
- Reads entire file line-by-line to maintain state
- Skips comments to avoid false positives
- Severity: CRITICAL (script fails at runtime)
Implementation:
- Function detection: matches `function_name()` pattern
- Brace tracking: counts { and } to detect function exit
- State machine: in_function flag toggles based on brace depth
- Reports line number and file for easy fixing
Testing:
✅ Correctly identifies 'local' outside functions
✅ Does NOT flag 'local' inside functions (no false positives)
✅ Found existing issues in test files
Example error caught:
/tmp/test-local-outside-function.sh:4|'local' keyword outside function
This check prevents runtime failures and makes QA more comprehensive.
This commit is contained in:
+83
-30
@@ -58,7 +58,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 1: grep -F with regex anchors (CRITICAL - causes wrong results)
|
||||
#==============================================================================
|
||||
echo "[1/30] Checking: grep -F with regex anchors..."
|
||||
echo "[1/31] 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/30] Checking: SCRIPT_DIR variable collisions..."
|
||||
echo "[2/31] 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/30] Checking: SYS_* variable resets..."
|
||||
echo "[3/31] 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/30] Checking: Missing function exports..."
|
||||
echo "[4/31] 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/30] Checking: Unsafe integer comparisons (top 10)..."
|
||||
echo "[5/31] 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/30] Checking: Missing common-functions.sh..."
|
||||
echo "[6/31] 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/30] Checking: exit in library files..."
|
||||
echo "[7/31] 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/30] Checking: bc command usage..."
|
||||
echo "[8/31] 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/30] Checking: Hardcoded /var/cpanel paths..."
|
||||
echo "[9/31] 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/30] Checking: Undefined color variables..."
|
||||
echo "[10/31] 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/30] Checking: Bash syntax errors..."
|
||||
echo "[11/31] Checking: Bash syntax errors..."
|
||||
{
|
||||
echo "## CHECK 11: Bash syntax validation"
|
||||
echo "Severity: CRITICAL"
|
||||
@@ -310,7 +310,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 12: Dangerous rm commands (CRITICAL - data loss risk)
|
||||
#==============================================================================
|
||||
echo "[12/30] Checking: Dangerous rm commands..."
|
||||
echo "[12/31] Checking: Dangerous rm commands..."
|
||||
{
|
||||
echo "## CHECK 12: Dangerous rm commands"
|
||||
echo "Severity: CRITICAL"
|
||||
@@ -339,7 +339,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 13: Unquoted variable expansions (HIGH - word splitting/globbing risks)
|
||||
#==============================================================================
|
||||
echo "[13/30] Checking: Unquoted variables in dangerous contexts..."
|
||||
echo "[13/31] Checking: Unquoted variables in dangerous contexts..."
|
||||
{
|
||||
echo "## CHECK 13: Unquoted variable expansions"
|
||||
echo "Severity: HIGH"
|
||||
@@ -363,7 +363,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 14: Command injection via eval (CRITICAL - arbitrary code execution)
|
||||
#==============================================================================
|
||||
echo "[14/30] Checking: Command injection risks..."
|
||||
echo "[14/31] Checking: Command injection risks..."
|
||||
{
|
||||
echo "## CHECK 14: Command injection via eval"
|
||||
echo "Severity: CRITICAL"
|
||||
@@ -384,7 +384,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 15: Temp file security (MEDIUM - race conditions/predictable names)
|
||||
#==============================================================================
|
||||
echo "[15/30] Checking: Temp file security..."
|
||||
echo "[15/31] Checking: Temp file security..."
|
||||
{
|
||||
echo "## CHECK 15: Insecure temp file creation"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -407,7 +407,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 16: TODO/FIXME/HACK markers (LOW - technical debt tracking)
|
||||
#==============================================================================
|
||||
echo "[16/30] Checking: Technical debt markers..."
|
||||
echo "[16/31] Checking: Technical debt markers..."
|
||||
{
|
||||
echo "## CHECK 16: TODO/FIXME/HACK comments"
|
||||
echo "Severity: LOW"
|
||||
@@ -431,7 +431,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 17: Duplicate function definitions (MEDIUM - causes conflicts)
|
||||
#==============================================================================
|
||||
echo "[17/30] Checking: Duplicate function definitions..."
|
||||
echo "[17/31] Checking: Duplicate function definitions..."
|
||||
{
|
||||
echo "## CHECK 17: Duplicate function definitions"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -457,7 +457,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 18: Missing input validation (HIGH - security/reliability risk)
|
||||
#==============================================================================
|
||||
echo "[18/30] Checking: Missing input validation..."
|
||||
echo "[18/31] Checking: Missing input validation..."
|
||||
{
|
||||
echo "## CHECK 18: Functions without parameter validation"
|
||||
echo "Severity: HIGH"
|
||||
@@ -555,7 +555,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 19: Long functions (MEDIUM - maintainability issue)
|
||||
#==============================================================================
|
||||
echo "[19/30] Checking: Overly long functions..."
|
||||
echo "[19/31] Checking: Overly long functions..."
|
||||
{
|
||||
echo "## CHECK 19: Long functions (>100 lines)"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -600,7 +600,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 20: ShellCheck integration (if available)
|
||||
#==============================================================================
|
||||
echo "[20/30] Checking: ShellCheck warnings (if available)..."
|
||||
echo "[20/31] Checking: ShellCheck warnings (if available)..."
|
||||
{
|
||||
echo "## CHECK 20: ShellCheck static analysis"
|
||||
echo "Severity: VARIES"
|
||||
@@ -636,7 +636,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 21: Using [ ] instead of [[ ]] (MEDIUM - less safe)
|
||||
#==============================================================================
|
||||
echo "[21/30] Checking: Single bracket conditionals..."
|
||||
echo "[21/31] Checking: Single bracket conditionals..."
|
||||
{
|
||||
echo "## CHECK 21: Using [ ] instead of [[ ]]"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -664,7 +664,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 22: Looping over ls output (HIGH - fatally flawed pattern)
|
||||
#==============================================================================
|
||||
echo "[22/30] Checking: Loops over ls output..."
|
||||
echo "[22/31] Checking: Loops over ls output..."
|
||||
{
|
||||
echo "## CHECK 22: Looping over ls output"
|
||||
echo "Severity: HIGH"
|
||||
@@ -684,7 +684,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 23: Missing set -euo pipefail (MEDIUM - silent failures)
|
||||
#==============================================================================
|
||||
echo "[23/30] Checking: Missing error handling flags..."
|
||||
echo "[23/31] Checking: Missing error handling flags..."
|
||||
{
|
||||
echo "## CHECK 23: Missing set -euo pipefail"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -717,7 +717,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 24: Unused variables (LOW - dead code)
|
||||
#==============================================================================
|
||||
echo "[24/30] Checking: Unused variables..."
|
||||
echo "[24/31] Checking: Unused variables..."
|
||||
{
|
||||
echo "## CHECK 24: Unused variables"
|
||||
echo "Severity: LOW"
|
||||
@@ -748,7 +748,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 25: Backticks instead of $() (LOW - deprecated syntax)
|
||||
#==============================================================================
|
||||
echo "[25/30] Checking: Deprecated backticks..."
|
||||
echo "[25/31] Checking: Deprecated backticks..."
|
||||
{
|
||||
echo "## CHECK 25: Using backticks instead of \$()"
|
||||
echo "Severity: LOW"
|
||||
@@ -768,7 +768,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 26: Missing or wrong shebang (HIGH - execution issues)
|
||||
#==============================================================================
|
||||
echo "[26/30] Checking: Shebang issues..."
|
||||
echo "[26/31] Checking: Shebang issues..."
|
||||
{
|
||||
echo "## CHECK 26: Missing or incorrect shebang"
|
||||
echo "Severity: HIGH"
|
||||
@@ -801,7 +801,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 27: Not checking command exit status (MEDIUM - silent failures)
|
||||
#==============================================================================
|
||||
echo "[27/30] Checking: Unchecked critical commands..."
|
||||
echo "[27/31] Checking: Unchecked critical commands..."
|
||||
{
|
||||
echo "## CHECK 27: Critical commands without exit status checks"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -831,7 +831,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 28: Incorrect string/number comparison (HIGH - type confusion)
|
||||
#==============================================================================
|
||||
echo "[28/30] Checking: Type confusion in comparisons..."
|
||||
echo "[28/31] Checking: Type confusion in comparisons..."
|
||||
{
|
||||
echo "## CHECK 28: Using wrong comparison operators"
|
||||
echo "Severity: HIGH"
|
||||
@@ -856,7 +856,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 29: Unsafe array iteration (MEDIUM - word splitting)
|
||||
#==============================================================================
|
||||
echo "[29/30] Checking: Unsafe array expansions..."
|
||||
echo "[29/31] Checking: Unsafe array expansions..."
|
||||
{
|
||||
echo "## CHECK 29: Array iteration without quotes"
|
||||
echo "Severity: MEDIUM"
|
||||
@@ -882,7 +882,7 @@ echo ""
|
||||
#==============================================================================
|
||||
# CHECK 30: Hardcoded credentials or secrets (CRITICAL - security)
|
||||
#==============================================================================
|
||||
echo "[30/30] Checking: Hardcoded credentials..."
|
||||
echo "[30/31] Checking: Hardcoded credentials..."
|
||||
{
|
||||
echo "## CHECK 30: Hardcoded passwords/API keys"
|
||||
echo "Severity: CRITICAL"
|
||||
@@ -901,6 +901,59 @@ done < <(grep -rniE '(password|passwd|api_key|apikey|secret|token)=' "$TOOLKIT_P
|
||||
echo ""
|
||||
} >> "$REPORT"
|
||||
|
||||
#==============================================================================
|
||||
# CHECK 31: local keyword outside functions (CRITICAL - script fails)
|
||||
#==============================================================================
|
||||
echo "[31/31] Checking: 'local' outside functions..."
|
||||
{
|
||||
echo "## CHECK 31: 'local' keyword outside function context"
|
||||
echo "Severity: CRITICAL"
|
||||
echo "Issue: 'local' can only be used inside functions, causes runtime error"
|
||||
echo ""
|
||||
|
||||
while read -r file; do
|
||||
# Read entire file and track function boundaries
|
||||
in_function=0
|
||||
brace_depth=0
|
||||
line_num=0
|
||||
|
||||
while IFS= read -r line_content; do
|
||||
line_num=$((line_num + 1))
|
||||
|
||||
# Skip comments
|
||||
if echo "$line_content" | grep -q '^\s*#'; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Detect function start
|
||||
if echo "$line_content" | grep -qE '^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*\(\)'; then
|
||||
in_function=1
|
||||
brace_depth=0
|
||||
fi
|
||||
|
||||
# Track braces
|
||||
open_braces=$(echo "$line_content" | grep -o '{' | wc -l)
|
||||
close_braces=$(echo "$line_content" | grep -o '}' | wc -l)
|
||||
brace_depth=$((brace_depth + open_braces - close_braces))
|
||||
|
||||
# If we were in a function and braces are now balanced back to 0, we've exited
|
||||
if [ "$in_function" -eq 1 ] && [ "$brace_depth" -le 0 ]; then
|
||||
in_function=0
|
||||
fi
|
||||
|
||||
# Check for 'local' keyword outside function
|
||||
if [ "$in_function" -eq 0 ]; then
|
||||
if echo "$line_content" | grep -qE '^\s*local\s+[a-zA-Z_]'; then
|
||||
echo "CRITICAL|$file|$line_num|'local' keyword outside function (runtime error)"
|
||||
count_issue "CRITICAL"
|
||||
fi
|
||||
fi
|
||||
done < "$file"
|
||||
done < <(find "$TOOLKIT_PATH" -name "*.sh" -type f 2>/dev/null)
|
||||
|
||||
echo ""
|
||||
} >> "$REPORT"
|
||||
|
||||
#==============================================================================
|
||||
# PERFORMANCE CHECKS (INFO level - not counted as issues)
|
||||
#==============================================================================
|
||||
|
||||
Reference in New Issue
Block a user