Quyền có trong bảng phân quyền nhưng không route nào kiểm tra
Bảng phân quyền ghi session.manage chỉ dành cho quản trị hệ thống, còn route thu hồi phiên đăng nhập lại kiểm một quyền khác. Test quét route vẫn xanh. Cách phát hiện quyền khai báo mà không ai dùng, và một test ngược chiều để bắt nó.
Một hệ thống tuyển sinh có 50 quyền và 5 vai trò (cán bộ, trưởng ban, biên tập, quản trị hệ thống, người xem). Mỗi quyền là một chuỗi như application.review hay user.manage, và có một bảng ghi vai trò nào được quyền nào. Bảng này còn có test riêng, viết tay độc lập với code, để ai sửa nhầm một ô là test đỏ.
Vậy mà vẫn có một quyền nằm trong bảng, đúng từng ô, và không route nào hỏi tới nó.
Cái gì đã xảy ra
Quyền session.manage nghĩa là “được thu hồi phiên đăng nhập của người khác”. Trong bảng, chỉ quản trị hệ thống có quyền này. Còn route làm việc đó, DELETE /api/admin/users/[id]/sessions, lại khai báo:
Sửa là đổi đúng một chuỗi. Với bảng hiện tại, user.manage và session.manage cùng chỉ có ở quản trị hệ thống, nên chưa ai bị ảnh hưởng. Nhưng lỗi vẫn thật: bảng phân quyền nói một đằng, code làm một nẻo. Ngày bạn muốn cho trưởng ban thu hồi phiên mà không được sửa tài khoản, bạn cấp session.manage trong bảng, test bảng xanh, và trưởng ban vẫn bị chặn. Ngược lại, ai đó được cấp user.manage để quản lý tài khoản sẽ tự nhiên có thêm quyền ngắt phiên của mọi người.
Quyền được cấp nhiều hơn dự định thì là lỗ hổng. Được cấp ít hơn thì là lỗi khó hiểu. Cả hai đến từ cùng một chỗ.
Vì sao hai lớp test đều không thấy
Dự án này đã làm khá kỹ:
Test ma trận: mỗi quyền, mỗi vai trò, có hay không, khớp với một bảng viết tay.
Test E2E quét mã nguồn, liệt kê mọi route, và bắt buộc route nào cho nhân viên đều phải khai báo một quyền. Ai quên khai báo là đỏ.
Hai test này cùng nhìn một hướng: từ route đi tới quyền (“route có khai báo quyền không”) và từ vai trò đi tới quyền (“vai trò có đúng quyền không”). Không test nào hỏi chiều ngược lại: quyền này có route nào dùng không? Route khai báo user.manage là hợp lệ. Quyền session.manage có mặt trong bảng là hợp lệ. Mỗi mảnh đều đúng, chỉ cái mối nối giữa chúng đứt.
Mình thấy kiểu đứt này hay gặp ở code do AI viết từng mảnh. Một lần nhờ “thêm quyền session.manage vào bảng”, lần khác nhờ “viết route thu hồi phiên”. Mỗi lần AI làm đúng việc được giao, và chọn quyền gần nghĩa nhất đang có sẵn ở lần sau.
Test ngược chiều
Ý rất ngắn: mọi quyền trong danh sách phải được dùng ít nhất một lần ngoài file định nghĩa.
import { PERMISSIONS } from './permissions'it('mọi quyền đều có nơi kiểm tra', () => { const source = readAllSources(['apps', 'packages'], { skip: ['auth/permissions'] }) for (const p of PERMISSIONS) { expect(source, `quyền ${p} không nơi nào dùng`).toContain(`'${p}'`) }})
Còn nếu chưa muốn viết test, quét tay bằng grep cũng được: với mỗi quyền, tìm chuỗi 'tên.quyền' trong code, bỏ file định nghĩa và file test ma trận. Không ra kết quả nào là quyền đang treo.
Mình chạy cách quét này trên dự án sau khi sửa: cả 50 quyền đều có chỗ dùng. Trước khi sửa, session.manage là quyền duy nhất không route nào gọi tên.
Cách này chỉ bắt được “quyền không ai dùng”. Nó không bắt được trường hợp route dùng nhầm một quyền khác đã có người dùng. Cái đó cần đọc từng route đối chiếu với mô tả quyền, hoặc viết test E2E gọi route bằng từng vai trò và xem ai bị chặn. Dự án này có test kiểu đó cho các route nhạy cảm.
Kiểm tra app của bạn
Liệt kê toàn bộ quyền hoặc vai trò của app (enum, bảng, file cấu hình).
Với mỗi quyền, grep xem có bao nhiêu route hoặc hàm kiểm tra nó. Quyền ra 0 kết quả thì hoặc là thừa, hoặc là một chỗ nào đó đang kiểm nhầm quyền khác.
Đọc lại mô tả của mỗi quyền và mở route tương ứng, xem hành động thực tế có đúng như tên quyền nói không. Chú ý các hành động cắt đứt hay xóa: thu hồi phiên, xóa tài khoản, xuất dữ liệu.
Thêm test ngược chiều ở trên để lần sau AI thêm quyền mà quên nối, test đỏ ngay.
phân quyềnkiểm thửvibe code/anh/web/quyen-khai-bao-roi-khong-route-nao-kiem-tra-480.webpphân quyền · kiểm thử · vibe code
Quyen co trong bang phan quyen nhung khong route nao kiem tra Bang phan quyen ghi session.manage chi danh cho quan tri he thong, con route thu hoi phien dang nhap lai kiem mot quyen khac. Test quet route van xanh. Cach phat hien quyen khai bao ma khong ai dung, va mot test nguoc chieu de bat no. phan quyen kiem thu vibe code Mot he thong tuyen sinh co 50 quyen va 5 vai tro (can bo, truong ban, bien tap, quan tri he thong, nguoi xem). Moi quyen la mot chuoi nhu `application.review` hay `user.manage`, va co mot bang ghi vai tro nao duoc quyen nao. Bang nay con co test rieng, viet tay doc lap voi code, de ai sua nham mot o la test do.

