refactor: standardize error handling to 422, enable debug mode in FastAPI, and add API documentation

main
Cizz22 1 month ago
parent 73bc6481c9
commit bc05b0b9db

@ -0,0 +1,208 @@
# DigitalTwin - Optimum Overhaul App (be-optimumoh) API Documentation
This document maps all the API endpoints, route handlers, database models, and external service layers inside the `be-optimumoh` microservice. It is a FastAPI-based backend engine managing Overhaul schedules, standard scopes, spare parts readiness, Temporal workflow executions, and optimization/constraint calculations.
---
## 📊 Summary of Services
| Service / Module | Purpose | Endpoints Count | Primary Database Tables |
| :--- | :--- | :---: | :--- |
| **Overhauls** (`overhauls`) | Core overhaul session status, critical parts, schedules, and systems overview. | 4 | `oh_ms_overhaul` |
| **Standard Scope** (`scope-equipments`) | Fleet scopes configuration, master equipment availability, and historical overhaul logs. | 4 | `oh_ms_standard_scope`, `oh_ms_equipment_oh_history` |
| **Overhaul Activities** (`overhaul-activity`) | Operations/activities scheduling and batch additions to active overhaul sessions. | 4 | `oh_tr_overhaul_activity` |
| **Workscope Groups** (`workscopes`) | Maintenance activity groups, tasks, and overhaul scheduling. | 5 | `oh_ms_workscope_group`, `oh_ms_workscope_task` |
| **Spare Parts** (`spareparts`) | Global inventory levels, procurement planning status, and planning remarks. | 2 | `oh_ms_sparepart`, `oh_ms_sparepart_remark` |
| **Equipment Workscopes** (`equipment-workscopes`) | Equipment-specific maintenance work scope groups mapping and jobs tracking. | 3 | `oh_tr_equipment_workscope_group` |
| **Equipment Spare Parts** (`equipment-spareparts`) | Material part catalog tracking per asset location tag. | 1 | `oh_ms_scope_equipment_part` |
| **Monitoring Gantt** (`overhaul-gantt`) | Google Sheets Gantt performance charts extraction and sync triggers. | 3 | `oh_ms_monitoring_spreadsheet` |
| **Overhaul Schedules** (`overhaul-schedules`) | Detailed calendar session creation, history tracking, updates, and deletes. | 6 | `oh_ms_overhaul` |
| **Time Constraints** (`time-constraint`) | Scheduling simulations under a rigid time window restriction. | 9 | `oh_ms_calculation_param`, `oh_tr_calculation_result` |
| **Optimized Time Constraints** | Simulations for ideal schedules under a variable optimal calendar logic. | 9 | `oh_tr_calculation_data`, `oh_tr_calculation_equipment_result` |
| **Target Reliability** | Background RBD Monte Carlo simulations executed via Temporal workflows. | 2 | None (Leverages Temporal Client SDK) |
| **Budget Constraints** | Financial threshold filtering and consequence calculation matrix. | 1 | `oh_tr_calculation_result` |
---
## 🛡️ App Middlewares & Framework Architecture
### 1. Security Headers Middleware
FastAPI adds rigid HTTP security headers to all incoming connections inside `src/main.py`. In production, it enforces `Strict-Transport-Security`, `X-Frame-Options` (DENY), and full CSP blockades. In development mode, it supports relaxed parameters.
### 2. Request Sanitization & Slowapi Limiting
All JSON and path structures pass through `RequestValidationMiddleware` (`slowapi` integration) to enforce rate limiting thresholds globally, returning standard payload error formatting on breaches.
### 3. Multi-Session Context Scoping
Scoped database sessions are generated per request context dynamically utilizing ContextVars in `src/context.py` and SQLAlchemy's async connection pool engine:
* `db` session: Optimum overhaul local PostgreSQL dataset (`default`).
* `collector_db` session: Asset metadata and equipment configurations.
---
## 🛠️ Complete API Endpoints Catalog
```mermaid
graph TD
UI[Frontend Client Application] -->|JWTBearer token| G[FastAPI Gateway Router]
G -->|Overhaul Master| OH[Overhaul Service]
G -->|Standard Scopes| SS[Standard Scope Service]
G -->|Spare Parts| SP[Spare Parts Service]
G -->|Gantt Tracking| GT[Gantt Chart Service]
G -->|Simulations API| TC[Constraint Calculations Service]
TC -->|Simulation Worker| TMP[Temporalio Cluster Engine]
```
### 1. 📂 Overhauls Service (`overhauls`)
Prefix: `/overhauls` — Exposes master overhaul dashboard summaries, schedules, critical parts status, and system maps.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Overhauls** | `/overhauls` | `GET` | Algorithm | `oh_ms_overhaul` | Frontend | ~28 | **Y** | JWTBearer |
| **Overhauls** | `/overhauls/schedules` | `GET` | CRUD | `oh_ms_overhaul` | Frontend | ~8 | **Y** | JWTBearer |
| **Overhauls** | `/overhauls/critical-parts` | `GET` | CRUD | `oh_ms_sparepart`, `oh_ms_sparepart_procurement` | Frontend | ~8 | **Y** | JWTBearer |
| **Overhauls** | `/overhauls/system-components` | `GET` | CRUD | None (Static mapping) | Frontend | ~10 | **Y** | JWTBearer |
---
### 2. 📋 Standard Scope Service (`scope-equipments`)
Prefix: `/scope-equipments` — Manages fleet-wide equipment checklists and standard scopes configurations.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Standard Scope** | `/scope-equipments` | `GET` | CRUD | `oh_ms_standard_scope` | Frontend | ~10 | **Y** | JWTBearer |
| **Standard Scope** | `/scope-equipments/available/{scope_name}` | `GET` | CRUD | `ms_equipment_master`, `oh_ms_standard_scope` | Frontend | ~9 | **Y** | JWTBearer |
| **Standard Scope** | `/scope-equipments` | `POST` | CRUD | `oh_ms_standard_scope` | Frontend | ~8 | **Y** | JWTBearer |
| **Standard Scope** | `/scope-equipments/history/{oh_session_id}`| `GET` | CRUD | `oh_ms_equipment_oh_history`, `ms_equipment_master` | Frontend | ~10 | **Y** | JWTBearer |
---
### 3. 🏃‍♂️ Overhaul Activity Service (`overhaul-activity`)
Prefix: `/overhaul-activity` — Controls tasks assigned to individual overhaul sessions.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Overhaul Activity** | `/overhaul-activity/{overhaul_session}` | `GET` | CRUD | `oh_tr_overhaul_activity` | Frontend | ~25 | **Y** | JWTBearer |
| **Overhaul Activity** | `/overhaul-activity/{overhaul_session_id}`| `POST` | CRUD | `oh_tr_overhaul_activity` | Frontend | ~15 | **Y** | JWTBearer |
| **Overhaul Activity** | `/overhaul-activity/{overhaul_session}/{assetnum}`| `GET` | CRUD | `oh_tr_overhaul_activity` | Frontend | ~17 | **Y** | JWTBearer |
| **Overhaul Activity** | `/overhaul-activity/delete/{overhaul_session}/{location_tag}`| `POST` | CRUD | `oh_tr_overhaul_activity` | Frontend | ~8 | **Y** | JWTBearer |
---
### 4. 🔨 Workscope Group Service (`workscopes`)
Prefix: `/workscopes` — Defines tasks and maintenance groupings.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Workscope Group** | `/workscopes` | `GET` | CRUD | `oh_ms_workscope_group` | Frontend | ~12 | **Y** | JWTBearer |
| **Workscope Group** | `/workscopes` | `POST` | CRUD | `oh_ms_workscope_group` | Frontend | ~8 | **Y** | JWTBearer |
| **Workscope Group** | `/workscopes/{scope_equipment_activity_id}`| `GET` | CRUD | `oh_ms_workscope_task` | Frontend | ~12 | **Y** | JWTBearer |
| **Workscope Group** | `/workscopes/update/{scope_equipment_activity_id}`| `POST` | CRUD | `oh_ms_workscope_task` | Frontend | ~17 | **Y** | JWTBearer |
| **Workscope Group** | `/workscopes/delete/{scope_equipment_activity_id}`| `POST` | CRUD | `oh_ms_workscope_task` | Frontend | ~14 | **Y** | JWTBearer |
---
### 5. 📦 Spare Parts Service (`spareparts`)
Prefix: `/spareparts` — Manages part catalogs and remark notations.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Spare Parts** | `/spareparts` | `GET` | CRUD | `oh_ms_sparepart`, `oh_ms_sparepart_procurement` | Frontend | ~12 | **Y** | JWTBearer |
| **Spare Parts** | `/spareparts` | `POST` | CRUD | `oh_ms_sparepart_remark` | Frontend | ~8 | **Y** | JWTBearer |
---
### 6. 🔌 Equipment Workscopes Service (`equipment-workscopes`)
Prefix: `/equipment-workscopes` — Maps equipment directly to defined work scopes.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Equipment Workscopes**| `/equipment-workscopes/{location_tag}`| `GET` | CRUD | `oh_tr_equipment_workscope_group` | Frontend | ~12 | **Y** | JWTBearer |
| **Equipment Workscopes**| `/equipment-workscopes/{assetnum}` | `POST` | CRUD | `oh_tr_equipment_workscope_group` | Frontend | ~11 | **Y** | JWTBearer |
| **Equipment Workscopes**| `/equipment-workscopes/delete/{scope_job_id}`| `POST` | CRUD | `oh_tr_equipment_workscope_group` | Frontend | ~9 | **Y** | JWTBearer |
---
### 7. 🔩 Equipment Spare Parts Service (`equipment-spareparts`)
Prefix: `/equipment-spareparts` — Lists active spare parts mapping per equipment tag.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Equipment Spareparts**| `/equipment-spareparts/{location_tag}`| `GET` | CRUD | `oh_ms_scope_equipment_part` | Frontend | ~10 | **Y** | JWTBearer |
---
### 8. 📊 Overhaul Gantt Chart Service (`overhaul-gantt`)
Prefix: `/overhaul-gantt` — Coordinates Google Sheets sync actions to build overhaul performance monitoring dashboards.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Overhaul Gantt** | `/overhaul-gantt` | `GET` | Integration | `oh_ms_monitoring_spreadsheet` | Frontend | ~19 | **Y** | Google Sheets APIs, cell parsers |
| **Overhaul Gantt** | `/overhaul-gantt/spreadsheet`| `GET` | CRUD | `oh_ms_monitoring_spreadsheet` | Frontend | ~22 | **Y** | JWTBearer |
| **Overhaul Gantt** | `/overhaul-gantt/spreadsheet`| `POST` | CRUD | `oh_ms_monitoring_spreadsheet` | Frontend | ~36 | **Y** | Google Sheets URL validator |
---
### 9. 📅 Overhaul Session Schedules Service (`overhaul-schedules`)
Prefix: `/overhaul-schedules` — Controls scheduler calendar timelines.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Schedules** | `/overhaul-schedules` | `GET` | CRUD | `oh_ms_overhaul` | Frontend | ~10 | **Y** | JWTBearer |
| **Schedules** | `/overhaul-schedules/history`| `GET` | CRUD | `oh_ms_overhaul` | Frontend | ~4 | **Y** | JWTBearer |
| **Schedules** | `/overhaul-schedules/{overhaul_session_id}`| `GET` | CRUD | `oh_ms_overhaul` | Frontend | ~10 | **Y** | JWTBearer |
| **Schedules** | `/overhaul-schedules` | `POST` | CRUD | `oh_ms_overhaul` | Frontend | ~5 | **Y** | JWTBearer |
| **Schedules** | `/overhaul-schedules/update/{scope_id}`| `POST` | CRUD | `oh_ms_overhaul` | Frontend | ~12 | **Y** | JWTBearer |
| **Schedules** | `/overhaul-schedules/delete/{scope_id}`| `POST` | CRUD | `oh_ms_overhaul` | Frontend | ~13 | **Y** | JWTBearer |
---
### 10. ⏱️ Time Constraints Calculation Service (`time-constraint`)
Prefix: `/calculation/time-constraint` — Simulates failure counts and risks under strict overhaul downtime constraints.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Time Constraints** | `/calculation/time-constraint` | `POST` | Algorithm | `oh_ms_calculation_param` | Frontend | ~36 | **Y** | RBD risk simulation logic |
| **Time Constraints** | `/calculation/time-constraint` | `GET` | CRUD | `oh_tr_calculation_data` | Frontend | ~18 | **Y** | JWTBearer |
| **Time Constraints** | `/calculation/time-constraint/parameters`| `GET` | CRUD | `oh_ms_calculation_param` | Frontend | ~13 | **Y** | JWTBearer |
| **Time Constraints** | `/calculation/time-constraint/{calculation_id}`| `GET` | Algorithm | `oh_tr_calculation_result` | Frontend | ~18 | **N** | Internal Auth Key (Unprotected endpoint) |
| **Time Constraints** | `/calculation/time-constraint/{calculation_id}/{assetnum}`| `GET` | CRUD | `oh_tr_calculation_equipment_result` | Frontend | ~9 | **Y** | JWTBearer |
| **Time Constraints** | `/calculation/time-constraint/{calculation_id}/simulation`| `POST` | Algorithm | `oh_tr_calculation_result` | Frontend | ~13 | **Y** | Temporal timelines calculator |
| **Time Constraints** | `/calculation/time-constraint/update/{calculation_id}`| `POST` | CRUD | `oh_tr_calculation_equipment_result` | Frontend | ~18 | **Y** | Bulk parameters updates |
| **Time Constraints** | `/calculation/time-constraint/{calculation_id}/refresh-spareparts`| `POST` | Integration | `oh_ms_sparepart`, `oh_ms_calculation_param` | Frontend | ~15 | **Y** | Inventory sync parameters |
| **Time Constraints** | `/calculation/time-constraint/{calculation_id}/recalculate`| `POST` | Algorithm / Int | `oh_tr_calculation_result` | Frontend | ~17 | **Y** | Temporal workflows trigger |
---
### 11. ⚙️ Optimized Time Constraints Service (`optimum-time-constraint`)
Prefix: `/calculation/optimum-time-constraint` — Solves for optimized downtime intervals.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Optimum Constraints** | `/calculation/optimum-time-constraint` | `POST` | Algorithm | `oh_ms_calculation_param` | Frontend | ~29 | **Y** | Optimum solver iterations |
| **Optimum Constraints** | `/calculation/optimum-time-constraint` | `GET` | CRUD | `oh_tr_calculation_data` | Frontend | ~15 | **Y** | JWTBearer |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/parameters`| `GET` | CRUD | `oh_ms_calculation_param` | Frontend | ~13 | **Y** | JWTBearer |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/{calculation_id}`| `GET` | Algorithm | `oh_tr_calculation_result` | Frontend | ~19 | **N** | Internal Auth Key (Unprotected endpoint) |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/{calculation_id}/{assetnum}`| `GET` | CRUD | `oh_tr_calculation_equipment_result` | Frontend | ~8 | **Y** | JWTBearer |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/{calculation_id}/simulation`| `POST` | Algorithm | `oh_tr_calculation_result` | Frontend | ~13 | **Y** | Optimization simulation matrix |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/update/{calculation_id}`| `POST` | CRUD | `oh_tr_calculation_equipment_result` | Frontend | ~18 | **Y** | JWTBearer |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/{calculation_id}/refresh-spareparts`| `POST` | Integration | `oh_ms_sparepart` | Frontend | ~15 | **Y** | Inventory sync parameters |
| **Optimum Constraints** | `/calculation/optimum-time-constraint/{calculation_id}/recalculate`| `POST` | Algorithm / Int | `oh_tr_calculation_result` | Frontend | ~17 | **Y** | Temporal workflows trigger |
---
### 12. ⚡ Target Reliability Simulation Service (`target-reliability`)
Prefix: `/calculation/target-reliability` — Leverages Temporal client triggers to dispatch heavy RBD Monte Carlo workflows.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Target Reliability** | `/calculation/target-reliability/simulate`| `POST` | Integration | None (Triggers Temporal workflow) | Frontend | ~18 | **Y** | Temporal IO client runner |
| **Target Reliability** | `/calculation/target-reliability` | `GET` | Algorithm | `oh_ms_overhaul` | Frontend | ~88 | **Y** | Temporal client status tracking, EAF math |
---
### 13. 💰 Budget Constraints Service (`budget-constraint`)
Prefix: `/calculation/budget-constraint` — Computes maintenance strategies according to cost limit thresholds.
| Service | Endpoint | Method | Type | DB Tables Touched | Called By | LOC | Protect? (Y/N) | Dependencies |
| :--- | :--- | :---: | :--- | :--- | :--- | :---: | :---: | :--- |
| **Budget Constraints** | `/calculation/budget-constraint/{session_id}`| `GET` | Algorithm | `oh_ms_overhaul`, `oh_tr_calculation_result` | Frontend | ~25 | **Y** | Risk-cost matrix calculator |

