[CLAUDE] Infra: go nhanh S92 khoi revoker (owner supersede: hien thi het) + skeleton menu GD2/GD4 + ComingSoonPage x2
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m56s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m56s
- RevokeTemporarilyHiddenModulesAsync: GO Contracts+Ct_*/Master-set khoi predicate (bai tra gia: grant SQL tay bi revoker lat o restart #423 - 447/494 row roi; regrant=447 da chay truoc commit nay). Hrm/Off/Personal GIU (y owner: vung dang-lam chi admin) - reviewKeys += ContractMenuKeys + MasterMenuKeys + KhkkKeys + HdcKeys (CanRead-only all-role, fresh-env hoi tu) - Seeder tree.Add: Khkk_G1 + 4 leaves (khuon Duyet NCC) + Hdc_x7 (tai dung nhan 01.-07.) - prod da INSERT truc tiep (perm=156) - ComingSoonPage mirror x2 (md5-identical) + route /coming-soon x2 + staticMap 11 leaf x2 (gotcha #50) - Test: AdminOnlyModulesRevokeTests tach StillHidden/Reopened + REGRESSION-GUARD S159 (re-add nhanh S92 => do); ProcurementMasterAccessSeedTests doc lai isolation bang CO CAO (spec-change S92->S159, update test + code chung commit) - 562 test PASS - nghiem thu cuoi = restart THAT khi deploy run nay (khuon S91) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@ -32,26 +32,37 @@ namespace SolutionErp.Infrastructure.Tests.Application;
|
||||
// (Cascade) → PHẢI seed MenuItem rows + Role TRƯỚC khi seed Permission (nếu không SQLite FK Error 19).
|
||||
public class AdminOnlyModulesRevokeTests
|
||||
{
|
||||
// Đại diện 5 nhóm anh chốt admin-only — sau revoke PHẢI CanRead=false (non-Admin).
|
||||
// Dùng const/factory MenuKeys (KHÔNG hardcode string) để bắt đồng-bộ nếu key đổi.
|
||||
private static readonly string[] S92HiddenKeys =
|
||||
// [S159 2026-07-29] Owner SUPERSEDE S92: "đang phát triển → cho hiển thị hết để mọi
|
||||
// người góp ý; Duyệt NCC để như cũ" ⇒ nhánh Contracts/Ct_*/Master-set GỠ khỏi revoker.
|
||||
// Tập ẩn CÒN LẠI = 3 nhóm đang-làm (Hrm/Off/Personal — ý ❸ owner cùng ngày).
|
||||
private static readonly string[] StillHiddenKeys =
|
||||
{
|
||||
MenuKeys.Hrm, // "Hrm" — match StartsWith("Hrm")
|
||||
MenuKeys.Off, // "Off" — match StartsWith("Off")
|
||||
MenuKeys.Personal, // "Personal" — match == Personal
|
||||
};
|
||||
|
||||
// [S159] Bộ key S92 cũ nay MỞ LẠI — revoker KHÔNG ĐƯỢC chạm nữa. Giữ danh sách này
|
||||
// làm REGRESSION-GUARD: bài trả giá 2026-07-29 = grant 38 key bằng SQL tay bị chính
|
||||
// revoker lật ở app-restart kế (Run #423, 447/494 row rơi, 11/13 role về 0 —
|
||||
// cicd-verify-1a47a61.md mục 9). Ai re-add nhánh S92 vào predicate ⇒ test này ĐỎ.
|
||||
private static readonly string[] ReopenedKeys =
|
||||
{
|
||||
// HỢP ĐỒNG (Contracts + Ct_*)
|
||||
MenuKeys.Contracts,
|
||||
MenuKeys.ContractTypeGroup("ThauPhu"), // "Ct_ThauPhu" — match StartsWith("Ct_")
|
||||
MenuKeys.ContractTypeGroup("ThauPhu"), // "Ct_ThauPhu"
|
||||
// DANH MỤC (Master + 3 leaf + Catalog*)
|
||||
MenuKeys.Master,
|
||||
MenuKeys.Suppliers,
|
||||
MenuKeys.Projects,
|
||||
MenuKeys.Departments,
|
||||
MenuKeys.Catalogs, // "Catalogs" — match StartsWith("Catalog")
|
||||
MenuKeys.CatalogWorkItems, // "CatalogWorkItems" — match StartsWith("Catalog")
|
||||
// Nhóm cũ S58 (regression — vẫn phải ẩn)
|
||||
MenuKeys.Hrm, // "Hrm" — match StartsWith("Hrm")
|
||||
MenuKeys.Off, // "Off" — match StartsWith("Off")
|
||||
MenuKeys.Personal, // "Personal" — match == Personal
|
||||
MenuKeys.Catalogs,
|
||||
MenuKeys.CatalogWorkItems,
|
||||
};
|
||||
|
||||
private static readonly string[] S92HiddenKeys =
|
||||
StillHiddenKeys.Concat(ReopenedKeys).ToArray(); // giữ tên cho seed-helper cũ
|
||||
|
||||
// Pe_* (Duyệt NCC) + root PurchaseEvaluations — KHÔNG bị revoke (giữ cho user thường).
|
||||
private static readonly string[] PeKeptKeys =
|
||||
{
|
||||
@ -130,15 +141,22 @@ public class AdminOnlyModulesRevokeTests
|
||||
|
||||
await InvokeRevokeAsync(fix);
|
||||
|
||||
foreach (var key in S92HiddenKeys)
|
||||
// Vế 1 — 3 nhóm đang-làm VẪN bị revoke (ý ❸ giữ).
|
||||
foreach (var key in StillHiddenKeys)
|
||||
{
|
||||
var row = await GetPermAsync(db, nonAdminId, key);
|
||||
row.Should().NotBeNull($"{key} vẫn có row (revoke chỉ hạ cờ, KHÔNG xóa — giữ vết flip lại)");
|
||||
row!.CanRead.Should().BeFalse($"{key} bị revoke CanRead — menu ẩn khỏi non-Admin (chỉ Admin thấy)");
|
||||
row!.CanRead.Should().BeFalse($"{key} bị revoke CanRead — nhóm đang-làm ẩn khỏi non-Admin");
|
||||
row.CanCreate.Should().BeFalse($"{key} revoke CanCreate");
|
||||
row.CanUpdate.Should().BeFalse($"{key} revoke CanUpdate");
|
||||
row.CanDelete.Should().BeFalse($"{key} revoke CanDelete");
|
||||
}
|
||||
|
||||
// Vế 2 — ⭐ REGRESSION-GUARD S159: bộ key MỞ LẠI phải GIỮ NGUYÊN CanRead=true
|
||||
// sau revoke (revoker không còn nhánh S92; re-add là test này đỏ ngay).
|
||||
foreach (var key in ReopenedKeys)
|
||||
(await CanReadAsync(db, nonAdminId, key)).Should().BeTrue(
|
||||
$"{key} — owner S159 mở lại cho mọi role; revoker KHÔNG được lật grant này nữa");
|
||||
}
|
||||
|
||||
// Admin loại trừ khỏi revoke → giữ nguyên CanRead=true (vẫn thấy 5 nhóm).
|
||||
|
||||
@ -189,12 +189,14 @@ public class ProcurementMasterAccessSeedTests
|
||||
await InvokeRevokeAsync(fix); // revoke CẢ HAI role về false
|
||||
await InvokeSeedProcurementAsync(fix); // CHỈ nâng lại Procurement
|
||||
|
||||
// ⭐ ISOLATION: DeptManager row TỒN TẠI (revoke giữ vết) NHƯNG mọi cờ = false — seeder
|
||||
// Procurement KHÔNG chạm role khác. Assert cả Master + Suppliers (2 key task chốt) + 7 key kia.
|
||||
// ⭐ ISOLATION (đọc lại theo S159): revoker KHÔNG còn chạm Master-set ⇒ CanRead=true
|
||||
// pre-grant của DeptManager GIỮ NGUYÊN (chính sách all-role read — owner 2026-07-29
|
||||
// supersede S92). Isolation của Procurement-seed nay đo bằng CỜ CAO: seeder chỉ nâng
|
||||
// CanCreate/Update cho Procurement, KHÔNG rò cờ cao sang role khác.
|
||||
foreach (var key in AllGrantKeys)
|
||||
await AssertFlagsAsync(db, otherId, key,
|
||||
r: false, c: false, u: false, d: false,
|
||||
"DeptManager KHÔNG được Procurement-grant chạm — S92 'chỉ Admin thấy' giữ nguyên role khác");
|
||||
r: true, c: false, u: false, d: false,
|
||||
"S159 all-role read GIỮ; cờ cao KHÔNG rò sang DeptManager từ Procurement-grant");
|
||||
|
||||
// CONTRAST (chống vacuous-pass): Procurement THẬT SỰ được nâng → chứng seeder CÓ chạy,
|
||||
// nên isolation ở trên KHÔNG phải "false vì seeder no-op".
|
||||
@ -246,10 +248,10 @@ public class ProcurementMasterAccessSeedTests
|
||||
var procCount = await db.Permissions.AsNoTracking().CountAsync(p => p.RoleId == procurementId);
|
||||
procCount.Should().Be(AllGrantKeys.Length, "idempotent — chạy lại KHÔNG tạo row trùng");
|
||||
|
||||
// Role khác vẫn bị ẩn sau lần 2 (isolation bền vững).
|
||||
// Isolation bền vững sau lần 2 (S159: CanRead all-role GIỮ true; cờ cao vẫn false).
|
||||
foreach (var key in AllGrantKeys)
|
||||
await AssertFlagsAsync(db, otherId, key,
|
||||
r: false, c: false, u: false, d: false,
|
||||
"idempotent — lần seed thứ 2 KHÔNG rò sang DeptManager");
|
||||
r: true, c: false, u: false, d: false,
|
||||
"idempotent — lần seed thứ 2 KHÔNG rò CỜ CAO sang DeptManager (CanRead all-role S159 giữ)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user