package financewithdrawal import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func TestCanAuditWithdrawalUsesDedicatedPermission(t *testing.T) { if !canAuditWithdrawal([]string{"finance-withdrawal:audit"}) { t.Fatal("finance withdrawal permission must allow finance final review") } if canAuditWithdrawal([]string{"operations-withdrawal:audit"}) { t.Fatal("operations permission must not allow finance final review") } if canAuditWithdrawal([]string{"finance-application:audit"}) { t.Fatal("removed finance application permission must not authorize withdrawal auditing") } } func TestCanAuditOperationsWithdrawalUsesDedicatedPermission(t *testing.T) { if !canAuditOperationsWithdrawal([]string{"operations-withdrawal:audit"}) { t.Fatal("operations withdrawal permission must allow operations initial review") } if canAuditOperationsWithdrawal([]string{"finance-withdrawal:audit"}) { t.Fatal("finance permission must not allow operations initial review") } } func TestWithdrawalAuditHandlersRequireExplicitAppHeader(t *testing.T) { gin.SetMode(gin.TestMode) handler := &Handler{} router := gin.New() router.POST("/finance/:application_id/approve", handler.ApproveApplication) router.POST("/finance/:application_id/reject", handler.RejectApplication) router.POST("/operations/:application_id/approve", handler.ApproveOperationsApplication) router.POST("/operations/:application_id/reject", handler.RejectOperationsApplication) for _, path := range []string{ "/finance/77/approve", "/finance/77/reject", "/operations/77/approve", "/operations/77/reject", } { request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(`{}`)) request.Header.Set("Content-Type", "application/json") response := httptest.NewRecorder() router.ServeHTTP(response, request) if response.Code != http.StatusBadRequest || !strings.Contains(response.Body.String(), "X-App-Code") { t.Fatalf("missing App header path %s status=%d body=%s", path, response.Code, response.Body.String()) } } }