Skip to content

halilibrahimd27/api-sentinel

Repository files navigation

🛰️ API-Sentinel

3. parti API'lerin response schema'ları sessizce değiştiğinde, sizden önce siz fark edin.

Plugin tabanlı · severity-aware · sıfır-config ayağa kalkan API izleme sistemi

GitHub Stars GitHub Forks Python FastAPI SQLite Docker License

⭐ İşine yaradıysa yıldız bırak — production'da yangın söndürme şansını arttırır.


TL;DR

Sürekli kullandığınız 3. parti API'ler — Iyzico, ParamPos, Twitter/X, Wakapi, Sentry, Slack, sizinki — bir günden ötekine user_id'yi userId yapar, amount'ı string'e çevirir, ya da bir alanı sessizce kaldırırlar. Production'da bunu kullanıcıyla aynı anda öğrenmek istemezsiniz.

API-Sentinel arka planda her endpoint'i belirlediğiniz aralıklarla çağırır, JSON response'unun schema'sını (alanlar, tipleri, nullable, enum, derinlik vs.) hashleyerek snapshot'lar, son snapshot ile karşılaştırır ve kırılma seviyesine göre (CRITICAL / WARNING / INFO) e-posta, SMS, webhook veya yazdığınız herhangi bir kanal üzerinden alert gönderir.

┌────────┐  scrape  ┌──────────────┐  diff   ┌──────────┐  severity  ┌────────┐
│  3rd   ├─────────▶│ schema       │────────▶│  differ  │───────────▶│ alert  │
│  API   │   N dk   │ extractor    │         │ (deepdiff)│            │ router │
└────────┘          └──────┬───────┘         └──────────┘            └───┬────┘
                           │                                             │
                           ▼                                             ▼
                  ┌─────────────────┐                          ┌─────────────────┐
                  │ SQLite + JSON   │                          │ E-mail · SMS ·  │
                  │ schema arşivi   │                          │ Webhook · ...   │
                  └─────────────────┘                          └─────────────────┘

İçindekiler


Neden API-Sentinel?

Senaryo API-Sentinel'siz API-Sentinel ile
3rd party data.user_iddata.userId rename İlk patlamayı son kullanıcı bildirir 5 dk içinde CRITICAL alert + diff snapshot
Auth header tipini değiştirir (BearerBasic) 401 fırtınası, sessiz drop'lar Auth değişimi CRITICAL kategorisinde, ayrı kanaldan alert
Değer int iken artık string JSON parse / cast hataları, mobile crash type_changed ile CRITICAL alert + eski/yeni schema diff
Yeni alan eklemiş, eski hala çalışıyor Bilinmiyor, gözden kaçıyor INFO seviyesinde haber, ekip backlog'a alıyor
Bir alan nullable olmaktan çıktı Random NPE'ler WARNING alert, kontrat netleştiriliyor

Tasarım felsefesi: Hiçbir entegrasyon — alert kanalı, auth yöntemi, storage backend, provider — hardcoded değildir. Yeni bir kanal eklemek için bir Python dosyası bırakıp YAML'da etkinleştirmek yeterli. Sıfır plugin ile bile sistem ayağa kalkar; alert atmaz, sadece izler.


Mimari

Plugin Registry Pattern

core/registry.py üzerinde merkezi PluginRegistry:

┌──────────────────── PluginRegistry ────────────────────┐
│                                                        │
│  alert_channels:  {email: EmailAlertChannel,           │
│                    sms: SmsAlertChannel,               │
│                    webhook: WebhookAlertChannel, ...}  │
│                                                        │
│  auth_handlers:   {bearer: BearerAuth,                 │
│                    basic: BasicAuth,                   │
│                    api_key: ApiKeyAuth,                │
│                    oauth2: OAuth2Auth, ...}            │
│                                                        │
│  storage_backends:{sqlite: SqliteStorageBackend,       │
│                    file: FileStore, ...}               │
│                                                        │
└────────────────────────────────────────────────────────┘

auto_discover(package_path) ile her plugin dizinindeki .py dosyaları import edilir, BaseAlertChannel / BaseAuthHandler türevleri otomatik register edilir. Yeni dosya bırak, restart et, hazır.

Akış

┌────────────────┐
│   Scheduler    │  APScheduler AsyncIOScheduler
│ (her endpoint  │  endpoint başına bağımsız cron/interval
│  için ayrı job)│
└───────┬────────┘
        ▼
