Skip to content

Commit 58a8b46

Browse files
committed
feat: mejora lógica de alertas, reset mensual y documentación v2.0
1 parent c5016d6 commit 58a8b46

8 files changed

Lines changed: 170 additions & 153 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: ShellCheck Private Scan
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
permissions:
10+
contents: read
11+
security-events: write
12+
13+
jobs:
14+
shellcheck:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
20+
- name: Install ShellCheck
21+
run: sudo apt-get update && sudo apt-get install -y shellcheck
22+
23+
- name: Run ShellCheck on all .sh and save output
24+
run: |
25+
files=$(find . -type f -name "*.sh" -not -path "./.git/*" -print)
26+
if [ -z "$files" ]; then
27+
echo "No shell scripts found"
28+
echo "NO_SCRIPTS" > shellcheck-output.txt
29+
exit 0
30+
fi
31+
shellcheck $files > shellcheck-output.txt || true
32+
shellcheck -f sarif $files > shellcheck-results.sarif || true
33+
34+
- name: Upload results as artifact (private to repo collaborators)
35+
uses: actions/upload-artifact@v4
36+
with:
37+
name: shellcheck-results-${{ github.run_id }}
38+
path: |
39+
shellcheck-output.txt
40+
shellcheck-results.sarif

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
<img src="assets/banner.png" alt="MyIronGuard Banner" />
33
</p>
44

