#!/usr/bin/env bash set -Eeuo pipefail umask 022 # STEP002 - SERVER ATTESO: 215.6 / ax-accessi # Audit funzionale rapido di presenze.distribuite. Nessuna modifica. START_DIR="$PWD" STAMP="$(date '+%Y%m%d_%H%M%S')" BASE="STEP002_2156_DISTRIBUITE_BASE_READINESS_AUDIT_ONLY_${STAMP}" WORKDIR="${START_DIR}/.${BASE}_work_$$" OUTZIP="${START_DIR}/${BASE}.zip" LOGFILE="${WORKDIR}/run.log" REPORT="${WORKDIR}/report.txt" PACKAGED=0 FAILURES=0 WARNINGS=0 EXPECTED_HOST="${STEP_EXPECTED_HOST:-ax-accessi}" EXPECTED_IP="${STEP_EXPECTED_IP:-192.168.215.6}" PORTAL_PATH="${STEP_PORTAL_PATH:-/var/www/html/presenze.distribuite}" PORTAL_HOST="${STEP_PORTAL_HOST:-presenze.distribuite.axuno.it}" SHARED_RELEASE="${STEP_SHARED_RELEASE:-/var/www/presenze-shared-libs/releases/presenze-legacy-20260723-v1}" PORTAL_DB="${STEP_PORTAL_DB:-presenze_distribuite}" MASTER_DB="${STEP_MASTER_DB:-ax-master-license}" EXPECTED_LICENSE="${STEP_EXPECTED_LICENSE:-A9002}" SKIP_SERVER_CHECK="${STEP_SKIP_SERVER_CHECK:-0}" SKIP_DB="${STEP_SKIP_DB:-0}" SKIP_HTTP="${STEP_SKIP_HTTP:-0}" mkdir -p "$WORKDIR" : > "$LOGFILE" : > "$REPORT" log() { printf '%s\n' "$*" | tee -a "$LOGFILE" } report() { printf '%s\n' "$*" >> "$REPORT" } fail() { FAILURES=$((FAILURES + 1)) log "ERRORE: $*" report "ERRORE: $*" } warn() { WARNINGS=$((WARNINGS + 1)) log "ATTENZIONE: $*" report "ATTENZIONE: $*" } package_results() { local rc="${1:-0}" local zip_rc=0 if [[ "$PACKAGED" -eq 1 ]]; then return 0 fi PACKAGED=1 report "" report "Esito finale: errori=${FAILURES}, avvisi=${WARNINGS}, exit_code=${rc}" rm -f -- "$OUTZIP" if command -v zip >/dev/null 2>&1; then ( cd "$WORKDIR" zip -qr "$OUTZIP" . ) || zip_rc=$? if [[ "$zip_rc" -eq 0 ]]; then zip -T "$OUTZIP" >> "$LOGFILE" 2>&1 || zip_rc=$? fi else zip_rc=127 fi rm -rf -- "$WORKDIR" if [[ "$zip_rc" -ne 0 ]]; then rm -f -- "$OUTZIP" printf '%s\n' "ERRORE: creazione o verifica ZIP fallita (rc=${zip_rc})." >&2 return "$zip_rc" fi printf '%s\n' "ZIP CREATO E VERIFICATO: $OUTZIP" } on_exit() { local rc=$? trap - EXIT INT TERM HUP package_results "$rc" || rc=$? exit "$rc" } trap on_exit EXIT trap 'exit 130' INT trap 'exit 143' TERM HUP log "$BASE" log "SERVER ATTESO: 215.6 / ax-accessi" log "MODALITA': AUDIT ONLY - NESSUNA MODIFICA" log "Avvio: $(date --iso-8601=seconds)" ACTUAL_HOST="$(hostname -s 2>/dev/null || hostname)" ACTUAL_IPS="$(hostname -I 2>/dev/null | xargs || true)" { echo "STEP: $BASE" echo "Server atteso: 215.6 / ax-accessi" echo "Modalita': AUDIT ONLY" echo "Data: $(date --iso-8601=seconds)" echo "Hostname: $ACTUAL_HOST" echo "IP: $ACTUAL_IPS" echo "Portale: $PORTAL_PATH" echo "Host web: $PORTAL_HOST" echo "Database: $PORTAL_DB" echo "Licenza attesa: $EXPECTED_LICENSE" echo "Release condivisa: $SHARED_RELEASE" echo } >> "$REPORT" for cmd in find grep sed awk wc sort readlink stat du php zip hostname xargs; do if ! command -v "$cmd" >/dev/null 2>&1; then fail "comando richiesto non disponibile: $cmd" fi done if [[ "$FAILURES" -ne 0 ]]; then exit 20 fi if [[ "$SKIP_SERVER_CHECK" != "1" ]]; then if [[ "$ACTUAL_HOST" != "$EXPECTED_HOST" ]]; then fail "hostname non atteso: ${ACTUAL_HOST}; previsto: ${EXPECTED_HOST}" fi if [[ -n "$EXPECTED_IP" ]] && ! grep -qw -- "$EXPECTED_IP" <<< "$ACTUAL_IPS"; then fail "IP atteso ${EXPECTED_IP} non presente tra: ${ACTUAL_IPS}" fi else report "Controllo identita' server saltato tramite STEP_SKIP_SERVER_CHECK=1." fi if [[ ! -d "$PORTAL_PATH" ]]; then fail "cartella portale non trovata: $PORTAL_PATH" exit 21 fi { echo "== ROOT ==" stat -c 'Tipo/permessi: %F %A (%a)%nProprietario: %U:%G%nModificato: %y' "$PORTAL_PATH" du -sh "$PORTAL_PATH" echo } > "${WORKDIR}/01_ROOT.txt" { echo "== LIBRERIE CONDIVISE ==" for name in node_modules bower_components; do link="${PORTAL_PATH}/${name}" expected="${SHARED_RELEASE}/${name}" if [[ -L "$link" ]]; then target="$(readlink -f "$link" 2>/dev/null || true)" printf '%s\tSYMLINK\t%s\tREALE=%s\n' "$name" "$(readlink "$link")" "$target" if [[ "$target" != "$expected" ]]; then fail "$name punta a ${target:-NON RISOLTO}, atteso $expected" elif [[ ! -d "$target" ]]; then fail "target $name non disponibile: $target" fi else printf '%s\tNON_SYMLINK\n' "$name" fail "$link non e' un collegamento simbolico" fi done } > "${WORKDIR}/02_SHARED_LIBS.txt" TEMPLATE_ROOT="${PORTAL_PATH}/components/templates/custom_templates/ax_attendance" TEMPLATE_LIST="${WORKDIR}/03_SCHEDE_PRESENZE.txt" if [[ -d "$TEMPLATE_ROOT" ]]; then find "$TEMPLATE_ROOT" -mindepth 1 -maxdepth 1 -type d -name 'ax_schede_presenze_*' -printf '%f\n' | LC_ALL=C sort > "$TEMPLATE_LIST" mapfile -t SCHEDE < "$TEMPLATE_LIST" if [[ "${#SCHEDE[@]}" -ne 2 || "${SCHEDE[0]:-}" != "ax_schede_presenze_modA" || "${SCHEDE[1]:-}" != "ax_schede_presenze_modB" ]]; then fail "le cartelle ax_schede_presenze_* non sono soltanto modA e modB" fi else : > "$TEMPLATE_LIST" fail "cartella template non trovata: $TEMPLATE_ROOT" fi KEY_PATHS=( ".htaccess" "index.php" "phpgen_settings.php" "ax_common/a000_ax_glob.php" "ax_common/a000_ax_include_controller.php" "components/templates/custom_templates/ax_attendance/ax_schede_presenze_modA" "components/templates/custom_templates/ax_attendance/ax_schede_presenze_modB" "libs/stimulsoft_legacy/viewer.php" "libs/stimulsoft_legacy/designer.php" ) { echo "== FILE E CARTELLE CHIAVE ==" for rel in "${KEY_PATHS[@]}"; do path="${PORTAL_PATH}/${rel}" if [[ -e "$path" || -L "$path" ]]; then stat -c '%F\t%A\t%U:%G\t%n' "$path" else printf 'MANCANTE\t%s\n' "$path" fail "elemento chiave mancante: $path" fi done } > "${WORKDIR}/04_KEY_PATHS.txt" GLOB_FILE="${PORTAL_PATH}/ax_common/a000_ax_glob.php" if [[ -f "$GLOB_FILE" ]]; then grep -nE 'AXLICCODE|presenze_distribuite|presenze_silvelox|A9002' "$GLOB_FILE" > "${WORKDIR}/05_GLOB_REFERENCES.txt" || true active_line="$(grep -E 'AXLICCODE' "$GLOB_FILE" | grep -vE '^[[:space:]]*(//|#|/\*)' | head -n 1 || true)" active_code="$(printf '%s\n' "$active_line" | grep -oE 'A[0-9]{4,}' | head -n 1 || true)" if [[ "$active_code" != "$EXPECTED_LICENSE" ]]; then fail "AXLICCODE rilevato '${active_code:-NESSUNO}', atteso '$EXPECTED_LICENSE'" fi fi SEARCH_LIST="${WORKDIR}/source_files.list" find "$PORTAL_PATH" \ \( -path "$PORTAL_PATH/node_modules" -o -path "$PORTAL_PATH/bower_components" -o -path "$PORTAL_PATH/vendor" -o -path "$PORTAL_PATH/templates_c" -o -path "$PORTAL_PATH/log" -o -path "$PORTAL_PATH/logs" -o -path "$PORTAL_PATH/tmp" -o -path "$PORTAL_PATH/cache" \) -prune -o \ -type f \( -name '*.php' -o -name '*.js' -o -name '*.html' -o -name '*.json' -o -name '.htaccess' \) -print0 > "$SEARCH_LIST" if xargs -0 -r grep -Il --binary-files=without-match -E 'presenze[._-]?silvelox|presenze_silvelox' < "$SEARCH_LIST" > "${WORKDIR}/06_SILVELOX_REFERENCES.txt"; then if [[ -s "${WORKDIR}/06_SILVELOX_REFERENCES.txt" ]]; then warn "riferimenti Silvelox trovati nel codice di Distribuite; vedere 06_SILVELOX_REFERENCES.txt" fi fi LINT_LIST="${WORKDIR}/php_lint_files.list" { find "${PORTAL_PATH}/ax_common" -type f -name '*.php' -print 2>/dev/null || true find "${TEMPLATE_ROOT}/ax_schede_presenze_modA" -type f -name '*.php' -print 2>/dev/null || true find "${TEMPLATE_ROOT}/ax_schede_presenze_modB" -type f -name '*.php' -print 2>/dev/null || true for rel in index.php phpgen_settings.php admin_utility.php; do [[ -f "${PORTAL_PATH}/${rel}" ]] && printf '%s\n' "${PORTAL_PATH}/${rel}" done } | LC_ALL=C sort -u > "$LINT_LIST" LINT_COUNT="$(wc -l < "$LINT_LIST" | tr -d ' ')" LINT_ERRORS=0 : > "${WORKDIR}/07_PHP_LINT.txt" log "Controllo sintassi PHP: ${LINT_COUNT} file" index=0 while IFS= read -r php_file; do [[ -n "$php_file" ]] || continue index=$((index + 1)) if ! php -l "$php_file" >> "${WORKDIR}/07_PHP_LINT.txt" 2>&1; then LINT_ERRORS=$((LINT_ERRORS + 1)) fi if (( index % 50 == 0 )); then log "PHP lint: ${index}/${LINT_COUNT}" fi done < "$LINT_LIST" if [[ "$LINT_ERRORS" -ne 0 ]]; then fail "sintassi PHP non valida in ${LINT_ERRORS} file" else report "Sintassi PHP: OK su ${LINT_COUNT} file controllati." fi if [[ "$SKIP_DB" != "1" ]]; then MYSQL_BIN="${STEP_MYSQL_BIN:-}" if [[ -z "$MYSQL_BIN" ]]; then if command -v mysql >/dev/null 2>&1; then MYSQL_BIN="$(command -v mysql)" elif command -v mariadb >/dev/null 2>&1; then MYSQL_BIN="$(command -v mariadb)" fi fi if [[ -z "$MYSQL_BIN" || ! -x "$MYSQL_BIN" ]]; then fail "client mysql/mariadb non disponibile" else MYSQL=("$MYSQL_BIN" --batch --raw --default-character-set=utf8mb4) if ! "${MYSQL[@]}" --skip-column-names -e 'SELECT 1' >/dev/null 2>&1; then fail "accesso MySQL locale non riuscito" else DB_REPORT="${WORKDIR}/08_DATABASE.txt" : > "$DB_REPORT" db_exists="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='${PORTAL_DB}';")" echo "Database ${PORTAL_DB} presente: ${db_exists}" >> "$DB_REPORT" if [[ "$db_exists" != "1" ]]; then fail "database ${PORTAL_DB} assente" else table_count="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${PORTAL_DB}';")" echo "Numero tabelle: ${table_count}" >> "$DB_REPORT" for table in ax_user ax_associazioni_temporali ax_firms ax_turns_cycle accessi_clockings terminal_clockings; do exists="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${PORTAL_DB}' AND TABLE_NAME='${table}';")" if [[ "$exists" == "1" ]]; then rows="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM \`${PORTAL_DB}\`.\`${table}\`;" 2>>"$LOGFILE" || printf 'ERRORE')" printf '%s\t%s\n' "$table" "$rows" >> "$DB_REPORT" else printf '%s\tMANCANTE\n' "$table" >> "$DB_REPORT" warn "tabella demo attesa mancante: ${PORTAL_DB}.${table}" fi done fi lic_table="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='${MASTER_DB}' AND TABLE_NAME='ax_license';")" if [[ "$lic_table" == "1" ]]; then "${MYSQL[@]}" -e "SELECT lic_id,lic_code_firm,lic_serial,lic_db_name,lic_name,lic_www,lic_end FROM \`${MASTER_DB}\`.ax_license WHERE lic_code_firm='${EXPECTED_LICENSE}' OR lic_db_name='${PORTAL_DB}' ORDER BY lic_id;" > "${WORKDIR}/09_LICENSE.txt" lic_count="$("${MYSQL[@]}" --skip-column-names -e "SELECT COUNT(*) FROM \`${MASTER_DB}\`.ax_license WHERE lic_code_firm='${EXPECTED_LICENSE}' AND lic_db_name='${PORTAL_DB}';")" if [[ "$lic_count" != "1" ]]; then fail "licenza ${EXPECTED_LICENSE}/${PORTAL_DB}: trovati ${lic_count} record, atteso 1" fi else fail "tabella ${MASTER_DB}.ax_license assente" fi fi fi else report "Controllo database saltato tramite STEP_SKIP_DB=1." fi if [[ "$SKIP_HTTP" != "1" ]]; then if ! command -v curl >/dev/null 2>&1; then fail "curl non disponibile" else HTTP_HEADERS="${WORKDIR}/10_HTTP_HEADERS.txt" HTTP_BODY="${WORKDIR}/10_HTTP_BODY_HEAD.txt" http_code="$(curl -sS --max-time 20 -D "$HTTP_HEADERS" -o "${WORKDIR}/http_body.tmp" -H "Host: ${PORTAL_HOST}" -w '%{http_code}' 'http://127.0.0.1/' || printf '000')" head -c 4096 "${WORKDIR}/http_body.tmp" > "$HTTP_BODY" 2>/dev/null || true rm -f "${WORKDIR}/http_body.tmp" echo "HTTP locale con Host ${PORTAL_HOST}: ${http_code}" >> "$REPORT" case "$http_code" in 200|301|302|303|307|308) ;; *) fail "risposta HTTP locale inattesa: ${http_code}" ;; esac fi else report "Controllo HTTP saltato tramite STEP_SKIP_HTTP=1." fi { echo "AUDIT COMPLETATO" echo "Errori: $FAILURES" echo "Avvisi: $WARNINGS" echo "File PHP controllati: $LINT_COUNT" echo "Nessun file applicativo e nessun dato sono stati modificati." } > "${WORKDIR}/99_SUMMARY.txt" log "Audit completato: errori=${FAILURES}, avvisi=${WARNINGS}" if [[ "$FAILURES" -ne 0 ]]; then exit 30 fi