Status: ✅ All issues resolved
Standard: ShellCheck 0.9.x
Scripts audited: 8 source files
Violations found: 6 categories
Violations fixed: 6 categories (100%)
# Install (Debian/Ubuntu)
sudo apt-get install shellcheck
# Run against all scripts
shellcheck bin/*.sh lib/*.sh scripts/*.sh tests/*.sh
# Run with JSON output for CI integration
shellcheck --format=json bin/cluster-manager.sh | jq .
Risk: If the command substitution fails, local always returns 0,
hiding the failure from set -e.
Before (dangerous):
local cluster_id="cls-$(date +%s)-$(openssl rand -hex 3)"
local total=$((PASSED+FAILED+SKIPPED))
After (safe):
local cluster_id
cluster_id="cls-$(date +%s)-$(openssl rand -hex 3)"
local total
total=$((PASSED+FAILED+SKIPPED))
Files fixed: tests/run_tests.sh
Risk: Filenames or node names with spaces would split incorrectly.
Before:
local up_nodes=()
up_nodes+=($node_id) # splits on spaces
After:
local up_nodes=()
up_nodes+=("$node_id") # safe for node names with spaces
Files fixed: lib/cluster-lib.sh (elect_leader function)
Risk: Counter variables modified inside $() subshells are lost.
Before:
total_nodes=$(( total_nodes + 1 )) # inside subshell = lost
After: Redesigned all loops to avoid subshell variable modification.
Used while read pattern for loops that need to accumulate state.
Files fixed: lib/cluster-lib.sh (check_cluster_health, get_cluster_metrics)
Risk: Backslashes in input are interpreted, corrupting node names or paths.
Before:
while read line; do
After:
while IFS= read -r line; do
Files fixed: lib/cluster-lib.sh, tests/run_tests.sh
Risk: Multiple >> redirections to the same file are inefficient
and can cause interleaving in concurrent scenarios.
Before:
echo "line1" >> "$LOG_FILE"
echo "line2" >> "$LOG_FILE"
After:
{
echo "line1"
echo "line2"
} >> "$LOG_FILE"
Files fixed: lib/logger.sh
Risk: Unquoted variables in [[ ]] conditions or command arguments can
trigger glob expansion when node IDs contain special characters.
Before:
if [[ $status == $NODE_STATUS_UP ]]; then
After:
if [[ "$status" == "$NODE_STATUS_UP" ]]; then
Files fixed: All scripts (systematic pass)
Risk: Unused variables indicate logic errors or dead code.
Found in scripts/chaos-engineering.sh: local variable volume_id was declared
but never used in the simulate_data_corruption branch path.
Fixed: Removed dead variable.
Where a ShellCheck warning is a false positive (i.e., we intentionally violate the guideline), we annotate the source with a disable comment and an explanation:
# shellcheck disable=SC2029
# SC2029: Variables in ssh command intentionally expanded on the CLIENT side.
# We want the cluster CIDR to be resolved locally before sending to the remote.
ssh "$target_node" "sudo iptables -A INPUT -s $CLUSTER_IPS -j DROP"
Add this to your GitHub Actions workflow to block PRs with ShellCheck violations:
# .github/workflows/shellcheck.yml
name: ShellCheck
on: [push, pull_request]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: '.'
severity: warning # fail on warnings too
additional_files: 'lib/logger.sh lib/cluster-lib.sh lib/network_checks.sh'
Report generated: 2026-02-22
All scripts re-audited after each fix to prevent regressions.