GitHub Integration — Посібник з налаштування
Phase 49.3 (Light) — webhook-нотифікації + UI sidebar feed для прив'язаних GitHub repos. Без bidirectional sync (це Phase 49.5+ Heavy).
ARC OS приймає webhook-події з прив'язаних GitHub repos і одночасно:
- Шле Telegram-нотифікацію власнику проєкту
- Оновлює sidebar feed у Workspace ContextRail (polling 30s)
Архітектура
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 (для UI feed)
└─→ shared/github-notifier.ts → Telegram (master bot token)
Підтримувані події: push, pull_request, workflow_run, issues. Решта (releases, deployments, discussions) ігноруються.
Multi-repo: один проєкт може прив'язати кілька repos (напр. frontend + backend + docs). Constraint: UNIQUE(project_name, owner, repo).
Швидке налаштування (3 хвилини)
1. Згенеруй webhook URL+secret
arc github link <project-name> <owner/repo>
Приклад:
arc github link arc-v2 SerhiiInUa/citadel-v2
CLI поверне:
- Webhook URL —
https://arc-os.co/api/webhooks/github - Secret — 32-byte hex (унікальний для кожного link)
- Покрокові інструкції для GitHub UI
2. Додай webhook у GitHub repo
На сторінці https://github.com/<owner>/<repo>/settings/hooks:
- Натисни Add webhook
- Payload URL:
https://arc-os.co/api/webhooks/github - Content type:
application/json(важливо!) - Secret: встав значення з CLI output
- Which events? → "Let me select individual events":
- ☑ Pushes
- ☑ Pull requests
- ☑ Workflow runs
- ☑ Issues
- ☑ Active
- Натисни Add webhook
GitHub одразу шле тестову подію ping — її буде silently rejected (бо ARC очікує лише підтримувані типи). Це нормально.
3. Перевір що працює
Зроби push у repo, відкрий PR або запусти workflow. Через ~1-3 секунди:
- Прийде Telegram-нотифікація власнику проєкту з іконкою + summary + GitHub-посиланням
- Sidebar feed у Workspace ContextRail оновиться (через ~30s polling)
Керування links
Список прив'язаних repos
arc github links arc-v2
Видалити link
arc github unlink arc-v2 <id>
ID береться з output arc github links. Webhook на GitHub при цьому не видаляється автоматично — invalid signatures будуть silent reject. Кращий workflow: спочатку видали webhook у GitHub UI, потім arc github unlink.
Безпека
- HMAC-SHA256 signature — кожен webhook secret =
crypto.randomBytes(32).toString('hex')(256 біт ентропії) - Timing-safe compare —
node:crypto timingSafeEqualзапобігає timing-атакам на верифікацію signature - Silent reject — invalid signatures отримують
401 ""без body (без витоку інформації для сканерів) - Rate limit — 100 req/min на проєкт (in-memory window). Перевищення →
429 Rate limited - Ліміт розміру payload — 50KB у handler, 64KB у nginx (захист від DoS)
- Multi-repo signature routing — handler шукає candidates за
repository.full_name, потім перевіряє signature кожного перш ніж accept (запобігає secret reuse cross-project) - Ізоляція public endpoint — nginx config
/api/webhooks/githubмаєauth_basic offіproxy_read_timeout 5s
Що бачиш у sidebar
ContextRail (правий panel у Workspace) показує секцію GitHub ⤵
- Автоматично прихована, якщо проєкт не має linked repos
- Останні 8 events (newest first)
- Іконка для кожної події: GitBranch (push) / GitPullRequest (PR) / CircleCheck (CI success) / CircleAlert (CI failure) / CircleDot (issues)
- Формат відносного часу: 30s, 5m, 2h, 1d
- Клік на рядок → відкриває GitHub URL у новій вкладці
- Polling кожні 30s (свіжі дані без ручного refresh)
Telegram-повідомлення
Master bot шле відформатоване повідомлення власнику проєкту:
🔀 [arc-v2] SerhiiInUa/citadel-v2
PR #42 opened: feat: add lazy worker lifecycle by @Sergei89
View on GitHub
Іконки:
- 📦 push
- 🔀 pull_request
- ✅ workflow_run (success)
- ❌ workflow_run (failure)
- ⚙️ workflow_run (other)
- 🐛 issues
Troubleshooting
Webhook повертає 401 на тестовий ping
Очікувано — ARC silently rejects unsupported events (наприклад ping). Обробляються лише production events (push, PR, workflow_run, issues).
Webhook повертає 401 на push event
- Перевір, що в GitHub webhook налаштовано
Content type: application/json(неform-urlencoded) - Перевір secret — він має точно збігатися з тим, що повернув
arc github link - Якщо secret загублено — видали link і створи заново (
arc github unlink→arc github link)
Sidebar feed порожній, хоч Telegram приходить
- Перевір, що ContextRail взагалі видно (≥1280px viewport)
- Hard refresh frontend (Ctrl+Shift+R) — компонент кешується
- Перевір DB:
sqlite3 data/citadel.db "SELECT COUNT(*) FROM github_events WHERE project_name='<name>';"
Telegram не приходить
- Перевір, що проєкт має
owner_idу DB:sqlite3 ... "SELECT name, owner_id FROM projects;" - Перевір master bot token у vault:
grep MASTER_BOT_TOKEN config/vault.json(має бути encrypted) - Webhook event у DB є, але notify failed → дивись master logs:
tmux capture-pane -t citadel-master -p | grep github-notifier
Досягнуто rate limit
Hard limit 100 req/min на проєкт. Якщо CI з тисячами runners — підвищ у shared/routes/github.ts:RATE_MAX.
API endpoints
Детально: API Reference.
| Endpoint | Auth | Опис |
|---|---|---|
POST /api/crm/projects/:name/github |
JWT | Прив'язати repo |
GET /api/crm/projects/:name/github |
JWT | Список links |
DELETE /api/crm/projects/:name/github/:id |
JWT | Відв'язати |
GET /api/crm/projects/:name/github/events?limit=N |
JWT | Список events (max 200) |
POST /api/webhooks/github |
HMAC | Public receiver |
Roadmap
| Phase | Scope | Status |
|---|---|---|
| 49.3 | Webhook receiver + Telegram | ✅ DONE |
| 49.3.1 | UI sidebar feed | ✅ DONE |
| 49.4 | API polling, Workspace GitHub tab, multi-repo dashboard | BACKLOG (P2) |
| 49.5 | Bidirectional issue sync, auto-PR review workers | BACKLOG (P2) |