ในการทดสอบเว็บฮุก GitLab บนเครื่อง localhost ให้เปิดเผยตัวจัดการท้องถิ่นของคุณผ่านอุโมงค์ HTTPS เพิ่ม URL นั้นภายใต้ การตั้งค่า → เว็บฮุก สร้างโทเค็นสำหรับการลงชื่อ และตรวจสอบลายเซ็นมาตรฐานของเว็บฮุก GitLab ก่อนวิเคราะห์ payload กระตุ้นการ push หรือ merge request ตรวจสอบการส่ง และทำซ้ำในเครื่องของคุณโดยไม่ต้องปรับใช้การรวมหลังจากทุกการเปลี่ยนแปลง
ใช้โทเค็นการลงชื่อของ GitLab แทนการใช้โทเค็นความลับแบบข้อความธรรมดาใหม่
GitLab รองรับกลไกสองแบบที่ง่ายต่อการสับสน โทเค็นความลับแบบเก่าจะถูกคัดลอกลงใน X-Gitlab-Token header ของคำขอ มันยืนยันความรู้ของค่าที่ใช้ร่วมกันแต่ไม่ปกป้องความสมบูรณ์ของตัวเนื้อหา GitLab แนะนำตอนนี้ให้ใช้ โทเค็นการลงชื่อ สำหรับเว็บฮุกใหม่ มันสร้างลายเซ็น HMAC-SHA256 และเป็นไปตามรูปแบบข้อความของเว็บฮุกมาตรฐาน
เอกสารเว็บฮุค GitLab อย่างเป็นทางการ กล่าวว่าคำขอที่ลงนามมี webhook-id, webhook-timestamp, และ webhook-signatureลายเซ็นครอบคลุมทั้งรหัสข้อความ เวลา และเนื้อหา JSON ดิบที่แน่นอน ซึ่งช่วยปกป้องความสมบูรณ์ทั้งต้นทางและข้อมูลที่ส่ง
ใช้งานการตรวจสอบ Webhooks มาตรฐานใน Node.js
โทเค็นการลงชื่อ GitLab จะแสดงเพียงครั้งเดียวและใช้ whsec_ คำนำหน้า ลบคำนำหน้านั้นออกและถอดรหัส Base64 ของส่วนที่เหลือเพื่อให้ได้คีย์ HMAC ลายเซ็นที่ได้รับแต่ละตัวมีรูปแบบ v1,<base64 signature>; ส่วนหัวอาจมีลายเซ็นที่คั่นด้วยช่องว่างหลายอัน
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));
}
หน้าต่างเวลาตราประทับห้านาทีที่แสดงที่นี่เป็นนโยบายของแอปพลิเคชัน ไม่ใช่ค่าที่จะคัดลอกโดยไม่คิด เลือกระดับความคลาดเคลื่อนที่รองรับความแตกต่างของนาฬิกาแต่ป้องกันการเล่นซ้ำที่มีประโยชน์ ซิงโครไนซ์นาฬิกาของเครื่องที่รับข้อมูล เก็บข้อมูลทุกชิ้นที่ยอมรับ webhook-id ภายใต้ข้อจำกัดเฉพาะเนื่องจากการตรวจสอบเวลาล่าสุดเพียงอย่างเดียวไม่สามารถป้องกันการส่งข้อความซ้ำสองครั้งทันทีได้
สร้างเส้นทาง webhook ของ Express
จับร่างกายดิบบนเส้นทางนี้ การเรียกใช้แบบทั่วโลก express.json() ก่อนการยืนยันจะทำลายการแทนค่าตามไบต์ทั้งหมดที่ GitLab ลงนาม
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);
ติดตั้งตัวแยกวิเคราะห์ JSON ปกติหลังเส้นทางเว็บฮุคหรือใช้ verify callback ของมันเพื่อรักษาบัฟเฟอร์ดิบ อย่าปิดการตรวจสอบลายเซ็นเพียงเพราะจุดสิ้นสุดส่งต่อไปที่ localhost URL ของอุโมงค์ยังสามารถเข้าถึงได้จากอินเทอร์เน็ตสาธารณะ
สร้างจุดสิ้นสุด HTTPS สาธารณะ
- เริ่มการรวมในเครื่องและทดสอบเส้นทางด้วยคำขอที่ตั้งใจไม่เซ็น มันควรคืนค่า 401 ซึ่งพิสูจน์ว่าการรับรองความถูกต้องทำงานอยู่
- รัน
npx portpreview 3000ในเทอร์มินัลอื่น - คัดลอกต้นทาง HTTPS และต่อท้าย
/webhooks/gitlab. - เก็บอุโมงค์ให้เปิดอยู่ตลอดทั้งการตั้งค่าและการทดสอบเหตุการณ์
การตรวจสอบ SSL ของ GitLab ควรเปิดใช้งานอยู่เสมอ อุโมงค์ที่มี TLS ที่ได้รับการยอมรับสาธารณะช่วยหลีกเลี่ยงข้อผิดพลาดของใบรับรองที่เซ็นด้วยตนเอง หาก GitLab ทำงานในเครือข่ายที่จัดการเองแบบส่วนตัว จะต้องสามารถเข้าถึง URL อุโมงค์สาธารณะได้เช่นกัน
ตั้งค่า webhook ของโปรเจ็ค
- เปิดโปรเจ็ค GitLab และเลือก การตั้งค่า → Webhooks.
- เลือก เพิ่ม webhook ใหม่ และวาง URL การส่งของอุโมงค์ทั้งหมด
- เลือก สร้างโทเค็นเซ็นชื่อ, คัดลอกโทเค็นทันที และบันทึกไว้ใน
GITLAB_WEBHOOK_SIGNING_TOKEN. - เลือกเฉพาะทริกเกอร์ที่จำเป็น เช่น เหตุการณ์ Push, เหตุการณ์ Merge request, เหตุการณ์ Tag push หรือเหตุการณ์ Pipeline
- ปล่อยการตรวจสอบ SSL ไว้และบันทึก webhook.
- ใช้การกระทำทดสอบของ GitLab หรือสร้างเหตุการณ์จริง แล้วตรวจสอบคำขอภายในเครื่องและประวัติการส่งของ GitLab.
รีสตาร์ทกระบวนการภายในเครื่องหลังจากตั้งค่าตัวแปรสภาพแวดล้อม หากคุณกำลังย้ายการรวมระบบที่มีอยู่ GitLab อนุญาตให้ใช้โทเค็นลายเซ็นและโทเค็นลับแบบเก่าพร้อมกัน ตรวจสอบ webhook-signature เมื่อมีอยู่ หากจำเป็น ให้กลับไปใช้ X-Gitlab-Token ชั่วคราว จากนั้นลบโทเค็นลับที่อ่อนกว่าออกเมื่อผู้รับทั้งหมดรองรับลายเซ็นแล้ว.
ส่งเหตุการณ์ GitLab ตามเฮดเดอร์และเพย์โหลด
X-Gitlab-Event จะให้ชื่อเหตุการณ์ที่อ่านได้ เช่น Push Hook หรือ Merge Request Hook ใช้มันเพื่อการกำหนดเส้นทาง แต่ต้องตรวจสอบ object_kind ของเพย์โหลดด้วย สิ่งนี้ทำให้การรวมกันที่ไม่คาดคิดสามารถมองเห็นได้.
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
ทดสอบการสร้างสาขา, การคอมมิตธรรมดา, การบังคับ push, และการลบสาขา ค่า SHA เป็นศูนย์สามารถแทนด้านที่หายไปของการเปลี่ยนแปลง ref การ push ขนาดใหญ่สามารถแตกต่างจาก fixture ที่มีเพียงคอมมิตเดียว ดังนั้นอย่าสมมติว่าคอมมิตที่เปลี่ยนแปลงทุกอันจะปรากฏในอาร์เรย์ที่ไม่มีขีดจำกัด ใช้ตัวระบุโปรเจกต์และ ref แทนการแยกวิเคราะห์สตริงที่แสดงผล
เหตุการณ์คำขอการรวม
การกระทำเช่น เปิด, อัปเดต, อนุมัติ, รวม, และปิด อาจแชร์ประเภทเหตุการณ์กว้างเดียวกัน ส่งเส้นทางตามคุณสมบัติของวัตถุที่มีเอกสารและทำให้อัปเดตซ้ำ ๆ เป็น idempotent อย่ารวมโค้ดหรืออนุมัติการปรับใช้เพียงเพราะชื่อเรื่องหรือชื่อผู้ใช้ที่เปลี่ยนแปลงได้ตรงกัน
เหตุการณ์ pipeline และงาน
สิ่งเหล่านี้สามารถเกิดบ่อย กรองที่ GitLab และอีกครั้งในตัวจัดการของคุณตามโปรเจกต์, สาขา, สถานะ, และสภาพแวดล้อม จัดลำดับคิวงานชิ้นงาน artifact หรือ deployment ที่ช้าและยืนยัน webhook ก่อน
ออกแบบสำหรับการลองใหม่และทริกเกอร์แบบเรียกซ้ำ
GitLab รวมถึง webhook-id, ซึ่งยังคงความสอดคล้องกันในทุกครั้งที่ลองใหม่และเท่ากับแบบเดิม Idempotency-Key. ใช้มันเป็นคีย์ความไม่เปลี่ยนแปลงของการส่ง X-Gitlab-Webhook-UUID ระบุการทำงานของเว็บฮุค ในขณะที่ X-Gitlab-Event-UUID สามารถช่วยติดตามเหตุการณ์ได้; เว็บฮุกแบบวนซ้ำอาจแชร์ UUID ของเหตุการณ์
หากผู้จัดการแก้ไข GitLab ผ่าน API อาจสร้าง webhook อีกตัว เพิ่มการป้องกันลูปอย่างชัดเจน: ทำเครื่องหมายการกระทำด้วยตัวตนของการรวมของคุณ มองข้ามการเปลี่ยนแปลงที่ไม่ได้เปลี่ยนแปลงสถานะที่ต้องการ และจำกัดการเปลี่ยนแปลงของเวิร์กโฟลว์ คู่มือการลองใหม่และความสามารถในการดำเนินการซ้ำโดยไม่เปลี่ยนผลลัพธ์ ครอบคลุมรูปแบบกล่องจดหมายธุรกรรม
แก้ไขปัญหาการทดสอบ webhook ของ GitLab ที่ล้มเหลว
GitLab ไม่สามารถเชื่อมต่อกับ URL ได้
ยืนยันว่ากระบวนการท่อยังทำงานอยู่, เส้นทางเต็มถูกต้อง, และเซิร์ฟเวอร์ภายในเครื่องของคุณรอฟังที่พอร์ตที่ส่งต่อ สำหรับ GitLab ที่จัดการเอง, ตรวจสอบนโยบายเครือข่ายขาออกและ DNS อย่าลบการตรวจสอบ SSL เพื่อปกปิดความล้มเหลวของการส่งต่อที่ไม่เกี่ยวข้อง
ลายเซ็นไม่ตรงกันเลย
ใช้โทเค็นการเซ็น, ไม่ใช่โทเค็นความลับเก่า ตัด whsec_, ถอดรหัส Base64 ของโทเค็นที่เหลือ, และเซ็น {webhook-id}.{webhook-timestamp}.{raw body} เข้ารหัส Base64 ของ HMAC digest แบบไบนารี่และเติมหน้า v1, เปรียบเทียบกับลายเซ็นที่คั่นด้วยช่องว่างทั้งหมด
เวลาประทับถูกปฏิเสธ
ตรวจสอบเวลาระบบและการจัดการเขตเวลา; เฮดเดอร์เป็นเวลาสำหรับ Unix เป็นวินาที อย่าเปรียบเทียบกับมิลลิวินาทีของ JavaScript โดยไม่หารด้วย 1000 หากกำลังดีบักคำขอเก่าที่จับไว้, การปฏิเสธเวลาประทับถือเป็นการป้องกันการเล่นซ้ำที่ถูกต้อง
GitLab ปิดใช้งานหรือถอยกลับ webhook
ตรวจสอบสถานะการส่งล่าสุดและการตอบสนองของเส้นทางของคุณ ส่งกลับ 2xx อย่างรวดเร็วหลังจากการยอมรับที่ทนทาน 401 ซ้ำ ๆ หมายถึงการตั้งค่าโทเค็นผิดพลาด; 5xx ซ้ำ ๆ หมายถึงข้อผิดพลาดของตัวจัดการ; เวลา timeout บ่งชี้ว่ามีงาน synchronous มากเกินไป
มีเพียงบางเหตุการณ์ที่มาถึง
ตรวจสอบทริกเกอร์ที่เลือกและตัวกรองสาขา Webhook ของกลุ่มและโปรเจ็กต์มีขอบเขตต่างกัน ยืนยันว่าเหตุการณ์เกิดขึ้นในโปรเจ็กต์ที่ตั้งค่า webhook นี้อย่างถูกต้อง
เก็บข้อมูล webhook ของ GitLab ในเครื่องให้ปลอดภัย
- เก็บโทเค็นการลงชื่อในไฟล์สภาพแวดล้อมที่ถูกละเว้นเท่านั้นและหมุนเวียนโทเค็นที่รั่วไหลใด ๆ
- ตรวจสอบลายเซ็น เวลาโปรแกรมโปรเจ็กต์ และประเภทเหตุการณ์ที่อนุญาตก่อนผลกระทบทางด้านข้าง
- ลบข้อความ commit, URL ของ repository ส่วนตัว, อีเมลผู้ใช้ และตัวแปร CI จากการจับข้อมูล
- ให้โทเค็น API การรวมระบบมีเพียงขอบเขตที่จำเป็นสำหรับการกระทำด้านล่างของมันเท่านั้น
- ลบประวัติข้อความ payload ในเครื่องเมื่อการทดสอบสิ้นสุดลง
สำหรับการวินิจฉัยที่ไม่ขึ้นกับผู้ให้บริการ ให้ใช้ คู่มือการดีบัก webhook ในเครื่อง GitHub ใช้รูปแบบลายเซ็นที่แตกต่างกัน ดังนั้นให้ปรึกษา คู่มือ webhook ของ GitHub แยกต่างหาก แทนที่จะนำตัวตรวจสอบของมันมาใช้ซ้ำ
