Plataforma de inteligencia de Ciberseguridad e IA que recolecta, analiza y distribuye noticias automáticamente vía Telegram. Funciona 24/7 mediante GitHub Actions y Cloudflare Workers.
┌─────────────┐ Telegram ┌─────────────────────┐ dispatches ┌──────────────────┐
│ Usuario │ ◄───────────────► │ Cloudflare Workers │ ───────────────► │ GitHub Actions │
└─────────────┘ Webhook │ (api/webhook.js) │ Workflow │ (run_job.py) │
└─────────────────────┘ └────────┬─────────┘
│
┌────────▼─────────┐
│ RECOLECCIÓN │
│ RSS + APIs + │
│ Telegram Chans │
└────────┬─────────┘
│
┌────────▼─────────┐
│ INTELIGENCIA │
│ Groq (config.) │
│ MITRE ATT&CK │
│ IoC Extraction │
│ Severity Class. │
└────────┬─────────┘
│
┌─────────────────────┐ guarda datos ┌──────▼──────────┐
│ Repo: cYHBernews │ ◄──────────────── │ DISTRIBUCIÓN │
└─────────────────────┘ │ Telegram │
▲ └─────────────────┘
│
┌───────┴───────┐
│ noticias.json │
│ + TTPs + IoCs │
└───────────────┘
- GitHub Actions (
.github/workflows/bot.yml): Motor del bot. Se ejecuta cada 3 horas o manualmente. Recolecta → Analiza → Distribuye. - Cloudflare Workers (
api/webhook.js): Receptor de Telegram. Dispara el Action vía/noticias. - Sources (
sources/): RSS/Atom, NVD CVE API, Exploit-DB, GreyNoise y previews públicos de canales de Telegram. Vulners está desactivado en el job. - Intelligence (
intelligence/): Análisis avanzado — clasificación MITRE ATT&CK, extracción de IoCs, clasificación de severidad. - Persistencia (
DevCop95/cYHBernews):bot-state/noticias.json(ramabot-state, archivonoticias.json) conserva el historial y los estados de entrega.main/noticias.jsonrecibe una única instantánea por ejecución, solo con noticias confirmadas y sin metadatos de Telegram. - CI (
.github/workflows/ci.yml): Pruebas offline Python/Worker, cobertura y auditoría de dependencias antes de publicar.
Crear el environment production en GitHub, restringir sus ramas de despliegue a main y mover allí los secretos del publicador. Eliminar las copias equivalentes de los secretos del repositorio para que otra rama no pueda acceder a ellos modificando el workflow. Si se exigen revisores, cada ejecución programada esperará aprobación; elegir esa política conscientemente para el bot automático.
| Secreto | Descripción |
|---|---|
GIT_TOKEN |
Token dedicado fine-grained: solo DevCop95/cYHBernews, permiso Contents: read/write |
TELEGRAM_TOKEN |
Token del bot obtenido con @BotFather |
TELEGRAM_CHAT_ID |
Tu ID de Telegram (obtenido con @userinfobot) |
GROQ_API_KEY |
API Key de console.groq.com |
UNSPLASH_ACCESS_KEY |
(Opcional) Para imágenes aleatorias |
NVD_API_KEY |
(Opcional) API Key de NVD para mejor rate limit |
GREYNOISE_API_KEY |
(Opcional) API Key de GreyNoise Community |
GROQ_API_KEY_2, GROQ_API_KEY_3, GROQ_API_KEYS |
(Opcional) Claves adicionales; la última variable admite CSV |
NVIDIA_API_KEY |
(Opcional) Proveedor alternativo si Groq no está disponible |
El fallback histórico GH_PAT sigue admitido para no romper instalaciones existentes; migrarlo a GIT_TOKEN con alcance limitado. No reutilizar este token en el Worker. Los modelos se configuran con GROQ_MODEL, GROQ_FALLBACK_MODEL y NVIDIA_MODEL como variables de Actions.
En tu dashboard de Cloudflare Workers > tu worker > Settings > Variables and Secrets:
| Variable | Valor |
|---|---|
TELEGRAM_TOKEN_ENV |
El mismo token de Telegram |
TELEGRAM_CHAT_ID_ENV |
Tu ID de Telegram |
GH_PAT_ENV |
Token distinto: solo DevCop95/dev101_bot, permiso Actions: write |
TELEGRAM_WEBHOOK_SECRET |
Secreto aleatorio independiente, 1-256 caracteres de A-Z, a-z, 0-9, _, -; usar al menos 32 caracteres aleatorios |
TELEGRAM_USER_ID_ENV |
(Opcional) ID numérico positivo del usuario autorizado, además del chat |
Configurar cada entorno por separado. wrangler.toml declara el Durable Object SQLite WEBHOOK_STATE y su migración para default y production. El despliegue del Worker debe aplicar esa migración; no basta con copiar el archivo JavaScript. La configuración incompleta devuelve 503 y no procesa comandos.
Workers Builds instala automáticamente requirements.txt cuando la raíz del build es /. .python-version fija Python 3.11, igual que Actions, para usar los wheels Linux cuyos hashes incluye el lock y evitar compilar lxml sin libxml2/libxslt. Mantener esa versión alineada con CI; no eliminar hashes para resolver un fallo de instalación.
Registrar el webhook después de configurar secretos y desplegar el Worker. El siguiente ejemplo es una operación real de configuración, no una prueba: requiere TELEGRAM_TOKEN, TELEGRAM_WEBHOOK_SECRET y WEBHOOK_URL exportados en un entorno de confianza. No introducir tokens en el navegador ni imprimir respuestas que puedan contener datos sensibles.
import os
import requests
token = os.environ["TELEGRAM_TOKEN"]
response = requests.post(
f"https://api.telegram.org/bot{token}/setWebhook",
json={
"url": os.environ["WEBHOOK_URL"],
"secret_token": os.environ["TELEGRAM_WEBHOOK_SECRET"],
"allowed_updates": ["message"],
},
timeout=15,
)
print("Webhook registrado" if response.ok and response.json().get("ok") else "Registro fallido")El Worker comprueba X-Telegram-Bot-Api-Secret-Token, chat y usuario opcional. Deduplica update_id durante siete días con almacenamiento persistente y reserva atómica; /noticias tiene un intervalo mínimo de 60 segundos. Cada entorno mantiene su propio estado. Ante un dispatch incierto, revisar Actions antes de enviar otro comando: no existe una garantía de ejecución exactamente una vez.
| Comando | Descripción |
|---|---|
/noticias |
Fuerza búsqueda y envío de noticias |
/help |
Muestra comandos disponibles |
/start |
Muestra la ayuda inicial |
Envío automático cada 3 horas vía cron en GitHub Actions.
dev101_bot/
├── .github/workflows/bot.yml # GitHub Actions (cron + dispatch)
├── api/webhook.js # Cloudflare Worker — Telegram webhook
├── sources/ # Módulos de recolección
│ ├── rss_feeds.py # 15 fuentes RSS (ES + EN)
│ ├── nvd_cve.py # NVD CVE API 2.0 (NIST)
│ ├── exploitdb.py # Exploit-DB RSS; helper Vulners no conectado
│ ├── greynoise.py # GreyNoise Community API
│ └── telegram_monitor.py # Previews oficiales t.me/s
├── intelligence/ # Análisis de inteligencia
│ ├── mitre_tagger.py # Clasificación MITRE ATT&CK (Groq)
│ ├── ioc_extractor.py # Extracción de IoCs (regex + STIX)
│ └── severity_classifier.py # Clasificación de severidad
├── run_job.py # Orquestador principal
├── groq_rotation.py # Rotación, cooldown y fallback NVIDIA
├── tests/ # Regresiones de fuentes, inteligencia y entregas
├── tools/run_tests.py # Runner aislado, sin red ni .env
├── tools/update_attack_catalog.py # Generador del catálogo MITRE versionado
├── api/webhook.test.mjs # Pruebas Node del Worker y almacenamiento
├── intelligence/attack_catalog.json # Enterprise ATT&CK v17.1 completo
├── requirements.txt
├── requirements-dev.txt
├── wrangler.toml
└── .env.example
| Fuente | Categoría | Idioma |
|---|---|---|
| CyberSecurity News | Ciberseguridad / IA | 🇪🇸 |
| WeLiveSecurity (ESET) | Ciberseguridad | 🇪🇸 |
| DragonJAR | Ciberseguridad | 🇪🇸 |
| El Lado Del Mal | Ciberseguridad | 🇪🇸 |
| Una al Día (Hispasec) | Ciberseguridad | 🇪🇸 |
| Bleeping Computer | Ciberseguridad | 🇬🇧 (auto-traducido) |
| The Hacker News | Ciberseguridad | 🇬🇧 (auto-traducido) |
| Krebs on Security | Ciberseguridad | 🇬🇧 (auto-traducido) |
| Dark Reading | Ciberseguridad | 🇬🇧 (auto-traducido) |
| Schneier on Security | Ciberseguridad | 🇬🇧 (auto-traducido) |
| SANS ISC | Ciberseguridad | 🇬🇧 (auto-traducido) |
| The Record | Ciberseguridad | 🇬🇧 (auto-traducido) |
| Wired Security | Ciberseguridad | 🇬🇧 (auto-traducido) |
| IA en Español (Substack) | IA | 🇪🇸 |
| Xataka IA | IA | 🇪🇸 |
| Fuente | Tipo | Costo |
|---|---|---|
| NVD CVE API 2.0 | Vulnerabilidades CVSS v4/v3 ≥ 7.0, incluyendo críticas | Gratuita |
| Exploit-DB RSS | Exploits públicos | Gratuita |
| GreyNoise Community | IPs maliciosas trending | Gratuita |
Vulners conserva un helper probado, pero no está conectado al job porque su API anónima dejó de funcionar. Los permisos y límites de GreyNoise dependen de la cuenta. NVD ordena por CVSS después de paginar, con máximo de 10 páginas de 2.000 registros; un fallo parcial o límite alcanzado se registra en logs.
| Canal | Temática |
|---|---|
vx-underground (vxunderground) |
Malware e inteligencia de amenazas |
CVE Notify (cveNotify) |
Vulnerabilidades |
Security Harvester (secharvester) |
Inteligencia de amenazas |
Cyber Security Channel (Cyber_Security_Channel) |
Ciberseguridad |
Android Malware (androidMalware) |
Amenazas Android |
Cada noticia pasa por este pipeline:
- Recolección → RSS, APIs, Telegram channels
- Filtro de relevancia → Groq (modelo configurable por
GROQ_MODEL) - Resumen IA → Estilo analista CTI senior
- Extracción IoCs → URLs, IPs públicas normalizadas, dominios, hashes y CVEs, incluyendo indicadores defanged. Una coincidencia no demuestra maliciosidad.
- Clasificación MITRE → IDs y nombres del catálogo Enterprise ATT&CK v17.1, incluyendo históricos. IDs desconocidos se descartan; la inferencia del modelo no es evidencia confirmada.
- Severidad → 🔴 Crítica / 🟠 Alta / 🟡 Media / 🟢 Baja / 🔵 Info
- Deduplicación → Similitud Jaccard + URLs ya publicadas
- Persistencia → GitHub
noticias.jsonen la ramabot-state, mensaje preparado en estadopending - Distribución → Reserva
sending, envío a Telegram y confirmaciónsentconmessage_id - Publicación web → Una instantánea en
main/noticias.json, sin estados intermedios
La utilidad iocs_to_stix() está disponible y probada, pero el job no exporta bundles STIX automáticamente. RSS y Telegram comparan timestamps completos en UTC: se rechazan fechas futuras o inválidas y se conservan entradas sin fecha.
El límite es de cinco noticias nuevas y doce llamadas lógicas de IA por ejecución, contando resumen y MITRE; los reintentos internos de proveedor pueden producir más peticiones HTTP. Groq aplica cooldown recuperable a fallos transitorios en vez de invalidar permanentemente una clave válida.
La primera ejecución crea automáticamente la rama bot-state desde main; requiere que GIT_TOKEN pueda crear esa rama con su permiso Contents: read/write. La copia conserva los estados existentes, incluidos pendientes e inciertos. Una rama ya existente nunca se reinicializa. No eliminarla ni fusionarla a main: es el historial autoritativo del bot y su cola de entregas.
Los registros históricos sin campo telegram se consideran ya publicados y no se reenvían. Los nuevos registros incluyen estado, número de intentos y un identificador único de reserva. La deduplicación y el recorte del historial nunca eliminan entregas pendientes o inciertas.
| Estado | Comportamiento |
|---|---|
pending |
Guardado, todavía no enviado |
sending |
Reserva persistida antes de la petición; si sobrevive a un reinicio pasa a uncertain |
sent |
Telegram confirmó el envío; se conserva message_id y sent_at |
failed |
Rechazo confirmado o fallo de conexión seguro; reintento en otro run, respetando retry_at, hasta cinco intentos |
uncertain |
No puede determinarse si Telegram aceptó; no se reenvía automáticamente |
Una entrega bloqueada detiene el procesamiento y hace fallar Actions, en vez de perder noticias silenciosamente. Las entregas ya confirmadas sí se publican, leyendo el estado persistido y no una copia en memoria. Los pendientes anteriores se resuelven antes de recolectar más noticias. Un conflicto de SHA aborta sin sobrescribir datos ajenos; una escritura de GitHub con respuesta perdida se reconcilia por lectura antes de continuar. Si falla solo la publicación web, el siguiente run vuelve a intentarla sin reenviar las noticias a Telegram, incluso si no hay noticias nuevas.
Para recuperar una entrega incierta, pausar los workflows y cualquier proceso local y revisar el mensaje en el chat. Corregir noticias.json en la rama bot-state, no en main. Si ya existe el mensaje, marcar telegram.status como sent y registrar el message_id. Solo si se confirma que no existe, cambiar a pending, conservar text, reiniciar attempts a 0 y eliminar retry_at/error. Hacer la corrección mediante una escritura que respete el SHA actual y reanudar el job. No eliminar el campo telegram ni reiniciar estados a ciegas: eso puede perder o duplicar entregas.
Ambas ramas pueden ser públicas: no introducir secretos en mensajes ni metadatos. Los checkpoints se guardan en bot-state, fuera de la rama de Pages y del filtro del workflow Split news data (main, noticias.json). Así, las escrituras internas no disparan publicaciones concurrentes. Solo se modifica main una vez por ejecución si la instantánea pública cambió; la rama de estado no debe configurarse como fuente de Pages.
requests
beautifulsoup4
lxml
groq
httpx
python-dotenv
cloudscraper
Requisitos: Python 3.11 o 3.12 y Node 22 para las pruebas del Worker. requirements.txt fija versiones directas y transitivas con hashes para Linux/Windows x64. Usar un entorno virtual; los comandos de instalación y auditoría consultan índices externos, pero las pruebas no necesitan red ni credenciales.
python -m pip install --require-hashes --only-binary=:all: -r requirements.txt
python -m pip install -r requirements-dev.txt
python -B tools/run_tests.py
node --test api/webhook.test.mjs
python -m coverage run tools/run_tests.py
python -m coverage report
python -m pip_audit --strict --require-hashes -r requirements.txt --progress-spinner offEl runner elimina credenciales del entorno, bloquea lecturas .env y conexiones de red, y solo descubre test_run_job.py y tests/test_*.py. Los diagnósticos locales ignorados por Git (test_scrapers.py, verify_rss.py) no forman parte de la suite y pueden estar obsoletos; no usar descubrimiento indiscriminado desde la raíz. python run_job.py sí realiza publicación real.
CI ejecuta estas comprobaciones para PRs/push y auditoría periódica; el publicador depende de que pasen y solo admite main. La cobertura combinada de líneas/ramas exige un mínimo global del 80% en los módulos de producción. Los requisitos de desarrollo están fijados directamente, pero sus transitivas aún no tienen lock con hashes.
Para actualizar MITRE, revisar ATTACK_VERSION en tools/update_attack_catalog.py, ejecutar el generador y revisar el diff de intelligence/attack_catalog.json. El generador consulta únicamente el bundle público oficial, registra su SHA256 y crea un artefacto determinista; el bot utiliza ese artefacto sin descargar catálogos en producción.
MIT © 2026 DevYHB