fix(lint): resolve all ruff lint errors
Add ruff config to exclude alembic E402, SQLAlchemy F821, and pre-existing E501 line-length issues. Auto-fix 69 unused imports and 2 f-strings without placeholders. Manually fix 8 unused variables. Apply ruff format to 127 files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -241,6 +241,7 @@ async def test_app(admin_engine, app_engine):
|
||||
|
||||
# Register rate limiter (auth endpoints use @limiter.limit)
|
||||
from app.middleware.rate_limit import setup_rate_limiting
|
||||
|
||||
setup_rate_limiting(app)
|
||||
|
||||
# Create test session factories
|
||||
|
||||
@@ -258,9 +258,7 @@ class TestAlertEvents:
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/devices/{device_id}/alerts returns paginated response."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
|
||||
@@ -19,7 +19,7 @@ from app.services.auth import hash_password
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
|
||||
from tests.integration.conftest import TEST_DATABASE_URL
|
||||
from tests.integration.conftest import TEST_DATABASE_URL # noqa: E402
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -93,7 +93,6 @@ async def test_login_success(client, admin_engine):
|
||||
assert len(body["refresh_token"]) > 0
|
||||
|
||||
# Verify httpOnly cookie is set
|
||||
cookies = resp.cookies
|
||||
# Cookie may or may not appear in httpx depending on secure flag
|
||||
# Just verify the response contains Set-Cookie header
|
||||
set_cookie = resp.headers.get("set-cookie", "")
|
||||
@@ -193,7 +192,6 @@ async def test_token_refresh(client, admin_engine):
|
||||
assert login_resp.status_code == 200
|
||||
tokens = login_resp.json()
|
||||
refresh_token = tokens["refresh_token"]
|
||||
original_access = tokens["access_token"]
|
||||
|
||||
# Use refresh token to get new access token
|
||||
refresh_resp = await client.post(
|
||||
|
||||
@@ -32,9 +32,7 @@ class TestConfigBackups:
|
||||
):
|
||||
"""GET config backups for a device with no backups returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -58,9 +56,7 @@ class TestConfigBackups:
|
||||
):
|
||||
"""GET schedule returns synthetic default when no schedule configured."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -118,9 +114,7 @@ class TestConfigBackups:
|
||||
):
|
||||
"""Config backup router responds (not 404) for expected paths."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -143,7 +137,5 @@ class TestConfigBackups:
|
||||
"""GET config backups without auth returns 401."""
|
||||
tenant_id = str(uuid.uuid4())
|
||||
device_id = str(uuid.uuid4())
|
||||
resp = await client.get(
|
||||
f"/api/tenants/{tenant_id}/devices/{device_id}/config/backups"
|
||||
)
|
||||
resp = await client.get(f"/api/tenants/{tenant_id}/devices/{device_id}/config/backups")
|
||||
assert resp.status_code == 401
|
||||
|
||||
@@ -10,7 +10,6 @@ All tests are independent and create their own test data.
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
@@ -90,9 +89,7 @@ class TestDevicesCRUD:
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/devices/{device_id} returns correct device."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
@@ -178,9 +175,7 @@ class TestDevicesCRUD:
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/devices?status=online returns filtered results."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
# Create devices with different statuses
|
||||
|
||||
@@ -36,9 +36,7 @@ class TestHealthMetrics:
|
||||
):
|
||||
"""GET health metrics for a device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
@@ -68,9 +66,7 @@ class TestHealthMetrics:
|
||||
):
|
||||
"""GET health metrics returns bucketed data when rows exist."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.flush()
|
||||
@@ -131,9 +127,7 @@ class TestInterfaceMetrics:
|
||||
):
|
||||
"""GET interface metrics for device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -160,9 +154,7 @@ class TestInterfaceMetrics:
|
||||
):
|
||||
"""GET interface list for device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -188,9 +180,7 @@ class TestSparkline:
|
||||
):
|
||||
"""GET sparkline for device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -215,9 +205,7 @@ class TestFleetSummary:
|
||||
):
|
||||
"""GET /api/tenants/{tenant_id}/fleet/summary returns 200 with empty fleet."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
resp = await client.get(
|
||||
@@ -238,9 +226,7 @@ class TestFleetSummary:
|
||||
):
|
||||
"""GET fleet summary returns device data when devices exist."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
|
||||
await create_test_device(admin_session, tenant.id, hostname="fleet-dev-1")
|
||||
@@ -279,9 +265,7 @@ class TestWirelessMetrics:
|
||||
):
|
||||
"""GET wireless metrics for device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
@@ -308,9 +292,7 @@ class TestWirelessMetrics:
|
||||
):
|
||||
"""GET wireless latest for device with no data returns 200 + empty list."""
|
||||
tenant = await create_test_tenant(admin_session)
|
||||
auth = await auth_headers_factory(
|
||||
admin_session, existing_tenant_id=tenant.id
|
||||
)
|
||||
auth = await auth_headers_factory(admin_session, existing_tenant_id=tenant.id)
|
||||
tenant_id = auth["tenant_id"]
|
||||
device = await create_test_device(admin_session, tenant.id)
|
||||
await admin_session.commit()
|
||||
|
||||
@@ -28,7 +28,7 @@ from app.services.auth import hash_password
|
||||
pytestmark = pytest.mark.integration
|
||||
|
||||
# Use the same test DB URLs as conftest
|
||||
from tests.integration.conftest import TEST_APP_USER_DATABASE_URL, TEST_DATABASE_URL
|
||||
from tests.integration.conftest import TEST_APP_USER_DATABASE_URL, TEST_DATABASE_URL # noqa: E402
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -86,12 +86,20 @@ async def test_tenant_a_cannot_see_tenant_b_devices():
|
||||
await session.flush()
|
||||
|
||||
da = Device(
|
||||
tenant_id=ta.id, hostname=f"rls-ra-{uid}", ip_address="10.1.1.1",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=ta.id,
|
||||
hostname=f"rls-ra-{uid}",
|
||||
ip_address="10.1.1.1",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
db = Device(
|
||||
tenant_id=tb.id, hostname=f"rls-rb-{uid}", ip_address="10.1.1.2",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=tb.id,
|
||||
hostname=f"rls-rb-{uid}",
|
||||
ip_address="10.1.1.2",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
session.add_all([da, db])
|
||||
await session.flush()
|
||||
@@ -129,12 +137,20 @@ async def test_tenant_a_cannot_see_tenant_b_alerts():
|
||||
await session.flush()
|
||||
|
||||
ra = AlertRule(
|
||||
tenant_id=ta.id, name=f"CPU Alert A {uid}",
|
||||
metric="cpu_load", operator=">", threshold=90.0, severity="warning",
|
||||
tenant_id=ta.id,
|
||||
name=f"CPU Alert A {uid}",
|
||||
metric="cpu_load",
|
||||
operator=">",
|
||||
threshold=90.0,
|
||||
severity="warning",
|
||||
)
|
||||
rb = AlertRule(
|
||||
tenant_id=tb.id, name=f"CPU Alert B {uid}",
|
||||
metric="cpu_load", operator=">", threshold=85.0, severity="critical",
|
||||
tenant_id=tb.id,
|
||||
name=f"CPU Alert B {uid}",
|
||||
metric="cpu_load",
|
||||
operator=">",
|
||||
threshold=85.0,
|
||||
severity="critical",
|
||||
)
|
||||
session.add_all([ra, rb])
|
||||
await session.flush()
|
||||
@@ -256,12 +272,20 @@ async def test_super_admin_sees_all_tenants():
|
||||
await session.flush()
|
||||
|
||||
da = Device(
|
||||
tenant_id=ta.id, hostname=f"sa-ra-{uid}", ip_address="10.2.1.1",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=ta.id,
|
||||
hostname=f"sa-ra-{uid}",
|
||||
ip_address="10.2.1.1",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
db = Device(
|
||||
tenant_id=tb.id, hostname=f"sa-rb-{uid}", ip_address="10.2.1.2",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=tb.id,
|
||||
hostname=f"sa-rb-{uid}",
|
||||
ip_address="10.2.1.2",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
session.add_all([da, db])
|
||||
await session.flush()
|
||||
@@ -311,31 +335,45 @@ async def test_api_rls_isolation_devices_endpoint(client, admin_engine):
|
||||
ua = User(
|
||||
email=f"api-ua-{uid}@example.com",
|
||||
hashed_password=hash_password("TestPass123!"),
|
||||
name="User A", role="tenant_admin",
|
||||
tenant_id=ta.id, is_active=True,
|
||||
name="User A",
|
||||
role="tenant_admin",
|
||||
tenant_id=ta.id,
|
||||
is_active=True,
|
||||
)
|
||||
ub = User(
|
||||
email=f"api-ub-{uid}@example.com",
|
||||
hashed_password=hash_password("TestPass123!"),
|
||||
name="User B", role="tenant_admin",
|
||||
tenant_id=tb.id, is_active=True,
|
||||
name="User B",
|
||||
role="tenant_admin",
|
||||
tenant_id=tb.id,
|
||||
is_active=True,
|
||||
)
|
||||
session.add_all([ua, ub])
|
||||
await session.flush()
|
||||
|
||||
da = Device(
|
||||
tenant_id=ta.id, hostname=f"api-ra-{uid}", ip_address="10.3.1.1",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=ta.id,
|
||||
hostname=f"api-ra-{uid}",
|
||||
ip_address="10.3.1.1",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
db = Device(
|
||||
tenant_id=tb.id, hostname=f"api-rb-{uid}", ip_address="10.3.1.2",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=tb.id,
|
||||
hostname=f"api-rb-{uid}",
|
||||
ip_address="10.3.1.2",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
session.add_all([da, db])
|
||||
await session.flush()
|
||||
return {
|
||||
"ta_id": str(ta.id), "tb_id": str(tb.id),
|
||||
"ua_email": ua.email, "ub_email": ub.email,
|
||||
"ta_id": str(ta.id),
|
||||
"tb_id": str(tb.id),
|
||||
"ua_email": ua.email,
|
||||
"ub_email": ub.email,
|
||||
}
|
||||
|
||||
ids = await _admin_commit(TEST_DATABASE_URL, setup)
|
||||
@@ -398,21 +436,29 @@ async def test_api_rls_isolation_cross_tenant_device_access(client, admin_engine
|
||||
ua = User(
|
||||
email=f"api-xt-ua-{uid}@example.com",
|
||||
hashed_password=hash_password("TestPass123!"),
|
||||
name="User A", role="tenant_admin",
|
||||
tenant_id=ta.id, is_active=True,
|
||||
name="User A",
|
||||
role="tenant_admin",
|
||||
tenant_id=ta.id,
|
||||
is_active=True,
|
||||
)
|
||||
session.add(ua)
|
||||
await session.flush()
|
||||
|
||||
db = Device(
|
||||
tenant_id=tb.id, hostname=f"api-xt-rb-{uid}", ip_address="10.4.1.1",
|
||||
api_port=8728, api_ssl_port=8729, status="online",
|
||||
tenant_id=tb.id,
|
||||
hostname=f"api-xt-rb-{uid}",
|
||||
ip_address="10.4.1.1",
|
||||
api_port=8728,
|
||||
api_ssl_port=8729,
|
||||
status="online",
|
||||
)
|
||||
session.add(db)
|
||||
await session.flush()
|
||||
return {
|
||||
"ta_id": str(ta.id), "tb_id": str(tb.id),
|
||||
"ua_email": ua.email, "db_id": str(db.id),
|
||||
"ta_id": str(ta.id),
|
||||
"tb_id": str(tb.id),
|
||||
"ua_email": ua.email,
|
||||
"db_id": str(db.id),
|
||||
}
|
||||
|
||||
ids = await _admin_commit(TEST_DATABASE_URL, setup)
|
||||
|
||||
@@ -5,22 +5,16 @@ tenant deletion cleanup, and allowed-IPs validation.
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from sqlalchemy import select, text
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.models.vpn import VpnConfig, VpnPeer
|
||||
from app.services.vpn_service import (
|
||||
add_peer,
|
||||
get_peer_config,
|
||||
get_vpn_config,
|
||||
remove_peer,
|
||||
setup_vpn,
|
||||
sync_wireguard_config,
|
||||
_get_wg_config_path,
|
||||
)
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
@@ -213,9 +207,8 @@ class TestTenantDeletion:
|
||||
|
||||
# Delete tenant 2
|
||||
from app.models.tenant import Tenant
|
||||
result = await admin_session.execute(
|
||||
select(Tenant).where(Tenant.id == t2.id)
|
||||
)
|
||||
|
||||
result = await admin_session.execute(select(Tenant).where(Tenant.id == t2.id))
|
||||
tenant_obj = result.scalar_one()
|
||||
await admin_session.delete(tenant_obj)
|
||||
await admin_session.flush()
|
||||
|
||||
Reference in New Issue
Block a user