diff --git a/wavefront/server/apps/inference_app/inference_app/inference_app_container.py b/wavefront/server/apps/inference_app/inference_app/inference_app_container.py index c7eb3055..8666dcbe 100644 --- a/wavefront/server/apps/inference_app/inference_app/inference_app_container.py +++ b/wavefront/server/apps/inference_app/inference_app/inference_app_container.py @@ -20,12 +20,12 @@ class InferenceAppContainer(containers.DeclarativeContainer): cloud_storage_manager=cloud_storage_manager, ) - model_inference = providers.Factory(ModelInferenceService) + model_inference = providers.Singleton(ModelInferenceService) - image_analyser = providers.Factory( + image_analyser = providers.Singleton( ImageClarityService, ) - image_embedding = providers.Factory( + image_embedding = providers.Singleton( ImageEmbedding, ) diff --git a/wavefront/server/docker/floware.Dockerfile b/wavefront/server/docker/floware.Dockerfile index 1aeacb5d..a47141e5 100644 --- a/wavefront/server/docker/floware.Dockerfile +++ b/wavefront/server/docker/floware.Dockerfile @@ -39,6 +39,12 @@ COPY wavefront/server/apps/floware /app/apps/floware RUN uv sync --package floware --frozen --no-dev +# Create a non-root user and change ownership of the /app directory +RUN useradd -m -u 1000 floware && \ + chown -R floware:floware /app + +USER floware + WORKDIR /app/apps/floware/floware CMD ["uv", "run", "server.py"] diff --git a/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py b/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py index ef8d8305..8d43711a 100644 --- a/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py +++ b/wavefront/server/modules/gold_module/gold_module/models/gold_image_request.py @@ -28,24 +28,24 @@ class ImageMetadata(BaseModel): item_id: str = None # Unique indentifier for gold image timestamp: datetime = None - loan_date: datetime = None + loan_date: datetime gold_loan_category: str = None loan_tenure: int = None loan_amount: float = None - gross_weight: float = None - stone_weight: float = None - net_weight: float = None + gross_weight: float + stone_weight: float + net_weight: float jewellery_items_count: int = None gold_purity: float = None items: List[Item] = None - metadata_1: str = None - metadata_2: str = None - metadata_3: str = None - metadata_4: str = None - metadata_5: str = None + metadata_1: dict = None + metadata_2: dict = None + metadata_3: dict = None + metadata_4: dict = None + metadata_5: dict = None filter_1: str = None filter_2: str = None @@ -85,6 +85,4 @@ def to_str_recursive(val): class ImageAnalysisRequest(BaseModel): image: str # data URL (base64 with MIME) or direct URL - metadata: ImageMetadata = ( - ImageMetadata() - ) # Ensure metadata is always an ImageMetadata instance + metadata: ImageMetadata diff --git a/wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py b/wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py index 969046bc..d37b30bd 100644 --- a/wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py +++ b/wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py @@ -264,14 +264,18 @@ async def validate_mtls_auth(request: Request) -> bool: if not xfcc: return False - # Extract SPIFFE ID from URI field - # Format: Hash=...;URI=spiffe://...;... + # Extract SPIFFE ID from URI field or use the whole header if it's a SPIFFE ID + principal = None match = re.search(r'URI=(spiffe://[^;,]+)', xfcc) if match: principal = match.group(1) + elif xfcc.startswith('spiffe://'): + principal = xfcc + + if principal: if not principal.startswith( 'spiffe://cluster.local/ns/client-applications' - ): + ) and not principal.startswith('spiffe://cluster.local/ns/gpu-processing'): logger.error(f'Invalid mTLS authentication. Principal: {principal}') return False @@ -290,7 +294,7 @@ async def validate_mtls_auth(request: Request) -> bool: request_id = getattr(request.state, 'request_id', get_current_request_id()) logger.warning( - f'mTLS header present but no valid URI found: {xfcc} [Request ID: {request_id}]' + f'mTLS header present but no valid principal found: {xfcc} [Request ID: {request_id}]' ) return False @@ -331,8 +335,9 @@ async def dispatch( if request.method == 'OPTIONS': return await call_next(request) + authorization = request.headers.get('Authorization') # Check if this endpoint requires HMAC validation (skip JWT validation then) - if request.url.path in required_hmac_apis: + if request.url.path in required_hmac_apis and not authorization: if not await validate_hmac_signature(request, auth_secrets_repository): request_id = getattr( request.state, 'request_id', get_current_request_id() @@ -363,9 +368,8 @@ async def dispatch( 'Invalid service authentication' ), ) - else: # Do the JWT validation or passthrough - authorization = request.headers.get('Authorization') - + else: + # Normal auth token flow token = None if authorization and authorization.startswith('Bearer '): token = authorization.split(' ')[1] @@ -418,9 +422,21 @@ async def dispatch( return await call_next(request) # Check for mTLS authentication if no token is present - if request.headers.get('X-Forwarded-Client-Cert'): + mtls_header = request.headers.get('X-Forwarded-Client-Cert') + if mtls_header and not token: + logger.info(f'mTLS authentication by {mtls_header}') if await validate_mtls_auth(request): return await call_next(request) + else: + logger.error( + f'Invalid mTLS authentication for {request.url.path}' + ) + return JSONResponse( + status_code=status.HTTP_403_FORBIDDEN, + content=response_formatter.buildErrorResponse( + error='Invalid mTLS authentication' + ), + ) if not token: request_id = getattr(