┌────────────────┐  httpx async client
│   Fetcher      │  auth handler (bearer/basic/api_key/oauth2) inject eder
└───────┬────────┘  retry, timeout, status code tracking
        ▼
┌────────────────┐  JSON / XML / TEXT / RSS desteği
│ Schema         │  pydantic-benzeri ağaç:
│ Extractor      │    {field, type, nullable, enum, depth, format}
└───────┬────────┘
        ▼
┌────────────────┐  deepdiff ile previous vs current
│   Differ       │  her diff item'ı için severity hesaplar
└───────┬────────┘
        ▼
┌────────────────┐  cooldown bastırma (alert flood koruması)
│ Alert Router   │  her aktif kanala paralel async dispatch
└───────┬────────┘  başarısız kanalı log'lar, diğerlerini bekletmez
        ▼
┌────────────────┐  SQLite default · FileStore opsiyonel
│   Storage      │  schemas, changes, alerts, providers, endpoints,
│                │  credentials (Fernet ile şifreli), settings
└────────────────┘

Storage Layout

/app/data/
  schemas.db          ← SQLite (providers, endpoints, changes, alerts, ...)

/app/schemas/
  iyzico/
    payment_create/
      2026-04-30T12:00:00Z.json    ← snapshot
      2026-04-30T12:05:00Z.json
      ...
  twitter/
    user_lookup/
      ...

Servisler

schema-monitor (ana servis, 8080)

  • FastAPI + uvicorn + APScheduler (AsyncIOScheduler)
  • Plugin tabanlı alert / auth / storage
  • Web Dashboard (Tailwind CSS + Alpine.js, vanilla template)
  • REST API (provider/endpoint/credential/changes/alerts CRUD)
  • Auth Middleware (token bazlı)
  • Rate Limiting (check endpoint'leri için 10 req/dk)
  • Credential şifreleme (Fernet)
  • Alert cooldown (default 300 sn, tekrar bastırma)
  • /health, /metrics endpoint'leri (Prometheus uyumlu)

changelog-watcher (yardımcı servis)

  • 3rd party API'lerin changelog sayfalarını scrape eder (HTML/Markdown/RSS)
  • Yeni post tespit edilirse schema-monitor'a webhook atarak proaktif alert üretir
  • Kullanım: API sağlayıcı duyurmadan önce siz yakalayın
  • Hedefler changelog-watcher/config/targets.yaml ile tanımlanır

middleware/ (opsiyonel app-side hook'lar)

  • dotnet/ThirdPartyApiMiddleware.cs — ASP.NET Core middleware: outgoing HTTP isteklerini intercept edip API-Sentinel'e raporlar.
  • laravel/ThirdPartyApiMonitor.php — Laravel HTTP client macro / middleware: aynı işi PHP tarafında yapar.

Severity Matrisi

core/severity.py — diff'ten alert seviyesine deterministik eşleşme.

Değişiklik Severity Neden
field_removed 🔴 CRITICAL Mevcut tüketici breaks
type_changed 🔴 CRITICAL Cast hataları, JSON parse fail
array_item_schema_changed 🔴 CRITICAL Liste içindeki yapı değişti
auth_changed 🔴 CRITICAL 401 fırtınası
nullable_changed_to_false 🟡 WARNING Beklenmedik NOT NULL
required_field_added 🟡 WARNING Eksik gönderim → 4xx
enum_value_removed 🟡 WARNING Switch/case düşer
depth_changed 🟡 WARNING Nesting değişti, parser etkilenir
format_changed 🟡 WARNING date-timedate, regex format
field_added 🔵 INFO Tüketici geriye uyumlu
enum_value_added 🔵 INFO Yeni state, izlenmeli
status_code_changed_2xx 🔵 INFO 200 → 201 vb.

Bu tablo core/severity.py'da kanonik tanımlıdır — değiştirmeyin. Yeni diff türü eklemek istersek aynı dosyada genişletilir.


Hızlı Başlangıç

Önkoşullar

  • Docker 24+ ve Docker Compose v2
  • 512 MB RAM minimum (önerilen 1 GB)
  • Linux/macOS/WSL2

1) Klonla

git clone https://github.com/halilibrahimd27/api-sentinel.git
cd api-sentinel

2) Ortam değişkenleri

cp .env.example .env
# Üretimde MUTLAKA değiştirilmesi gereken alanlar:
#   SECRET_KEY  → openssl rand -base64 32
#   AUTH_ENABLED=true ise ADMIN_PASSWORD belirleyin

