99from time import monotonic
1010
1111from celery import Celery , Task , current_task
12- from flask import current_app , g , has_request_context , jsonify , make_response , request
12+ from flask import (
13+ current_app ,
14+ g ,
15+ has_request_context ,
16+ jsonify ,
17+ make_response ,
18+ request ,
19+ )
1320from flask .ctx import has_app_context
1421from flask_migrate import Migrate
1522from flask_socketio import SocketIO
@@ -294,15 +301,44 @@ def record_request_details():
294301 g .start = monotonic ()
295302 g .endpoint = request .endpoint
296303
304+ @app .before_request
305+ def handle_options ():
306+ if request .method == "OPTIONS" :
307+ response = make_response ("" , 204 )
308+ response .headers ["Access-Control-Allow-Origin" ] = "*"
309+ response .headers ["Access-Control-Allow-Methods" ] = (
310+ "GET, POST, PUT, DELETE, OPTIONS"
311+ )
312+ response .headers ["Access-Control-Allow-Headers" ] = (
313+ "Content-Type, Authorization"
314+ )
315+ response .headers ["Access-Control-Max-Age" ] = "3600"
316+ return response
317+
297318 @app .after_request
298319 def after_request (response ):
320+ # Security headers for government compliance
299321 response .headers .add ("X-Content-Type-Options" , "nosniff" )
322+ response .headers .add ("X-Frame-Options" , "DENY" )
323+ response .headers .add ("X-XSS-Protection" , "1; mode=block" )
324+ response .headers .add ("Referrer-Policy" , "strict-origin-when-cross-origin" )
325+ response .headers .add (
326+ "Permissions-Policy" , "geolocation=(), microphone=(), camera=()"
327+ )
300328
301- # Some dynamic scan findings
329+ # CORS-related security headers
302330 response .headers .add ("Cross-Origin-Opener-Policy" , "same-origin" )
303331 response .headers .add ("Cross-Origin-Embedder-Policy" , "require-corp" )
304332 response .headers .add ("Cross-Origin-Resource-Policy" , "same-origin" )
305- response .headers .add ("Cross-Origin-Opener-Policy" , "same-origin" )
333+
334+ if not request .path .startswith ("/docs" ):
335+ response .headers .add (
336+ "Content-Security-Policy" , "default-src 'none'; frame-ancestors 'none';"
337+ )
338+
339+ response .headers .add (
340+ "Strict-Transport-Security" , "max-age=31536000; includeSubDomains"
341+ )
306342
307343 return response
308344
@@ -352,15 +388,18 @@ def setup_sqlalchemy_events(app):
352388 with app .app_context ():
353389
354390 @event .listens_for (db .engine , "connect" )
355- def connect (dbapi_connection , connection_record ): # noqa
391+ def connect (dbapi_connection , connection_record ):
392+ current_app .logger .debug (f"Using { dbapi_connection } { connection_record } " )
356393 pass
357394
358395 @event .listens_for (db .engine , "close" )
359- def close (dbapi_connection , connection_record ): # noqa
396+ def close (dbapi_connection , connection_record ):
360397 pass
361398
362399 @event .listens_for (db .engine , "checkout" )
363- def checkout (dbapi_connection , connection_record , connection_proxy ): # noqa
400+ def checkout (dbapi_connection , connection_record , connection_proxy ):
401+ current_app .logger .debug (f"Using { dbapi_connection } { connection_proxy } " )
402+
364403 try :
365404 # this will overwrite any previous checkout_at timestamp
366405 connection_record .info ["checkout_at" ] = time .monotonic ()
@@ -401,7 +440,7 @@ def checkout(dbapi_connection, connection_record, connection_proxy): # noqa
401440 )
402441
403442 @event .listens_for (db .engine , "checkin" )
404- def checkin (dbapi_connection , connection_record ): # noqa
443+ def checkin (dbapi_connection , connection_record ):
405444 pass
406445
407446
@@ -428,7 +467,7 @@ def app_context(self):
428467 g .request_id = self .request_id
429468 yield
430469
431- def on_success (self , retval , task_id , args , kwargs ): # noqa
470+ def on_success (self , retval , task_id , args , kwargs ):
432471 # enables request id tracing for these logs
433472 with self .app_context ():
434473 elapsed_time = time .monotonic () - self .start
@@ -441,9 +480,11 @@ def on_success(self, retval, task_id, args, kwargs): # noqa
441480 )
442481 )
443482
444- def on_failure (self , exc , task_id , args , kwargs , einfo ): # noqa
483+ def on_failure (self , exc , task_id , args , kwargs , einfo ):
484+
445485 # enables request id tracing for these logs
446486 with self .app_context ():
487+ app .logger .debug (f"einfo is { einfo } " )
447488 app .logger .exception (
448489 "Celery task {task_name} (queue: {queue_name}) failed" .format (
449490 task_name = self .name ,
0 commit comments