- Fix IPv6 host parsing with _strip_port() utility - Remove dangerous StorePlatform→Store.subdomain silent fallback - Close storefront gate bypass when frontend_type is None - Add custom subdomain management UI and API for stores - Add domain health diagnostic tool - Convert db.add() in loops to db.add_all() (24 PERF-006 fixes) - Add tests for all new functionality (18 subdomain service tests) - Add .github templates for validator compliance Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
# tests/unit/middleware/test_storefront_gate_bypass.py
|
|
"""
|
|
Unit tests for the storefront gate bypass safety net.
|
|
|
|
Ensures that when frontend_type is None (upstream middleware failed),
|
|
storefront paths are BLOCKED rather than passed through. Non-storefront
|
|
paths with None frontend_type should pass through unchanged.
|
|
"""
|
|
|
|
from unittest.mock import AsyncMock, Mock, patch
|
|
|
|
import pytest
|
|
from fastapi import Request
|
|
from starlette.responses import JSONResponse
|
|
|
|
from middleware.storefront_access import (
|
|
StorefrontAccessMiddleware,
|
|
_looks_like_storefront,
|
|
)
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.middleware
|
|
class TestLooksLikeStorefront:
|
|
"""Test the _looks_like_storefront helper."""
|
|
|
|
def test_storefront_page_path(self):
|
|
assert _looks_like_storefront("/storefront/products") is True
|
|
|
|
def test_storefront_api_path(self):
|
|
assert _looks_like_storefront("/api/v1/storefront/cart") is True
|
|
|
|
def test_admin_path(self):
|
|
assert _looks_like_storefront("/admin/dashboard") is False
|
|
|
|
def test_static_path(self):
|
|
assert _looks_like_storefront("/static/css/style.css") is False
|
|
|
|
def test_store_path(self):
|
|
assert _looks_like_storefront("/store/ACME/login") is False
|
|
|
|
def test_root_path(self):
|
|
assert _looks_like_storefront("/") is False
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.middleware
|
|
class TestStorefrontGateBypass:
|
|
"""Test that None frontend_type can't bypass the storefront gate."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_none_frontend_type_storefront_page_blocked(self):
|
|
"""frontend_type=None + /storefront/ path → blocked with HTML 403."""
|
|
middleware = StorefrontAccessMiddleware(app=None)
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path="/storefront/products")
|
|
request.state = Mock()
|
|
request.state.frontend_type = None
|
|
request.state.store = None
|
|
request.state.language = "en"
|
|
request.state.theme = None
|
|
call_next = AsyncMock()
|
|
|
|
with patch("app.templates_config.templates") as mock_templates:
|
|
mock_templates.TemplateResponse.return_value = Mock(status_code=403)
|
|
await middleware.dispatch(request, call_next)
|
|
|
|
call_next.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_none_frontend_type_storefront_api_blocked(self):
|
|
"""frontend_type=None + /api/v1/storefront/ path → JSON 403."""
|
|
middleware = StorefrontAccessMiddleware(app=None)
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path="/api/v1/storefront/cart")
|
|
request.state = Mock()
|
|
request.state.frontend_type = None
|
|
call_next = AsyncMock()
|
|
|
|
response = await middleware.dispatch(request, call_next)
|
|
|
|
call_next.assert_not_called()
|
|
assert isinstance(response, JSONResponse)
|
|
assert response.status_code == 403
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_none_frontend_type_admin_passes_through(self):
|
|
"""frontend_type=None + /admin/ path → passes through (not storefront)."""
|
|
middleware = StorefrontAccessMiddleware(app=None)
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path="/admin/dashboard")
|
|
request.state = Mock()
|
|
request.state.frontend_type = None
|
|
call_next = AsyncMock(return_value=Mock())
|
|
|
|
await middleware.dispatch(request, call_next)
|
|
|
|
call_next.assert_called_once_with(request)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_none_frontend_type_static_passes_through(self):
|
|
"""frontend_type=None + /static/ path → passes through."""
|
|
middleware = StorefrontAccessMiddleware(app=None)
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path="/static/css/style.css")
|
|
request.state = Mock()
|
|
request.state.frontend_type = None
|
|
call_next = AsyncMock(return_value=Mock())
|
|
|
|
await middleware.dispatch(request, call_next)
|
|
|
|
call_next.assert_called_once_with(request)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_none_frontend_type_root_passes_through(self):
|
|
"""frontend_type=None + / path → passes through."""
|
|
middleware = StorefrontAccessMiddleware(app=None)
|
|
request = Mock(spec=Request)
|
|
request.url = Mock(path="/")
|
|
request.state = Mock()
|
|
request.state.frontend_type = None
|
|
call_next = AsyncMock(return_value=Mock())
|
|
|
|
await middleware.dispatch(request, call_next)
|
|
|
|
call_next.assert_called_once_with(request)
|