GitHub Integration — Guía de configuración
Phase 49.3 (Light) — notificaciones basadas en webhooks + feed lateral en el sidebar para repos de GitHub vinculados. Sin sincronización bidireccional (eso es Phase 49.5+ Heavy).
Arc OS recibe eventos de webhook de los repos de GitHub vinculados y simultáneamente:
- Envía una notificación de Telegram al owner del proyecto
- Actualiza el feed del sidebar en el Workspace ContextRail (polling cada 30s)
Arquitectura
GitHub repo
│ (push / PR / CI / issue events)
▼
arc-os.co/api/webhooks/github
│ HMAC-SHA256 timing-safe verify (X-Hub-Signature-256)
│ Rate limit 100 req/min/project
│ Payload max 50KB
▼
shared/routes/github.ts handleGithubWebhook
├─→ DB: github_events (para el feed de UI)
└─→ shared/github-notifier.ts → Telegram (master bot token)
Eventos soportados: push, pull_request, workflow_run, issues. El resto (releases, deployments, discussions) se ignoran.
Multi-repo: un proyecto puede vincular varios repos (ej. frontend + backend + docs). Restricción: UNIQUE(project_name, owner, repo).
Configuración rápida (3 minutos)
1. Genera la URL + secret del webhook
arc github link <project-name> <owner/repo>
Ejemplo:
arc github link arc-v2 SerhiiInUa/citadel-v2
El CLI devolverá:
- Webhook URL —
https://arc-os.co/api/webhooks/github - Secret — hex de 32 bytes (único por cada vínculo)
- Instrucciones paso a paso para la UI de GitHub
2. Agrega el webhook en el repo de GitHub
En la página https://github.com/<owner>/<repo>/settings/hooks:
- Haz clic en Add webhook
- Payload URL:
https://arc-os.co/api/webhooks/github - Content type:
application/json(¡importante!) - Secret: pega el valor del output del CLI
- Which events? → "Let me select individual events":
- ☑ Pushes
- ☑ Pull requests
- ☑ Workflow runs
- ☑ Issues
- ☑ Active
- Haz clic en Add webhook
GitHub envía inmediatamente un evento ping de prueba — será rechazado silenciosamente (porque Arc OS solo espera los tipos soportados). Esto es normal.
3. Verifica que funciona
Haz un push al repo, abre un PR o ejecuta un workflow. En ~1-3 segundos:
- Llegará una notificación de Telegram al owner del proyecto con icon + resumen + enlace a GitHub
- El feed del sidebar en el Workspace ContextRail se actualizará (en ~30s de polling)
Gestión de vínculos
Lista de repos vinculados
arc github links arc-v2
Eliminar un vínculo
arc github unlink arc-v2 <id>
El ID se obtiene del output de arc github links. El webhook en GitHub no se elimina automáticamente — las firmas inválidas serán rechazadas silenciosamente. El flujo recomendado: primero elimina el webhook en la UI de GitHub, luego ejecuta arc github unlink.
Seguridad
- Firma HMAC-SHA256 — cada secret de webhook =
crypto.randomBytes(32).toString('hex')(256 bits de entropía) - Comparación timing-safe —
node:crypto timingSafeEqualpreviene timing attacks en la verificación de firmas - Rechazo silencioso — las firmas inválidas reciben
401 ""sin body (sin filtración de información a scanners) - Rate limit — 100 req/min por proyecto (ventana en memoria). Si se supera →
429 Rate limited - Límite de tamaño de payload — 50KB en el handler, 64KB en nginx (protección contra DoS)
- Enrutamiento de firmas multi-repo — el handler busca candidatos por
repository.full_name, luego verifica la firma de cada uno antes de aceptar (previene reutilización de secrets entre proyectos) - Aislamiento del endpoint público — la configuración de nginx para
/api/webhooks/githubtieneauth_basic offyproxy_read_timeout 5s
Qué ves en el sidebar
El ContextRail (panel derecho en el Workspace) muestra la sección GitHub ⤵
- Se oculta automáticamente si el proyecto no tiene repos vinculados
- Los últimos 8 eventos (más recientes primero)
- Icono por evento: GitBranch (push) / GitPullRequest (PR) / CircleCheck (CI success) / CircleAlert (CI failure) / CircleDot (issues)
- Formato de tiempo relativo: 30s, 5m, 2h, 1d
- Haz clic en una fila → abre la URL de GitHub en una nueva pestaña
- Polling cada 30s (datos frescos sin refresh manual)
Mensajes de Telegram
El Master Bot envía un mensaje formateado al owner del proyecto:
🔀 [arc-v2] SerhiiInUa/citadel-v2
PR #42 opened: feat: add lazy worker lifecycle by @Sergei89
View on GitHub
Iconos:
- 📦 push
- 🔀 pull_request
- ✅ workflow_run (success)
- ❌ workflow_run (failure)
- ⚙️ workflow_run (other)
- 🐛 issues
Solución de problemas
El webhook devuelve 401 en el ping de prueba
Es lo esperado — Arc OS rechaza silenciosamente los eventos no soportados (como ping). Solo se procesan los eventos de producción (push, PR, workflow_run, issues).
El webhook devuelve 401 en un evento push
- Verifica que en el webhook de GitHub esté configurado
Content type: application/json(noform-urlencoded) - Verifica el secret — debe coincidir exactamente con el que devolvió
arc github link - Si se perdió el secret — elimina el vínculo y créalo de nuevo (
arc github unlink→arc github link)
El feed del sidebar está vacío aunque llegan mensajes de Telegram
- Verifica que el ContextRail sea visible (viewport ≥1280px)
- Recarga forzada el frontend (Ctrl+Shift+R) — el componente se cachea
- Verifica la DB:
sqlite3 data/citadel.db "SELECT COUNT(*) FROM github_events WHERE project_name='<name>';"
No llegan mensajes de Telegram
- Verifica que el proyecto tenga
owner_iden la DB:sqlite3 ... "SELECT name, owner_id FROM projects;" - Verifica el token del Master Bot en el vault:
grep MASTER_BOT_TOKEN config/vault.json(debe estar cifrado) - El evento webhook está en la DB pero la notificación falló → revisa los logs del master:
tmux capture-pane -t citadel-master -p | grep github-notifier
Se alcanzó el rate limit
El límite máximo es 100 req/min por proyecto. Si usas CI con miles de runners — auméntalo en shared/routes/github.ts:RATE_MAX.
API endpoints
Detalles: API Reference.
| Endpoint | Auth | Descripción |
|---|---|---|
POST /api/crm/projects/:name/github |
JWT | Vincular repo |
GET /api/crm/projects/:name/github |
JWT | Listar vínculos |
DELETE /api/crm/projects/:name/github/:id |
JWT | Desvincular |
GET /api/crm/projects/:name/github/events?limit=N |
JWT | Listar eventos (máx. 200) |
POST /api/webhooks/github |
HMAC | Receptor público |
Roadmap
| Phase | Alcance | Estado |
|---|---|---|
| 49.3 | Receptor de webhooks + Telegram | ✅ DONE |
| 49.3.1 | Feed del sidebar en la UI | ✅ DONE |
| 49.4 | Polling de API, pestaña GitHub en Workspace, dashboard multi-repo | BACKLOG (P2) |
| 49.5 | Sincronización bidireccional de issues, workers de revisión automática de PRs | BACKLOG (P2) |