3) Stack'i ayağa kaldır

docker compose up -d
docker compose ps

4) İlk login

Tarayıcı → http://localhost:8080
Kullanıcı : admin
Şifre     : <ADMIN_PASSWORD veya SECRET_KEY>

5) İlk endpoint'i ekle

  1. Providers sekmesi → + Yeni Provider → ad: iyzico
  2. Endpoints+ Yeni Endpoint:
    • URL: https://api.iyzico.com/payment/auth
    • Interval: 5m
    • Auth: bearer + token
  3. Manuel tetikle veya 5 dk bekle → ilk snapshot atılır.
  4. Alert kanalı ekle (Settings → Alert Channels → e-mail/SMS/webhook).

6) Doğrulama

curl http://localhost:8080/health
curl http://localhost:8080/metrics       # Prometheus formatı
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/api/providers

Web UI Turu

Sayfa Ne yapar?
Dashboard Stats grid (toplam provider, endpoint, son 24 saatteki değişimler), severity dağılım chart'ı, son alert'ler timeline.
Providers Provider CRUD. Her provider'ın endpoint sayısı, son sağlık durumu, ortalama response time.
Endpoints Endpoint CRUD. URL, interval, auth tipi, son fetch durumu, son schema diff'i (collapsible).
Changes Tüm schema değişiklikleri (filter: severity, provider, tarih). Detayda eski vs yeni schema yan yana, diff highlight.
Alerts Alert geçmişi, hangi kanaldan gönderildi, başarılı/başarısız. Tekrar gönder butonu.
Channels Alert kanallarını aktif/pasif yapma, config doğrulama, "Test Mesajı Gönder".
Plugins Discover edilmiş tüm plugin'leri listele (alerts/auth/store). Hangileri aktif, hangileri config eksik.
Settings Cooldown süreleri, log seviyesi, schema retention, dump/restore.

Plugin Yazımı

Yeni Alert Kanalı (örnek: Slack)

schema-monitor/alerts/slack.py:

from alerts.base import BaseAlertChannel
import httpx

class SlackAlertChannel(BaseAlertChannel):
    """Slack incoming webhook üzerinden alert gönderir."""

    channel_name = "slack"

    @classmethod
    def required_env_vars(cls) -> list[str]:
        return []  # config webhook_url üzerinden gelir

    def validate_config(self, config: dict) -> bool:
        return bool(config.get("webhook_url", "").startswith("https://hooks.slack.com/"))

    async def send(self, severity, title, message, details) -> bool:
        emoji = {"CRITICAL": "🔴", "WARNING": "🟡", "INFO": "🔵"}[severity]
        payload = {
            "text": f"{emoji} *{title}*\n{message}",
            "attachments": [{"text": str(details), "color": severity.lower()}],
        }
        async with httpx.AsyncClient(timeout=10) as client:
            resp = await client.post(self.config["webhook_url"], json=payload)
        return resp.status_code == 200

schema-monitor/config/alerts.yaml:

channels:
  slack:
    enabled: true
    webhook_url: https://hooks.slack.com/services/T00/B00/XXX
    min_severity: WARNING

Container'ı restart et → Web UI > Plugins > slack görünür ve aktif.

Yeni Auth Handler (örnek: HMAC-imzalı)

schema-monitor/auth/hmac.py:

from auth.base import BaseAuthHandler
import hmac, hashlib, time

class HmacAuthHandler(BaseAuthHandler):
    auth_name = "hmac"

    def apply(self, request, credentials):
        timestamp = str(int(time.time()))
        signature = hmac.new(
            credentials["secret"].encode(),
            f"{timestamp}{request.url}".encode(),
            hashlib.sha256,
        ).hexdigest()
        request.headers["X-Timestamp"] = timestamp
        request.headers["X-Signature"] = signature
        return request

Yeni Storage Backend

store/base.py'da 25 metodlu abstract interface var. PostgreSQL, MongoDB, S3 backend'i yazmak için bu interface'i uygulayan bir sınıf yeterli.


Middleware Entegrasyonları

  1. parti API'ye giden istekleri uygulama tarafından monitör etmek için. Schema-monitor zaten dışarıdan endpoint çağırıyor; middleware ekstra bir gerçek-zamanlı katmandır: prod trafiğindeki schema'yı da raporlar.

.NET (ASP.NET Core)

