
    i                       d Z ddlmZ ddlmZ ddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZmZ ddlmZ dd	lmZmZ  ee                                          j        d
         Z eedz             ddlmZ ddlmZ ddlmZ ddl mZ! ddl"mZ# ddl$m%Z% ddl&m'Z' ddl(m)Z) ddl*m+Z+  e'              ej,        e-          Z.h dZ/dZ0e0fd8dZ1d9dZ2d:dZ3 ed d!d"#          Z4dd$l5m6Z6 d% Z7e7e4_8        dd&l9m:Z: e4;                    ee:j<        d'd(gd(g)           e4=                    e!           e4=                    e           e4=                    e           e4=                    e           e4=                    e#           e4>                    d*          d;d-            Z?e4@                    d.          d<d0            ZAe4B                    e%          d=d5            ZCe4B                    eD          d>d7            ZEdS )?u  
Nom du script : main.py
Chemin : /gitlab-bridge/app/main.py
Description : Point d'entrée FastAPI du bridge GitLab entre OpenWebUI et GitLab.
Options éventuelles : Démarrage via uvicorn.
Exemples d'utilisation : `uvicorn app.main:app --reload --host 0.0.0.0 --port 8080`.
Prérequis : Python 3.11+, FastAPI, GitLab accessible, base MariaDB disponible.
Auteur : Sylvain SCATTOLINI
Date de création / modification : 2026-03-25
Version : 1.1
    )annotations)PathN)Any)load_dotenv)FastAPIRequest)CORSMiddleware)JSONResponseResponse   z.env)router)BridgeError)configure_logging)Base)engine>   tokensecretpassword	api_tokenaccess_tokenauthorizationprivate_tokenrefresh_tokeni  valuestrlimitintreturnc                n    t          |           |k    r| S | d |         dt          |           |z
   dz   S )Nz... [truncated z chars])len)r   r   s     '/var/www/html/gitlab-bridge/app/main.py_truncate_log_valuer"   9   sB    
5zzU%=HSZZ%-?HHHHH    r   c                   t          | t                    ri }|                                 D ]q\  }}t          |                                                                          t          v rd|t          |          <   Rt          |          |t          |          <   r|S t          | t                    rd | D             S t          | t                    rd | D             S t          | t                    rt          |           S | S )Nz***REDACTED***c                ,    g | ]}t          |          S  _sanitize_for_log.0items     r!   
<listcomp>z%_sanitize_for_log.<locals>.<listcomp>K   !    :::D!$'':::r#   c                ,    g | ]}t          |          S r&   r'   r)   s     r!   r,   z%_sanitize_for_log.<locals>.<listcomp>N   r-   r#   )
isinstancedictitemsr   striplowerSENSITIVE_LOG_KEYSr(   listtupler"   )r   	sanitizedkeyr+   s       r!   r(   r(   @   s   % $&	 	> 	>IC3xx~~%%''+===&6	#c((##&7&=&=	#c((##% ;::E::::% ;::E::::% *"5)))Lr#   bodybytes | Nonecontent_type
str | Nonec                V   | sd S |pd                                 }d|v rE	 t          t          j        |                     d                              S # t
          $ r Y nw xY wd|v sd|v sd|v sd|v r$t          |                     dd	                    S d
t          |            dS )N zapplication/jsonzutf-8ztext/jsonxmlzx-www-form-urlencodedreplace)errors<z bytes binary>)r3   r(   r?   loadsdecode	Exceptionr"   r    )r9   r;   raw_content_types      r!   _decode_body_for_logrH   W   s     t$*1133---	$TZG0D0D%E%EFFF 	 	 	D	 	###%%%$$$"&666"4;;wy;#I#IJJJ(s4yy((((s   3A 
A! A!zGitLab Bridgez1.13.0.3)titleversionopenapi_version)get_openapic                     t           j        rt           j        S t          t           j        t           j        dt           j        t           j                  } | t           _        t           j        S )NrI   )rJ   rK   rL   descriptionroutes)appopenapi_schemarM   rJ   rK   rO   rP   )rR   s    r!   custom_openapirS   v   sT    
 "!! iOz  N (Cr#   )settingsT*)allow_originsallow_credentialsallow_methodsallow_headershttprequestr   c                T  K   t          j                    j        d d         }t          j                    }|                                  d {V }d|| j        | j        j        t          | j        j
        pd          | j        r| j        j        nd | j                            d          | j                            d          t          || j                            d                    d	}t                               d|           	  ||            d {V }nY# t$          $ rL t'          t          j                    |z
  d	z  d
          }t                               di |d|d            w xY wd}t+          |d          r|j        |j        }nxt+          |d          rh|j        ad |j        2              d {V }	d                    |	          }t1          ||j        t5          |j                  |j        |j                  }||j        d<   t'          t          j                    |z
  d	z  d
          }t                               di |d|j        ||j                            d          t          ||j                            d                    d           |S )N   http_requestr>   z
