diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d44dd02..c8e65785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,13 @@ All notable changes to ForgeLM are documented here. ### Fixed +- Stop saying that Microsoft Teams and Discord accept the webhook payload directly. The user manual (English and Turkish) and the + `webhook` field descriptions said all three ingest it; the body is a Slack-style `attachments` block with no top-level `text`, + `content` or `embeds`. Discord needs `content` or `embeds` and answers HTTP 400; Teams retired Office 365 Connectors in May 2026 and + its Workflows webhooks expect an Adaptive Card. Both need a relay. The page now shows the real payload, and the access-control SOP + no longer claims that a payload carries `FORGELM_OPERATOR` (it does not) or lists five events (there are eight). The `url_env` + description said it overrides `url`; it is read only when `url` is empty, so `url` wins. A formatter for Teams and Discord is a + separate, larger change and stays open on the issue (#112). - Fix the KTO bullet on the Alignment overview user-manual page (English and Turkish): it named the fields `(prompt, response, good?)`, but the KTO loader reads `prompt`, `completion` and a boolean `label` (#965). diff --git a/docs/qms/access_control-tr.md b/docs/qms/access_control-tr.md index 13341c3a..4ad7f9fb 100644 --- a/docs/qms/access_control-tr.md +++ b/docs/qms/access_control-tr.md @@ -230,20 +230,23 @@ webhook: ForgeLM webhook gövdelerini HMAC ile **imzalamaz** — `WebhookConfig` üzerinde `webhook.secret_env` alanı yoktur (bkz. -`forgelm/config.py::WebhookConfig`). Hedef-tarafı atıf (a) HTTPS + -`webhook.url_env` üzerinden URL-gizliliğine, (b) curated payload -içinde taşınan `FORGELM_OPERATOR` kimliğine, ve (c) alıcı sistemin -kendi bearer-token / imzalı-istek kontrollerine (Slack signing -secret, Teams connector token) düşer. - -Webhook wire-format olay sözlüğü (5 olay): `training.start`, -`training.success`, `training.failure`, `training.reverted`, -`approval.required` — Phase 8. In-process notifier metot adları -`notify_*` öneki kullanır (`notify_start`, `notify_success`, -`notify_failure`, `notify_reverted`, `notify_awaiting_approval`) -ve bu beş wire olayına dispatch eder. Her payload `FORGELM_OPERATOR` -kimliğini taşır böylece alıcı sistem (Slack, Teams, custom -incident-management) bildirimi attribute edebilir. +`forgelm/config.py::WebhookConfig`). Hedef-tarafı özgünlük (a) HTTPS + +`webhook.url_env` üzerinden URL-gizliliğine ve (b) alıcı sistemin +kendi bearer-token / imzalı-istek kontrollerine (örneğin Slack'in +signing secret'ı) düşer. Webhook payload'u `FORGELM_OPERATOR` +kimliğini **taşımaz**; bir modeli kimin çalıştırdığı veya onayladığı +bildirimden değil, audit log'dan okunur. + +Webhook wire-format olay sözlüğü sekiz olaydır: beş tek-aşamalı +yaşam-döngüsü olayı `training.start`, `training.success`, +`training.failure`, `training.reverted` ve `approval.required`, ayrıca +çok-aşamalı bir koşunun bunlarla birlikte yaydığı üç `pipeline.*` +olayı (`pipeline.started`, `pipeline.completed`, +`pipeline.stage_reverted`). In-process notifier metotları `notify_*` +öneki kullanır (`notify_start`, `notify_success`, `notify_failure`, +`notify_reverted`, `notify_awaiting_approval`, +`notify_pipeline_started`, `notify_pipeline_completed`, +`notify_pipeline_reverted`) ve bu wire olaylarına dispatch eder. ## 8. Doğrulama checklist'i diff --git a/docs/qms/access_control.md b/docs/qms/access_control.md index e3cb1aed..ad5d97c1 100644 --- a/docs/qms/access_control.md +++ b/docs/qms/access_control.md @@ -228,21 +228,23 @@ webhook: ForgeLM does **not** HMAC-sign webhook bodies — there is no `webhook.secret_env` field on `WebhookConfig` (see -`forgelm/config.py::WebhookConfig`). Destination-side attribution falls to (a) -HTTPS + URL-secrecy via `webhook.url_env`, (b) the -`FORGELM_OPERATOR` identity carried inside the curated payload, and -(c) the receiving system's own bearer-token / signed-request -controls (Slack signing secret, Teams connector token). - -The webhook wire-format event vocabulary (5 events) is -`training.start`, `training.success`, `training.failure`, -`training.reverted`, and `approval.required` — Phase 8. The -in-process notifier method names use the `notify_*` prefix -(`notify_start`, `notify_success`, `notify_failure`, -`notify_reverted`, `notify_awaiting_approval`) and dispatch to those -five wire events. Every payload carries the `FORGELM_OPERATOR` -identity so the receiving system (Slack, Teams, custom -incident-management) can attribute the notification. +`forgelm/config.py::WebhookConfig`). Destination-side authenticity falls to +(a) HTTPS + URL-secrecy via `webhook.url_env` and (b) the receiving +system's own bearer-token / signed-request controls (for example Slack's +signing secret). A webhook payload does **not** carry the +`FORGELM_OPERATOR` identity; attribution of who ran or approved a model +comes from the audit log, not from the notification. + +The webhook wire-format event vocabulary has eight events: the five +single-stage lifecycle events `training.start`, `training.success`, +`training.failure`, `training.reverted` and `approval.required`, plus the +three `pipeline.*` events (`pipeline.started`, `pipeline.completed`, +`pipeline.stage_reverted`) that a multi-stage run emits alongside them. The +in-process notifier methods use the `notify_*` prefix (`notify_start`, +`notify_success`, `notify_failure`, `notify_reverted`, +`notify_awaiting_approval`, `notify_pipeline_started`, +`notify_pipeline_completed`, `notify_pipeline_reverted`) and dispatch to +those wire events. ## 8. Verification checklist diff --git a/docs/reference/configuration-tr.md b/docs/reference/configuration-tr.md index b78fa07f..3535ecb0 100644 --- a/docs/reference/configuration-tr.md +++ b/docs/reference/configuration-tr.md @@ -433,11 +433,11 @@ kaynağı kaydedilmemiştir. | Alan | Tip | Varsayılan | Açıklama | |------|-----|-----------|----------| -| `url` | string | `null` | Webhook hedef URL | -| `url_env` | string | `null` | URL'yi içeren ortam değişkeni adı | +| `url` | string | `null` | Webhook hedef URL'si: bir Slack incoming webhook'u ya da bir relay (Teams ve Discord payload'u doğrudan reddeder) | +| `url_env` | string | `null` | URL'yi içeren ortam değişkeni adı; yalnızca `url` boşken okunur | | `notify_on_start` | bool | `true` | Eğitim başlangıcında bildir | | `notify_on_success` | bool | `true` | Başarıda bildir | -| `notify_on_failure` | bool | `true` | Hata durumunda bildir | +| `notify_on_failure` | bool | `true` | Eğitim hata verdiğinde ya da eğitim sonrası bir kapı modeli geri aldığında bildir | | `timeout` | int | `10` | HTTP istek zaman aşımı (saniye). Notifier ≥ 1s'ye clamp'ler. v0.5.5'te varsayılan 10s'ye çıkarıldı (önceden 5s'di) — Slack/Teams gateway gecikme atışları production'da düzenli olarak 5s'yi aşıyor ve bir webhook zaman aşımı audit chain'i sessizce zayıflatıyor (webhook arızası best-effort). | | `allow_private_destinations` | bool | `false` | RFC1918 / loopback / link-local hedeflere webhook gönderimine izin verir (cluster içi Slack proxy, on-prem Teams gateway gibi). Varsayılan yalnızca genel internet — SSRF koruması | | `require_https` | bool | `false` | TLS-only zorlama. `true`, plaintext bir `http://` URL'ini reddeder (SSRF chokepoint raise eder; POST atlanır), warn-and-send yerine. Varsayılan `false`, warn-then-send davranışını korur | diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 0f83d16e..a8880b2a 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -292,11 +292,11 @@ silently extend the retention horizon by re-using a stale workspace. | Field | Type | Default | Description | |-------|------|---------|-------------| -| `url` | string | `null` | Webhook destination URL | -| `url_env` | string | `null` | Env var name containing URL | +| `url` | string | `null` | Webhook destination URL: a Slack incoming webhook, or a relay (Teams and Discord reject the payload directly) | +| `url_env` | string | `null` | Env var name containing the URL; read only when `url` is empty | | `notify_on_start` | bool | `true` | Notify on training start | | `notify_on_success` | bool | `true` | Notify on success | -| `notify_on_failure` | bool | `true` | Notify on failure | +| `notify_on_failure` | bool | `true` | Notify when training raises or a post-training gate reverts the model | | `timeout` | int | `10` | HTTP request timeout (seconds). Clamped to ≥ 1s by the notifier. Default raised to 10s in v0.5.5 (was 5s) — Slack/Teams gateway latency spikes regularly cross 5s in production, and a webhook timeout silently degrades the audit chain (webhook failure is best-effort). | | `allow_private_destinations` | bool | `false` | Opt in to webhooks pointing at RFC1918 / loopback / link-local hosts (in-cluster Slack proxy, on-prem Teams gateway). Defaults to public-internet only — SSRF guard | | `require_https` | bool | `false` | TLS-only enforcement. `true` refuses a plaintext `http://` URL (the SSRF chokepoint raises; the POST is skipped) instead of warn-and-send. Default `false` preserves warn-then-send | diff --git a/docs/usermanuals/en/operations/webhooks.md b/docs/usermanuals/en/operations/webhooks.md index d7cf7107..52e76eb3 100644 --- a/docs/usermanuals/en/operations/webhooks.md +++ b/docs/usermanuals/en/operations/webhooks.md @@ -1,11 +1,11 @@ --- title: Webhooks -description: Slack and Teams notifications on training events — start, success, failure, auto-revert. +description: Slack-format webhook notifications on training events — start, success, failure, auto-revert. Teams and Discord need a relay. --- # Webhooks -ForgeLM fires structured webhooks on training milestones. Wire them into Slack, Teams, or any incident tool that accepts JSON payloads — get the right context to the right humans without anyone watching a log. +ForgeLM fires structured webhooks on training milestones. Wire them into Slack, or into any incident tool or relay that accepts this JSON payload (Microsoft Teams and Discord need a relay; see below) — get the right context to the right humans without anyone watching a log. ## Quick example @@ -17,8 +17,9 @@ webhook: notify_on_failure: true # default true (covers training.failure + training.reverted) ``` -The notifier emits a generic JSON payload — Slack and Teams ingest it directly via -their incoming-webhook endpoints. Per-event subscription is not currently +The notifier emits one generic JSON payload with a Slack-style `attachments` block. +Slack's incoming webhooks accept it; Microsoft Teams and Discord do not (see +"Slack / Teams / Discord ingestion" below). Per-event subscription is not currently configurable; toggle the three `notify_on_*` flags to coarse-control which lifecycle events fire. @@ -50,40 +51,56 @@ surface mirrored in the ## Payload shape -Single generic JSON shape — Slack / Teams / Discord all accept it -directly via incoming-webhook endpoints; ForgeLM does **not** wrap it in -provider-specific templates: +One generic JSON shape. Every payload carries `event`, `run_name`, `status`, `metrics`, `reason`, +`model_path` and an `attachments` array with one Slack-style block (`title`, `text`, `color`). +ForgeLM does **not** wrap it in provider-specific templates, and it has no top-level `text`, +`content` or `embeds` field: ```json { "event": "training.reverted", - "run_name": "customer-support-v1.2.0", + "run_name": "llama3-support-sft", "status": "reverted", - "reason": "safety regression: S5 hate-speech +0.18 over baseline" + "metrics": {}, + "reason": "Safety gate failed: unsafe_rate 0.08 exceeds max_unsafe_rate 0.05", + "model_path": null, + "attachments": [ + { + "title": "Training Reverted: llama3-support-sft", + "text": "Auto-revert fired. Generated artifacts were deleted because a post-training gate (evaluation, safety, judge, or benchmark) rejected the run.\n\nReason: Safety gate failed: unsafe_rate 0.08 exceeds max_unsafe_rate 0.05", + "color": "#ff9900" + } + ] } ``` -Payload keys vary by event; the full per-event field list is in the -[Audit Event Catalog on GitHub](https://github.com/HodeTech/ForgeLM/blob/main/docs/reference/audit_event_catalog.md) -under the *Webhook lifecycle events* table. +The `pipeline.*` events add a few fields. The full per-event field list is in the +[Webhook Payload Schema on GitHub](https://github.com/HodeTech/ForgeLM/blob/main/docs/reference/webhook_schema.md). ## Slack / Teams / Discord ingestion -The single generic JSON payload shown above is what Slack, Teams, and Discord -all expect on their incoming-webhook endpoints. There are **no per-provider +The payload above is a Slack-style body. There are **no per-provider templates** in `WebhookConfig` (no `template:`, no `events:` allow-list, no `channel:` / `mention_on_failure:` formatting knobs, no per-destination fan-out array). Routing and formatting happen on the receiving side: -- **Slack** — paste the payload into a Slack workflow or incoming-webhook - app; Slack renders the JSON's top-level fields. To get a richer - formatted card, point the webhook at a relay (Slack workflow / AWS - Lambda / your own gateway) that translates the ForgeLM payload into - Slack Block Kit. -- **Microsoft Teams** — similar pattern. Teams renders incoming JSON - natively but the visual is plain; for MessageCard / Adaptive Card - formatting, run a relay. -- **Discord** — accepts the JSON directly via the bot/webhook URL. +- **Slack** — an incoming webhook accepts the body and shows the + `attachments` block (title, text, colour). That is the legacy attachment + format, which Slack treats as secondary; for a richer card point the + webhook at a relay (Slack workflow / AWS Lambda / your own gateway) that + translates the ForgeLM payload into Slack Block Kit. +- **Microsoft Teams** — not accepted directly. Office 365 Connectors were + retired in May 2026, and a Teams Workflows (Power Automate) webhook expects + an Adaptive Card message, which this payload is not. Run a relay that wraps + the payload in an Adaptive Card. +- **Discord** — not accepted directly. A Discord webhook needs `content` or + `embeds` (or a file or poll) in the body, and ForgeLM sends none of them, so + Discord answers with HTTP 400. Run a relay that maps `attachments[0]` to + `content` or an embed. + +A receiver that rejects a delivery does not fail the run, and nothing is paged: +the rejection is a `WARNING` in the run's log (see *Common pitfalls*). Send a +test event to a new destination before relying on it. For multiple destinations, run multiple separate ForgeLM training configs (each pinned to its own `webhook.url_env`) or fan out from a @@ -97,7 +114,7 @@ Real `WebhookConfig` (see `forgelm/config.py::WebhookConfig`): | Field | Default | Notes | |---|---|---| | `url` | `null` | Inline URL — prefer `url_env` for secret hygiene. | -| `url_env` | `null` | Env-var name carrying the URL. Overrides `url` when set. | +| `url_env` | `null` | Env-var name carrying the URL. Read only when `url` is empty; when both are set, `url` wins. | | `notify_on_start` | `true` | Gates `training.start` AND `pipeline.started`. | | `notify_on_success` | `true` | Gates `training.success`, `approval.required`, AND a successful `pipeline.completed`. | | `notify_on_failure` | `true` | Gates `training.failure`, `training.reverted`, `pipeline.stage_reverted`, AND a failing `pipeline.completed`. | @@ -117,7 +134,7 @@ live outside ForgeLM. - **TLS strongly recommended.** ForgeLM permits both HTTPS and HTTP webhook URLs — HTTP destinations log a `Webhook URL uses HTTP (not HTTPS). Data will be sent unencrypted.` warning but are not rejected by default (see `forgelm/webhook.py` `_send`). On a regulated estate set `webhook.require_https: true` to make a plaintext `http://` URL a hard failure (the delivery is refused, not sent). Pin `https://` URLs in production. - **Curated payload.** ForgeLM never includes raw training data, full configs, or unredacted PII in webhook payloads. The notifier wraps a fixed-shape JSON; there is no `webhook.redact` toggle because there's nothing user-controllable to redact. - **Server-Side Request Forgery (SSRF) guard.** ForgeLM blocks webhook URLs pointing at internal IPs — RFC 1918, loopback, link-local (incl. cloud IMDS at `169.254.169.254`), RFC 6598 Shared Address Space / Carrier-Grade-NAT (`100.64.0.0/10`, which also covers Alibaba Cloud ECS's IMDS at `100.100.100.200` — the stdlib `ipaddress` predicates don't flag that block as private or reserved on their own), plus reserved and multicast destinations — unless you explicitly opt-in with `webhook.allow_private_destinations: true`. This prevents misconfigured runs from probing your internal network or leaking the payload to a cloud metadata service. -- **No HMAC body signing.** ForgeLM does not sign webhook bodies — destination-side authenticity falls to TLS + URL secrecy via `url_env` plus the receiving system's bearer-token / signed-request controls (Slack signing secret, Teams connector token). +- **No HMAC body signing.** ForgeLM does not sign webhook bodies — destination-side authenticity falls to TLS + URL secrecy via `url_env` plus the receiving system's bearer-token / signed-request controls (for example Slack's signing secret). ## Common pitfalls diff --git a/docs/usermanuals/en/reference/configuration.md b/docs/usermanuals/en/reference/configuration.md index c4ba73c2..d14da1e9 100644 --- a/docs/usermanuals/en/reference/configuration.md +++ b/docs/usermanuals/en/reference/configuration.md @@ -262,8 +262,8 @@ compliance: ```yaml webhook: - url: null # Slack / Teams / Discord / custom; prefer url_env - url_env: null # env var carrying the webhook URL + url: null # Slack incoming webhook, or a relay for Teams / Discord; prefer url_env + url_env: null # env var carrying the webhook URL; read only when url is empty notify_on_start: true notify_on_success: true notify_on_failure: true diff --git a/docs/usermanuals/tr/operations/webhooks.md b/docs/usermanuals/tr/operations/webhooks.md index 6f80a377..efe79dab 100644 --- a/docs/usermanuals/tr/operations/webhooks.md +++ b/docs/usermanuals/tr/operations/webhooks.md @@ -1,11 +1,11 @@ --- title: Webhook'lar -description: Eğitim olaylarında Slack ve Teams bildirimleri — başlangıç, başarı, hata, otomatik geri alma. +description: Eğitim olaylarında Slack biçiminde webhook bildirimleri — başlangıç, başarı, hata, otomatik geri alma. Teams ve Discord için relay gerekir. --- # Webhook'lar -ForgeLM eğitim dönüm noktalarında yapılandırılmış webhook fırlatır. Bunları Slack, Teams veya JSON payload kabul eden herhangi bir incident aracına bağlayın — hiç kimsenin log izlemesine gerek kalmadan doğru bağlamı doğru insanlara getirin. +ForgeLM eğitim dönüm noktalarında yapılandırılmış webhook fırlatır. Bunları Slack'e ya da bu JSON payload'u kabul eden herhangi bir incident aracına veya relay'e bağlayın (Microsoft Teams ve Discord için relay gerekir; aşağıya bakın) — hiç kimsenin log izlemesine gerek kalmadan doğru bağlamı doğru insanlara getirin. ## Hızlı örnek @@ -17,8 +17,9 @@ webhook: notify_on_failure: true # default true (training.failure + training.reverted'i kapsar) ``` -Notifier generic JSON payload yayar — Slack ve Teams bunu incoming-webhook -uçlarından doğrudan kabul eder. Per-event abonelik şu an konfigüre +Notifier, Slack tarzı bir `attachments` bloğu taşıyan tek bir generic JSON payload yayar. +Slack'in incoming webhook'ları bunu kabul eder; Microsoft Teams ve Discord etmez +(aşağıdaki "Slack / Teams / Discord ingest" bölümüne bakın). Per-event abonelik şu an konfigüre edilemiyor; üç `notify_on_*` flag'iyle hangi yaşam-döngüsü olaylarının fırlatılacağı kaba ayarlanır. @@ -50,41 +51,58 @@ ile aynalanan kanonik yüzeydir: ## Payload yapısı -Tek generic JSON şekil — Slack / Teams / Discord hepsi bunu incoming-webhook -uçlarından doğrudan kabul eder; ForgeLM provider'a-özel template'lerle -sarmalama **yapmaz**: +Tek generic JSON şekil. Her payload `event`, `run_name`, `status`, `metrics`, `reason`, +`model_path` ve tek bir Slack tarzı blok (`title`, `text`, `color`) içeren bir `attachments` +dizisi taşır. ForgeLM provider'a-özel template'lerle sarmalama **yapmaz** ve üst düzeyde +`text`, `content` veya `embeds` alanı yoktur: ```json { "event": "training.reverted", - "run_name": "customer-support-v1.2.0", + "run_name": "llama3-support-sft", "status": "reverted", - "reason": "safety regression: S5 hate-speech +0.18 over baseline" + "metrics": {}, + "reason": "Safety gate failed: unsafe_rate 0.08 exceeds max_unsafe_rate 0.05", + "model_path": null, + "attachments": [ + { + "title": "Training Reverted: llama3-support-sft", + "text": "Auto-revert fired. Generated artifacts were deleted because a post-training gate (evaluation, safety, judge, or benchmark) rejected the run.\n\nReason: Safety gate failed: unsafe_rate 0.08 exceeds max_unsafe_rate 0.05", + "color": "#ff9900" + } + ] } ``` -Payload anahtarları event'e göre değişir; tam per-event alan listesi -[GitHub'daki Audit Event Kataloğu](https://github.com/HodeTech/ForgeLM/blob/main/docs/reference/audit_event_catalog.md) -*Webhook lifecycle events* tablosundadır. +`pipeline.*` event'leri birkaç alan ekler. Tam per-event alan listesi +[GitHub'daki Webhook Payload Şeması](https://github.com/HodeTech/ForgeLM/blob/main/docs/reference/webhook_schema.md) +sayfasındadır. ## Slack / Teams / Discord ingest -Yukarıdaki tek generic JSON payload, Slack, Teams ve Discord'un -incoming-webhook endpoint'lerinde beklediği şeydir. `WebhookConfig`'te +Yukarıdaki payload Slack tarzı bir gövdedir. `WebhookConfig`'te **provider başına template yoktur** (no `template:`, no `events:` allow-list, no `channel:` / `mention_on_failure:` formatlama knob'ları, no per-destination fan-out array). Routing ve formatlama alıcı tarafta yapılır: -- **Slack** — payload'u Slack workflow veya incoming-webhook - uygulamasına yapıştırın; Slack JSON'un top-level alanlarını render - eder. Daha zengin formatlanmış bir kart için, webhook'u ForgeLM - payload'unu Slack Block Kit'e çeviren bir relay'e (Slack +- **Slack** — incoming webhook gövdeyi kabul eder ve `attachments` + bloğunu (başlık, metin, renk) gösterir. Bu eski attachment biçimidir + ve Slack onu ikincil sayar; daha zengin bir kart için webhook'u + ForgeLM payload'unu Slack Block Kit'e çeviren bir relay'e (Slack workflow / AWS Lambda / kendi gateway'iniz) yönlendirin. -- **Microsoft Teams** — benzer pattern. Teams gelen JSON'u natively - render eder ama görsel düz; MessageCard / Adaptive Card - formatlama için bir relay çalıştırın. -- **Discord** — JSON'u doğrudan bot/webhook URL üzerinden kabul eder. +- **Microsoft Teams** — doğrudan kabul edilmez. Office 365 Connector'lar + Mayıs 2026'da kapatıldı ve bir Teams Workflows (Power Automate) + webhook'u Adaptive Card mesajı bekler; bu payload öyle değildir. + Payload'u Adaptive Card'a saran bir relay çalıştırın. +- **Discord** — doğrudan kabul edilmez. Discord webhook'u gövdede + `content` veya `embeds` (ya da dosya ya da anket) ister; ForgeLM bunların + hiçbirini göndermez, bu yüzden Discord HTTP 400 döner. `attachments[0]`'ı + `content`'e veya bir embed'e eşleyen bir relay çalıştırın. + +Teslimatı reddeden bir alıcı run'ı başarısız etmez ve kimseye alarm gitmez: +ret, run log'unda bir `WARNING`'dir (bkz. *Sık hatalar*). Yeni bir hedefe güvenmeden +önce ona bir test event'i gönderin. Birden çok hedef için, her biri kendi `webhook.url_env`'ine pinlenmiş birden çok ayrı ForgeLM training config'i çalıştırın @@ -99,7 +117,7 @@ Gerçek `WebhookConfig` (bkz. `forgelm/config.py::WebhookConfig`): | Alan | Vars. | Notlar | |---|---|---| | `url` | `null` | Inline URL — secret hijyeni için `url_env`'i tercih edin. | -| `url_env` | `null` | URL'i taşıyan env var adı. Set edildiğinde `url`'i override eder. | +| `url_env` | `null` | URL'i taşıyan env var adı. Yalnızca `url` boşken okunur; ikisi de set ise `url` kazanır. | | `notify_on_start` | `true` | `training.start` VE `pipeline.started`'ı gate'ler. | | `notify_on_success` | `true` | `training.success`, `approval.required` VE başarılı bir `pipeline.completed`'ı gate'ler. | | `notify_on_failure` | `true` | `training.failure`, `training.reverted`, `pipeline.stage_reverted` VE başarısız bir `pipeline.completed`'ı gate'ler. | @@ -118,7 +136,7 @@ payload zaten curated), ve routing hepsi ForgeLM'in dışında yaşar. - **TLS şiddetle önerilir.** ForgeLM hem HTTPS hem HTTP webhook URL'lerine izin verir — HTTP hedefleri `Webhook URL uses HTTP (not HTTPS). Data will be sent unencrypted.` uyarısı loglar ama varsayılan olarak reddedilmez (bkz. `forgelm/webhook.py` `_send`). Regüle bir ortamda `webhook.require_https: true` ile plaintext bir `http://` URL'ini hard failure yapın (teslimat reddedilir, gönderilmez). Üretimde `https://` URL'leri pinleyin. - **Curated payload.** ForgeLM webhook payload'larına asla raw eğitim verisi, tam config'ler veya unredacted PII koymaz. Notifier sabit-şekilli bir JSON sarar; `webhook.redact` toggle'ı yoktur çünkü kullanıcı-kontrollü redakte edilecek bir şey yok. - **SSRF guard.** ForgeLM iç IP'lere işaret eden webhook URL'lerini engeller — RFC 1918, loopback, link-local (bulut IMDS `169.254.169.254` dahil), RFC 6598 Shared Address Space / Carrier-Grade-NAT (`100.64.0.0/10`; bu blok, Alibaba Cloud ECS'in IMDS'ini de kapsar — `100.100.100.200` — stdlib `ipaddress` predicate'leri bu bloğu kendiliğinden private veya reserved olarak işaretlemez), ayrıca reserved ve multicast hedefler — `webhook.allow_private_destinations: true` ile açıkça opt-in olmadıkça. Yanlış konfigüre koşuların iç ağınızı sondalamasını veya payload'ı bir bulut metadata servisine sızdırmasını önler. -- **HMAC body imzalama yok.** ForgeLM webhook gövdelerini imzalamaz — hedef-tarafı authenticity TLS + `url_env` üzerinden URL gizliliği artı alıcı sistemin bearer-token / signed-request kontrollerine (Slack signing secret, Teams connector token) düşer. +- **HMAC body imzalama yok.** ForgeLM webhook gövdelerini imzalamaz — hedef-tarafı authenticity TLS + `url_env` üzerinden URL gizliliği artı alıcı sistemin bearer-token / signed-request kontrollerine (örneğin Slack signing secret) düşer. ## Sık hatalar diff --git a/docs/usermanuals/tr/reference/configuration.md b/docs/usermanuals/tr/reference/configuration.md index 39f8e44b..4a7902fd 100644 --- a/docs/usermanuals/tr/reference/configuration.md +++ b/docs/usermanuals/tr/reference/configuration.md @@ -264,8 +264,8 @@ compliance: ```yaml webhook: - url: null # Slack / Teams / Discord / özel; url_env tercihli - url_env: null # webhook URL'sini taşıyan env değişkeni + url: null # Slack incoming webhook'u ya da Teams / Discord için relay; url_env tercihli + url_env: null # webhook URL'sini taşıyan env değişkeni; yalnızca url boşken okunur notify_on_start: true notify_on_success: true notify_on_failure: true diff --git a/forgelm/config.py b/forgelm/config.py index 4114f2df..f3f7ba74 100644 --- a/forgelm/config.py +++ b/forgelm/config.py @@ -1523,17 +1523,17 @@ class WebhookConfig(BaseModel): url: Optional[str] = Field( default=None, - description="Webhook URL (Slack / Teams / Discord / custom). Use `url_env` to read from env to avoid committing secrets.", + description="Webhook URL (a Slack incoming webhook, or a relay that forwards to Teams / Discord / custom). Use `url_env` to avoid committing secrets.", ) url_env: Optional[str] = Field( - default=None, description="Env var name carrying the webhook URL (overrides `url` when set)." + default=None, description="Env var name carrying the webhook URL; read only when `url` is empty." ) notify_on_start: bool = Field(default=True, description="POST a `notify_start` event when training begins.") notify_on_success: bool = Field( default=True, description="POST a `notify_success` event when training completes successfully." ) notify_on_failure: bool = Field( - default=True, description="POST a `notify_failure` event when training fails (any non-zero exit)." + default=True, description="POST a failure event when training raises or a post-training gate reverts the model." ) timeout: int = Field( default=10, @@ -1677,7 +1677,7 @@ class ForgeConfig(BaseModel): description="Post-training evaluation block (loss / benchmark / safety / judge / human-approval gate).", ) webhook: Optional[WebhookConfig] = Field( - default=None, description="Webhook notification block (Slack / Teams / Discord / custom)." + default=None, description="Webhook notification block (Slack-format JSON; Teams and Discord need a relay)." ) distributed: Optional[DistributedConfig] = Field( default=None, description="DeepSpeed / FSDP multi-GPU configuration block."