feat(middleware): harden routing with fail-closed policy, custom subdomain management, and perf fixes
Some checks failed
CI / pytest (push) Waiting to run
CI / ruff (push) Successful in 12s
CI / validate (push) Successful in 26s
CI / dependency-scanning (push) Successful in 31s
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled

- 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>
This commit is contained in:
2026-03-15 18:13:01 +01:00
parent 07fab01f6a
commit 540205402f
38 changed files with 1827 additions and 134 deletions

View File

@@ -83,6 +83,11 @@ def _is_static_request(path: str) -> bool:
return "favicon.ico" in lower
def _looks_like_storefront(path: str) -> bool:
"""Return True if path belongs to the storefront surface."""
return path.startswith(("/storefront/", "/api/v1/storefront/"))
class StorefrontAccessMiddleware(BaseHTTPMiddleware):
"""
Gate storefront requests behind an active subscription.
@@ -94,6 +99,25 @@ class StorefrontAccessMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next) -> Response:
frontend_type = getattr(request.state, "frontend_type", None)
# Safety net: if frontend_type is None (upstream middleware failed) but
# the path looks like a storefront path, block instead of letting it
# through — a None frontend_type must never bypass the gate.
if frontend_type is None and _looks_like_storefront(request.url.path):
logger.error(
"[STOREFRONT_ACCESS] frontend_type is None on storefront path "
f"'{request.url.path}' — blocking (fail-closed). "
"Check middleware chain ordering."
)
if request.url.path.startswith("/api/"):
return JSONResponse(
status_code=403,
content={
"error": "storefront_not_available",
"reason": "middleware_misconfigured",
},
)
return self._render_unavailable(request, "not_found")
# Only gate storefront requests
if frontend_type != FrontendType.STOREFRONT:
return await call_next(request)