diff --git a/src/anthias_server/app/migrations/0005_migrate_basic_auth_to_user.py b/src/anthias_server/app/migrations/0005_migrate_basic_auth_to_user.py index ce95719c..d0089e67 100644 --- a/src/anthias_server/app/migrations/0005_migrate_basic_auth_to_user.py +++ b/src/anthias_server/app/migrations/0005_migrate_basic_auth_to_user.py @@ -184,10 +184,15 @@ def _migrate(apps, schema_editor): # type: ignore[no-untyped-def] # clearing the flag. # * ``auth_basic`` selected with a legacy SHA256 / plaintext hash # → unverifiable by Django's hashers. Same fail-open. + # These two branches are operator-config conditions we handle by + # failing open, not bugs: the device recovers on its own and the + # log line already tells the operator how to re-set the password. + # Log at warning, not error — an ERROR-level record is what Sentry's + # logging integration turns into an event (ANTHIAS-1S / ANTHIAS-1Z). disable_auth = False if auth_backend == 'auth_basic': if not creds_present: - logging.error( + logging.warning( 'auth_basic enabled in %s but credentials are missing; ' 'disabling basic auth to avoid a lockout. Re-set the ' 'password from the Settings page.', @@ -195,7 +200,7 @@ def _migrate(apps, schema_editor): # type: ignore[no-untyped-def] ) disable_auth = True elif not creds_django_format: - logging.error( + logging.warning( 'Insecure password hash in %s; clearing credentials and ' 'disabling basic auth. Re-set the password from the ' 'Settings page.', diff --git a/src/anthias_server/django_project/settings.py b/src/anthias_server/django_project/settings.py index 950335b7..f0b56f7f 100644 --- a/src/anthias_server/django_project/settings.py +++ b/src/anthias_server/django_project/settings.py @@ -201,6 +201,16 @@ ignore_logger('celery.backends.redis') # fetch); a persistent outage still surfaces via the watchdog restart # loop. (Sentry ANTHIAS-3X.) ignore_logger('celery.backends.asynchronous') +# A device exposed to the internet gets a steady drip of background +# scanners and bots hitting it with a bogus/spoofed Host header +# ("Invalid HTTP_HOST header: '141.212.44.121/..'"). Django rejects the +# request with a 400 and logs it at ERROR to ``django.security. +# DisallowedHost``, which the logging integration then turns into a +# Sentry event. It is neither an Anthias bug nor actionable — the +# request never reaches a view — so silence the logger, exactly as +# Django's own docs suggest for this well-known noise source. (Sentry +# ANTHIAS-2A.) +ignore_logger('django.security.DisallowedHost') def get_sentry_release() -> str | None: diff --git a/tests/test_sentry.py b/tests/test_sentry.py index a4c49838..740d2e7f 100644 --- a/tests/test_sentry.py +++ b/tests/test_sentry.py @@ -278,6 +278,17 @@ class TestBeforeSendTransientNoise: # fatal level on a sustained redis outage (Sentry ANTHIAS-3X). assert 'celery.backends.asynchronous' in _IGNORED_LOGGERS + def test_disallowed_host_logger_is_ignored(self) -> None: + # An internet-exposed device gets scanned with bogus/spoofed + # Host headers; Django rejects each with a 400 and logs it at + # ERROR to django.security.DisallowedHost, which the logging + # integration would otherwise turn into a Sentry event. It is + # non-actionable background-scanner noise (Sentry ANTHIAS-2A). + import anthias_server.django_project.settings # noqa: F401 + from sentry_sdk.integrations.logging import _IGNORED_LOGGERS + + assert 'django.security.DisallowedHost' in _IGNORED_LOGGERS + class TestGetBoardModel: """Board-model detection feeding the fleet-triage Sentry tags."""