@@ -356,6 +356,66 @@ func TestCreateMiddleware(t *testing.T) {
356356 require .NoError (t , mw .Close ())
357357}
358358
359+ //nolint:paralleltest // Uses httptest server.
360+ func TestValidatingMiddleware_HTTP422AlwaysDenies (t * testing.T ) {
361+ tests := []struct {
362+ name string
363+ failurePolicy webhook.FailurePolicy
364+ }{
365+ {
366+ name : "fail policy" ,
367+ failurePolicy : webhook .FailurePolicyFail ,
368+ },
369+ {
370+ name : "ignore policy" ,
371+ failurePolicy : webhook .FailurePolicyIgnore ,
372+ },
373+ }
374+
375+ for _ , tt := range tests {
376+ tt := tt
377+ t .Run (tt .name , func (t * testing.T ) {
378+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
379+ w .WriteHeader (http .StatusUnprocessableEntity )
380+ _ , _ = w .Write ([]byte ("unprocessable request" ))
381+ }))
382+ defer server .Close ()
383+
384+ cfg := webhook.Config {
385+ Name : "test-webhook" ,
386+ URL : server .URL ,
387+ Timeout : webhook .DefaultTimeout ,
388+ FailurePolicy : tt .failurePolicy ,
389+ TLSConfig : & webhook.TLSConfig {
390+ InsecureSkipVerify : true ,
391+ },
392+ }
393+
394+ client , err := webhook .NewClient (cfg , webhook .TypeValidating , nil )
395+ require .NoError (t , err )
396+
397+ mw := createValidatingHandler ([]clientExecutor {{client : client , config : cfg }}, "test-server" , "stdio" )
398+
399+ reqBody := []byte (`{"jsonrpc":"2.0","method":"tools/call","id":1}` )
400+ req := httptest .NewRequest (http .MethodPost , "/" , bytes .NewReader (reqBody ))
401+ ctx := context .WithValue (req .Context (), mcp .MCPRequestContextKey , & mcp.ParsedMCPRequest {Method : "tools/call" , ID : 1 })
402+ req = req .WithContext (ctx )
403+
404+ var nextCalled bool
405+ nextHandler := http .HandlerFunc (func (_ http.ResponseWriter , _ * http.Request ) {
406+ nextCalled = true
407+ })
408+
409+ rr := httptest .NewRecorder ()
410+ mw (nextHandler ).ServeHTTP (rr , req )
411+
412+ assert .False (t , nextCalled )
413+ assert .Equal (t , http .StatusForbidden , rr .Code )
414+ assert .Contains (t , rr .Body .String (), "Request denied by policy" )
415+ })
416+ }
417+ }
418+
359419//nolint:paralleltest // Shares a mock HTTP server and lastRequest state
360420func TestMultiWebhookChain (t * testing.T ) {
361421 // Setup mock webhook servers
0 commit comments