fix: resolve backend CI errors for MyPy and Ruff

- Fix PyPNGImage save() method call (remove format parameter)
- Fix return type annotation in is_mfa_required()
- Remove unused imports and reorder imports
- Update timezone imports from timezone to UTC
- Fix test assertions formatting

Frontend CI fixes to follow in subsequent commit

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
pull/22455/head
k-brahma-claude 10 months ago
parent 9202c05d4c
commit 1bdbbb7140

@ -14,8 +14,6 @@ from controllers.console.auth.error import (
EmailPasswordLoginLimitError, EmailPasswordLoginLimitError,
InvalidEmailError, InvalidEmailError,
InvalidTokenError, InvalidTokenError,
MFARequiredError,
MFATokenRequiredError,
) )
from controllers.console.error import ( from controllers.console.error import (
AccountBannedError, AccountBannedError,

@ -1,12 +1,8 @@
from typing import cast from typing import cast
import flask_login import flask_login
from flask import request
from flask_restful import Resource, reqparse from flask_restful import Resource, reqparse
from controllers.console.auth.error import (
TokenValidationError,
)
from controllers.console.wraps import account_initialization_required from controllers.console.wraps import account_initialization_required
from libs.login import login_required from libs.login import login_required
from models.account import Account from models.account import Account

@ -389,7 +389,8 @@ api.add_resource(EducationAutoCompleteApi, "/account/education/autocomplete")
# api.add_resource(AccountEmailVerifyApi, '/account/email-verify') # api.add_resource(AccountEmailVerifyApi, '/account/email-verify')
# MFA endpoints # MFA endpoints
from controllers.console.auth.mfa import MFASetupInitApi, MFASetupCompleteApi, MFADisableApi, MFAStatusApi from controllers.console.auth.mfa import MFADisableApi, MFASetupCompleteApi, MFASetupInitApi, MFAStatusApi
api.add_resource(MFAStatusApi, "/account/mfa/status") api.add_resource(MFAStatusApi, "/account/mfa/status")
api.add_resource(MFASetupInitApi, "/account/mfa/setup") api.add_resource(MFASetupInitApi, "/account/mfa/setup")
api.add_resource(MFASetupCompleteApi, "/account/mfa/setup/complete") api.add_resource(MFASetupCompleteApi, "/account/mfa/setup/complete")

@ -2,13 +2,10 @@ import base64
import io import io
import json import json
import secrets import secrets
from datetime import datetime, timezone from datetime import UTC, datetime
from typing import Optional
import pyotp import pyotp
import qrcode import qrcode
from sqlalchemy import and_
from sqlalchemy.orm import Session
from models.account import Account, AccountMFASettings from models.account import Account, AccountMFASettings
from models.engine import db from models.engine import db
@ -53,7 +50,7 @@ class MFAService:
# Convert to base64 # Convert to base64
buffer = io.BytesIO() buffer = io.BytesIO()
img.save(buffer, format='PNG') img.save(buffer)
img_str = base64.b64encode(buffer.getvalue()).decode() img_str = base64.b64encode(buffer.getvalue()).decode()
return f"data:image/png;base64,{img_str}" return f"data:image/png;base64,{img_str}"
@ -120,7 +117,7 @@ class MFAService:
# Enable MFA # Enable MFA
mfa_settings.enabled = True mfa_settings.enabled = True
mfa_settings.backup_codes = json.dumps(backup_codes) mfa_settings.backup_codes = json.dumps(backup_codes)
mfa_settings.setup_at = datetime.now(timezone.utc) mfa_settings.setup_at = datetime.now(UTC)
db.session.commit() db.session.commit()
@ -176,7 +173,7 @@ class MFAService:
def is_mfa_required(account: Account) -> bool: def is_mfa_required(account: Account) -> bool:
"""Check if MFA is required for this account.""" """Check if MFA is required for this account."""
mfa_settings = db.session.query(AccountMFASettings).filter_by(account_id=account.id).first() mfa_settings = db.session.query(AccountMFASettings).filter_by(account_id=account.id).first()
return mfa_settings and mfa_settings.enabled and mfa_settings.secret is not None return bool(mfa_settings and mfa_settings.enabled and mfa_settings.secret is not None)
@staticmethod @staticmethod
def authenticate_with_mfa(account: Account, token: str) -> bool: def authenticate_with_mfa(account: Account, token: str) -> bool:

@ -1,14 +1,8 @@
import json import json
import sys import sys
import pytest
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from datetime import datetime
from flask import Flask from flask import Flask
from flask_restful import Api
from controllers.console.auth.login import LoginApi
from models.account import Account, AccountMFASettings
class TestLoginMFAIntegration: class TestLoginMFAIntegration:
@ -292,8 +286,8 @@ class TestMFAEndToEndFlow:
@patch('services.mfa_service.db.session') @patch('services.mfa_service.db.session')
def test_complete_mfa_setup_flow(self, mock_session, mock_gen_codes, mock_verify, mock_gen_qr, mock_gen_secret): def test_complete_mfa_setup_flow(self, mock_session, mock_gen_codes, mock_verify, mock_gen_qr, mock_gen_secret):
"""Test complete MFA setup flow from init to completion.""" """Test complete MFA setup flow from init to completion."""
from services.mfa_service import MFAService
from models.account import Account from models.account import Account
from services.mfa_service import MFAService
# Mock account # Mock account
account = Mock(spec=Account) account = Mock(spec=Account)

@ -1,7 +1,8 @@
import pytest from datetime import UTC, datetime
from datetime import datetime, timezone
from unittest.mock import patch from unittest.mock import patch
import pytest
from services.account_service import AccountService from services.account_service import AccountService
from services.mfa_service import MFAService from services.mfa_service import MFAService
@ -71,7 +72,7 @@ class TestMFAEndpoints:
with patch.object(MFAService, 'setup_mfa') as mock_setup: with patch.object(MFAService, 'setup_mfa') as mock_setup:
mock_setup.return_value = { mock_setup.return_value = {
"backup_codes": ["CODE1", "CODE2", "CODE3", "CODE4", "CODE5", "CODE6", "CODE7", "CODE8"], "backup_codes": ["CODE1", "CODE2", "CODE3", "CODE4", "CODE5", "CODE6", "CODE7", "CODE8"],
"setup_at": datetime(2024, 1, 1, 0, 0, 0, tzinfo=timezone.utc) "setup_at": datetime(2024, 1, 1, 0, 0, 0, tzinfo=UTC)
} }
response = test_client.post( response = test_client.post(
@ -97,7 +98,8 @@ class TestMFAEndpoints:
assert response.status_code == 400 assert response.status_code == 400
data = response.json data = response.json
assert "message" in data and "TOTP token is required" in data["message"] assert "message" in data
assert "TOTP token is required" in data["message"]
def test_mfa_setup_complete_invalid_token(self, test_client, setup_account, auth_header): def test_mfa_setup_complete_invalid_token(self, test_client, setup_account, auth_header):
"""Test MFA setup completion with invalid token.""" """Test MFA setup completion with invalid token."""

@ -1,7 +1,5 @@
import json
from unittest import mock from unittest import mock
from models.account import Account
from services.mfa_service import MFAService from services.mfa_service import MFAService
@ -12,7 +10,7 @@ class TestMFASimpleIntegration:
"""Test MFA setup flow end-to-end.""" """Test MFA setup flow end-to-end."""
# Step 1: Check initial MFA status # Step 1: Check initial MFA status
response = test_client.get( response = test_client.get(
f"/console/api/account/mfa/status", "/console/api/account/mfa/status",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200
@ -21,7 +19,7 @@ class TestMFASimpleIntegration:
# Step 2: Initialize MFA setup # Step 2: Initialize MFA setup
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/setup", "/console/api/account/mfa/setup",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200
@ -33,7 +31,7 @@ class TestMFASimpleIntegration:
# Step 3: Complete MFA setup with mocked TOTP # Step 3: Complete MFA setup with mocked TOTP
with mock.patch.object(MFAService, 'verify_totp', return_value=True): with mock.patch.object(MFAService, 'verify_totp', return_value=True):
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/setup/complete", "/console/api/account/mfa/setup/complete",
headers=auth_header, headers=auth_header,
json={"totp_token": "123456"} json={"totp_token": "123456"}
) )
@ -44,7 +42,7 @@ class TestMFASimpleIntegration:
# Step 4: Verify MFA is now enabled # Step 4: Verify MFA is now enabled
response = test_client.get( response = test_client.get(
f"/console/api/account/mfa/status", "/console/api/account/mfa/status",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200
@ -55,7 +53,7 @@ class TestMFASimpleIntegration:
"""Test MFA disable flow.""" """Test MFA disable flow."""
# First check MFA status and disable if already enabled # First check MFA status and disable if already enabled
response = test_client.get( response = test_client.get(
f"/console/api/account/mfa/status", "/console/api/account/mfa/status",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200
@ -65,7 +63,7 @@ class TestMFASimpleIntegration:
# MFA is already enabled, disable it first with mocked password verification # MFA is already enabled, disable it first with mocked password verification
with mock.patch('libs.password.compare_password', return_value=True): with mock.patch('libs.password.compare_password', return_value=True):
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/disable", "/console/api/account/mfa/disable",
headers=auth_header, headers=auth_header,
json={"password": "any_password"} # Password doesn't matter, it's mocked json={"password": "any_password"} # Password doesn't matter, it's mocked
) )
@ -75,14 +73,14 @@ class TestMFASimpleIntegration:
with mock.patch.object(MFAService, 'verify_totp', return_value=True): with mock.patch.object(MFAService, 'verify_totp', return_value=True):
# Initialize setup # Initialize setup
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/setup", "/console/api/account/mfa/setup",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200
# Complete setup # Complete setup
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/setup/complete", "/console/api/account/mfa/setup/complete",
headers=auth_header, headers=auth_header,
json={"totp_token": "123456"} json={"totp_token": "123456"}
) )
@ -91,7 +89,7 @@ class TestMFASimpleIntegration:
# Now disable MFA with mocked password verification # Now disable MFA with mocked password verification
with mock.patch('libs.password.compare_password', return_value=True): with mock.patch('libs.password.compare_password', return_value=True):
response = test_client.post( response = test_client.post(
f"/console/api/account/mfa/disable", "/console/api/account/mfa/disable",
headers=auth_header, headers=auth_header,
json={"password": "any_password"} # Password doesn't matter, it's mocked json={"password": "any_password"} # Password doesn't matter, it's mocked
) )
@ -101,7 +99,7 @@ class TestMFASimpleIntegration:
# Verify MFA is disabled # Verify MFA is disabled
response = test_client.get( response = test_client.get(
f"/console/api/account/mfa/status", "/console/api/account/mfa/status",
headers=auth_header headers=auth_header
) )
assert response.status_code == 200 assert response.status_code == 200

@ -1,9 +1,7 @@
import json import json
import unittest import unittest
from datetime import datetime
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from datetime import datetime, timezone
import pytest
from models.account import Account, AccountMFASettings from models.account import Account, AccountMFASettings
from services.mfa_service import MFAService from services.mfa_service import MFAService

Loading…
Cancel
Save