From 51d041c0da2a4f9f2c35caacacd8ec1a3e89c21e Mon Sep 17 00:00:00 2001 From: neckfire Date: Sat, 20 Jun 2026 12:21:47 +0200 Subject: [PATCH] ci: dockerise l'API + connexion DB et CORS configurables par env - config.py: connexion SQL via DB_* (driver 18, auth SQL), fallback Windows local - main.py: origines CORS via CORS_ORIGINS - Dockerfile (python 3.12 + msodbcsql18) + workflow Gitea Actions (build/push image) --- .gitea/workflows/build.yml | 37 +++++++++++++++++++++++++++++++++++++ Dockerfile | 21 +++++++++++++++++++++ config.py | 34 ++++++++++++++++++++++++++++------ main.py | 12 +++++++++++- 4 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 .gitea/workflows/build.yml create mode 100644 Dockerfile diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..e471371 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,37 @@ +name: Build & Deploy + +on: + push: + branches: [main] + workflow_dispatch: {} + +env: + IMAGE: git.nfteam.ovh/neckfire/datasentinel-api + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build & push image + run: | + set -e + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login git.nfteam.ovh -u "${{ secrets.REGISTRY_USER }}" --password-stdin + docker build -t "${IMAGE}:latest" -t "${IMAGE}:${GITHUB_SHA::12}" . + docker push --all-tags "${IMAGE}" + echo "pushed ${IMAGE}" + + - name: Notify ntfy (success/failure) + if: always() + run: | + if [ "${{ job.status }}" = "success" ]; then EMOJI="white_check_mark"; PRIO="default"; else EMOJI="rotating_light"; PRIO="high"; fi + curl -s \ + -H "Authorization: Bearer ${{ secrets.NTFY_TOKEN }}" \ + -H "Title: ${GITHUB_REPOSITORY} — ${{ job.status }}" \ + -H "Priority: ${PRIO}" \ + -H "Tags: ${EMOJI}" \ + -H "Click: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions" \ + -d "${GITHUB_WORKFLOW} sur ${GITHUB_REF_NAME} (run #${GITHUB_RUN_NUMBER}) : ${{ job.status }}" \ + "${{ secrets.NTFY_URL }}/${{ secrets.NTFY_TOPIC }}" || true diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..83f3eb4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# API Data Sentinel — FastAPI + pyodbc (ODBC Driver 18 pour SQL Server). +FROM python:3.12-slim + +# Pilote Microsoft ODBC 18 (le 17 n'est plus packagé sur Debian 12 / bookworm). +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl gnupg ca-certificates apt-transport-https \ + && curl -sSL https://packages.microsoft.com/keys/microsoft.asc \ + | gpg --dearmor -o /usr/share/keyrings/microsoft-prod.gpg \ + && echo "deb [arch=amd64,arm64 signed-by=/usr/share/keyrings/microsoft-prod.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" \ + > /etc/apt/sources.list.d/mssql-release.list \ + && apt-get update \ + && ACCEPT_EULA=Y apt-get install -y msodbcsql18 unixodbc-dev \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . + +EXPOSE 8000 +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/config.py b/config.py index 481990d..4b67bc7 100644 --- a/config.py +++ b/config.py @@ -3,28 +3,50 @@ # Data Sentinel | COYAUD Anthony | 2026 # ============================================================ +import os import pyodbc from contextlib import contextmanager -class Config: - # Chaîne de connexion SQL Server - DB_CONNECTION_STRING = ( +def _build_connection_string() -> str: + """ + En déploiement (variables d'environnement présentes), on se connecte en + authentification SQL. Sinon, on garde la connexion Windows locale par défaut + (poste de dev). + """ + server = os.getenv("DB_SERVER") + if server: + driver = os.getenv("DB_DRIVER", "ODBC Driver 18 for SQL Server") + port = os.getenv("DB_PORT", "1433") + return ( + f"Driver={{{driver}}};" + f"Server={server},{port};" + f"Database={os.getenv('DB_NAME', 'DataSentinel')};" + f"UID={os.getenv('DB_USER')};" + f"PWD={os.getenv('DB_PASSWORD')};" + "Encrypt=yes;TrustServerCertificate=yes;" + ) + return ( "Driver={ODBC Driver 17 for SQL Server};" "Server=LaptopCA\\SQLEXPRESS;" "Database=DataSentinel;" "Trusted_Connection=yes;" ) + +class Config: + # Chaîne de connexion SQL Server (env en prod, Windows en local) + DB_CONNECTION_STRING = _build_connection_string() + # Paramètres API API_TITLE = "Data Sentinel API" API_VERSION = "1.0.0" API_DESCRIPTION = "API de monitoring de la qualité des données — XEFI" # Sécurité JWT - SECRET_KEY = "data-sentinel-secret-change-in-prod" - ALGORITHM = "HS256" - TOKEN_EXPIRE_MINUTES = 60 + SECRET_KEY = os.getenv("JWT_SECRET", "data-sentinel-secret-change-in-prod") + ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256") + TOKEN_EXPIRE_MINUTES = int(os.getenv("JWT_EXPIRE_MINUTES", "60")) # ---------------------------------------------------------------- diff --git a/main.py b/main.py index ffefada..404a35d 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,8 @@ # Swagger : http://localhost:8000/docs # ============================================================ +import os + from fastapi import FastAPI, HTTPException, Query from fastapi.middleware.cors import CORSMiddleware from typing import Optional @@ -14,6 +16,14 @@ from datetime import date from config import Config, get_cursor +# Origines autorisées : depuis CORS_ORIGINS (séparées par des virgules) en prod, +# localhost par défaut en dev. +CORS_ORIGINS = [ + o.strip() + for o in os.getenv("CORS_ORIGINS", "http://localhost:5173,http://localhost:3000").split(",") + if o.strip() +] + # ============================================================ # Initialisation # ============================================================ @@ -26,7 +36,7 @@ app = FastAPI( app.add_middleware( CORSMiddleware, - allow_origins = ["http://localhost:5173", "http://localhost:3000"], + allow_origins = CORS_ORIGINS, allow_methods = ["GET"], allow_headers = ["*"], )