Przejdź do treści

Przewodniki

Webhooki

Punkt końcowy webhooka otrzymuje to, co kierują do niego reguły alertów obszaru roboczego: zablokowane wydanie, wynik czekający na człowieka, zakończony przebieg zarządzany, alarm monitora produkcyjnego. Każda dostawa to treść JSON podpisana sekretem punktu końcowego, aby Twój serwer mógł sprawdzić, że pochodzi z Twojego obszaru roboczego, zanim na nią zareaguje.

Dodawanie punktu końcowego

Na stronie Integrations obszaru roboczego Owner lub Admin dodaje podpisany webhook z nazwą i publicznym adresem URL https na porcie 443 lub 8443. Strona pokazuje wtedy sekret podpisu punktu końcowego, zaczynający się od whsec_. Skopiuj go od razu: jest przechowywany w postaci zaszyfrowanej i nie zostanie pokazany ponownie. Aby go zastąpić, usuń punkt końcowy i dodaj go ponownie.

Następnie na stronie Alerts wybierz punkt końcowy jako kanał jednej lub kilku reguł. „Send a test” wysyła dostawę oloproof.test i pokazuje status, którym odpowiedział Twój serwer.

Co jest wysyłane

{
  "type": "oloproof.gate_blocked",
  "id": "dlv_8c1f0a2b3c4d5e6f7a8b9c0d",
  "created_at": "2026-10-26T14:03:00.000Z",
  "workspace": "acme",
  "rule": { "id": "rul_1a2b3c4d5e6f7a8b9c0d1e2f", "name": "Do not ship" },
  "event": "gate_blocked",
  "items": [
    {
      "project": "support",
      "kind": "run",
      "id": "run_20261026T140100_4f2a",
      "release_action": "BLOCK",
      "rules": [["faithfulness", "FAIL"]],
      "href": "https://oloproof.com/app/workspaces/acme/projects/support/runs/run_20261026T140100_4f2a"
    }
  ],
  "more": 0
}

Element zawiera identyfikatory, stany decyzji silnika, akcję wydania, stan i wynik zadania, poziom, próg i przedział monitora w postaci zapisanej przez silnik oraz linki. Nigdy nie zawiera wejścia, wyjścia, oczekiwanej odpowiedzi ani etykiet przypadku. Dostawa zawiera najwyżej 50 elementów; more liczy zdarzenia ponad nie.

Weryfikacja dostawy

Każda dostawa niesie trzy nagłówki w formie Standard Webhooks:

  • webhook-id: identyfikator dostawy, taki sam przy każdej ponownej próbie.
  • webhook-timestamp: kiedy wysłano tę próbę, w sekundach od 1970 roku.
  • webhook-signature: v1, i HMAC-SHA256 w base64 z id.timestamp.body, z kluczem w postaci bajtów sekretu (części po whsec_, zdekodowanej z base64).

Oblicz podpis na surowej treści w postaci otrzymanej, porównaj go w stałym czasie i odrzuć znacznik czasu różniący się od Twojego zegara o więcej niż pięć minut.

import base64, hashlib, hmac, time

def verify(secret: str, headers: dict, body: bytes) -> bool:
    key = base64.b64decode(secret.removeprefix("whsec_"))
    msg = f"{headers['webhook-id']}.{headers['webhook-timestamp']}.".encode() + body
    expected = base64.b64encode(hmac.new(key, msg, hashlib.sha256).digest()).decode()
    fresh = abs(time.time() - int(headers["webhook-timestamp"])) <= 300
    given = [part.split(",", 1)[-1] for part in headers["webhook-signature"].split()]
    return fresh and any(hmac.compare_digest(expected, sig) for sig in given)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, headers, body) {
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
  const expected = createHmac("sha256", key).update(`${id}.${ts}.${body}`).digest("base64");
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
  return fresh && headers["webhook-signature"].split(" ").some((part) => {
    const sig = Buffer.from(part.split(",").pop());
    return sig.length === expected.length && timingSafeEqual(sig, Buffer.from(expected));
  });
}

Biblioteki Standard Webhooks weryfikują te same nagłówki.

Dostawa

Odpowiedz dowolnym statusem 2xx w ciągu dziesięciu sekund. Wszystko inne, łącznie z przekierowaniem, jest nieudaną próbą, ponawianą po 1, 5, 30, 120 i 360 minutach, a potem porzucaną. Ponieważ odpowiedź może zginąć już po tym, jak Twój serwer na nią zareagował, ta sama dostawa może przyjść dwa razy: użyj webhook-id, aby odrzucić powtórzenie. Reguła uruchamia się najwyżej raz dla każdego zdarzenia, więc nowy identyfikator to nowa dostawa.

Przed każdą próbą nazwa punktu końcowego jest rozwiązywana ponownie, a żądanie trafia tylko na adres publiczny: adresy loopback, prywatne, link-local, współdzielone, zarezerwowane i adresy metadanych chmury są odrzucane, podobnie jak formy IPv6, które zawierają jeden z nich. Połączenie jest nawiązywane z adresem, który sprawdzono, a certyfikat jest sprawdzany względem nazwy.

Slack

Punkt końcowy Slacka to adres URL incoming webhooka. Otrzymuje krótką wiadomość po angielsku, jeden wiersz na zdarzenie, z linkiem do każdego wyniku. Slack nie sprawdza nagłówków podpisu, które i tak są wysyłane.