[CLAUDE] App: Plan B Hotfix Reviewer — CreateContractCommand validate ApplicableType=Contract
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Reviewer pre-push verify (agentId ace4799) catch MAJOR security gap: CreateContractCommand thiếu validation guard rằng ApprovalWorkflowId pin phải có ApplicableType=Contract(3). Attacker forge POST body với V2 PE workflow ID (ApplicableType=1/2 DuyetNcc) → contract pin sai workflow type → Service ApproveV2Async sẽ run pattern PE workflow trên Contract entity → behavior nondeterministic + audit log nhầm. Fix: Mirror PE pattern PurchaseEvaluationFeatures.cs:62-77. Validation block thêm vào CreateContractCommandHandler.Handle sau activeWfId query: 1. Load aw entity by Id (throw NotFound nếu invalid Guid) 2. Verify aw.ApplicableType == Contract(3) (throw Conflict nếu mismatch) Defense-in-depth: FE Workspace dropdown (Chunk D62b50d1) đã filter ApplicableType=3 client-side; BE guard chặn request forge. Verify: - dotnet build PASS 0 err 2 pre-existing warn - dotnet test 111/111 PASS — 0 regression - Mirror PE pattern exact (only switch enum DuyetNcc/PhuongAn → Contract literal) Smart Friend ROI: Reviewer caught MAJOR before push prod. Cumulative S22 #44 + S25 #48 + S29 (this Hotfix) — pattern proven 3× Reviewer save UAT 401/403 prod incidents. Plan B chain COMPLETE 10/10 (9 + 1 hotfix): - A158898e8/ A2a85e437/ B138469d/ C26c98d3/ B21f199b0- E1ef23308/ D62b50d1/ E248f6d22/ E314feb69- Hotfix Rev (this) ApplicableType=Contract guard Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -70,6 +70,21 @@ public class CreateContractCommandHandler(
|
||||
.Select(w => (Guid?)w.Id)
|
||||
.FirstOrDefaultAsync(ct);
|
||||
|
||||
// [Plan B S29 2026-05-22 Hotfix Reviewer] Validate ApprovalWorkflowId V2
|
||||
// (Mig 32) — User chọn lúc create. Phải tồn tại + ApplicableType=Contract(3).
|
||||
// Mirror PE pattern PurchaseEvaluationFeatures.cs:62-77. Defense-in-depth:
|
||||
// FE Workspace dropdown đã filter ApplicableType=3 server-side; BE guard
|
||||
// chặn attacker forge POST với PE workflow ID (ApplicableType=1/2).
|
||||
if (request.ApprovalWorkflowId is Guid awId)
|
||||
{
|
||||
var aw = await db.ApprovalWorkflows.AsNoTracking()
|
||||
.FirstOrDefaultAsync(w => w.Id == awId, ct)
|
||||
?? throw new NotFoundException("ApprovalWorkflow", awId);
|
||||
if (aw.ApplicableType != Domain.ApprovalWorkflowsV2.ApprovalWorkflowApplicableType.Contract)
|
||||
throw new ConflictException(
|
||||
$"Quy trình {aw.Code} áp dụng cho {aw.ApplicableType}, không khớp với HĐ (cần ApplicableType=Contract).");
|
||||
}
|
||||
|
||||
// Validate Budget link nếu có: cùng Project + Phase=DaDuyet.
|
||||
if (request.BudgetId is Guid bid)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user