Phase 0.1: Remove backend deprecated code

- Delete routes: counter.py, sum.py
- Delete jobs.py and worker.py
- Delete tests: test_counter.py, test_jobs.py
- Update audit.py: keep only price-history endpoints
- Update models.py: remove VIEW_COUNTER, INCREMENT_COUNTER, USE_SUM permissions
- Update models.py: remove Counter, SumRecord, CounterRecord, RandomNumberOutcome models
- Update schemas.py: remove sum/counter related schemas
- Update main.py: remove deleted router imports
- Update test_permissions.py: remove tests for deprecated features
- Update test_price_history.py: remove worker-related tests
- Update conftest.py: remove mock_enqueue_job fixture
- Update auth.py: fix example in docstring
This commit is contained in:
counterweight 2025-12-22 18:07:14 +01:00
parent ea85198171
commit 5bad1e7e17
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
14 changed files with 35 additions and 1393 deletions

View file

@ -50,10 +50,10 @@ class TestRoleAssignment:
data = response.json()
permissions = data["permissions"]
# Should have counter and sum permissions
assert Permission.VIEW_COUNTER.value in permissions
assert Permission.INCREMENT_COUNTER.value in permissions
assert Permission.USE_SUM.value in permissions
# Should have profile and booking permissions
assert Permission.MANAGE_OWN_PROFILE.value in permissions
assert Permission.BOOK_APPOINTMENT.value in permissions
assert Permission.VIEW_OWN_APPOINTMENTS.value in permissions
# Should NOT have audit permission
assert Permission.VIEW_AUDIT.value not in permissions
@ -69,10 +69,8 @@ class TestRoleAssignment:
# Should have audit permission
assert Permission.VIEW_AUDIT.value in permissions
# Should NOT have counter/sum permissions
assert Permission.VIEW_COUNTER.value not in permissions
assert Permission.INCREMENT_COUNTER.value not in permissions
assert Permission.USE_SUM.value not in permissions
# Should NOT have booking permissions (those are for regular users)
assert Permission.BOOK_APPOINTMENT.value not in permissions
@pytest.mark.asyncio
async def test_user_with_no_roles_has_no_permissions(
@ -86,124 +84,6 @@ class TestRoleAssignment:
assert data["permissions"] == []
# =============================================================================
# Counter Endpoint Access Tests
# =============================================================================
class TestCounterAccess:
"""Test access control for counter endpoints."""
@pytest.mark.asyncio
async def test_regular_user_can_view_counter(self, client_factory, regular_user):
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.get("/api/counter")
assert response.status_code == 200
assert "value" in response.json()
@pytest.mark.asyncio
async def test_regular_user_can_increment_counter(
self, client_factory, regular_user, mock_enqueue_job
):
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.post("/api/counter/increment")
assert response.status_code == 200
assert "value" in response.json()
@pytest.mark.asyncio
async def test_admin_cannot_view_counter(self, client_factory, admin_user):
"""Admin users should be forbidden from counter endpoints."""
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/counter")
assert response.status_code == 403
assert "permission" in response.json()["detail"].lower()
@pytest.mark.asyncio
async def test_admin_cannot_increment_counter(self, client_factory, admin_user):
"""Admin users should be forbidden from incrementing counter."""
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.post("/api/counter/increment")
assert response.status_code == 403
@pytest.mark.asyncio
async def test_user_without_roles_cannot_view_counter(
self, client_factory, user_no_roles
):
"""Users with no roles should be forbidden."""
async with client_factory.create(cookies=user_no_roles["cookies"]) as client:
response = await client.get("/api/counter")
assert response.status_code == 403
@pytest.mark.asyncio
async def test_unauthenticated_cannot_view_counter(self, client):
"""Unauthenticated requests should get 401."""
response = await client.get("/api/counter")
assert response.status_code == 401
@pytest.mark.asyncio
async def test_unauthenticated_cannot_increment_counter(self, client):
"""Unauthenticated requests should get 401."""
response = await client.post("/api/counter/increment")
assert response.status_code == 401
# =============================================================================
# Sum Endpoint Access Tests
# =============================================================================
class TestSumAccess:
"""Test access control for sum endpoint."""
@pytest.mark.asyncio
async def test_regular_user_can_use_sum(self, client_factory, regular_user):
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.post(
"/api/sum",
json={"a": 5, "b": 3},
)
assert response.status_code == 200
data = response.json()
assert data["result"] == 8
@pytest.mark.asyncio
async def test_admin_cannot_use_sum(self, client_factory, admin_user):
"""Admin users should be forbidden from sum endpoint."""
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.post(
"/api/sum",
json={"a": 5, "b": 3},
)
assert response.status_code == 403
@pytest.mark.asyncio
async def test_user_without_roles_cannot_use_sum(
self, client_factory, user_no_roles
):
async with client_factory.create(cookies=user_no_roles["cookies"]) as client:
response = await client.post(
"/api/sum",
json={"a": 5, "b": 3},
)
assert response.status_code == 403
@pytest.mark.asyncio
async def test_unauthenticated_cannot_use_sum(self, client):
response = await client.post(
"/api/sum",
json={"a": 5, "b": 3},
)
assert response.status_code == 401
# =============================================================================
# Audit Endpoint Access Tests
# =============================================================================
@ -213,89 +93,37 @@ class TestAuditAccess:
"""Test access control for audit endpoints."""
@pytest.mark.asyncio
async def test_admin_can_view_counter_audit(self, client_factory, admin_user):
async def test_admin_can_view_price_history(self, client_factory, admin_user):
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/audit/counter")
response = await client.get("/api/audit/price-history")
assert response.status_code == 200
data = response.json()
assert "records" in data
assert "total" in data
# Returns a list
assert isinstance(response.json(), list)
@pytest.mark.asyncio
async def test_admin_can_view_sum_audit(self, client_factory, admin_user):
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/audit/sum")
assert response.status_code == 200
data = response.json()
assert "records" in data
assert "total" in data
@pytest.mark.asyncio
async def test_regular_user_cannot_view_counter_audit(
async def test_regular_user_cannot_view_price_history(
self, client_factory, regular_user
):
"""Regular users should be forbidden from audit endpoints."""
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.get("/api/audit/counter")
response = await client.get("/api/audit/price-history")
assert response.status_code == 403
assert "permission" in response.json()["detail"].lower()
@pytest.mark.asyncio
async def test_regular_user_cannot_view_sum_audit(
self, client_factory, regular_user
):
"""Regular users should be forbidden from audit endpoints."""
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.get("/api/audit/sum")
assert response.status_code == 403
@pytest.mark.asyncio
async def test_user_without_roles_cannot_view_audit(
self, client_factory, user_no_roles
):
async with client_factory.create(cookies=user_no_roles["cookies"]) as client:
response = await client.get("/api/audit/counter")
response = await client.get("/api/audit/price-history")
assert response.status_code == 403
@pytest.mark.asyncio
async def test_unauthenticated_cannot_view_counter_audit(self, client):
response = await client.get("/api/audit/counter")
assert response.status_code == 401
@pytest.mark.asyncio
async def test_unauthenticated_cannot_view_sum_audit(self, client):
response = await client.get("/api/audit/sum")
assert response.status_code == 401
@pytest.mark.asyncio
async def test_admin_can_view_random_jobs(self, client_factory, admin_user):
"""Admin should be able to view random job outcomes."""
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/audit/random-jobs")
assert response.status_code == 200
# Returns a list (no pagination)
assert isinstance(response.json(), list)
@pytest.mark.asyncio
async def test_regular_user_cannot_view_random_jobs(
self, client_factory, regular_user
):
"""Regular users should be forbidden from random-jobs endpoint."""
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.get("/api/audit/random-jobs")
assert response.status_code == 403
@pytest.mark.asyncio
async def test_unauthenticated_cannot_view_random_jobs(self, client):
"""Unauthenticated users should get 401."""
response = await client.get("/api/audit/random-jobs")
async def test_unauthenticated_cannot_view_price_history(self, client):
response = await client.get("/api/audit/price-history")
assert response.status_code == 401
@ -320,18 +148,18 @@ class TestSecurityBypassAttempts:
"""
# Regular user tries to access audit endpoint
async with client_factory.create(cookies=regular_user["cookies"]) as client:
response = await client.get("/api/audit/counter")
response = await client.get("/api/audit/price-history")
# Should be denied regardless of any manipulation attempts
assert response.status_code == 403
@pytest.mark.asyncio
async def test_cannot_access_counter_with_expired_session(self, client_factory):
async def test_cannot_access_with_expired_session(self, client_factory):
"""Test that invalid/expired tokens are rejected."""
fake_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5OTk5IiwiZXhwIjoxfQ.invalid"
async with client_factory.create(cookies={"auth_token": fake_token}) as client:
response = await client.get("/api/counter")
response = await client.get("/api/profile")
assert response.status_code == 401
@ -348,7 +176,7 @@ class TestSecurityBypassAttempts:
async with client_factory.create(
cookies={"auth_token": tampered_token}
) as client:
response = await client.get("/api/counter")
response = await client.get("/api/profile")
assert response.status_code == 401
@ -386,7 +214,7 @@ class TestSecurityBypassAttempts:
# Try to access audit with this new user
async with client_factory.create(cookies=dict(response.cookies)) as client:
audit_response = await client.get("/api/audit/counter")
audit_response = await client.get("/api/audit/price-history")
assert audit_response.status_code == 403
@ -452,10 +280,10 @@ class TestSecurityBypassAttempts:
)
cookies = dict(login_response.cookies)
# Verify can access counter but not audit
# Verify can access profile but not audit
async with client_factory.create(cookies=cookies) as client:
assert (await client.get("/api/counter")).status_code == 200
assert (await client.get("/api/audit/counter")).status_code == 403
assert (await client.get("/api/profile")).status_code == 200
assert (await client.get("/api/audit/price-history")).status_code == 403
# Change user's role from regular to admin
async with client_factory.get_db_session() as db:
@ -468,62 +296,7 @@ class TestSecurityBypassAttempts:
user.roles = [admin_role] # Replace roles with admin only
await db.commit()
# Now should have audit access but not counter access
# Now should have audit access but not profile access (admin doesn't have MANAGE_OWN_PROFILE)
async with client_factory.create(cookies=cookies) as client:
assert (await client.get("/api/audit/counter")).status_code == 200
assert (await client.get("/api/counter")).status_code == 403
# =============================================================================
# Audit Record Tests
# =============================================================================
class TestAuditRecords:
"""Test that actions are properly recorded in audit logs."""
@pytest.mark.asyncio
async def test_counter_increment_creates_audit_record(
self, client_factory, regular_user, admin_user, mock_enqueue_job
):
"""Verify that counter increments are recorded and visible in audit."""
# Regular user increments counter
async with client_factory.create(cookies=regular_user["cookies"]) as client:
await client.post("/api/counter/increment")
# Admin checks audit
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/audit/counter")
assert response.status_code == 200
data = response.json()
assert data["total"] >= 1
# Find record for our user
records = data["records"]
user_records = [r for r in records if r["user_email"] == regular_user["email"]]
assert len(user_records) >= 1
@pytest.mark.asyncio
async def test_sum_operation_creates_audit_record(
self, client_factory, regular_user, admin_user
):
"""Verify that sum operations are recorded and visible in audit."""
# Regular user uses sum
async with client_factory.create(cookies=regular_user["cookies"]) as client:
await client.post("/api/sum", json={"a": 10, "b": 20})
# Admin checks audit
async with client_factory.create(cookies=admin_user["cookies"]) as client:
response = await client.get("/api/audit/sum")
assert response.status_code == 200
data = response.json()
assert data["total"] >= 1
# Find record with our values
records = data["records"]
matching = [
r for r in records if r["a"] == 10 and r["b"] == 20 and r["result"] == 30
]
assert len(matching) >= 1
assert (await client.get("/api/audit/price-history")).status_code == 200
assert (await client.get("/api/profile")).status_code == 403