Spaces:
Sleeping
Sleeping
Parth Kansal commited on
Commit Β·
35dc52d
1
Parent(s): f17ed53
commit
Browse files
app/db/__pycache__/client.cpython-314.pyc
CHANGED
|
Binary files a/app/db/__pycache__/client.cpython-314.pyc and b/app/db/__pycache__/client.cpython-314.pyc differ
|
|
|
app/db/client.py
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
|
|
|
|
|
| 1 |
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
|
|
|
|
| 2 |
from ..core.config import settings
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
_client: AsyncIOMotorClient = None
|
| 5 |
_db: AsyncIOMotorDatabase = None
|
| 6 |
|
|
@@ -8,7 +19,13 @@ _db: AsyncIOMotorDatabase = None
|
|
| 8 |
async def connect():
|
| 9 |
global _client, _db
|
| 10 |
_client = AsyncIOMotorClient(settings.MONGO_URL)
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
await _db.alerts.create_index([("location", "2dsphere")])
|
| 13 |
await _db.users.create_index("email", unique=True)
|
| 14 |
|
|
|
|
| 1 |
+
from pymongo.errors import ConfigurationError
|
| 2 |
+
|
| 3 |
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabase
|
| 4 |
+
|
| 5 |
from ..core.config import settings
|
| 6 |
|
| 7 |
+
# Default DB name used when the connection string doesn't carry one.
|
| 8 |
+
# Atlas users routinely paste a URL of the form
|
| 9 |
+
# `mongodb+srv://.../?retryWrites=true&w=majority` (no `/dbname` segment),
|
| 10 |
+
# which makes `get_default_database()` raise. Falling back to this name
|
| 11 |
+
# matches what the local-dev URL uses (`mongodb://localhost:27017/neighbouraid`)
|
| 12 |
+
# and keeps deploys forgiving.
|
| 13 |
+
_DEFAULT_DB_NAME = "neighbouraid"
|
| 14 |
+
|
| 15 |
_client: AsyncIOMotorClient = None
|
| 16 |
_db: AsyncIOMotorDatabase = None
|
| 17 |
|
|
|
|
| 19 |
async def connect():
|
| 20 |
global _client, _db
|
| 21 |
_client = AsyncIOMotorClient(settings.MONGO_URL)
|
| 22 |
+
try:
|
| 23 |
+
_db = _client.get_default_database()
|
| 24 |
+
except ConfigurationError:
|
| 25 |
+
# Atlas SRV strings often omit the database segment. Picking up
|
| 26 |
+
# `neighbouraid` here keeps the user from having to learn the
|
| 27 |
+
# exact connection-string syntax just to deploy.
|
| 28 |
+
_db = _client[_DEFAULT_DB_NAME]
|
| 29 |
await _db.alerts.create_index([("location", "2dsphere")])
|
| 30 |
await _db.users.create_index("email", unique=True)
|
| 31 |
|
tests/__pycache__/test_security.cpython-314-pytest-9.0.3.pyc
CHANGED
|
Binary files a/tests/__pycache__/test_security.cpython-314-pytest-9.0.3.pyc and b/tests/__pycache__/test_security.cpython-314-pytest-9.0.3.pyc differ
|
|
|
tests/test_security.py
CHANGED
|
@@ -1,18 +1,20 @@
|
|
| 1 |
-
"""Tests for the security hardening layer.
|
| 2 |
|
| 3 |
Covers:
|
| 4 |
- Security-headers middleware applies on every response
|
| 5 |
- Strengthened password rules (length, letter+digit complexity)
|
| 6 |
- Per-IP rate limit on login + register + write endpoints
|
| 7 |
- python-jose deprecation warning is silenced via pytest config
|
|
|
|
| 8 |
"""
|
| 9 |
|
| 10 |
from __future__ import annotations
|
| 11 |
|
| 12 |
-
from unittest.mock import AsyncMock, MagicMock
|
| 13 |
|
| 14 |
import pytest
|
| 15 |
from bson import ObjectId
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -190,3 +192,43 @@ async def test_rate_limiter_dependency_returns_429_message():
|
|
| 190 |
await dep(_FakeReq())
|
| 191 |
assert exc.value.status_code == 429
|
| 192 |
assert "unit" in exc.value.detail
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for the security hardening + reliability layer.
|
| 2 |
|
| 3 |
Covers:
|
| 4 |
- Security-headers middleware applies on every response
|
| 5 |
- Strengthened password rules (length, letter+digit complexity)
|
| 6 |
- Per-IP rate limit on login + register + write endpoints
|
| 7 |
- python-jose deprecation warning is silenced via pytest config
|
| 8 |
+
- DB connect fallback when the Atlas URL omits the database segment
|
| 9 |
"""
|
| 10 |
|
| 11 |
from __future__ import annotations
|
| 12 |
|
| 13 |
+
from unittest.mock import AsyncMock, MagicMock, patch
|
| 14 |
|
| 15 |
import pytest
|
| 16 |
from bson import ObjectId
|
| 17 |
+
from pymongo.errors import ConfigurationError
|
| 18 |
|
| 19 |
|
| 20 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 192 |
await dep(_FakeReq())
|
| 193 |
assert exc.value.status_code == 429
|
| 194 |
assert "unit" in exc.value.detail
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 198 |
+
# DB connect fallback β the most common HF Spaces deploy crash
|
| 199 |
+
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
@pytest.mark.asyncio
|
| 203 |
+
async def test_connect_falls_back_to_default_db_name():
|
| 204 |
+
"""Atlas users routinely paste a connection string with no /dbname
|
| 205 |
+
segment, which makes `get_default_database()` raise. Our connect()
|
| 206 |
+
should fall back to the `neighbouraid` database silently."""
|
| 207 |
+
from app.db import client as db_client
|
| 208 |
+
|
| 209 |
+
# Build a fake Motor client that:
|
| 210 |
+
# - raises ConfigurationError on get_default_database (the bug shape)
|
| 211 |
+
# - returns a mock DB when subscripted by name (the fallback path)
|
| 212 |
+
fake_db = MagicMock()
|
| 213 |
+
fake_db.alerts.create_index = AsyncMock()
|
| 214 |
+
fake_db.users.create_index = AsyncMock()
|
| 215 |
+
|
| 216 |
+
fake_client = MagicMock()
|
| 217 |
+
fake_client.get_default_database = MagicMock(
|
| 218 |
+
side_effect=ConfigurationError("no default db")
|
| 219 |
+
)
|
| 220 |
+
fake_client.__getitem__ = MagicMock(return_value=fake_db)
|
| 221 |
+
|
| 222 |
+
with patch.object(
|
| 223 |
+
db_client, "AsyncIOMotorClient", return_value=fake_client
|
| 224 |
+
):
|
| 225 |
+
# Cache the original to restore afterwards so we don't pollute
|
| 226 |
+
# other tests (the global fixture swaps _db too).
|
| 227 |
+
original = db_client._db
|
| 228 |
+
try:
|
| 229 |
+
await db_client.connect()
|
| 230 |
+
# The fallback should have indexed `neighbouraid`
|
| 231 |
+
fake_client.__getitem__.assert_called_with("neighbouraid")
|
| 232 |
+
assert db_client._db is fake_db
|
| 233 |
+
finally:
|
| 234 |
+
db_client._db = original
|