#!/bin/bash # ╔═══════════════════════════════════════════════════════════════╗ # ║ 🔐 DEPLOY VALIDATOR — Pre-deploy integrity check ║ # ║ Usage: deploy-validator.sh [target_dir] ║ # ║ Returns 0 if safe, 1 if blocked ║ # ║ Must pass ALL checks before any file is deployed ║ # ╚═══════════════════════════════════════════════════════════════╝ FILE="$1" TARGET="${2:-/opt/wevads/public}" VAULT="/opt/wevads/vault" LOG="/opt/wevads/logs/deploy-validator.log" if [ -z "$FILE" ]; then echo '{"ok":false,"error":"Usage: deploy-validator.sh [target_dir]"}' exit 1 fi fname=$(basename "$FILE") ext="${fname##*.}" TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') ERRORS="" WARNINGS="" new_size=$(wc -c < "$FILE" 2>/dev/null || echo 0) log() { echo "[$TIMESTAMP] $1" >> "$LOG"; } # ═══════════════════════════════════════ # CHECK 1: File exists and has content # ═══════════════════════════════════════ if [ ! -f "$FILE" ]; then echo '{"ok":false,"error":"File not found: '"$FILE"'"}' exit 1 fi if [ "$new_size" -lt 100 ]; then echo '{"ok":false,"error":"File too small: '"$new_size"'B (min 100B)"}' exit 1 fi # ═══════════════════════════════════════ # CHECK 2: HTML-specific validations # ═══════════════════════════════════════ if [ "$ext" = "html" ]; then # Must have closing tags if [ "$new_size" -gt 5000 ]; then has_close_html=$(grep -c '' "$FILE") has_style=$(grep -c '' "$FILE") [ "$has_close_html" -eq 0 ] && ERRORS="${ERRORS}missing_close_html " [ "$has_style" -eq 0 ] && WARNINGS="${WARNINGS}no_css " [ "$has_script" -gt 0 ] && [ "$has_close_script" -eq 0 ] && ERRORS="${ERRORS}unclosed_script " # Check onclick without script has_onclick=$(grep -cE 'onclick|oninput' "$FILE") [ "$has_onclick" -gt 0 ] && [ "$has_script" -eq 0 ] && ERRORS="${ERRORS}onclick_no_script " fi # Size regression check vs gold gold="$VAULT/${fname}.gold" if [ -f "$gold" ]; then gold_size=$(wc -c < "$gold") if [ "$gold_size" -gt 1000 ] && [ "$new_size" -lt "$((gold_size * 50 / 100))" ]; then ERRORS="${ERRORS}size_regression(gold=${gold_size}B,new=${new_size}B) " fi fi fi # ═══════════════════════════════════════ # CHECK 3: PHP syntax validation # ═══════════════════════════════════════ if [ "$ext" = "php" ]; then result=$(php -l "$FILE" 2>&1) if echo "$result" | grep -q 'Parse error\|Fatal'; then ERRORS="${ERRORS}php_syntax_error " fi # Size regression vs gold goldname=$(echo "$TARGET/$fname" | sed 's|/|__|g' | sed 's|^__||').gold gold="$VAULT/$goldname" if [ -f "$gold" ]; then gold_size=$(wc -c < "$gold") if [ "$gold_size" -gt 1000 ] && [ "$new_size" -lt "$((gold_size * 50 / 100))" ]; then ERRORS="${ERRORS}size_regression(gold=${gold_size}B,new=${new_size}B) " fi fi fi # ═══════════════════════════════════════ # VERDICT # ═══════════════════════════════════════ if [ -n "$ERRORS" ]; then log "BLOCKED: $fname — $ERRORS" echo '{"ok":false,"file":"'"$fname"'","size":'"$new_size"',"errors":"'"$ERRORS"'","warnings":"'"$WARNINGS"'"}' exit 1 else log "APPROVED: $fname (${new_size}B) $WARNINGS" # Auto-backup current live before deploy target_file="$TARGET/$fname" if [ -f "$target_file" ]; then cp "$target_file" "$target_file.bak-$(date +%Y%m%d%H%M%S)" 2>/dev/null fi echo '{"ok":true,"file":"'"$fname"'","size":'"$new_size"',"warnings":"'"$WARNINGS"'"}' exit 0 fi