diff --git a/.agents/scripts/_archive/README.md b/.agents/scripts/_archive/README.md new file mode 100644 index 00000000..0e2d08be --- /dev/null +++ b/.agents/scripts/_archive/README.md @@ -0,0 +1,22 @@ +# Archived Scripts + +One-time fix scripts that have completed their purpose. Preserved for reference +and git history (patterns may be useful for future bulk fixes). + +## Scripts + +| Script | Purpose | Origin | +|--------|---------|--------| +| fix-auth-headers.sh | Fix Authorization header string literals | .agent->.agents rename | +| fix-common-strings.sh | Common string literals fix | .agent->.agents rename | +| fix-content-type.sh | Fix Content-Type string literals | .agent->.agents rename | +| fix-error-messages.sh | Fix common error message string literals | .agent->.agents rename | +| fix-misplaced-returns.sh | Fix misplaced return statements in mainwp-helper | .agent->.agents rename | +| fix-remaining-literals.sh | Fix remaining string literals | .agent->.agents rename | +| fix-return-statements.sh | Add return statements to functions | .agent->.agents rename | +| fix-s131-default-cases.sh | Add default case to case statements (SonarCloud S131) | Quality hardening | +| fix-sc2155-simple.sh | Fix SC2155 (declare and assign separately) | ShellCheck compliance | +| fix-shellcheck-critical.sh | Fix critical ShellCheck issues | ShellCheck compliance | +| fix-string-literals.sh | String literals fix | .agent->.agents rename | + +All scripts have 0 references in the active codebase as of 2026-02-07. diff --git a/.agents/scripts/add-missing-returns.sh b/.agents/scripts/_archive/add-missing-returns.sh similarity index 100% rename from .agents/scripts/add-missing-returns.sh rename to .agents/scripts/_archive/add-missing-returns.sh diff --git a/.agents/scripts/fix-auth-headers.sh b/.agents/scripts/_archive/fix-auth-headers.sh similarity index 100% rename from .agents/scripts/fix-auth-headers.sh rename to .agents/scripts/_archive/fix-auth-headers.sh diff --git a/.agents/scripts/fix-common-strings.sh b/.agents/scripts/_archive/fix-common-strings.sh similarity index 100% rename from .agents/scripts/fix-common-strings.sh rename to .agents/scripts/_archive/fix-common-strings.sh diff --git a/.agents/scripts/fix-content-type.sh b/.agents/scripts/_archive/fix-content-type.sh similarity index 100% rename from .agents/scripts/fix-content-type.sh rename to .agents/scripts/_archive/fix-content-type.sh diff --git a/.agents/scripts/fix-error-messages.sh b/.agents/scripts/_archive/fix-error-messages.sh similarity index 100% rename from .agents/scripts/fix-error-messages.sh rename to .agents/scripts/_archive/fix-error-messages.sh diff --git a/.agents/scripts/fix-misplaced-returns.sh b/.agents/scripts/_archive/fix-misplaced-returns.sh similarity index 100% rename from .agents/scripts/fix-misplaced-returns.sh rename to .agents/scripts/_archive/fix-misplaced-returns.sh diff --git a/.agents/scripts/fix-remaining-literals.sh b/.agents/scripts/_archive/fix-remaining-literals.sh similarity index 100% rename from .agents/scripts/fix-remaining-literals.sh rename to .agents/scripts/_archive/fix-remaining-literals.sh diff --git a/.agents/scripts/fix-return-statements.sh b/.agents/scripts/_archive/fix-return-statements.sh similarity index 100% rename from .agents/scripts/fix-return-statements.sh rename to .agents/scripts/_archive/fix-return-statements.sh diff --git a/.agents/scripts/fix-s131-default-cases.sh b/.agents/scripts/_archive/fix-s131-default-cases.sh similarity index 100% rename from .agents/scripts/fix-s131-default-cases.sh rename to .agents/scripts/_archive/fix-s131-default-cases.sh diff --git a/.agents/scripts/fix-sc2155-simple.sh b/.agents/scripts/_archive/fix-sc2155-simple.sh similarity index 100% rename from .agents/scripts/fix-sc2155-simple.sh rename to .agents/scripts/_archive/fix-sc2155-simple.sh diff --git a/.agents/scripts/fix-shellcheck-critical.sh b/.agents/scripts/_archive/fix-shellcheck-critical.sh similarity index 100% rename from .agents/scripts/fix-shellcheck-critical.sh rename to .agents/scripts/_archive/fix-shellcheck-critical.sh diff --git a/.agents/scripts/fix-string-literals.sh b/.agents/scripts/_archive/fix-string-literals.sh similarity index 100% rename from .agents/scripts/fix-string-literals.sh rename to .agents/scripts/_archive/fix-string-literals.sh diff --git a/.agents/scripts/clawdhub-helper.sh b/.agents/scripts/clawdhub-helper.sh index 6dfdd80c..4da71bf6 100755 --- a/.agents/scripts/clawdhub-helper.sh +++ b/.agents/scripts/clawdhub-helper.sh @@ -287,9 +287,9 @@ PLAYWRIGHT_SCRIPT # Install playwright and run the fetch script log_info "Installing Playwright (temporary)..." - if (cd "$pw_dir" && npm install --silent 2>/dev/null && npx playwright install chromium --with-deps 2>/dev/null); then || exit + if (cd "$pw_dir" && npm install --silent 2>/dev/null && npx playwright install chromium --with-deps 2>/dev/null); then log_info "Running browser extraction..." - if (cd "$pw_dir" && node fetch.mjs "$skill_url" "$output_file" 2>/dev/null); then || exit + if (cd "$pw_dir" && node fetch.mjs "$skill_url" "$output_file" 2>/dev/null); then rm -rf "$pw_dir" if [[ -f "$output_file" && -s "$output_file" ]]; then log_success "Extracted SKILL.md ($(wc -c < "$output_file" | tr -d ' ') bytes)" @@ -304,7 +304,7 @@ PLAYWRIGHT_SCRIPT # Fallback: try clawdhub CLI if command -v npx &>/dev/null; then log_info "Trying: npx clawdhub install $slug" - if (cd "$output_dir" && npx --yes clawdhub@latest install "$slug" --force 2>/dev/null); then || exit + if (cd "$output_dir" && npx --yes clawdhub@latest install "$slug" --force 2>/dev/null); then # clawdhub installs to ./skills//SKILL.md local installed_skill installed_skill=$(find "$output_dir" -name "SKILL.md" -type f 2>/dev/null | head -1) diff --git a/.agents/scripts/codacy-cli.sh b/.agents/scripts/codacy-cli.sh index 3f15ac00..0893140c 100755 --- a/.agents/scripts/codacy-cli.sh +++ b/.agents/scripts/codacy-cli.sh @@ -235,31 +235,29 @@ run_codacy_analysis() { return 1 fi - # Build analysis command - local cmd="codacy-cli analyze" + # Build analysis command as array to avoid eval + local cmd=("codacy-cli" "analyze") # Handle auto-fix flag if [[ "$tool" == "--fix" ]]; then - cmd="$cmd --fix" + cmd+=("--fix") print_info "Auto-fix enabled: Will apply fixes when available" print_info "Running analysis with all configured tools" elif [[ -n "$tool" ]]; then - cmd="$cmd --tool $tool" + cmd+=("--tool" "$tool") print_info "Running analysis with tool: $tool" else print_info "Running analysis with all configured tools" fi if [[ "$output_format" == "sarif" ]]; then - cmd="$cmd --format sarif --output $output_file" + cmd+=("--format" "sarif" "--output" "$output_file") print_info "Output format: SARIF → $output_file" fi # Execute analysis - print_info "Executing: $cmd" - eval "$cmd" - - if [[ $? -eq 0 ]]; then + print_info "Executing: ${cmd[*]}" + if "${cmd[@]}"; then print_success "Code analysis completed successfully" if [[ -f "$output_file" ]]; then print_info "Results saved to: $output_file" @@ -296,13 +294,13 @@ upload_codacy_results() { local organization="${CODACY_ORGANIZATION:-}" local repository="${CODACY_REPOSITORY:-}" - local cmd="codacy-cli upload -s $sarif_file -c $commit_uuid" + local cmd=("codacy-cli" "upload" "-s" "$sarif_file" "-c" "$commit_uuid") if [[ -n "$project_token" ]]; then - cmd="$cmd -t $project_token" + cmd+=("-t" "$project_token") print_info "Using project token for upload" elif [[ -n "$api_token" && -n "$provider" && -n "$organization" && -n "$repository" ]]; then - cmd="$cmd -a $api_token -p $provider -o $organization -r $repository" + cmd+=("-a" "$api_token" "-p" "$provider" "-o" "$organization" "-r" "$repository") print_info "Using API token for upload" else print_error "Upload credentials required:" @@ -312,16 +310,13 @@ upload_codacy_results() { fi print_info "Uploading: $sarif_file (commit: ${commit_uuid:0:8})" - eval "$cmd" - - if [[ $? -eq 0 ]]; then + if "${cmd[@]}"; then print_success "Results uploaded to Codacy successfully" return 0 else print_error "Upload failed" return 1 fi - return 0 } # Show CLI status diff --git a/.agents/scripts/coderabbit-cli.sh b/.agents/scripts/coderabbit-cli.sh index 68fca0eb..b5066b0d 100755 --- a/.agents/scripts/coderabbit-cli.sh +++ b/.agents/scripts/coderabbit-cli.sh @@ -299,27 +299,27 @@ review_changes() { print_info "Analyzing uncommitted git changes..." - # Build command based on mode - local cmd="coderabbit" + # Build command as array to avoid eval + local cmd=("coderabbit") case "$mode" in "plain") - cmd="$cmd --plain --type uncommitted" + cmd+=("--plain" "--type" "uncommitted") ;; "prompt-only") - cmd="$cmd --prompt-only --type uncommitted" + cmd+=("--prompt-only" "--type" "uncommitted") ;; "interactive") - cmd="$cmd --type uncommitted" + cmd+=("--type" "uncommitted") ;; esac # Add base branch if specified if [[ -n "$base_branch" ]]; then - cmd="$cmd --base $base_branch" + cmd+=("--base" "$base_branch") fi - print_info "Running: $cmd" - if eval "$cmd"; then + print_info "Running: ${cmd[*]}" + if "${cmd[@]}"; then print_success "Code review completed" return 0 else @@ -342,27 +342,27 @@ review_all_changes() { print_info "Analyzing all git changes (committed + uncommitted)..." - # Build command based on mode - local cmd="coderabbit" + # Build command as array to avoid eval + local cmd=("coderabbit") case "$mode" in "plain") - cmd="$cmd --plain --type all" + cmd+=("--plain" "--type" "all") ;; "prompt-only") - cmd="$cmd --prompt-only --type all" + cmd+=("--prompt-only" "--type" "all") ;; "interactive") - cmd="$cmd --type all" + cmd+=("--type" "all") ;; esac # Add base branch if specified if [[ -n "$base_branch" ]]; then - cmd="$cmd --base $base_branch" + cmd+=("--base" "$base_branch") fi - print_info "Running: $cmd" - if eval "$cmd"; then + print_info "Running: ${cmd[*]}" + if "${cmd[@]}"; then print_success "Code review completed" return 0 else diff --git a/.agents/scripts/monitor-code-review.sh b/.agents/scripts/monitor-code-review.sh index d6910998..7d5a2a42 100755 --- a/.agents/scripts/monitor-code-review.sh +++ b/.agents/scripts/monitor-code-review.sh @@ -151,37 +151,12 @@ run_codacy_analysis() { # Apply automatic fixes based on common patterns apply_automatic_fixes() { - print_info "Applying automatic fixes for common issues..." - - local fixes_applied=0 - - # Fix shellcheck issues in new files - for file in .agents/scripts/*.sh .agents/scripts/*.sh; do - # Check if file exists and has been modified recently (within last hour) - if [[ -f "$file" ]] && [[ $(find "$file" -mmin -60 2>/dev/null) ]]; then - print_info "Checking recent file: $file" - - # Apply common fixes - if grep -q "cd " "$file" && ! grep -q "cd .*||" "$file"; then - print_info "Fixing cd commands in $file" - # Use portable sed syntax (GNU vs BSD) - if sed --version 2>/dev/null | grep -q GNU; then - sed -i 's/cd \([^|]*\)$/cd \1 || exit/g' "$file" - else - sed -i '' 's/cd \([^|]*\)$/cd \1 || exit/g' "$file" - fi - ((fixes_applied++)) - fi - fi - done - - if [[ $fixes_applied -gt 0 ]]; then - print_success "Applied $fixes_applied automatic fixes" - echo "$(date): Applied $fixes_applied automatic fixes" >> "$MONITOR_LOG" - else - print_info "No automatic fixes needed" - fi - + # DISABLED: The cd || exit sed regex is too broad and introduces invalid syntax + # when cd appears inside subshells within if conditions, e.g.: + # if (cd "$dir" && cmd); then → if (cd "$dir" && cmd); then || exit + # This caused ShellCheck SC1073/SC1072 regressions (PR #435, commit aa276b3). + # Safe auto-fixes should validate with shellcheck before committing. + print_info "Automatic fixes disabled (see monitor-code-review.sh for details)" return 0 } diff --git a/.agents/scripts/pandoc-helper.sh b/.agents/scripts/pandoc-helper.sh index 6c3f870e..06cf654e 100755 --- a/.agents/scripts/pandoc-helper.sh +++ b/.agents/scripts/pandoc-helper.sh @@ -91,33 +91,34 @@ convert_to_markdown() { output_file="${input_file%.*}.md" fi - # Build pandoc command - local pandoc_cmd="pandoc" + # Build pandoc command as array to avoid eval + local pandoc_cmd=("pandoc") # Add input format if specified if [[ -n "$input_format" ]]; then - pandoc_cmd="$pandoc_cmd -f $input_format" + pandoc_cmd+=("-f" "$input_format") fi # Add output format (always markdown) - pandoc_cmd="$pandoc_cmd -t markdown" + pandoc_cmd+=("-t" "markdown") # Add common options for better markdown output - pandoc_cmd="$pandoc_cmd --wrap=none --markdown-headings=atx" + pandoc_cmd+=("--wrap=none" "--markdown-headings=atx") # Add custom options if provided if [[ -n "$options" ]]; then - pandoc_cmd="$pandoc_cmd $options" + # shellcheck disable=SC2206 + pandoc_cmd+=($options) fi # Add input and output files - pandoc_cmd="$pandoc_cmd \"$input_file\" -o \"$output_file\"" + pandoc_cmd+=("$input_file" "-o" "$output_file") print_info "Converting: $input_file → $output_file" - print_info "Command: $pandoc_cmd" + print_info "Command: ${pandoc_cmd[*]}" # Execute conversion - if eval "$pandoc_cmd"; then + if "${pandoc_cmd[@]}"; then print_success "Converted successfully: $output_file" # Show file size and preview diff --git a/.agents/scripts/secret-helper.sh b/.agents/scripts/secret-helper.sh index 156e3f0c..99c07f42 100755 --- a/.agents/scripts/secret-helper.sh +++ b/.agents/scripts/secret-helper.sh @@ -341,9 +341,12 @@ cmd_run() { return 1 fi - # Build environment + # Build environment in temp file with trap cleanup for security local env_file env_file=$(mktemp) + # shellcheck disable=SC2064 + trap "rm -f '$env_file'" EXIT + build_secret_env > "$env_file" # Execute command with secrets in environment, redact output @@ -359,8 +362,9 @@ cmd_run() { "${cmd_args[@]}" ) 2>&1 | redact_stream || exit_code=$? - # Clean up + # Clean up (also handled by trap on abnormal exit) rm -f "$env_file" + trap - EXIT return "$exit_code" } @@ -388,9 +392,12 @@ cmd_run_specific() { return 1 fi - # Build environment with specific secrets only + # Build environment with specific secrets only, trap cleanup for security local env_file env_file=$(mktemp) + # shellcheck disable=SC2064 + trap "rm -f '$env_file'" EXIT + build_secret_env "${secret_names[@]}" > "$env_file" # Execute command with secrets in environment, redact output @@ -405,6 +412,7 @@ cmd_run_specific() { ) 2>&1 | redact_stream || exit_code=$? rm -f "$env_file" + trap - EXIT return "$exit_code" } diff --git a/.agents/scripts/version-manager.sh b/.agents/scripts/version-manager.sh index 9d0129f2..f85c172e 100755 --- a/.agents/scripts/version-manager.sh +++ b/.agents/scripts/version-manager.sh @@ -295,10 +295,12 @@ EOF " fi - # Create temp files for the update + # Create temp files for the update with trap cleanup local temp_file content_file temp_file=$(mktemp) content_file=$(mktemp) + # shellcheck disable=SC2064 + trap "rm -f '$temp_file' '$content_file'" EXIT # Write the new version section to a temp file (avoids awk multiline issues) cat > "$content_file" << EOF @@ -336,6 +338,7 @@ EOF # Replace original file mv "$temp_file" "$changelog_file" rm -f "$content_file" + trap - EXIT print_success "Updated CHANGELOG.md: [Unreleased] → [$version] - $today" return 0 diff --git a/.agents/scripts/wp-helper.sh b/.agents/scripts/wp-helper.sh index 8189b445..4e386ed3 100755 --- a/.agents/scripts/wp-helper.sh +++ b/.agents/scripts/wp-helper.sh @@ -134,8 +134,9 @@ list_sites_by_category() { return 0 } -# Build SSH command based on hosting type -build_ssh_command() { +# Execute WP-CLI command via SSH based on hosting type +# Directly executes instead of building a string for eval +execute_wp_via_ssh() { local site_config="$1" local wp_command="$2" @@ -154,31 +155,20 @@ build_ssh_command() { local password_file password_file=$(echo "$site_config" | jq -r '.password_file // empty') - # Quote wp_command for safe execution - local quoted_wp_command - quoted_wp_command=$(printf %q "$wp_command") - case "$site_type" in localwp) # LocalWP - direct local access - # Expand ~ safely without eval local expanded_path="${local_path/#\~/$HOME}" - # Quote path for safe execution - local quoted_local_path - quoted_local_path=$(printf %q "$expanded_path") - echo "cd $quoted_local_path && wp $quoted_wp_command" || exit + (cd "$expanded_path" && wp $wp_command) + return $? ;; hostinger|closte) # Hostinger/Closte - sshpass with password file - # Note: sshpass is required due to hosting provider limitations - # SSH key auth is preferred when available check_sshpass local expanded_password_file if [[ -n "$password_file" ]]; then - # Expand ~ safely without eval expanded_password_file="${password_file/#\~/$HOME}" else - # Default password file locations if [[ "$site_type" == "hostinger" ]]; then expanded_password_file="${HOME}/.ssh/hostinger_password" else @@ -189,27 +179,23 @@ build_ssh_command() { if [[ ! -f "$expanded_password_file" ]]; then print_error "Password file not found: $expanded_password_file" print_info "Create the password file with your SSH password (chmod 600)" - exit 1 + return 1 fi - # Quote wp_path for safe remote execution - local quoted_wp_path - quoted_wp_path=$(printf %q "$wp_path") - echo "sshpass -f \"$expanded_password_file\" ssh -p $ssh_port $ssh_user@$ssh_host \"cd $quoted_wp_path && wp $quoted_wp_command\"" || exit + # Use array for sshpass + ssh command + sshpass -f "$expanded_password_file" ssh -p "$ssh_port" "${ssh_user}@${ssh_host}" "cd $(printf %q "$wp_path") && wp $wp_command" + return $? ;; hetzner|cloudways|cloudron) # SSH key-based authentication (preferred) - # Quote wp_path for safe remote execution - local quoted_wp_path - quoted_wp_path=$(printf %q "$wp_path") - echo "ssh -p $ssh_port $ssh_user@$ssh_host \"cd $quoted_wp_path && wp $quoted_wp_command\"" || exit + ssh -p "$ssh_port" "${ssh_user}@${ssh_host}" "cd $(printf %q "$wp_path") && wp $wp_command" + return $? ;; *) print_error "Unknown hosting type: $site_type" - exit 1 + return 1 ;; esac - return 0 } # Run WP-CLI command on a site @@ -233,11 +219,8 @@ run_wp_command() { print_info "Running on $site_name ($site_type): wp $wp_command" - local ssh_command - ssh_command=$(build_ssh_command "$site_config" "$wp_command") - - # Execute the command - eval "$ssh_command" + # Execute directly without eval + execute_wp_via_ssh "$site_config" "$wp_command" return $? } diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index cc31f476..2f112e96 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -11,7 +11,7 @@ "plugins": [ { "name": "aidevops", - "source": "./.agent", + "source": "./.agents", "description": "Complete AI DevOps framework - 14 domain agents, 80+ subagents, 100+ helper scripts for WordPress, SEO, hosting, code quality, browser automation, and more", "strict": false }