Um einen GitLab-Webhook auf localhost zu testen, machen Sie Ihren lokalen Handler über einen HTTPS-Tunnel zugänglich, fügen Sie diese URL unter Einstellungen → Webhooks hinzu, erzeugen Sie ein Signierungstoken und überprüfen Sie die Standard-Webhook-Signatur von GitLab, bevor Sie die Nutzlast parsen. Lösen Sie einen Push oder Merge Request aus, inspizieren Sie die Lieferung und arbeiten Sie lokal, ohne Ihre Integration nach jeder Änderung bereitzustellen.
Verwenden Sie GitLab-Signierungstoken, nicht ein neues Klartext-Geheimtoken.
GitLab unterstützt zwei Mechanismen, die leicht verwechselt werden können. Das ältere Geheimtoken wird in den X-Gitlab-Token Anforderungsheader kopiert. Es beweist die Kenntnis eines geteilten Wertes, schützt jedoch nicht die Integrität des Bodys. GitLab empfiehlt jetzt ein Signierungstoken für neue Webhooks. Es erzeugt eine HMAC-SHA256-Signatur und folgt dem Standard-Webhook-Nachrichtenformat.
Der Die offizielle GitLab-Webhooks-Dokumentation besagt, dass eine signierte Anfrage webhook-id, webhook-timestamp und webhook-signature enthält. Die Signatur deckt die Nachrichten-ID, den Zeitstempel und den genauen rohen JSON-Body ab. Dies schützt sowohl die Herkunft als auch die Integrität der Nutzlast.
Implementieren Sie die Standard-Webhooks-Überprüfung in Node.js
GitLab-Signierungstoken werden einmal angezeigt und verwenden ein whsec_ -Präfix. Entfernen Sie dieses Präfix und decodieren Sie den Rest mit Base64, um den HMAC-Schlüssel zu erhalten. Jede empfangene Signatur hat die Form v1,<base64 signature>; der Header kann mehrere durch Leerzeichen getrennte Signaturen enthalten.
import crypto from 'node:crypto';
function safeEqual(a, b) {
const left = Buffer.from(a);
const right = Buffer.from(b);
return left.length === right.length &&
crypto.timingSafeEqual(left, right);
}
function verifyGitLabWebhook({ token, id, timestamp, body, signatures }) {
if (!token?.startsWith('whsec_') || !id || !timestamp || !signatures) {
return false;
}
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return false;
const key = Buffer.from(token.slice(6), 'base64');
const message = `${id}.${timestamp}.${body}`;
const digest = crypto.createHmac('sha256', key).update(message).digest('base64');
const expected = `v1,${digest}`;
return signatures.split(' ').some((value) => safeEqual(value, expected));
}
Das hier gezeigte Fünf-Minuten-Zeitfenster ist eine Anwendungspolitik und kein Wert, der blind übernommen werden sollte. Wählen Sie eine Toleranz, die die Uhrabweichung berücksichtigt, aber nützliche Wiederholungen blockiert. Synchronisieren Sie die Uhr der empfangenden Maschine. Speichern Sie jede akzeptierte webhook-id unter einer eindeutigen Einschränkung, da eine frische Zeitstempelüberprüfung allein nicht verhindern kann, dass dieselbe Nachricht zweimal sofort zugestellt wird.
Erstellen Sie die Express-Webhook-Route
Erfassen Sie den Rohkörper auf dieser Route. Ein globaler express.json() -Aufruf vor der Überprüfung zerstört die Byte-für-Byte-Darstellung, die GitLab signiert hat.
import express from 'express';
const app = express();
app.post(
'/webhooks/gitlab',
express.raw({ type: 'application/json', limit: '2mb' }),
async (req, res) => {
const body = req.body.toString('utf8');
const valid = verifyGitLabWebhook({
token: process.env.GITLAB_WEBHOOK_SIGNING_TOKEN,
id: req.get('webhook-id'),
timestamp: req.get('webhook-timestamp'),
signatures: req.get('webhook-signature'),
body,
});
if (!valid) return res.sendStatus(401);
await inbox.insertOnce(req.get('webhook-id'), JSON.parse(body));
return res.sendStatus(202);
},
);
app.use(express.json());
app.listen(3000);
Binden Sie den normalen JSON-Parser nach der Webhook-Route ein oder verwenden Sie seinen verify -Callback, um einen Rohpuffer zu erhalten. Deaktivieren Sie niemals Signaturprüfungen, nur weil der Endpunkt an localhost weiterleitet; die Tunnel-URL ist weiterhin über das öffentliche Internet erreichbar.
Erstellen Sie einen öffentlichen HTTPS-Endpunkt
- Starten Sie die Integration lokal und testen Sie deren Route mit einer absichtlich unsignierten Anfrage. Sie sollte 401 zurückgeben, was beweist, dass die Authentifizierung aktiv ist.
- Führen Sie
npx portpreview 3000in einem anderen Terminal aus. - Kopieren Sie den HTTPS-Ursprung und fügen Sie ihn an.
/webhooks/gitlab. - Halten Sie den Tunnel während der gesamten Konfiguration und der Ereignistests offen.
Die SSL-Überprüfung von GitLab sollte aktiviert bleiben. Ein Tunnel mit öffentlich vertrauenswürdigem TLS vermeidet Fehler bei selbstsignierten Zertifikaten. Wenn GitLab in einem privaten, selbstverwalteten Netzwerk läuft, muss es auch einen ausgehenden Zugriff auf die öffentliche Tunnel-URL haben.
Konfigurieren Sie das Projekt-Webhook
- Öffnen Sie das GitLab-Projekt und wählen Sie Einstellungen → Webhooks.
- Wählen Sie Neues Webhook hinzufügen und fügen Sie die vollständige Tunnel-Delivery-URL ein.
- Wählen Sie Signatur-Token generieren, kopieren Sie das Token sofort und speichern Sie es in
GITLAB_WEBHOOK_SIGNING_TOKEN. - Wählen Sie nur die erforderlichen Trigger aus – zum Beispiel Push-Ereignisse, Merge-Request-Ereignisse, Tag-Push-Ereignisse oder Pipeline-Ereignisse.
- Lassen Sie die SSL-Überprüfung aktiviert und speichern Sie das Webhook.
- Verwenden Sie die Testaktion von GitLab oder erzeugen Sie ein echtes Ereignis und überprüfen Sie dann die lokale Anfrage und die GitLab-Lieferhistorie.
Starten Sie den lokalen Prozess nach dem Setzen der Umgebungsvariable neu. Wenn Sie eine bestehende Integration migrieren, erlaubt GitLab ein Signierungstoken und ein altes geheimes Token zusammen. Überprüfen Sie webhook-signature , wenn vorhanden, greifen Sie vorübergehend auf X-Gitlab-Token zurück, und entfernen Sie dann das schwächere geheime Token, nachdem alle Empfänger Signaturen unterstützen.
Versenden Sie GitLab-Ereignisse nach Header und Payload
X-Gitlab-Event gibt einen lesbaren Ereignisnamen wie Push Hook oder Merge Request Hook aus. Verwenden Sie ihn für das Routing, aber validieren Sie auch die object_kind der Payload. Dies macht unerwartete Kombinationen sichtbar.
switch (req.get('x-gitlab-event')) {
case 'Push Hook':
await handlePush(payload);
break;
case 'Merge Request Hook':
await handleMergeRequest(payload);
break;
case 'Pipeline Hook':
await handlePipeline(payload);
break;
default:
await recordUnsupportedGitLabEvent(payload.object_kind);
}
Push-Ereignisse
Erstellung von Test-Branches, normale Commits, Force-Pushes und Branch-Löschungen. Eine Null-SHA kann eine fehlende Seite eines Ref-Übergangs darstellen. Große Pushes können sich von einem Ein-Commit-Fixture unterscheiden, daher sollte man nicht annehmen, dass jeder geänderte Commit in einem unbegrenzten Array erscheint. Verwenden Sie Projekt- und Ref-Identifikatoren, anstatt einen Anzeige-String zu parsen.
Merge-Request-Ereignisse
Aktionen wie Öffnen, Aktualisieren, Genehmigen, Mergen und Schließen können denselben breiten Ereignistyp teilen. Leiten Sie nach dokumentierten Objektattributen und machen Sie wiederholte Aktualisierungen idempotent. Mergen Sie niemals Code oder genehmigen Sie eine Bereitstellung nur, weil ein veränderbarer Titel oder Benutzername übereinstimmt.
Pipeline- und Job-Ereignisse
Diese können häufig auftreten. Filtern Sie sowohl in GitLab als auch erneut in Ihrem Handler nach Projekt, Branch, Status und Umgebung. Queueen Sie langsame Artefakt- oder Bereitstellungsaufgaben und bestätigen Sie zunächst das Webhook.
Design für Wiederholungen und rekursive Trigger
GitLab enthält webhook-id, das über Wiederholungen hinweg konsistent bleibt und dem alten Idempotency-Key entspricht. Verwenden Sie es als Idempotenzschlüssel für die Lieferung. X-Gitlab-Webhook-UUID identifiziert eine Webhook-Ausführung, während X-Gitlab-Event-UUID helfen kann, Ereignisse nachzuverfolgen; rekursive Webhooks können die Ereignis-UUID teilen.
Wenn der Handler GitLab über die API ändert, kann er einen weiteren Webhook erstellen. Fügen Sie eine explizite Schleifenvermeidung hinzu: Kennzeichnen Sie Aktionen mit Ihrer Integrationsidentität, ignorieren Sie Änderungen, die den gewünschten Zustand nicht ändern, und begrenzen Sie Workflow-Übergänge. Der Retry- und Idempotenzleitfaden behandelt transaktionale Posteingangsmuster.
Fehlgeschlagene GitLab-Webhook-Tests beheben
GitLab kann keine Verbindung zur URL herstellen
Bestätigen Sie, dass der Tunnelprozess aktiv ist, der vollständige Pfad korrekt ist und Ihr lokaler Server auf dem weitergeleiteten Port lauscht. Bei selbst verwaltetem GitLab überprüfen Sie die ausgehenden Netzwerk-Richtlinien und DNS. Deaktivieren Sie die SSL-Überprüfung nicht, um einen nicht zusammenhängenden Routing-Fehler zu verbergen.
Die Signatur stimmt niemals überein
Verwenden Sie das Signier-Token, nicht das alte Geheim-Token. Entfernen Sie whsec_, decodieren Sie das verbleibende Token in Base64 und signieren Sie {webhook-id}.{webhook-timestamp}.{raw body}. Kodieren Sie das binäre HMAC-Digest in Base64 und setzen Sie v1, davor. Vergleichen Sie es mit jeder durch Leerzeichen getrennten Signatur.
Der Zeitstempel wird abgelehnt
Überprüfen Sie die Systemzeit und die Zeitzonenbehandlung; der Header ist ein Unix-Zeitstempel in Sekunden. Vergleichen Sie ihn nicht mit JavaScript-Millisekunden ohne Division durch 1000. Wenn Sie eine aufgezeichnete alte Anfrage debuggen, ist die Ablehnung des Zeitstempels ein korrekter Wiedergabeschutz.
GitLab deaktiviert oder reduziert den Webhook
Überprüfen Sie den aktuellen Lieferstatus und die Antwort Ihrer Route. Geben Sie nach dauerhafter Annahme schnell 2xx zurück. Wiederholte 401 bedeuten, dass die Token-Konfiguration falsch ist; wiederholte 5xx bedeuten Handler-Fehler; Zeitüberschreitungen weisen auf zu viel synchrone Arbeit hin.
Nur einige Ereignisse werden empfangen
Überprüfen Sie ausgewählte Trigger und Branch-Filter. Gruppen- und Projekt-Webhooks haben unterschiedliche Reichweiten. Bestätigen Sie, dass das Ereignis im genauen Projekt aufgetreten ist, in dem dieser Webhook konfiguriert ist.
Halten Sie lokale GitLab-Webhook-Daten sicher
- Speichern Sie Signierungstoken nur in ignorierten Umgebungsdateien und wechseln Sie alle durchgesickerten Token.
- Überprüfen Sie Signaturen, Zeitstempel, Projekt-IDs und erlaubte Ereignistypen, bevor Seiteneffekte auftreten.
- Schwärzen Sie Commit-Nachrichten, private Repository-URLs, Benutzer-E-Mails und CI-Variablen aus Aufzeichnungen.
- Geben Sie dem Integrations-API-Token nur die Berechtigungen, die für seine nachgelagerte Aktion erforderlich sind.
- Löschen Sie die lokale Payload-Historie, wenn der Test beendet ist.
Für providerunabhängige Diagnosen verwenden Sie die Anleitung zur lokalen Webhook-Debugging. GitHub verwendet ein anderes Signaturformat, daher konsultieren Sie die separate GitHub-Webhook-Anleitung , anstatt dessen Prüfer wiederzuverwenden.
