diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index ded6da8..95a9762 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -79,8 +79,16 @@ jobs: run: | set -o pipefail echo "Validating changed plugins: $CHANGED_PLUGINS" - read -ra PLUGINS_ARRAY <<< "$CHANGED_PLUGINS" - ./scripts/validate-plugin-structure.sh "${PLUGINS_ARRAY[@]}" 2>&1 | tee /tmp/structure-validation.log + echo "DEBUG: Length of CHANGED_PLUGINS: ${#CHANGED_PLUGINS}" + echo "DEBUG: CHANGED_PLUGINS (hex): $(echo -n "$CHANGED_PLUGINS" | od -A n -t x1)" + if [[ -n "$CHANGED_PLUGINS" ]]; then + IFS=' ' read -r -a PLUGINS_ARRAY <<< "$CHANGED_PLUGINS" + echo "DEBUG: Array length: ${#PLUGINS_ARRAY[@]}" + echo "DEBUG: Array contents: ${PLUGINS_ARRAY[@]}" + ./scripts/validate-plugin-structure.sh "${PLUGINS_ARRAY[@]}" 2>&1 | tee /tmp/structure-validation.log + else + echo "DEBUG: CHANGED_PLUGINS is empty, skipping validation" + fi - name: Validate marketplace.json id: marketplace @@ -91,8 +99,16 @@ jobs: run: | set -o pipefail echo "Validating marketplace entries for changed plugins: $CHANGED_PLUGINS" - read -ra PLUGINS_ARRAY <<< "$CHANGED_PLUGINS" - ./scripts/validate-marketplace.sh "${PLUGINS_ARRAY[@]}" 2>&1 | tee /tmp/marketplace-validation.log + echo "DEBUG: Length of CHANGED_PLUGINS: ${#CHANGED_PLUGINS}" + echo "DEBUG: CHANGED_PLUGINS (hex): $(echo -n "$CHANGED_PLUGINS" | od -A n -t x1)" + if [[ -n "$CHANGED_PLUGINS" ]]; then + IFS=' ' read -r -a PLUGINS_ARRAY <<< "$CHANGED_PLUGINS" + echo "DEBUG: Array length: ${#PLUGINS_ARRAY[@]}" + echo "DEBUG: Array contents: ${PLUGINS_ARRAY[@]}" + ./scripts/validate-marketplace.sh "${PLUGINS_ARRAY[@]}" 2>&1 | tee /tmp/marketplace-validation.log + else + echo "DEBUG: CHANGED_PLUGINS is empty, skipping validation" + fi - name: Log in to Azure if: steps.changed-files.outputs.has_components == 'true' diff --git a/scripts/lib/path-sanitization.sh b/scripts/lib/path-sanitization.sh index 56a94af..90f6214 100644 --- a/scripts/lib/path-sanitization.sh +++ b/scripts/lib/path-sanitization.sh @@ -50,6 +50,7 @@ sanitize_plugin_path() { # Reject paths containing null bytes, newlines, or carriage returns if [[ "$arg" =~ $'\0' ]] || [[ "$arg" =~ $'\n' ]] || [[ "$arg" =~ $'\r' ]]; then + echo "ERROR: Path contains invalid characters (null/newline/carriage return)" >&2 return 1 fi @@ -77,11 +78,13 @@ sanitize_plugin_path() { plugin_name="$arg" else # Invalid format or potentially dangerous pattern + echo "ERROR: Path format invalid. Expected 'plugins/name' or 'name', got: '$arg'" >&2 return 1 fi # Validate plugin name contains only safe characters if [[ ! "$plugin_name" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo "ERROR: Plugin name contains invalid characters: '$plugin_name'" >&2 return 1 fi @@ -90,20 +93,28 @@ sanitize_plugin_path() { # Verify the path exists and is a directory if [[ ! -d "$plugin_path" ]]; then + echo "ERROR: Plugin directory does not exist: $plugin_path" >&2 return 1 fi # Use realpath to resolve any symlinks and get canonical path local canonical_path - canonical_path="$(cd "$plugin_path" && pwd 2>/dev/null)" || return 1 + if ! canonical_path="$(cd "$plugin_path" && pwd 2>/dev/null)"; then + echo "ERROR: Failed to resolve canonical path for: $plugin_path" >&2 + return 1 + fi # Verify the resolved path is still under plugins_dir local canonical_plugins_dir - canonical_plugins_dir="$(cd "$plugins_dir" && pwd 2>/dev/null)" || return 1 + if ! canonical_plugins_dir="$(cd "$plugins_dir" && pwd 2>/dev/null)"; then + echo "ERROR: Failed to resolve plugins directory: $plugins_dir" >&2 + return 1 + fi if [[ "$canonical_path" != "$canonical_plugins_dir" ]] && \ [[ ! "$canonical_path" =~ ^"$canonical_plugins_dir"/ ]]; then # Path escapes the plugins directory - reject it + echo "ERROR: Path escapes plugins directory (security check failed)" >&2 return 1 fi diff --git a/scripts/validate-marketplace.sh b/scripts/validate-marketplace.sh index a0f3ef7..253473e 100755 --- a/scripts/validate-marketplace.sh +++ b/scripts/validate-marketplace.sh @@ -284,15 +284,21 @@ main() { # Build list of plugins to validate local target_plugins=() if [[ $# -gt 0 ]]; then + echo "DEBUG: Received $# argument(s): $*" # Arguments provided - extract plugin names for arg in "$@"; do + echo "DEBUG: Processing argument: '$arg'" # Use shared sanitization function to safely parse plugin path local sanitized_path - if sanitized_path=$(sanitize_plugin_path "$arg" "$REPO_ROOT/plugins" 2>/dev/null); then + if sanitized_path=$(sanitize_plugin_path "$arg" "$REPO_ROOT/plugins" 2>&1); then # Extract just the plugin name from the full path local plugin_name plugin_name=$(basename "$sanitized_path") + echo "DEBUG: ✓ Sanitized to: '$sanitized_path' → plugin name: '$plugin_name'" target_plugins+=("$plugin_name") + else + echo "DEBUG: ✗ Failed to sanitize argument '$arg'" + echo "DEBUG: Output from sanitize_plugin_path: $sanitized_path" fi done diff --git a/scripts/validate-plugin-structure.sh b/scripts/validate-plugin-structure.sh index f91e4ef..d07f253 100755 --- a/scripts/validate-plugin-structure.sh +++ b/scripts/validate-plugin-structure.sh @@ -369,11 +369,17 @@ main() { # If arguments provided, validate only those plugins if [[ $# -gt 0 ]]; then + echo "DEBUG: Received $# argument(s): $*" for arg in "$@"; do + echo "DEBUG: Processing argument: '$arg'" # Use shared sanitization function to safely parse plugin path local sanitized_path - if sanitized_path=$(sanitize_plugin_path "$arg" "$PLUGINS_DIR" 2>/dev/null); then + if sanitized_path=$(sanitize_plugin_path "$arg" "$PLUGINS_DIR" 2>&1); then + echo "DEBUG: ✓ Sanitized to: '$sanitized_path'" plugins+=("$sanitized_path") + else + echo "DEBUG: ✗ Failed to sanitize argument '$arg'" + echo "DEBUG: Output from sanitize_plugin_path: $sanitized_path" fi done