diff --git a/test/test_exceptionlog_sentry.py b/test/test_exceptionlog_sentry.py index fbafc4256..aaf2dd3eb 100644 --- a/test/test_exceptionlog_sentry.py +++ b/test/test_exceptionlog_sentry.py @@ -386,3 +386,29 @@ class TestSentryBeforeSendFilter: } result = _sentry_before_send_ignore_known(event, {}) assert result == event + + def test_filter_401_with_redis_in_repository_name(self): + """401 errors should be filtered even if repository name contains 'redis'.""" + event = { + "logentry": { + "formatted": "Error 401: Invalid Bearer [token] format; Arguments: {'repository': 'bitnami/redis-exporter', 'status_code': 401}" + } + } + result = _sentry_before_send_ignore_known(event, {}) + assert result is None + + def test_filter_401_with_database_in_repository_name(self): + """401 errors should be filtered even if repository name contains 'database'.""" + event = { + "logentry": { + "formatted": "Error 401: Invalid Bearer [token] format; Arguments: {'repository': 'vpenx/clamav-database-mirror'}" + } + } + result = _sentry_before_send_ignore_known(event, {}) + assert result is None + + def test_keep_actual_redis_error(self): + """Actual Redis errors should NOT be filtered.""" + event = {"logentry": {"formatted": "Redis connection refused: ECONNREFUSED 127.0.0.1:6379"}} + result = _sentry_before_send_ignore_known(event, {}) + assert result == event diff --git a/util/saas/exceptionlog.py b/util/saas/exceptionlog.py index 51cfc17f5..c2be94810 100644 --- a/util/saas/exceptionlog.py +++ b/util/saas/exceptionlog.py @@ -79,6 +79,10 @@ HTTP_4XX_PATTERN = re.compile( re.IGNORECASE, ) +# Regex pattern to strip Arguments metadata from error messages +# Matches: "; Arguments: {'repository': 'bitnami/redis-exporter', ...}" +ARGUMENTS_PATTERN = re.compile(r";\s*Arguments:\s*\{.*\}$", re.IGNORECASE | re.DOTALL) + BROWSER_ERROR_PATTERNS = [ "script error", "syntax error", @@ -146,6 +150,9 @@ def _extract_searchable_text(ex_event: Any) -> set[str]: if "culprit" in ex_event: texts.add(str(ex_event.get("culprit", "")).lower()) + # Strip Arguments metadata to prevent false positives from repository/image names + texts = {ARGUMENTS_PATTERN.sub("", t) for t in texts} + # Remove empty strings texts.discard("")