@ -32,7 +32,7 @@ async def run_rbd_simulation(*, sim_hours: int, oh_duration: int = 1200, oh_sess
CalculationData.analysis_metadata["oh_duration"].as_string() == str(oh_duration) CalculationData.analysis_metadata["oh_duration"].as_string() == str(oh_duration)
) )
result = await db_session.execute(stmt) result = await db_session.execute(stmt)
existing_calc = result.scalars().first() existing_calc = result.scalars(yield).first()
if existing_calc and existing_calc.rbd_simulation_id: if existing_calc and existing_calc.rbd_simulation_id:
return {"data": str(existing_calc.rbd_simulation_id), "status": "success", "message": "Loaded existing simulation"} return {"data": str(existing_calc.rbd_simulation_id), "status": "success", "message": "Loaded existing simulation"}

@ -46,7 +46,8 @@ config = get_config()
LOG_LEVEL = config("LOG_LEVEL", default="INFO") LOG_LEVEL = config("LOG_LEVEL", default="INFO")
ENV = config("ENV", default="local") ENV = (os.getenv("ENV") or os.getenv("ENVIRONMENT") or os.getenv("ENVIRONEMENT") or "production").strip()
DEBUG = 1 if (ENV.upper() in ("DEV", "DEVELOPMENT", "LOCAL") and "PROD" not in ENV.upper()) else 0
PORT = config("PORT", cast=int, default=8000) PORT = config("PORT", cast=int, default=8000)
HOST = config("HOST", default="localhost") HOST = config("HOST", default="localhost")
@ -92,3 +93,5 @@ API_KEY = config("API_KEY", default="0KFvcB7zWENyKVjoma9FKZNofVSViEshYr59zEQNGaY
TR_RBD_ID = config("TR_RBD_ID", default="f04f365e-25d8-4036-87c2-ba1bfe1f9229") TR_RBD_ID = config("TR_RBD_ID", default="f04f365e-25d8-4036-87c2-ba1bfe1f9229")
TC_RBD_ID = config("TC_RBD_ID", default="f8523cb0-dc3c-4edb-bcf1-eea7b62582f1") TC_RBD_ID = config("TC_RBD_ID", default="f8523cb0-dc3c-4edb-bcf1-eea7b62582f1")
DEFAULT_TC_ID = config("DEFAULT_TC_ID", default="44f483f3-bfe4-4094-a59f-b97a10f2fea6") DEFAULT_TC_ID = config("DEFAULT_TC_ID", default="44f483f3-bfe4-4094-a59f-b97a10f2fea6")
TEMPORAL_URL

@ -39,12 +39,15 @@ log = logging.getLogger(__name__)
# we configure the logging level and format # we configure the logging level and format
configure_logging() configure_logging()
from src.config import DEBUG
# we create the ASGI for the app # we create the ASGI for the app
app = FastAPI( app = FastAPI(
openapi_url="", openapi_url="",
title="LCCA API", title="LCCA API",
description="Welcome to LCCA's API documentation!", description="Welcome to LCCA's API documentation!",
version="0.1.0", version="0.1.0",
debug=bool(DEBUG),
) )
# we define the exception handlers # we define the exception handlers

@ -154,7 +154,7 @@ RCE_PATTERN = re.compile(
r"\$\(.*\)|`.*`|" # Command substitution $(...) or `...` r"\$\(.*\)|`.*`|" # Command substitution $(...) or `...`
r"[;&|]\s*(cat|ls|id|whoami|pwd|ifconfig|ip|netstat|nc|netcat|nmap|curl|wget|python|php|perl|ruby|bash|sh|cmd|powershell|pwsh|sc\s+|tasklist|taskkill|base64|sudo|crontab|ssh|ftp|tftp)|" r"[;&|]\s*(cat|ls|id|whoami|pwd|ifconfig|ip|netstat|nc|netcat|nmap|curl|wget|python|php|perl|ruby|bash|sh|cmd|powershell|pwsh|sc\s+|tasklist|taskkill|base64|sudo|crontab|ssh|ftp|tftp)|"
# Only flag naked commands if they are clearly standalone or system paths # Only flag naked commands if they are clearly standalone or system paths
r"\b(/etc/passwd|/etc/shadow|/etc/group|/etc/issue|/proc/self/|/windows/system32/|C:\\Windows\\)\b" r"(/etc/passwd|/etc/shadow|/etc/group|/etc/issue|/proc/self/|/windows/system32/|C:\\Windows\\)\b"
r")", r")",
re.IGNORECASE, re.IGNORECASE,
) )
@ -351,7 +351,7 @@ class RequestValidationMiddleware(BaseHTTPMiddleware):
if key in pagination_size_keys and value: if key in pagination_size_keys and value:
try: try:
size_val = int(value) size_val = int(value)
if size_val > 50: if size_val > 100:
log.warning(f"Security violation: Pagination size too large ({size_val})") log.warning(f"Security violation: Pagination size too large ({size_val})")
raise HTTPException( raise HTTPException(
status_code=422, status_code=422,

@ -11,7 +11,8 @@ async def test_request_validation_middleware_query_length():
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
await middleware.dispatch(request, AsyncMock()) await middleware.dispatch(request, AsyncMock())
assert excinfo.value.status_code == 414 assert excinfo.value.status_code == 422
assert "Invalid request parameters" in excinfo.value.detail
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_request_validation_middleware_too_many_params(): async def test_request_validation_middleware_too_many_params():
@ -22,8 +23,8 @@ async def test_request_validation_middleware_too_many_params():
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
await middleware.dispatch(request, AsyncMock()) await middleware.dispatch(request, AsyncMock())
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "Too many query parameters" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_request_validation_middleware_xss_detection(): async def test_request_validation_middleware_xss_detection():
@ -34,23 +35,24 @@ async def test_request_validation_middleware_xss_detection():
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
await middleware.dispatch(request, AsyncMock()) await middleware.dispatch(request, AsyncMock())
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "Potential XSS payload" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_request_validation_middleware_pagination_logic(): async def test_request_validation_middleware_pagination_logic():
middleware = RequestValidationMiddleware(app=MagicMock()) middleware = RequestValidationMiddleware(app=MagicMock())
request = MagicMock() request = MagicMock()
request.url.query = "size=55" request.url.query = "size=105"
request.query_params.multi_items.return_value = [("size", "55")] request.query_params.multi_items.return_value = [("size", "105")]
request.headers = {} request.headers = {}
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
await middleware.dispatch(request, AsyncMock()) await middleware.dispatch(request, AsyncMock())
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "cannot exceed 50" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
request.query_params.multi_items.return_value = [("size", "7")] request.query_params.multi_items.return_value = [("size", "7")]
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
await middleware.dispatch(request, AsyncMock()) await middleware.dispatch(request, AsyncMock())
assert "must be a multiple of 5" in excinfo.value.detail assert excinfo.value.status_code == 422
assert "Invalid request parameters" in excinfo.value.detail

@ -11,10 +11,10 @@ from src.middleware import (
def test_xss_patterns(): def test_xss_patterns():
# Test common XSS payloads in be-optimumoh # Test common XSS payloads in be-optimumoh
payloads = [ payloads = [
"<script>", "<script>alert(1)</script>",
"javascript:", "javascript:alert(1)",
"onerror=", "onerror=alert(1)",
"onload=", "onload=alert(1)",
"<svg", "<svg",
"<img" "<img"
] ]
@ -24,13 +24,10 @@ def test_xss_patterns():
def test_sqli_patterns(): def test_sqli_patterns():
# Test common SQLi payloads in be-optimumoh # Test common SQLi payloads in be-optimumoh
payloads = [ payloads = [
"UNION", "UNION SELECT * FROM users",
"SELECT", "OR 1=1",
"INSERT", "WAITFOR DELAY '0:0:5'",
"DELETE", "INFORMATION_SCHEMA.TABLES",
"DROP",
"--",
"OR 1=1"
] ]
for payload in payloads: for payload in payloads:
assert SQLI_PATTERN.search(payload) is not None assert SQLI_PATTERN.search(payload) is not None
@ -38,19 +35,19 @@ def test_sqli_patterns():
def test_inspect_value_raises(): def test_inspect_value_raises():
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
inspect_value("<script>", "source") inspect_value("<script>", "source")
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "Potential XSS payload" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
inspect_value("UNION SELECT", "source") inspect_value("UNION SELECT * FROM users", "source")
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "Potential SQL injection" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
def test_inspect_json_raises(): def test_inspect_json_raises():
with pytest.raises(HTTPException) as excinfo: with pytest.raises(HTTPException) as excinfo:
inspect_json({"__proto__": "polluted"}) inspect_json({"__proto__": "polluted"})
assert excinfo.value.status_code == 400 assert excinfo.value.status_code == 422
assert "Forbidden JSON key" in excinfo.value.detail assert "Invalid request parameters" in excinfo.value.detail
def test_has_control_chars(): def test_has_control_chars():
assert has_control_chars("normal string") is False assert has_control_chars("normal string") is False

Loading…
Cancel
Save