Skip to content

Commit 197cdef

Browse files
committed
fix test cases in attack_wave_detcetor_store
1 parent 518db28 commit 197cdef

1 file changed

Lines changed: 158 additions & 2 deletions

File tree

aikido_zen/storage/attack_wave_detector_store_test.py

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,13 @@ def test_samples_tracking_in_store():
268268
for i in range(3):
269269
store.is_attack_wave(context)
270270

271-
# Check that samples are being tracked
271+
# Check that samples are being tracked (should have 1 unique sample)
272272
samples = store.get_samples_for_ip(context.remote_address)
273-
assert len(samples) == 3
273+
assert len(samples) == 1 # Only 1 unique sample despite 3 identical requests
274+
275+
# Verify sample structure (should contain method and url only)
276+
sample = samples[0]
277+
assert set(sample.keys()) == {"method", "url"}
274278

275279
# Clear samples
276280
store.clear_samples_for_ip(context.remote_address)
@@ -280,6 +284,158 @@ def test_samples_tracking_in_store():
280284
assert len(samples) == 0
281285

282286

287+
def test_samples_structure_and_content():
288+
"""Test that samples contain correct structure and content"""
289+
store = AttackWaveDetectorStore()
290+
context = test_utils.generate_context(method="POST", route="/.env")
291+
292+
with patch(
293+
"aikido_zen.vulnerabilities.attack_wave_detection.attack_wave_detector.is_web_scanner",
294+
return_value=True,
295+
):
296+
# Make enough requests to trigger attack wave
297+
for i in range(15):
298+
store.is_attack_wave(context)
299+
300+
# Get samples
301+
samples = store.get_samples_for_ip(context.remote_address)
302+
303+
# Should have samples (number depends on uniqueness)
304+
assert len(samples) > 0
305+
306+
# Verify each sample has correct structure
307+
for sample in samples:
308+
assert set(sample.keys()) == {"method", "url"}
309+
assert sample["method"] == "POST"
310+
assert sample["url"] == context.url
311+
312+
313+
def test_samples_json_serialization():
314+
"""Test that samples can be JSON serialized correctly"""
315+
import json
316+
317+
store = AttackWaveDetectorStore()
318+
context = test_utils.generate_context()
319+
320+
with patch(
321+
"aikido_zen.vulnerabilities.attack_wave_detection.attack_wave_detector.is_web_scanner",
322+
return_value=True,
323+
):
324+
# Make enough requests to trigger attack wave
325+
for i in range(15):
326+
store.is_attack_wave(context)
327+
328+
# Get samples
329+
samples = store.get_samples_for_ip(context.remote_address)
330+
331+
# Verify samples can be JSON serialized
332+
samples_json = json.dumps(samples)
333+
assert isinstance(samples_json, str)
334+
335+
# Verify samples can be deserialized
336+
parsed_samples = json.loads(samples_json)
337+
assert len(parsed_samples) == len(samples)
338+
339+
# Verify structure is preserved
340+
for original, parsed in zip(samples, parsed_samples):
341+
assert original["method"] == parsed["method"]
342+
assert original["url"] == parsed["url"]
343+
344+
345+
def test_samples_with_different_contexts():
346+
"""Test samples with different contexts and IPs"""
347+
store = AttackWaveDetectorStore()
348+
349+
# Create contexts with different IPs
350+
context1 = test_utils.generate_context(ip="1.1.1.1", method="GET")
351+
context2 = test_utils.generate_context(ip="2.2.2.2", method="POST")
352+
353+
with patch(
354+
"aikido_zen.vulnerabilities.attack_wave_detection.attack_wave_detector.is_web_scanner",
355+
return_value=True,
356+
):
357+
# Make requests for both contexts
358+
for i in range(15):
359+
store.is_attack_wave(context1)
360+
store.is_attack_wave(context2)
361+
362+
# Get samples for each IP
363+
samples1 = store.get_samples_for_ip(context1.remote_address)
364+
samples2 = store.get_samples_for_ip(context2.remote_address)
365+
366+
# Both should have samples
367+
assert len(samples1) > 0
368+
assert len(samples2) > 0
369+
370+
# Verify structure for both
371+
for sample in samples1:
372+
assert set(sample.keys()) == {"method", "url"}
373+
assert sample["method"] == "GET"
374+
375+
for sample in samples2:
376+
assert set(sample.keys()) == {"method", "url"}
377+
assert sample["method"] == "POST"
378+
379+
# Clear samples for both IPs
380+
store.clear_samples_for_ip(context1.remote_address)
381+
store.clear_samples_for_ip(context2.remote_address)
382+
383+
# Verify both are cleared
384+
assert len(store.get_samples_for_ip(context1.remote_address)) == 0
385+
assert len(store.get_samples_for_ip(context2.remote_address)) == 0
386+
387+
388+
def test_samples_limit_enforcement():
389+
"""Test that sample limits are enforced"""
390+
store = AttackWaveDetectorStore()
391+
392+
# Create a helper function to create contexts with different URLs
393+
def create_context_with_url(ip, url, method="GET"):
394+
from aikido_zen.context import Context
395+
from aikido_zen.helpers.headers import Headers
396+
397+
headers = Headers()
398+
return Context(
399+
context_obj={
400+
"remote_address": ip,
401+
"method": method,
402+
"url": url,
403+
"query": {},
404+
"headers": headers,
405+
"body": None,
406+
"cookies": {},
407+
"source": "test",
408+
"route": "/test",
409+
"user": None,
410+
"executed_middleware": False,
411+
"parsed_userinput": {},
412+
}
413+
)
414+
415+
with patch(
416+
"aikido_zen.vulnerabilities.attack_wave_detection.attack_wave_detector.is_web_scanner",
417+
return_value=True,
418+
):
419+
# Create many unique contexts with different IPs to avoid cooldown
420+
for i in range(20):
421+
context = create_context_with_url(
422+
f"1.1.1.{i}", f"http://localhost/{i}", f"METHOD{i % 5}"
423+
)
424+
425+
# Make enough requests to trigger attack wave
426+
for j in range(15):
427+
store.is_attack_wave(context)
428+
429+
# Check a few IPs to verify sample structure
430+
for i in range(5):
431+
samples = store.get_samples_for_ip(f"1.1.1.{i}")
432+
assert len(samples) > 0
433+
434+
# Verify structure
435+
for sample in samples:
436+
assert set(sample.keys()) == {"method", "url"}
437+
438+
283439
@patch("aikido_zen.storage.attack_wave_detector_store.AttackWaveDetector")
284440
def test_mock_detector_integration(mock_detector_class):
285441
"""Test integration with mocked AttackWaveDetector"""

0 commit comments

Comments
 (0)