Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
6 changes: 6 additions & 0 deletions wavefront/server/docker/floware.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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}]'
)
Comment on lines 295 to 298
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security concern: Avoid logging raw certificate header.

Line 297 logs the full xfcc header content, which may contain sensitive certificate metadata (serial numbers, subject DNs, issuer info). Consider logging only that no valid principal was found, without exposing the raw header value.

🔒 Proposed fix to redact sensitive header data
         request_id = getattr(request.state, 'request_id', get_current_request_id())
         logger.warning(
-            f'mTLS header present but no valid principal found: {xfcc} [Request ID: {request_id}]'
+            f'mTLS header present but no valid SPIFFE principal found [Request ID: {request_id}]'
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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}]'
)
request_id = getattr(request.state, 'request_id', get_current_request_id())
logger.warning(
f'mTLS header present but no valid SPIFFE principal found [Request ID: {request_id}]'
)
🤖 Prompt for AI Agents
In
`@wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py`
around lines 295 - 298, The code logs the raw mTLS header variable xfcc in
logger.warning; remove or redact that sensitive value: locate the logger.warning
call near where request_id is computed (get_current_request_id()) and change the
message to omit xfcc (e.g., log "mTLS header present but no valid principal
found" with the request_id) or replace xfcc with a non-sensitive
token/hashing/redacted literal before logging; keep request_id in the log for
traceability and do not persist or print the raw certificate header anywhere.

return False

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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'
),
)
Comment on lines +425 to +439
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Security concern: Avoid logging sensitive certificate data.

Line 427 logs the entire X-Forwarded-Client-Cert header, which may contain sensitive certificate information such as serial numbers, subject distinguished names, and other metadata. This data should not be logged in full, as logs may be accessed by multiple systems and personnel.

The validate_mtls_auth function already logs authentication success/failure with the principal on lines 290-292 and 296-298, making this additional logging redundant.

🔒 Proposed fix to remove or redact sensitive header logging

Option 1 (Recommended): Remove the redundant log statement

Since validate_mtls_auth already provides detailed logging, simply remove this line:

                 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):

Option 2: Log only that mTLS is being attempted

If you need logging at the dispatch level, log without exposing the header value:

                 mtls_header = request.headers.get('X-Forwarded-Client-Cert')
                 if mtls_header and not token:
-                    logger.info(f'mTLS authentication by {mtls_header}')
+                    logger.info('Attempting mTLS authentication')
                     if await validate_mtls_auth(request):
🤖 Prompt for AI Agents
In
@wavefront/server/modules/user_management_module/user_management_module/authorization/require_auth.py
around lines 425 - 439, The code logs the full X-Forwarded-Client-Cert header
(mtls_header) in the middleware; remove or redact that sensitive logging. Locate
the block handling mtls_header in require_auth.py (look for the mtls_header =
request.headers.get('X-Forwarded-Client-Cert') line and the subsequent
logger.info call) and either delete the logger.info(f'mTLS authentication by
{mtls_header}') statement or replace it with a non-sensitive message like
logger.info('mTLS authentication attempt') while keeping the existing call to
validate_mtls_auth and the existing success/failure logging inside
validate_mtls_auth.


if not token:
request_id = getattr(
Expand Down
Loading