@@ -172,4 +172,252 @@ def call(payload:, headers:, config:)
172
172
)
173
173
end
174
174
end
175
+
176
+ describe "failure scenarios" do
177
+ describe "auth plugin loading failures" do
178
+ it "raises error when auth plugin file fails to load" do
179
+ temp_auth_dir = File . join ( temp_dir , "auth_failures" )
180
+ FileUtils . mkdir_p ( temp_auth_dir )
181
+
182
+ # Create a malformed Ruby file
183
+ malformed_file = File . join ( temp_auth_dir , "broken_auth.rb" )
184
+ File . write ( malformed_file , "class BrokenAuth\n # Missing end statement" )
185
+
186
+ expect {
187
+ described_class . load_all_plugins ( { auth_plugin_dir : temp_auth_dir } )
188
+ } . to raise_error ( StandardError , /Failed to load auth plugin from.*broken_auth\. rb/ )
189
+ end
190
+
191
+ it "raises error for auth plugin path traversal attempt" do
192
+ temp_auth_dir = File . join ( temp_dir , "auth_secure" )
193
+ FileUtils . mkdir_p ( temp_auth_dir )
194
+
195
+ # Create a plugin file outside the auth directory
196
+ outside_file = File . join ( temp_dir , "outside_auth.rb" )
197
+ File . write ( outside_file , "# Outside file" )
198
+
199
+ expect {
200
+ described_class . send ( :load_custom_auth_plugin , outside_file , temp_auth_dir )
201
+ } . to raise_error ( SecurityError , /Auth plugin path outside of auth plugin directory/ )
202
+ end
203
+
204
+ it "raises error for invalid auth plugin class name" do
205
+ temp_auth_dir = File . join ( temp_dir , "auth_invalid" )
206
+ FileUtils . mkdir_p ( temp_auth_dir )
207
+
208
+ # Create plugin with invalid class name
209
+ invalid_file = File . join ( temp_auth_dir , "file.rb" )
210
+ File . write ( invalid_file , "# File with dangerous class name" )
211
+
212
+ expect {
213
+ described_class . send ( :load_custom_auth_plugin , invalid_file , temp_auth_dir )
214
+ } . to raise_error ( StandardError , /Invalid auth plugin class name: File/ )
215
+ end
216
+
217
+ it "raises error when auth plugin doesn't inherit from correct base class" do
218
+ temp_auth_dir = File . join ( temp_dir , "auth_inheritance" )
219
+ FileUtils . mkdir_p ( temp_auth_dir )
220
+
221
+ # Create plugin with wrong inheritance
222
+ wrong_file = File . join ( temp_auth_dir , "wrong_auth.rb" )
223
+ File . write ( wrong_file , <<~RUBY )
224
+ module Hooks
225
+ module Plugins
226
+ module Auth
227
+ class WrongAuth
228
+ def self.valid?(payload:, headers:, config:)
229
+ true
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
235
+ RUBY
236
+
237
+ expect {
238
+ described_class . send ( :load_custom_auth_plugin , wrong_file , temp_auth_dir )
239
+ } . to raise_error ( StandardError , /Auth plugin class must inherit from Hooks::Plugins::Auth::Base/ )
240
+ end
241
+ end
242
+
243
+ describe "handler plugin loading failures" do
244
+ it "raises error when handler plugin file fails to load" do
245
+ temp_handler_dir = File . join ( temp_dir , "handler_failures" )
246
+ FileUtils . mkdir_p ( temp_handler_dir )
247
+
248
+ # Create a malformed Ruby file
249
+ malformed_file = File . join ( temp_handler_dir , "broken_handler.rb" )
250
+ File . write ( malformed_file , "class BrokenHandler\n # Missing end statement" )
251
+
252
+ expect {
253
+ described_class . load_all_plugins ( { handler_plugin_dir : temp_handler_dir } )
254
+ } . to raise_error ( StandardError , /Failed to load handler plugin from.*broken_handler\. rb/ )
255
+ end
256
+
257
+ it "raises error for handler plugin path traversal attempt" do
258
+ temp_handler_dir = File . join ( temp_dir , "handler_secure" )
259
+ FileUtils . mkdir_p ( temp_handler_dir )
260
+
261
+ # Create a plugin file outside the handler directory
262
+ outside_file = File . join ( temp_dir , "outside_handler.rb" )
263
+ File . write ( outside_file , "# Outside file" )
264
+
265
+ expect {
266
+ described_class . send ( :load_custom_handler_plugin , outside_file , temp_handler_dir )
267
+ } . to raise_error ( SecurityError , /Handler plugin path outside of handler plugin directory/ )
268
+ end
269
+
270
+ it "raises error for invalid handler plugin class name" do
271
+ temp_handler_dir = File . join ( temp_dir , "handler_invalid" )
272
+ FileUtils . mkdir_p ( temp_handler_dir )
273
+
274
+ # Create plugin with invalid class name
275
+ invalid_file = File . join ( temp_handler_dir , "file.rb" )
276
+ File . write ( invalid_file , "# File with dangerous class name" )
277
+
278
+ expect {
279
+ described_class . send ( :load_custom_handler_plugin , invalid_file , temp_handler_dir )
280
+ } . to raise_error ( StandardError , /Invalid handler class name: File/ )
281
+ end
282
+
283
+ it "raises error when handler plugin doesn't inherit from correct base class" do
284
+ temp_handler_dir = File . join ( temp_dir , "handler_inheritance" )
285
+ FileUtils . mkdir_p ( temp_handler_dir )
286
+
287
+ # Create plugin with wrong inheritance
288
+ wrong_file = File . join ( temp_handler_dir , "wrong_handler.rb" )
289
+ File . write ( wrong_file , <<~RUBY )
290
+ class WrongHandler
291
+ def call(payload:, headers:, config:)
292
+ { message: "wrong handler" }
293
+ end
294
+ end
295
+ RUBY
296
+
297
+ expect {
298
+ described_class . send ( :load_custom_handler_plugin , wrong_file , temp_handler_dir )
299
+ } . to raise_error ( StandardError , /Handler class must inherit from Hooks::Plugins::Handlers::Base/ )
300
+ end
301
+ end
302
+
303
+ describe "lifecycle plugin loading failures" do
304
+ it "raises error when lifecycle plugin file fails to load" do
305
+ temp_lifecycle_dir = File . join ( temp_dir , "lifecycle_failures" )
306
+ FileUtils . mkdir_p ( temp_lifecycle_dir )
307
+
308
+ # Create a malformed Ruby file
309
+ malformed_file = File . join ( temp_lifecycle_dir , "broken_lifecycle.rb" )
310
+ File . write ( malformed_file , "class BrokenLifecycle\n # Missing end statement" )
311
+
312
+ expect {
313
+ described_class . load_all_plugins ( { lifecycle_plugin_dir : temp_lifecycle_dir } )
314
+ } . to raise_error ( StandardError , /Failed to load lifecycle plugin from.*broken_lifecycle\. rb/ )
315
+ end
316
+
317
+ it "raises error for lifecycle plugin path traversal attempt" do
318
+ temp_lifecycle_dir = File . join ( temp_dir , "lifecycle_secure" )
319
+ FileUtils . mkdir_p ( temp_lifecycle_dir )
320
+
321
+ # Create a plugin file outside the lifecycle directory
322
+ outside_file = File . join ( temp_dir , "outside_lifecycle.rb" )
323
+ File . write ( outside_file , "# Outside file" )
324
+
325
+ expect {
326
+ described_class . send ( :load_custom_lifecycle_plugin , outside_file , temp_lifecycle_dir )
327
+ } . to raise_error ( SecurityError , /Lifecycle plugin path outside of lifecycle plugin directory/ )
328
+ end
329
+
330
+ it "raises error for invalid lifecycle plugin class name" do
331
+ temp_lifecycle_dir = File . join ( temp_dir , "lifecycle_invalid" )
332
+ FileUtils . mkdir_p ( temp_lifecycle_dir )
333
+
334
+ # Create plugin with invalid class name
335
+ invalid_file = File . join ( temp_lifecycle_dir , "file.rb" )
336
+ File . write ( invalid_file , "# File with dangerous class name" )
337
+
338
+ expect {
339
+ described_class . send ( :load_custom_lifecycle_plugin , invalid_file , temp_lifecycle_dir )
340
+ } . to raise_error ( StandardError , /Invalid lifecycle plugin class name: File/ )
341
+ end
342
+
343
+ it "raises error when lifecycle plugin doesn't inherit from correct base class" do
344
+ temp_lifecycle_dir = File . join ( temp_dir , "lifecycle_inheritance" )
345
+ FileUtils . mkdir_p ( temp_lifecycle_dir )
346
+
347
+ # Create plugin with wrong inheritance
348
+ wrong_file = File . join ( temp_lifecycle_dir , "wrong_lifecycle.rb" )
349
+ File . write ( wrong_file , <<~RUBY )
350
+ class WrongLifecycle
351
+ def on_request(env)
352
+ # Wrong base class
353
+ end
354
+ end
355
+ RUBY
356
+
357
+ expect {
358
+ described_class . send ( :load_custom_lifecycle_plugin , wrong_file , temp_lifecycle_dir )
359
+ } . to raise_error ( StandardError , /Lifecycle plugin class must inherit from Hooks::Plugins::Lifecycle/ )
360
+ end
361
+ end
362
+
363
+ describe "instrument plugin loading failures" do
364
+ it "raises error when instrument plugin file fails to load" do
365
+ temp_instrument_dir = File . join ( temp_dir , "instrument_failures" )
366
+ FileUtils . mkdir_p ( temp_instrument_dir )
367
+
368
+ # Create a malformed Ruby file
369
+ malformed_file = File . join ( temp_instrument_dir , "broken_instrument.rb" )
370
+ File . write ( malformed_file , "class BrokenInstrument\n # Missing end statement" )
371
+
372
+ expect {
373
+ described_class . load_all_plugins ( { instruments_plugin_dir : temp_instrument_dir } )
374
+ } . to raise_error ( StandardError , /Failed to load instrument plugin from.*broken_instrument\. rb/ )
375
+ end
376
+
377
+ it "raises error for instrument plugin path traversal attempt" do
378
+ temp_instrument_dir = File . join ( temp_dir , "instrument_secure" )
379
+ FileUtils . mkdir_p ( temp_instrument_dir )
380
+
381
+ # Create a plugin file outside the instrument directory
382
+ outside_file = File . join ( temp_dir , "outside_instrument.rb" )
383
+ File . write ( outside_file , "# Outside file" )
384
+
385
+ expect {
386
+ described_class . send ( :load_custom_instrument_plugin , outside_file , temp_instrument_dir )
387
+ } . to raise_error ( SecurityError , /Instrument plugin path outside of instruments plugin directory/ )
388
+ end
389
+
390
+ it "raises error for invalid instrument plugin class name" do
391
+ temp_instrument_dir = File . join ( temp_dir , "instrument_invalid" )
392
+ FileUtils . mkdir_p ( temp_instrument_dir )
393
+
394
+ # Create plugin with invalid class name
395
+ invalid_file = File . join ( temp_instrument_dir , "file.rb" )
396
+ File . write ( invalid_file , "# File with dangerous class name" )
397
+
398
+ expect {
399
+ described_class . send ( :load_custom_instrument_plugin , invalid_file , temp_instrument_dir )
400
+ } . to raise_error ( StandardError , /Invalid instrument plugin class name: File/ )
401
+ end
402
+
403
+ it "raises error when instrument plugin doesn't inherit from correct base class" do
404
+ temp_instrument_dir = File . join ( temp_dir , "instrument_inheritance" )
405
+ FileUtils . mkdir_p ( temp_instrument_dir )
406
+
407
+ # Create plugin with wrong inheritance
408
+ wrong_file = File . join ( temp_instrument_dir , "wrong_instrument.rb" )
409
+ File . write ( wrong_file , <<~RUBY )
410
+ class WrongInstrument
411
+ def record(metric_name, value, tags = {})
412
+ # Wrong base class
413
+ end
414
+ end
415
+ RUBY
416
+
417
+ expect {
418
+ described_class . send ( :load_custom_instrument_plugin , wrong_file , temp_instrument_dir )
419
+ } . to raise_error ( StandardError , /Instrument plugin class must inherit from StatsBase or FailbotBase/ )
420
+ end
421
+ end
422
+ end
175
423
end
0 commit comments