Vay ma van co mot quyen nam trong bang, dung tung o, va khong route nao hoi toi no.
## Cai gi da xay ra
Quyen `session.manage` nghia la "duoc thu hoi phien dang nhap cua nguoi khac". Trong bang, chi quan tri he thong co quyen nay. Con route lam viec do, `DELETE /api/admin/users/[id]/sessions`, lai khai bao:
```ts
export const DELETE = handler(
{
auth: 'staff',
permission: 'user.manage', // bang noi session.manage
// ...
```
Sua la doi dung mot chuoi. Voi bang hien tai, `user.manage` va `session.manage` cung chi co o quan tri he thong, nen chua ai bi anh huong. Nhung loi van that: bang phan quyen noi mot dang, code lam mot neo. Ngay ban muon cho truong ban thu hoi phien ma khong duoc sua tai khoan, ban cap `session.manage` trong bang, test bang xanh, va truong ban van bi chan. Nguoc lai, ai do duoc cap `user.manage` de quan ly tai khoan se tu nhien co them quyen ngat phien cua moi nguoi.
Quyen duoc cap nhieu hon du dinh thi la lo hong. Duoc cap it hon thi la loi kho hieu. Ca hai den tu cung mot cho.
## Vi sao hai lop test deu khong thay
Du an nay da lam kha ky:
- Test ma tran: moi quyen, moi vai tro, co hay khong, khop voi mot bang viet tay.
- Test E2E quet ma nguon, liet ke moi route, va bat buoc route nao cho nhan vien deu phai khai bao mot quyen. Ai quen khai bao la do.
Hai test nay cung nhin mot huong: tu route di toi quyen ("route co khai bao quyen khong") va tu vai tro di toi quyen ("vai tro co dung quyen khong"). Khong test nao hoi chieu nguoc lai: **quyen nay co route nao dung khong?** Route khai bao `user.manage` la hop le. Quyen `session.manage` co mat trong bang la hop le. Moi manh deu dung, chi cai moi noi giua chung dut.
Minh thay kieu dut nay hay gap o code do AI viet tung manh. Mot lan nho "them quyen session.manage vao bang", lan khac nho "viet route thu hoi phien". Moi lan AI lam dung viec duoc giao, va chon quyen gan nghia nhat dang co san o lan sau.
## Test nguoc chieu
Y rat ngan: moi quyen trong danh sach phai duoc dung it nhat mot lan ngoai file dinh nghia.
```ts
import { PERMISSIONS } from './permissions'
it('moi quyen deu co noi kiem tra', () => {
const source = readAllSources(['apps', 'packages'], { skip: ['auth/permissions'] })
for (const p of PERMISSIONS) {
expect(source, `quyen ${p} khong noi nao dung`).toContain(`'${p}'`)
}
})
```
Con neu chua muon viet test, quet tay bang grep cung duoc: voi moi quyen, tim chuoi `'ten.quyen'` trong code, bo file dinh nghia va file test ma tran. Khong ra ket qua nao la quyen dang treo.
Minh chay cach quet nay tren du an sau khi sua: ca 50 quyen deu co cho dung. Truoc khi sua, `session.manage` la quyen duy nhat khong route nao goi ten.
Cach nay chi bat duoc "quyen khong ai dung". No khong bat duoc truong hop route dung nham mot quyen khac da co nguoi dung. Cai do can doc tung route doi chieu voi mo ta quyen, hoac viet test E2E goi route bang tung vai tro va xem ai bi chan. Du an nay co test kieu do cho cac route nhay cam.
## Kiem tra app cua ban
1. Liet ke toan bo quyen hoac vai tro cua app (enum, bang, file cau hinh).
2. Voi moi quyen, grep xem co bao nhieu route hoac ham kiem tra no. Quyen ra 0 ket qua thi hoac la thua, hoac la mot cho nao do dang kiem nham quyen khac.
3. Doc lai mo ta cua moi quyen va mo route tuong ung, xem hanh dong thuc te co dung nhu ten quyen noi khong. Chu y cac hanh dong cat dut hay xoa: thu hoi phien, xoa tai khoan, xuat du lieu.
4. Them test nguoc chieu o tren de lan sau AI them quyen ma quen noi, test do ngay.