ปกติเรามักอัปเดต package ตอนที่นึกขึ้นได้ หรือตอนที่มีข่าวช่องโหว่ใหญ่ ๆ แล้วรัน composer update ทีเดียวทั้งโปรเจกต์ ผลคือ package ขยับทีละหลายเวอร์ชัน พอมีอะไรพังก็ไล่ยากว่าพังเพราะตัวไหน
ใน repo ของเว็บนี้มี PR ชื่อ "Bump vite from 8.3.0 to 8.3.4" ที่เราไม่ได้เปิดเอง คนเปิดคือ Dependabot ใน PR แก้แค่ package.json กับ package-lock.json มี release notes ของ Vite แนบมาให้อ่าน และ CI รันเทสต์กับ lint ผ่านแล้ว สิ่งที่เหลือให้เราทำคืออ่านแล้วตัดสินใจว่าจะ merge ไหม
Dependabot คืออะไร
Dependabot เป็นบริการของ GitHub ที่ดูแล dependency ของโปรเจกต์ให้ ไม่ต้องติดตั้งอะไรลงเครื่อง ทำงานอยู่บน GitHub ทั้งหมด แบ่งเป็นสามส่วนที่เปิดแยกกันได้
| ส่วน | ทำอะไร | เปิดจากไหน |
|---|---|---|
| Dependabot alerts | แจ้งเตือนเมื่อ package ที่เราใช้มีช่องโหว่ที่ประกาศแล้ว | Settings ของ repo |
| Dependabot security updates | เปิด PR อัปเดต package ตัวนั้นไปเวอร์ชันที่แก้ช่องโหว่แล้ว | Settings ของ repo |
| Dependabot version updates | เปิด PR อัปเดต package ที่มีเวอร์ชันใหม่ ตามรอบที่ตั้งไว้ | ไฟล์ .github/dependabot.yml |
ส่วน alerts มีอยู่ในทุก plan ของ GitHub รวมถึง GitHub Free ตามหน้าเปรียบเทียบ plan ใช้กับ repo แบบ private ได้ด้วย อย่าง repo ของเว็บนี้ก็เป็น private
Dependabot อ่าน lock file แล้วเทียบกับฐานข้อมูลช่องโหว่
GitHub สร้าง dependency graph จากไฟล์ manifest กับ lock file ใน repo ของเรา สำหรับโปรเจกต์ Laravel ก็คือ composer.json กับ composer.lock ฝั่ง PHP และ package.json กับ package-lock.json ฝั่ง JavaScript ทุกครั้งที่เรา push แล้ว dependency เปลี่ยน หรือมีช่องโหว่ใหม่เข้ามาใน GitHub Advisory Database Dependabot จะเทียบสองอย่างนี้กันใหม่
ถ้าเจอว่าเราใช้เวอร์ชันที่มีช่องโหว่ หน้า Security ของ repo จะขึ้น alert ที่บอกว่า
- ช่องโหว่อะไร ร้ายแรงแค่ไหน พร้อมระดับ Low ถึง Critical ที่คิดจากคะแนน CVSS (อ่านวิธีดูคะแนนได้ในคะแนน CVSS คืออะไร)
- เราใช้ package นี้ตรง ๆ หรือมันติดมากับตัวอื่น (direct หรือ transitive)
- package อยู่ใน runtime หรือ development อย่าง Vite อยู่ใน
devDependenciesใช้แค่ตอนพัฒนาและตอน build - เวอร์ชันไหนแก้แล้ว
ถ้าเปิด security updates ไว้ Dependabot จะเปิด PR อัปเดต package ตัวนั้นไปเวอร์ชันที่แก้ช่องโหว่แล้วให้เลย โดยไม่ต้องรอรอบเวลา PR ที่ผูกกับ alert แบบนี้ GitHub จำกัดไว้ที่ครั้งละ 10 PR และเมื่อเรา merge แล้ว alert ก็ปิดเอง
version updates ทำงานคนละแบบ Dependabot จะดูตามรอบที่เราตั้ง เช่น ทุกสัปดาห์ ว่ามี package ไหนออกเวอร์ชันใหม่ แล้วเปิด PR ให้ทีละตัว หรือรวมเป็นกลุ่มก็ได้ ค่าเริ่มต้นคือเปิดค้างไว้ไม่เกิน 5 PR และจะรอให้เวอร์ชันใหม่ออกมาครบ 3 วันก่อน เผื่อมีแพตช์แก้ตามมา ช่วงรอนี้ไม่ใช้กับ security updates
PR ทั้งสองแบบมี release notes, changelog และรายการ commit ของ package แนบมาด้วย ถ้า branch หลักขยับไปจน PR เกิด conflict Dependabot จะrebase ให้เอง ไปจนครบ 30 วัน หลังจากนั้นต้อง rebase เอง
เปิด Dependabot ใน repo ของเรา
alerts กับ security updates เปิดได้จากหน้าเว็บ ไม่ต้องเขียนไฟล์
- เข้า repo บน GitHub แล้วไปที่ Settings
- เลือกเมนู Advanced Security
- กด Enable ที่ Dependency graph, Dependabot alerts และ Dependabot security updates
ส่วน version updates ต้องเพิ่มไฟล์ .github/dependabot.yml ใน branch หลัก จะกด Enable ที่ Dependabot version updates ในหน้าเดียวกันให้ GitHub สร้างไฟล์ตั้งต้นให้ก็ได้ หรือเขียนเองแล้ว commit ขึ้นไปเลย
สำหรับโปรเจกต์ Laravel ทั่วไปที่มีทั้ง Composer, npm และ GitHub Actions ไฟล์ตั้งต้นหน้าตาแบบนี้
version: 2
updates:
- package-ecosystem: composer
directory: /
schedule:
interval: weekly
groups:
composer-minor-patch:
patterns: ['*']
update-types: [minor, patch]
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
groups:
npm-minor-patch:
patterns: ['*']
update-types: [minor, patch]
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
package-ecosystemบอกว่าให้ดู package แบบไหน ใช้composer,npmและgithub-actionsสำหรับ action ใน workflowdirectoryคือโฟลเดอร์ที่มีcomposer.jsonหรือpackage.jsonโปรเจกต์ Laravel อยู่ที่ราก repo จึงเป็น/ส่วน GitHub Actions ใช้/เสมอschedule.intervalเลือกได้ตั้งแต่daily,weekly,monthlyไปจนถึงyearlygroupsรวมการอัปเดต minor กับ patch ไว้ใน PR เดียว ส่วน major ที่อาจมี breaking change ยังแยกเป็น PR ของตัวเอง จะได้อ่าน upgrade guide ทีละตัว
ตัวเลือกทั้งหมดอยู่ในเอกสาร dependabot.yml ถ้าโปรเจกต์ดึง package จาก private registry เช่น Laravel Nova ต้องตั้ง registries ให้ Dependabot เข้าถึงด้วย ไม่อย่างนั้น Dependabot จะ resolve dependency ไม่ผ่าน
เว็บนี้ปิด PR อัปเดตเวอร์ชันไว้ เพราะ merge ทุกครั้งคือ deploy
เว็บนี้ deploy ขึ้น production ทุกครั้งที่มี commit เข้า main ถ้าเปิด version updates รายสัปดาห์ไว้ ก็จะมี PR อัปเดตเวอร์ชันเข้ามาทุกสัปดาห์ และกด merge ทีไรก็ deploy ทีนั้น เราอยากอัปเดต package เป็นรอบ ๆ ตอนที่นั่งอ่าน release notes และลองเปิดเว็บดูเองได้มากกว่า จึงตั้งไฟล์ไว้แบบนี้
version: 2
updates:
- package-ecosystem: composer
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 0
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 0
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
open-pull-requests-limit: 2
groups:
actions:
patterns: ['*']
open-pull-requests-limit: 0ปิด version updates ของ Composer กับ npm แต่ security updates ยังเข้ามาตามปกติ เพราะ GitHub นับ PR สองแบบนี้แยกกัน- GitHub Actions อัปเดตเดือนละครั้ง รวมทุก action ไว้ใน PR เดียว เช่น
actions/checkoutกับactions/setup-nodeขยับเวอร์ชันพร้อมกัน - alerts กับ security updates เปิดไว้ในหน้า Settings
ผลคือ PR จาก Dependabot ที่เข้ามาเกือบทั้งหมดเป็นเรื่องช่องโหว่ อย่าง PR ของ Vite ข้างบน ส่วนการอัปเดตเวอร์ชันทั่วไปเราทำเองเป็นรอบ ถ้าวันหนึ่งอยากให้ Dependabot เปิด PR รายสัปดาห์ให้ ก็แค่เปลี่ยนเลข 0 เป็นจำนวน PR ที่อยากให้เปิดค้างไว้
สิ่งที่ดูก่อนกด merge PR ของ Dependabot
PR ของ Dependabot จะคุ้มค่าก็ต่อเมื่อมีเทสต์คอยจับ ถ้า repo มี CI ที่รันตอนเปิด PR อยู่แล้ว PR พวกนี้ก็จะรันเทสต์ให้ทันที ใน repo นี้ PR ของ Vite ผ่านทั้ง test และ lint ส่วนขั้น deploy ข้ามไปเพราะยังไม่ได้ merge เข้า main ถ้ายังไม่มี CI ก็ดึง branch ของ PR ลงมารันเทสต์ในเครื่องก่อนได้
ก่อน merge ลองดูทีละข้อแบบนี้
- CI ผ่านไหม ถ้าไม่ผ่าน ให้เปิด log ดูก่อนว่าพังเพราะ package จริง หรือพังเพราะ workflow ต้องใช้ secret
- อ่าน release notes โดยเฉพาะ PR ที่ขยับ major version
- ดูว่าช่องโหว่กระทบ production ไหม ช่องโหว่ใน Vite ที่ทำให้มี PR นี้อยู่ใน dev server ซึ่งเปิดเฉพาะตอน
npm run devบนเครื่องเรา ส่วน production เสิร์ฟไฟล์ที่ build แล้ว จึงไม่รีบเท่าช่องโหว่ใน package ที่รันอยู่บน production แต่ก็ควร merge เพราะเครื่องที่ใช้พัฒนาก็เสี่ยงได้
ถ้าอยากสั่ง Dependabot เพิ่ม ให้พิมพ์ comment ใน PR ได้เลย คำสั่งที่ใช้บ่อย มีดังนี้
@dependabot rebaseให้ rebase PR กับ branch หลักใหม่@dependabot recreateสร้าง PR ใหม่ทั้งอัน ทับสิ่งที่เราแก้ไว้ใน PR@dependabot ignore this major versionปิด PR นี้ และไม่ต้องเปิด PR ของ major version นี้อีก จนกว่าเราจะอัปเดตเอง@dependabot ignore this dependencyปิด PR และเลิกอัปเดต package ตัวนี้
คำสั่ง ignore จะเก็บไว้ในฝั่ง GitHub ไม่ได้อยู่ในไฟล์ ถ้าทำงานกันหลายคน ให้เขียน ignore ลงใน dependabot.yml แทน คนอื่นจะได้เห็นว่าข้าม package ไหนไว้
ถ้าโค้ดไม่ได้อยู่บน GitHub
Dependabot ทำงานกับ repo บน GitHub เท่านั้น ถ้าโปรเจกต์อยู่บน GitLab, Bitbucket หรือยังไม่ได้ใช้ Git เลย ก็ยังเช็คช่องโหว่ได้จากเครื่องเราเอง
composer audit
npm audit
composer audit เทียบ package ใน composer.lock กับฐานข้อมูล advisory แล้วบอกว่าตัวไหนมีช่องโหว่ npm audit ทำแบบเดียวกันกับ package-lock.json ใส่สองคำสั่งนี้ไว้ในขั้นตอน deploy หรือรันก่อนขึ้นงานใหม่ทุกครั้งก็ช่วยได้มาก
ถ้าอยากได้ PR อัปเดตอัตโนมัติแบบ Dependabot บนที่อื่น ลองดู Renovate ซึ่งเป็น open source รองรับทั้ง GitHub, GitLab และ Bitbucket และรันบนเซิร์ฟเวอร์ของเราเองได้