// Program.cs
app.UseMiddleware<ThirdPartyApiMiddleware>(new ThirdPartyApiMiddlewareOptions {
    SentinelUrl = "http://api-sentinel-monitor:8080",
    ApiToken = builder.Configuration["Sentinel:Token"],
    Provider = "iyzico"
});

middleware/dotnet/ThirdPartyApiMiddleware.cs referans implementasyondur.

Laravel

// app/Providers/AppServiceProvider.php
Http::macro('monitored', fn($provider) =>
    Http::withMiddleware(new ThirdPartyApiMonitor($provider))
);

// Kullanım:
Http::monitored('iyzico')->post('https://api.iyzico.com/payment/auth', $payload);

API Referansı

Tüm /api/* endpoint'leri Authorization: Bearer <TOKEN> ister (AUTH_ENABLED=true iken). Token /api/auth/login ile alınır.

Monitoring

GET  /health                 Liveness probe
GET  /metrics                Prometheus-formatlı metrics

Auth

POST /api/auth/login         {username, password} → {token}
POST /api/auth/logout        Token'ı geçersiz kıl

Provider / Endpoint

GET    /api/providers
POST   /api/providers
PUT    /api/providers/{name}
DELETE /api/providers/{name}

GET    /api/providers/{name}/endpoints
POST   /api/providers/{name}/endpoints
PUT    /api/providers/{name}/endpoints/{ep}
DELETE /api/providers/{name}/endpoints/{ep}

Credential

GET    /api/providers/{name}/credentials       (key listesi — value asla dönmez)
POST   /api/providers/{name}/credentials       {key, value}
DELETE /api/providers/{name}/credentials/{key}

Değişiklik

GET  /api/changes?severity=CRITICAL&provider=iyzico&limit=50&offset=0
GET  /api/changes/{id}
POST /api/changes/{id}/acknowledge

Manuel Tetikleme

POST /api/check/{provider}/{endpoint}      Tek endpoint
POST /api/check-all                        Tüm endpoint'ler (rate-limited)

Plugin

GET /api/plugins                  Tüm plugin'ler
GET /api/plugins/{type}           type: alerts | auth | store
GET /api/plugins/{type}/{name}/status

Alert Kanalı

GET    /api/alerts/channels
POST   /api/alerts/channels                  {name, config}
PUT    /api/alerts/channels/{name}
DELETE /api/alerts/channels/{name}
POST   /api/alerts/test/{channel_name}       Test mesajı
GET    /api/alerts/history?limit=100

Ayarlar / Durum

GET  /api/settings
POST /api/settings
POST /api/settings/clear              Tüm verileri sil (irreversible!)

GET  /api/statuses                    Endpoint sağlık özeti
GET  /api/stats                       Genel istatistikler

Güvenlik

Katman Mekanizma
Auth core/auth_middleware.py — token tabanlı, AUTH_ENABLED=true ile dashboard + tüm /api/* korumalı. Login → JWT-benzeri token, /api/auth/logout ile iptal.
Şifreleme Provider credential'ları cryptography.Fernet ile at-rest şifreli (key = SECRET_KEY). DB dump'ı ele geçse de plain credential leak olmaz.
Rate Limit _check_rate_limit() — IP başına, /api/check/* endpoint'leri için 10 req/dk in-memory bucket.
Cooldown Aynı kanal × provider × endpoint için ALERT_COOLDOWN_SECONDS (default 300) içinde tekrar alert gönderilmez. Flood engellenir.
Non-root Container sentinel user ile çalışır.
CORS Default kapalı; reverse proxy katmanında açın.
Input validation Tüm POST/PUT body'leri Pydantic model üzerinden geçer.

Önerilen production hardening

SECRET_KEY=<openssl rand -base64 32 ile üretilmiş>
AUTH_ENABLED=true
ADMIN_PASSWORD=<güçlü, unique parola>
ALERT_COOLDOWN_SECONDS=600
LOG_LEVEL=WARNING

ve docker-compose'da:

ports:
  - "127.0.0.1:8080:8080"   # Sadece localhost'a bind, reverse proxy önde olsun

Konfigürasyon

Ortam değişkenleri (.env)

LOG_LEVEL=INFO
CHECK_INTERVAL_DEFAULT=5m         # endpoint'te interval verilmediğinde
DB_PATH=/app/data/schemas.db
SCHEMA_DIR=/app/schemas

SECRET_KEY=change-me               # Fernet key + auth secret
AUTH_ENABLED=true
ADMIN_PASSWORD=                    # boş ise SECRET_KEY parola olur
API_TOKEN=                         # opsiyonel sabit harici token

ALERT_COOLDOWN_SECONDS=300

IMAGE_TAG=latest                   # docker compose image tag
MONITOR_PORT=8080

YAML config (opsiyonel seed)

  • config/endpoints.yaml — ilk kurulumda DB boşsa provider/endpoint seed'ler. Çalışan sistemde Web UI üzerinden CRUD yapılır; YAML re-import etmez (çakışma önler).
  • config/alerts.yaml — alert kanalı default'ları.
  • changelog-watcher/config/targets.yaml — changelog sayfalarının URL'leri.

Sorun Giderme

Container ayağa kalkıyor ama dashboard 401 dönüyor

AUTH_ENABLED=true ve henüz login olmadınız. admin + ADMIN_PASSWORD (veya SECRET_KEY) ile login.

"credential decrypt failed"

SECRET_KEY değişti, eski Fernet ile şifrelenmiş credential açılamıyor. Çözüm:

docker compose exec schema-monitor python -m core.crypto rotate \
    --old <eski_key> --new <yeni_key>

ya da credential'ları silip yeniden girin.

Alert atılmıyor

  1. Plugins sayfasında ilgili kanal aktif mi?
  2. Channels > "Test Mesajı Gönder" başarılı mı?
  3. Cooldown aktif olabilir — /api/alerts/history son alertleri göster.
  4. LOG_LEVEL=DEBUG yapın, docker compose logs schema-monitor.

Schema değişti ama yakalanmadı

  • Endpoint'in interval'ı çok uzun → kısaltın.
  • Response 200 dönmüyorsa snapshot atılmaz; Endpoints > Status sütununa bakın.
  • 3rd party A/B test yapıyor olabilir → Settings > Schema Stability Window artırın.

Disk doluyor (snapshot biriktiyor)

Settings > Schema Retention Days (default 90) düşürün. Manuel temizlik:

docker compose exec schema-monitor python -m core.store.cleanup --older-than 30d

Geliştirme & Test

Lokal kurulum (Docker olmadan)

cd schema-monitor
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export SECRET_KEY=dev-key-change-me
uvicorn main:app --reload --port 8080

Test

cd schema-monitor
pytest tests/ -v
pytest tests/ --cov=. --cov-report=term-missing

Konvansiyon: 3rd party HTTP çağrıları test'lerde httpx.MockTransport ile mocklanır — gerçek istek atılmaz. Fixture'lar tests/fixtures/ altında JSON.

Plugin testleri

  • tests/test_alert_plugins.py — her alert kanalı için ayrı test
  • tests/test_auth_plugins.py — auth handler'lar
  • tests/test_scheduler.py, tests/test_fetcher.py, tests/test_crypto.py — kritik modüller (≥%80 coverage zorunlu)

Kod kuralları (özet — detay CLAUDE.MD)

  • Türkçe yorum, Google-style docstring
  • Type hint zorunlu
  • print() yerine logging
  • asyncio.run() yerine uvicorn
  • Hardcoded credential / hardcoded plugin import yasak
  • Bare except: yasak
  • f-string > .format()

Lisans

MIT — LICENSE dosyasına bakın.


Katkı

PR'lar memnuniyetle. Yeni bir entegrasyon (alert kanalı / auth / storage) eklemek için schema-monitor/<plugin_dir>/ altında dosya oluşturmanız yeterli — registry otomatik discover eder. Test eklemeyi unutmayın.

CONTRIBUTING.md ve SECURITY.md okunmalı.

İpucu: Issue açarken hangi 3. parti API'yi izlediğinizi ve hangi diff türünün düzgün severity'lendirilmediğini paylaşırsanız hızlı çözeriz.


🌟 Destek olmak istersen

Süre Yardım
5 sn ⭐ Star
30 sn Twitter/LinkedIn'de paylaş ("3rd party API schema değişikliklerini sessizce yakalayan tool")
5 dk Eksik bulduğun bir konu için issue
30 dk Yeni bir alert kanalı plugin'i yaz (Slack, Discord, Telegram, ntfy...)
2 saat Yeni bir auth handler veya storage backend ekle

Star History Chart

About

🛰️ 3. parti API'lerin response schema değişikliklerini otomatik tespit eden, severity-aware monitoring sistemi. Plugin tabanlı (alert kanalı · auth · storage runtime plugin). FastAPI + APScheduler + deepdiff. Web Dashboard, REST API, .NET/Laravel middleware'leri ve changelog watcher dahil.

Topics

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors