Skip to content

Commit 6c809d3

Browse files
Merge pull request #1 from semanticintent/claude/security-scan-project-v8VrS
Scan project for malware and security issues
2 parents bed7652 + 16917d0 commit 6c809d3

3 files changed

Lines changed: 40 additions & 1 deletion

File tree

src/logparseiqx/cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
filter_errors,
2929
filter_slow_requests,
3030
filter_security_events,
31+
filter_by_status_class,
3132
aggregate_by_status,
3233
aggregate_by_country,
3334
aggregate_by_ip,
@@ -308,7 +309,7 @@ def cf_errors(ctx, logfile, tail, status):
308309
console.print("[orange3][CF] Scanning Cloudflare logs for errors...[/orange3]")
309310

310311
if status:
311-
filter_func = lambda x: str(x.get('EdgeResponseStatus', '')).startswith(status[:1]) or str(x.get('EdgeResponseStatus', '')) == status
312+
filter_func = filter_by_status_class(status)
312313
else:
313314
filter_func = filter_errors
314315

src/logparseiqx/parsers/cloudflare.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,28 @@ def _filter(log: Dict[str, Any]) -> bool:
153153
return _filter
154154

155155

156+
def filter_by_status_class(status_code: str) -> Callable[[Dict], bool]:
157+
"""
158+
Create a filter that matches an entire HTTP status class.
159+
160+
Uses the first digit to match all statuses in that class:
161+
- '502' or '5' -> matches all 5xx (500, 502, 503, etc.)
162+
- '404' or '4' -> matches all 4xx (400, 401, 404, etc.)
163+
164+
Args:
165+
status_code: A status code like '502' or class like '5'
166+
167+
Returns:
168+
Filter function that matches the status class
169+
"""
170+
status_class = status_code[:1] # First digit determines the class
171+
172+
def _filter(log: Dict[str, Any]) -> bool:
173+
status = str(log.get('EdgeResponseStatus', ''))
174+
return status.startswith(status_class) or status == status_code
175+
return _filter
176+
177+
156178
def filter_slow_requests(threshold_ms: int) -> Callable[[Dict], bool]:
157179
"""Create a filter for slow requests"""
158180
def _filter(log: Dict[str, Any]) -> bool:

tests/test_logparseiqx.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def safe_unlink(filepath):
3535
filter_server_errors,
3636
filter_client_errors,
3737
filter_by_status,
38+
filter_by_status_class,
3839
filter_slow_requests,
3940
filter_security_events,
4041
filter_by_country,
@@ -410,6 +411,21 @@ def test_filter_by_status(self):
410411
assert filter_5xx({'EdgeResponseStatus': 502}) is True
411412
assert filter_5xx({'EdgeResponseStatus': 404}) is False
412413

414+
def test_filter_by_status_class(self):
415+
"""Test that filter_by_status_class matches entire status class by first digit"""
416+
# Passing '502' should match all 5xx (uses first digit)
417+
filter_from_502 = filter_by_status_class("502")
418+
assert filter_from_502({'EdgeResponseStatus': 502}) is True # Exact match
419+
assert filter_from_502({'EdgeResponseStatus': 500}) is True # Same class (5xx)
420+
assert filter_from_502({'EdgeResponseStatus': 503}) is True # Same class (5xx)
421+
assert filter_from_502({'EdgeResponseStatus': 404}) is False # Different class
422+
423+
# Passing '4' should match all 4xx
424+
filter_4xx = filter_by_status_class("4")
425+
assert filter_4xx({'EdgeResponseStatus': 400}) is True
426+
assert filter_4xx({'EdgeResponseStatus': 404}) is True
427+
assert filter_4xx({'EdgeResponseStatus': 500}) is False
428+
413429
def test_filter_slow_requests(self):
414430
filter_func = filter_slow_requests(1000)
415431
assert filter_func({'OriginResponseTime': 2000}) is True

0 commit comments

Comments
 (0)