feat: enhance backend security and configuration

- Updated Dockerfile to improve security with a non-root user and added health checks.
- Modified docker-compose.yml to set containers as read-only, restrict ports to localhost, and implement health checks.
- Enhanced .env.example with additional environment variables for security and configuration.
- Improved FastAPI application with middleware for security headers, CORS, and body size limits.
- Refactored authentication flow in auth.py to include state validation and improved error handling.
- Added rate limiting to various endpoints to prevent abuse.
- Updated researcher and publication handling to ensure better validation and error management.
This commit is contained in:
Mireya Cueto Garrido
2026-05-08 11:19:52 +02:00
parent 96e58dbd16
commit af1b8e9956
37 changed files with 1375 additions and 282 deletions
+29 -6
View File
@@ -1,13 +1,18 @@
from pydantic import BaseModel, Field
from uuid import UUID
from typing import Optional, List, Dict
from datetime import datetime
from typing import Dict, List, Optional
from uuid import UUID
from pydantic import BaseModel, Field, field_validator
from app.core.config import settings
from app.schema.publication import PublicationSchema
from app.utils.orcid_validator import ORCID_PATTERN, is_valid_orcid
class ResearcherSchema(BaseModel):
id: UUID
orcid_id: str
name: Optional[str]
orcid_id: str = Field(min_length=19, max_length=19, pattern=ORCID_PATTERN)
name: Optional[str] = Field(default=None, max_length=255)
authenticated: bool
last_sync_at: Optional[datetime]
@@ -33,7 +38,25 @@ class ResearcherWithPublicationsSchema(BaseModel):
class ResearcherBatchSearchRequestSchema(BaseModel):
orcid_ids: List[str] = Field(min_length=1)
orcid_ids: List[str] = Field(
min_length=1,
max_length=settings.MAX_ORCID_BATCH,
)
@field_validator("orcid_ids")
@classmethod
def _validate_each(cls, value: List[str]) -> List[str]:
deduped: List[str] = []
seen = set()
for v in value:
if not isinstance(v, str):
raise ValueError("ORCID iD debe ser string")
if not is_valid_orcid(v):
raise ValueError(f"ORCID iD inválido: {v}")
if v not in seen:
seen.add(v)
deduped.append(v)
return deduped
class ResearcherSearchErrorSchema(BaseModel):