5+
# 🛡️ MyIronGuard
6+
7+
![Licencia](https://img.shields.io/badge/license-PolyForm_NC-blue)
8+
![Versión](https://img.shields.io/badge/version-2.0-orange)
9+
![Bash](https://img.shields.io/badge/script-Bash-green)
10+
![GitHub Stars](https://img.shields.io/github/stars/LadyKernel/MyIronGuard?style=social)
11+
![Visitas](https://komarev.com/ghpvc/?username=LadyKernel&repo=MyIronGuard&color=green)
12+
513
🛡️ MyIronGuard
614
Secure by design. Built by LadyKernel.
715

network-monitor/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
.env
44
.env.local
55
.env.*
6+
.alert_state_*
7+
.last_month_*
8+
69

710
# --- ARCHIVOS TEMPORALES Y DE PRUEBAS ---
811
# Ignorar los archivos de "memoria" del script (si se usan localmente)

network-monitor/README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ cd MyIronGuard/network-monitor/vps-estandar # o /gcloud
6060
| **LIMITE_DIARIO** | Umbral en GB para aviso diario | `1.5` |
6161
| **LIMITE_MENSUAL** | Umbral en GB para aviso mensual | `100.0` |
6262
| **PRECIO_GB** | Precio por GB de salida (Egress) | `0.12` |
63+
| **UMBRAL_ALERTA** | Configuración Umbral alerta Critica | `0.9 (90%)` |
64+
6365

6466
3. **Dale permisos de ejecución:**
6567
chmod +x monitor.sh
@@ -154,15 +156,15 @@ Sí, siempre y cuando **NO subas el archivo .env a GitHub**. El archivo `.gitign
154156
## Si este script te ha ahorrado tiempo en la monitorización de tus servidores, considera darle una ⭐ para que otros puedan encontrarlo.
155157

156158
---
157-
## 📝 Licencia
158-
Este proyecto se distribuye bajo la licencia PolyForm Noncommercial License 1.0.0.
159-
160-
Uso Comunitario: Eres libre de usar, modificar y mejorar este monitor para tus laboratorios personales y proyectos educativos.
159+
## 🛡️ Licencia y Uso Comercial
161160

162-
Uso Profesional: El uso en entornos corporativos, por organizaciones con ánimo de lucro o para fines comerciales requiere una autorización y licencia específica.
161+
Este proyecto se distribuye bajo la licencia **PolyForm Noncommercial License 1.0.0**.
163162

164-
Para entender todos los términos legales, consulta el archivo LICENSE.
163+
* **Uso Comunitario:** Eres libre de usar, modificar y mejorar este monitor para tus laboratorios personales y proyectos educativos.
164+
* **Uso Profesional:** El uso en entornos corporativos, organizaciones con ánimo de lucro o fines comerciales requiere una autorización específica.
165165

166-
¿Necesitas una licencia comercial o tienes dudas sobre su integración profesional?
166+
> [!IMPORTANT]
167+
> El uso de este software en entornos de producción empresarial sin la licencia correspondiente infringe los términos de uso. Para entender todos los términos legales, consulta el archivo `LICENSE`.
167168
168-
📩 Contacto: hola@lksys.es
169+
**¿Necesitas una licencia comercial o soporte para su integración?**
170+
📩 **Contacto:** [hola@lksys.es](mailto:hola@lksys.es)

network-monitor/gcloud/env.example_GCLOUD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@ LIMITE_MENSUAL=100.0
1616

1717
# Coste por GB de salida (Egress) en tu región de GCP (ej: 0.12 USD/EUR)
1818
PRECIO_GB=0.12
19+
20+
# Umbral para aviso crítico y mensaje de estrella (0.9 = 90%)
21+
UMBRAL_ALERTA=0.9

network-monitor/gcloud/monitor.sh

Lines changed: 48 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,14 @@
77
# Licencia: PolyForm Noncommercial License 1.0.0
88
# Copyright: (c) 2026 LadyKernel
99
# -------------------------------------------------------------------------
10-
# Se permite el uso personal y educativo gratuito.
1110
# El uso comercial o empresarial requiere autorización previa.
12-
#
1311
# Consultas de licencias o uso profesional: hola@lksys.es
1412
# -------------------------------------------------------------------------
1513

16-
# --- 1. SEGURIDAD DE EJECUCIÓN (Fail-safe) ---
1714
set -euo pipefail
18-
# Restringimos el PATH para evitar Path Hijacking
1915
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
2016

21-
# --- 2. RUTAS ABSOLUTAS DE HERRAMIENTAS (Anti-suplantación) ---
17+
# --- 1. RUTAS ---
2218
CURL="/usr/bin/curl"
2319
JQ="/usr/bin/jq"
2420
AWK="/usr/bin/awk"
@@ -29,152 +25,113 @@ CHMOD="/usr/bin/chmod"
2925
STAT="/usr/bin/stat"
3026
SED="/usr/bin/sed"
3127
GREP="/usr/bin/grep"
32-
33-
# Aseguramos formato numérico internacional
28+
REPO_URL="https://github.com/LadyKernel/MyIronGuard"
3429
export LC_ALL=C
3530

36-
# --- 3. CARGA SEGURA DE CONFIGURACIÓN ---
31+
# --- 2. CONFIGURACIÓN ---
3732
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3833
ENV_FILE="$DIR/.env"
3934

4035
if [ -f "$ENV_FILE" ]; then
41-
# Hardening: El .env solo debe ser legible por el dueño (600)
4236
PERMS=$($STAT -c "%a" "$ENV_FILE")
4337
[ "$PERMS" -ne 600 ] && $CHMOD 600 "$ENV_FILE"
44-
45-
# Limpiamos retornos de carro y cargamos variables
4638
$SED -i 's/\r//g' "$ENV_FILE"
47-
# Cargamos variables evitando que fallen si hay líneas vacías o comentarios
48-
set -a
49-
# shellcheck disable=SC1090
50-
. "$ENV_FILE"
51-
set +a
39+
set -a; . "$ENV_FILE"; set +a
5240
else
53-
echo "❌ Error: Archivo .env no encontrado en $DIR" >&2
54-
exit 1
41+
echo "❌ Error: .env no encontrado." >&2; exit 1
5542
fi
5643

57-
# Validaciones de variables críticas
5844
INTERFACE=${INTERFACE:-"ens6"}
5945
LIMITE_DIARIO=${LIMITE_DIARIO:-0.1}
6046
LIMITE_MENSUAL=${LIMITE_MENSUAL:-900}
6147
PRECIO_GB=${PRECIO_GB:-0}
6248
TOKEN=${TOKEN:-""}
6349
CHAT_ID=${CHAT_ID:-""}
50+
UMBRAL_ALERTA=${UMBRAL_ALERTA:-0.9}
51+
STEP_D=0.05
52+
STEP_M=0.1
6453

6554
STATE_DIA="$DIR/.alert_state_dia_${INTERFACE}.txt"
6655
STATE_MES="$DIR/.alert_state_mes_${INTERFACE}.txt"
56+
CONTROL_MES="$DIR/.last_month_${INTERFACE}.txt"
6757

68-
# --- 4. VERIFICACIÓN DE DEPENDENCIAS ---
69-
for cmd in "$CURL" "$JQ" "$AWK" "$VNSTAT"; do
70-
if [ ! -x "$cmd" ]; then
71-
echo "❌ Error: No se encuentra o no es ejecutable: $cmd" >&2
72-
exit 1
73-
fi
74-
done
58+
# --- 3. LÓGICA DE RESET MENSUAL ---
59+
MES_ACTUAL=$($DATE +%m)
60+
[ -f "$CONTROL_MES" ] || echo "$MES_ACTUAL" > "$CONTROL_MES"
61+
[ -f "$STATE_DIA" ] || echo "0" > "$STATE_DIA"
62+
[ -f "$STATE_MES" ] || echo "0" > "$STATE_MES"
63+
64+
if [ "$MES_ACTUAL" != "$(cat "$CONTROL_MES")" ]; then
65+
echo "0" > "$STATE_DIA"
66+
echo "0" > "$STATE_MES"
67+
echo "$MES_ACTUAL" > "$CONTROL_MES"
68+
[ -t 1 ] && echo "♻️ Cambio de mes detectado. Reiniciando contadores."
69+
fi
7570

76-
# --- 5. CAPTURA Y PROCESAMIENTO ---
77-
# Actualizamos vnstat
71+
# --- 4. CAPTURA Y PROCESAMIENTO ---
7872
$VNSTAT -u -i "$INTERFACE" > /dev/null 2>&1 || true
7973
JSON_DATA=$($VNSTAT -i "$INTERFACE" --json 2>/dev/null)
80-
81-
if [ -z "$JSON_DATA" ] || [ "$JSON_DATA" == "null" ]; then
82-
echo "❌ Error: Datos de vnstat vacíos para $INTERFACE" >&2
83-
exit 1
84-
fi
74+
[ -z "$JSON_DATA" ] || [ "$JSON_DATA" == "null" ] && exit 1
8575

8676
DIVISOR=1073741824
77+
calc_gb() { $AWK "BEGIN {printf \"%.2f\", $1 / $DIVISOR}"; }
8778

88-
# Extracción de bytes con JQ
8979
RX_D=$(echo "$JSON_DATA" | $JQ -r '(.interfaces[0].traffic.day // .interfaces[0].traffic.days) | last | .rx // 0')
9080
TX_D=$(echo "$JSON_DATA" | $JQ -r '(.interfaces[0].traffic.day // .interfaces[0].traffic.days) | last | .tx // 0')
9181
RX_M=$(echo "$JSON_DATA" | $JQ -r '(.interfaces[0].traffic.month // .interfaces[0].traffic.months) | last | .rx // 0')
9282
TX_M=$(echo "$JSON_DATA" | $JQ -r '(.interfaces[0].traffic.month // .interfaces[0].traffic.months) | last | .tx // 0')
9383

94-
# Cálculos con AWK
95-
calc_gb() { $AWK "BEGIN {printf \"%.2f\", $1 / $DIVISOR}"; }
96-
97-
RX_DIA_GB=$(calc_gb "$RX_D")
98-
TX_DIA_GB=$(calc_gb "$TX_D")
99-
TOTAL_DIA_GB=$(awk "BEGIN {printf \"%.2f\", $RX_DIA_GB + $TX_DIA_GB}")
100-
101-
RX_MES_GB=$(calc_gb "$RX_M")
102-
TX_MES_GB=$(calc_gb "$TX_M")
103-
TOTAL_MES_GB=$(awk "BEGIN {printf \"%.2f\", $RX_MES_GB + $TX_MES_GB}")
104-
105-
# --- 6. LÓGICA DE ALERTAS ---
106-
[ -f "$STATE_DIA" ] || echo "0" > "$STATE_DIA"
107-
[ -f "$STATE_MES" ] || echo "0" > "$STATE_MES"
108-
$CHMOD 600 "$STATE_DIA" "$STATE_MES"
84+
TOTAL_DIA_GB=$(awk "BEGIN {printf \"%.2f\", $(calc_gb "$RX_D") + $(calc_gb "$TX_D")}")
85+
TOTAL_MES_GB=$(awk "BEGIN {printf \"%.2f\", $(calc_gb "$RX_M") + $(calc_gb "$TX_M")}")
10986

87+
# --- 5. LÓGICA DE ALERTAS ---
11088
ULTIMO_ALERTA_DIA=$(cat "$STATE_DIA")
11189
ULTIMO_ALERTA_MES=$(cat "$STATE_MES")
11290

113-
AVISO_DIA=$(awk -v t="$TOTAL_DIA_GB" -v l="$LIMITE_DIARIO" -v u="$ULTIMO_ALERTA_DIA" 'BEGIN {print (t > l && t >= u + 0.05) ? 1 : 0}')
114-
AVISO_MES=$(awk -v t="$TOTAL_MES_GB" -v l="$LIMITE_MENSUAL" -v u="$ULTIMO_ALERTA_MES" 'BEGIN {print (t > l && t >= u + 0.1) ? 1 : 0}')
91+
ES_CRITICO=$(awk -v td="$TOTAL_DIA_GB" -v ld="$LIMITE_DIARIO" -v tm="$TOTAL_MES_GB" -v lm="$LIMITE_MENSUAL" -v u="$UMBRAL_ALERTA" 'BEGIN {print (td >= (ld*u) || tm >= (lm*u)) ? 1 : 0}')
92+
AVISO_DIA=$(awk -v t="$TOTAL_DIA_GB" -v l="$LIMITE_DIARIO" -v u="$UMBRAL_ALERTA" -v last="$ULTIMO_ALERTA_DIA" -v s="$STEP_D" 'BEGIN { inc=(t>=last+s); cross_u=(t>=l*u && last<l*u); print (inc || cross_u) ? 1 : 0 }')
93+
AVISO_MES=$(awk -v t="$TOTAL_MES_GB" -v l="$LIMITE_MENSUAL" -v u="$UMBRAL_ALERTA" -v last="$ULTIMO_ALERTA_MES" -v s="$STEP_M" 'BEGIN { inc=(t>=last+s); cross_u=(t>=l*u && last<l*u); print (inc || cross_u) ? 1 : 0 }')
11594

116-
# --- 7. SALIDA VISUAL (Modo Interactivo) ---
95+
# --- 6. SALIDA VISUAL ---
11796
if [ -t 1 ]; then
11897
echo "======================================"
119-
echo "📊 MONITOR DE RED (Interfaz: $INTERFACE))"
98+
echo "📊 MONITOR DE RED (Interfaz: $IFACE)"
12099
echo "======================================"
121-
echo "📅 Tráfico HOY: $TOTAL_DIA_GB GB (Límite: $LIMITE_DIARIO GB)"
122-
echo "🗓️ Tráfico MES: $TOTAL_MES_GB GB (Límite: $LIMITE_MENSUAL GB)"
123-
echo "🔔 Último aviso Telegram (Hoy): ${ULTIMO_ALERTA_DIA} GB"
124-
echo "🔔 Último aviso Telegram (Mes): ${ULTIMO_ALERTA_MES} GB"
100+
echo "📅 Tráfico HOY: $TOTAL_DIA_GB GB (Límite: $LIM_DIA GB)"
101+
echo "🗓️ Tráfico MES: $TOTAL_MES_GB GB (Límite: $LIM_MES GB)"
125102
echo "--------------------------------------"
126-
if [ "$AVISO_DIA" -eq 1 ] || [ "$AVISO_MES" -eq 1 ]; then
127-
echo "⚠️ LÍMITE SUPERADO - Preparando Telegram..."
128-
else
129-
echo "✅ Estado: Bajo control."
130-
fi
103+
echo "🛡️ MyIronGuard v2.0 (PolyForm NC)"
104+
echo "🏢 Empresa: hola@lksys.es"
105+
echo "⭐ Si te gusta el script, apóyame con una estrella en:"
106+
echo -e "🔗 \e[1;34mRepo: $REPO_URL\e[0m"
131107
echo "======================================"
132108
fi
133109

134-
# --- 8. ENVÍO A TELEGRAM ---
135-
if [ "$AVISO_DIA" -eq 1 ] || [ "$AVISO_MES" -eq 1 ]; then
136110

137-
COSTE_ESTIMADO=$(awk -v tx="$TOTAL_MES_GB" -v lim="$LIMITE_MENSUAL" -v p="$PRECIO_GB" \
138-
'BEGIN { if (tx > lim) printf "%.2f", (tx - lim) * p; else printf "0.00"; }')
139-
140-
formato_dinamico() {
141-
local val="$1"
142-
awk -v n="$val" 'BEGIN { if (n < 1 && n > 0) printf "%.2f MB", n * 1024; else printf "%.2f GB", n; }'
143-
}
111+
# --- 7. TELEGRAM ---
112+
if [ "$AVISO_DIA" -eq 1 ] || [ "$AVISO_MES" -eq 1 ]; then
113+
COSTE_ESTIMADO=$(awk -v tx="$TOTAL_MES_GB" -v lim="$LIMITE_MENSUAL" -v p="$PRECIO_GB" 'BEGIN { if (tx > lim) printf "%.2f", (tx - lim) * p; else printf "0.00"; }')
114+
formato_dinamico() { awk -v n="$1" 'BEGIN { if (n < 1 && n > 0) printf "%.2f MB", n * 1024; else printf "%.2f GB", n; }'; }
144115

145-
# Título fijo por seguridad y claridad
146-
TITULO="⚠️ *ALERTA DE TRÁFICO GCLOUD*"
116+
[ "$ES_CRITICO" -eq 1 ] && TITULO="⚠️ *ALERTA VPS CRÍTICA (GCLOUD)*" || TITULO="⚠️ *ALERTA VPS (GCLOUD)*"
117+
FOOTER=$([ "$ES_CRITICO" -eq 1 ] && echo -e "\n\n⭐ *¡Apoya el proyecto con una estrella!*\n$REPO_URL" || echo "")
147118

148119
MENSAJE="$TITULO
149120
-------------------------------
150121
📅 *CONSUMO DE HOY:*
151-
📥 Descarga: $(formato_dinamico "$RX_DIA_GB")
152-
📤 Subida: $(formato_dinamico "$TX_DIA_GB")
153122
📊 Total Día: *$(formato_dinamico "$TOTAL_DIA_GB")* / $LIMITE_DIARIO GB
154123
155124
🗓️ *CONSUMO DEL MES ($($DATE +%B)):*
156-
📥 Descarga: $(formato_dinamico "$RX_MES_GB")
157-
📤 Subida: $(formato_dinamico "$TX_MES_GB")
158125
✨ Total Mes: *$(formato_dinamico "$TOTAL_MES_GB")* / $LIMITE_MENSUAL GB
159126
💰 Coste Extra: *\$${COSTE_ESTIMADO}*
160127
-------------------------------
161128
🌐 Interfaz: $INTERFACE
162-
🖥️ Hostname: $($HOSTNAME_CMD)"
129+
🖥️ Hostname: $($HOSTNAME_CMD)$FOOTER"
163130

164131
if [ -n "$TOKEN" ] && [ -n "$CHAT_ID" ]; then
165-
# Generamos el JSON con JQ para neutralizar cualquier inyección en el mensaje
166132
PAYLOAD=$($JQ -n --arg cid "$CHAT_ID" --arg txt "$MENSAJE" '{chat_id: $cid, text: $txt, parse_mode: "Markdown"}')
167-
168-
RESPUESTA=$($CURL -s -m 10 -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
169-
-H "Content-Type: application/json" \
170-
-d "$PAYLOAD")
171-
172-
if echo "$RESPUESTA" | $GREP -q '"ok":true'; then
173-
echo "$TOTAL_DIA_GB" > "$STATE_DIA"
174-
echo "$TOTAL_MES_GB" > "$STATE_MES"
175-
else
176-
echo "❌ Error enviando a Telegram: $RESPUESTA" >&2
177-
fi
133+
$CURL -s -m 10 -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" -H "Content-Type: application/json" -d "$PAYLOAD" > /dev/null
134+
echo "$TOTAL_DIA_GB" > "$STATE_DIA"
135+
echo "$TOTAL_MES_GB" > "$STATE_MES"
178136
fi
179137
fi
180-

network-monitor/vps_estandar/env.example_VPS_estandar

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ LIMITE_MENSUAL=5000.0
1717

1818
# Coste por GB extra (Pon 0 si tu proveedor te da tráfico ilimitado)
1919
PRECIO_GB=0.00
20+
21+
# Umbral para aviso crítico y mensaje de estrella (0.9 = 90%)
22+
UMBRAL_ALERTA=0.9
23+

0 commit comments

Comments
 (0)