From d87b1757e00db1614c0208e0f3500bf076650143 Mon Sep 17 00:00:00 2001 From: Prekzursil Date: Fri, 26 Jun 2026 03:14:36 +0300 Subject: [PATCH 1/2] chore: clear CodeQL app-code hygiene alerts Resolve the genuine (non-QZP) CodeQL findings in backend app code that remain after the QZP retirement: - py/commented-out-code: remove dead commented-out blocks in problems/admin.py, users/models.py, users/serializers.py - py/unused-import: celery.py imported 'Any' only inside a string annotation; use the runtime type form cast(type[Any], Celery) so the symbol is genuinely referenced (keeps the type-checker satisfied) - py/multiple-definition: drop the redundant first DJ_REST_AUTH assignment in settings.py (it is fully overwritten before use) - py/mixed-returns: normalize bare 'return' to 'return None' in CustomSocialAccountAdapter.pre_social_login No behavioral change. --- backend/problems/admin.py | 16 ---------------- backend/users/adapters.py | 6 +++--- backend/users/models.py | 9 --------- backend/users/serializers.py | 4 ---- backend/webcoder_api/celery.py | 2 +- backend/webcoder_api/settings.py | 3 --- 6 files changed, 4 insertions(+), 36 deletions(-) diff --git a/backend/problems/admin.py b/backend/problems/admin.py index 8d9414c9..f072909c 100644 --- a/backend/problems/admin.py +++ b/backend/problems/admin.py @@ -103,22 +103,6 @@ def save_model(self, request, obj, form, change): obj.author = request.user super().save_model(request, obj, form, change) - # Customize queryset for admin to potentially show more fields or filter - # def get_queryset(self, request): - # qs = super().get_queryset(request) - # return qs - - -# TestCase can also be registered separately if needed for direct management, -# but often managed inline with Problems. -# class TestCaseAdmin(admin.ModelAdmin): -# list_display = ('id', 'problem_id_display', 'order', 'is_sample', 'points') -# list_filter = ('problem', 'is_sample') -# search_fields = ('problem__title_i18n', 'input_data', 'expected_output_data') - -# def problem_id_display(self, obj): -# return obj.problem.id -# problem_id_display.short_description = 'Problem ID' admin.site.register(Tag, TagAdmin) admin.site.register(Problem, ProblemAdmin) diff --git a/backend/users/adapters.py b/backend/users/adapters.py index a5d8aef9..cec5361d 100644 --- a/backend/users/adapters.py +++ b/backend/users/adapters.py @@ -13,7 +13,7 @@ def pre_social_login(self, request, sociallogin): # This method is called just before the user is logged in. # We can use it to check if the user is new and needs to complete registration. if sociallogin.is_existing: - return + return None # There is no existing social account for this user. # Check if a user already exists with the same email address. @@ -21,7 +21,7 @@ def pre_social_login(self, request, sociallogin): # This will fail if the user does not exist _ = sociallogin.user # If the user exists, we can just link the social account and log them in. - return + return None except Exception: # The user does not exist, so we need to redirect them to complete registration. # We'll pass the email address as a query parameter. @@ -33,4 +33,4 @@ def pre_social_login(self, request, sociallogin): return HttpResponseRedirect(redirect_url) # If we can't get an email, we'll just let allauth handle it. - return + return None diff --git a/backend/users/models.py b/backend/users/models.py index f4154b66..7ae43cd6 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -38,12 +38,3 @@ class Roles(models.TextChoices): def __str__(self): return self.username - - # You might add helper properties here later, e.g.: - # @property - # def is_problem_creator(self): - # return self.role in {self.Roles.PROBLEM_CREATOR, self.Roles.PROBLEM_VERIFIER, self.Roles.ADMIN} - - # @property - # def is_problem_verifier(self): - # return self.role in {self.Roles.PROBLEM_VERIFIER, self.Roles.ADMIN} diff --git a/backend/users/serializers.py b/backend/users/serializers.py index 58810807..7c64ed13 100644 --- a/backend/users/serializers.py +++ b/backend/users/serializers.py @@ -164,8 +164,4 @@ def save(self, **kwargs): user = self.context["request"].user user.set_password(self.validated_data["new_password1"]) user.save() - # Optionally, update session auth hash if using session authentication alongside JWT - # from django.contrib.auth import update_session_auth_hash - # if hasattr(self.context['request'], 'session'): - # update_session_auth_hash(self.context['request'], user) return user diff --git a/backend/webcoder_api/celery.py b/backend/webcoder_api/celery.py index a758c792..f0e24cdf 100644 --- a/backend/webcoder_api/celery.py +++ b/backend/webcoder_api/celery.py @@ -10,7 +10,7 @@ # ``celery`` ships no type information in the lean type-check environment, so the # imported ``Celery`` symbol is opaque (pyright cannot confirm it is callable). # Cast it to a callable to construct the app without losing checking elsewhere. -_Celery = cast("type[Any]", Celery) +_Celery = cast(type[Any], Celery) app = _Celery("webcoder_api") # Using a string here means the worker doesn't have to serialize diff --git a/backend/webcoder_api/settings.py b/backend/webcoder_api/settings.py index fcc541b8..817f0837 100644 --- a/backend/webcoder_api/settings.py +++ b/backend/webcoder_api/settings.py @@ -187,9 +187,6 @@ "email": {"required": True}, "password1": {"required": True}, } -DJ_REST_AUTH = { - "SIGNUP_FIELDS": ACCOUNT_SIGNUP_FIELDS, -} SOCIALACCOUNT_PROVIDERS = { "google": { "SCOPE": [ From 929e7123ab04b584e200714d16419a654d6cd47b Mon Sep 17 00:00:00 2001 From: Prekzursil Date: Fri, 26 Jun 2026 03:16:31 +0300 Subject: [PATCH 2/2] chore: externalize Django SECRET_KEY + DB credentials to env vars Removes the hardcoded Django secret key and PostgreSQL password from settings.py (clears the SonarCloud hardcoded-credential / disclosed-key findings). Values now come from the environment with dev-only fallbacks: - SECRET_KEY <- DJANGO_SECRET_KEY (insecure dev default kept for local) - DATABASES PASSWORD/USER/NAME/HOST/PORT <- POSTGRES_* env vars CI is unaffected: settings_ci copies SECRET_KEY (always bound via the default) and overrides DATABASES to sqlite, so it never reads these. NOTE: the previously-committed secret remains in git history and should be rotated by a maintainer in any environment where it was real. --- backend/webcoder_api/settings.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/webcoder_api/settings.py b/backend/webcoder_api/settings.py index 817f0837..e43fb4e0 100644 --- a/backend/webcoder_api/settings.py +++ b/backend/webcoder_api/settings.py @@ -22,7 +22,12 @@ # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-tra1bid*d3-t-+a$uu+1k&l+-aqxrp5u_ezlg5*oa%h$9cg45o" +# Sourced from the environment; the insecure fallback is for local/dev only and +# MUST be overridden via DJANGO_SECRET_KEY in any real deployment. +SECRET_KEY = os.environ.get( + "DJANGO_SECRET_KEY", + "django-insecure-dev-only-change-me", +) # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -104,11 +109,11 @@ DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql", - "NAME": "webcoder_db", # Replace with your database name - "USER": "webcoder_user", # Replace with your PostgreSQL username - "PASSWORD": "darkstarone", # Replace with your PostgreSQL password - "HOST": "localhost", # Or your PostgreSQL host - "PORT": "5432", # Or your PostgreSQL port + "NAME": os.environ.get("POSTGRES_DB", "webcoder_db"), + "USER": os.environ.get("POSTGRES_USER", "webcoder_user"), + "PASSWORD": os.environ.get("POSTGRES_PASSWORD", ""), + "HOST": os.environ.get("POSTGRES_HOST", "localhost"), + "PORT": os.environ.get("POSTGRES_PORT", "5432"), } }