user-agentzcontent-type)	event
request_idmethodpathquery	client_ip
user_agentrequest_content_typerequest_bodyzHTTP request received)extrai     zHTTP request failed
http_error)r_   duration_msr#   r9   body_iteratorc                "   K   g | 3 d {V }|
6 S )Nr&   )r*   chunks     r!   r,   z%log_http_requests.<locals>.<listcomp>   s.      BBBBBBBB%%BBBBs   )contentstatus_codeheaders
media_type
backgroundzX-Request-IDzHTTP response senthttp_response)r_   rp   rk   response_content_typeresponse_body)uuiduuid4hextimeperf_counterr9   ra   urlrb   r   rc   clienthostrq   getrH   loggerinforF   round	exceptionhasattrrl   joinr   rp   r0   rr   rs   )
r[   	call_nextr`   
started_atrg   request_extraresponserk   response_body_byteschunkss
             r!   log_http_requestsr      s	     !#2#&J"$$J ''''''L   . W[&,"--,3NDW^((o)),77 ' 3 3N C C,\7?;N;N~;^;^__
 
M KK'}K==="7++++++++ 
 
 
T.00:=EqII!%*   	 	
 	
 	
 	
 x   
X]%>&m	?	+	+ 	
0F0RBB8+ABBBBBBBBB!hhv..' ,)****
 
 
 (2H^$*,,z9TA1EEK
KK



$#/&%-%5%9%9.%I%I1# $$^44 

 

 

     Os   
D AE2startupNonec                     t           j                            t                     t                              d           dS )z)Initialisation minimale de l'application.)bindu   GitLab Bridge démarré.N)r   metadata
create_allr   r   r   r&   r#   r!   r   r      s6     	M&)))
KK*+++++r#   _excr   r
   c                V    t          |j        dvrdndd|j        |j        d          S )u<   Transforme les erreurs métier en réponses JSON homogènes.>   access_deniedi  i  Fsuccesserrormessagerp   ro   )r
   coder   r   r   s     r!   handle_bridge_errorr      sF     8+<<<CC#X{
 
   r#   rF   c                d    t                               d|           t          ddddd          S )	uM   Gère les erreurs inattendues sans divulguer de détails sensibles au client.zErreur inattendue.)exc_infoi  Finternal_errorz Une erreur interne est survenue.r   r   )r   r   r
   r   s     r!   handle_unexpected_errorr      sK     )C888%9
 
   r#   )r   r   r   r   r   r   )r   r   r   r   )r9   r:   r;   r<   r   r   )r[   r   )r   r   )r   r   r   r   r   r
   )r   r   r   rF   r   r
   )F__doc__
__future__r   pathlibr   r?   loggingrz   rw   typingr   dotenvr   fastapir   r   fastapi.middleware.corsr	   fastapi.responsesr
   r   __file__resolveparentsBASE_DIRapp.api.v1.healthr   health_routerapp.api.v1.issuesissues_routerapp.api.v1.projectsprojects_routerapp.api.v1.groupsgroups_routerapp.api.v1.milestonesmilestones_routerapp.core.exceptionsr   app.core.loggingr   app.db.baser   app.db.sessionr   	getLogger__name__r   r4   MAX_LOG_BODY_LENGTHr"   r(   rH   rQ   fastapi.openapi.utilsrM   rS   openapiapp.core.configrT   add_middlewarecors_originsinclude_router
middlewarer   on_eventr   exception_handlerr   rF   r   r&   r#   r!   <module>r      s  
 
 # " " " " "                       $ $ $ $ $ $ $ $ 2 2 2 2 2 2 4 4 4 4 4 4 4 44>>!!##+A. Hv    5 5 5 5 5 5 5 5 5 5 5 5 9 9 9 9 9 9 5 5 5 5 5 5 = = = = = = + + + + + + . . . . . .       ! ! ! ! ! !     		8	$	$	 	 	    2E I I I I I   .) ) ) ). g
   . - - - - -    $ $ $ $ $ $   '%%       = ! ! !   = ! ! !   ? # # #   = ! ! !   $ % % % A A A AH i, , , , {##	 	 	 $#	 y!!
 
 
 "!
 
 
r#   