Skip to content

Conversation

ann-aot
Copy link

@ann-aot ann-aot commented Jul 11, 2025

User description

Issue Tracking

JIRA:
Issue Type: FEATURE

Changes

  • Implemented custom registration and social logins for the try it now features
  • Created custom theme for multi-tenant registration/logins
  • Normal registration and logins for all other tenants
  • Created a new public API to trigger the Camunda workflow

Screenshots (if applicable)

try it now client/tenant
image
image
image
image
image
image
Other clents/tenants
image
image

Notes

Documents: https://docs.google.com/document/d/1XU7QpgK5BpxOMpBpr02GEYu5WlI-Gmxq9JmZ6fSdlBA/edit?tab=t.0

Todo

  • Check with the team if the new API needs/remove any decorators or permissions/roles.

PR Type

Enhancement


Description

  • Enhance BPM auth headers for multitenant clients

  • Add public /start endpoint for BPM workflows

  • Introduce Keycloak SPI: capture info and event listener

  • Add custom multitenant Keycloak theme and CSS

  • Update Docker and compose for providers and env


Changes diagram

flowchart LR
  U["User Registration"] --> KEL["KeycloakEventListenerProvider"]
  KEL -- "async POST /start" --> API["Public /<definition_key>/start endpoint"]
  API --> BPM["BPMService.post_process_start_tenant"]
  BPM --> Camunda["Camunda API"]
Loading

Changes walkthrough 📝

Relevant files
Enhancement
10 files
base_bpm.py
Support multitenant client secrets and error handling       
+23/-11 
public_endpoints.py
Add public process start endpoint                                               
+30/-0   
CaptureTenantInfoRequiredAction.java
Add required action to capture tenant info                             
+165/-0 
KeycloakEventListenerProvider.java
Add event listener to trigger Camunda workflow                     
+82/-0   
KeycloakEventListenerProviderFactory.java
Create event listener provider factory                                     
+32/-0   
template.ftl
Add multitenant registration template macro                           
+190/-0 
login.ftl
Create custom login form template                                               
+142/-0 
register.ftl
Create custom registration form template                                 
+153/-0 
capture-tenant-info.ftl
Add capture-tenant-info form template                                       
+29/-0   
registration-success.ftl
Add registration success template                                               
+7/-0     
Configuration changes
6 files
config.py
Add multitenant BPM env variables                                               
+2/-0     
start-keycloak.sh
Enhance startup script for SPI and cache args                       
+16/-5   
Dockerfile
Build and package SPI providers in image                                 
+19/-1   
docker-compose.yml
Expose envs for process workflow variables                             
+4/-0     
docker-compose.yml
Add multitenant BPM client env variables                                 
+3/-1     
theme.properties
Configure multitenant login theme properties                         
+135/-0 
Formatting
1 files
login.css
Custom CSS for multitenant login theme                                     
+642/-0 
Dependencies
2 files
pom.xml
Add event listener module POM                                                       
+82/-0   
pom.xml
Add capture-tenant SPI POM                                                             
+66/-0   
Documentation
1 files
messages_en.properties
Add tenant-specific messages and labels                                   
+441/-0 
Additional files
8 files
sample.env +7/-1     
org.keycloak.authentication.RequiredActionFactory +1/-0     
org.keycloak.events.EventListenerProviderFactory +1/-0     
sample.env +4/-0     
login-reset-password.ftl +40/-0   
login-update-password.ftl +71/-0   
fontawesome.min.css +5/-0     
tile.css +207/-0 

Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @ann-aot ann-aot requested review from a team as code owners July 11, 2025 18:43
    Copy link

    github-actions bot commented Jul 11, 2025

    PR Reviewer Guide 🔍

    (Review updated until commit 8129b1d)

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Undefined Variables

    In the new _get_headers_ implementation, the variables headers and payload are used in the token fetch requests.post call but never defined or constructed in that scope. This will result in a NameError at runtime.

    try:
        response = requests.post(
            bpm_token_api, headers=headers, data=payload, timeout=HTTP_TIMEOUT
        )
        data = json.loads(response.text)
        return {
            "Authorization": "Bearer " + data["access_token"],
            "Content-Type": "application/json",
        }
    Missing Authorization

    The new /start public endpoint does not enforce any authentication or permission checks. Verify if this route should be protected or rate-limited to prevent unauthorized or abusive use.

    @cors_preflight("POST,OPTIONS")
    @API.route("/<string:definition_key>/start", methods=["POST", "OPTIONS"])
    class ProcessByDefinitionKeyResource(Resource):
        """Resource for process resource by definition key."""
    
        @staticmethod
        @profiletime
        @API.response(201, "Created:- Request has been fulfilled and resulted in new resource being created.")
        @API.response(400, "BAD_REQUEST:- Invalid request.")
        @API.response(401, "UNAUTHORIZED:- Authorization header not provided or invalid token.")
        @API.response(403, "FORBIDDEN:- Authorization will not help.")
        # @API.expect(post_request_model)
        def post(definition_key: str):
            """Creates a new process instance using the specified definition key."""
            payload = request.get_json()
            tenant_key = request.args.get("tenantKey", default=None)
            camunda_start_task = BPMService.post_process_start_tenant(
                        process_key=definition_key,
                        payload=payload,
                        token=None,
                        tenant_key=tenant_key
                    )
            return camunda_start_task

    Copy link

    github-actions bot commented Jul 11, 2025

    PR Code Suggestions ✨

    Latest suggestions up to 8129b1d

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Ensure headers and payload are defined

    Ensure payload and headers are always defined before use, not only inside the
    multi-tenancy branch. Move their initialization above the try block so that the
    non-tenant code path does not reference undefined variables.

    forms-flow-api/src/formsflow_api/services/external/base_bpm.py [95-103]

    +# Define payload and headers for token request
    +payload = {
    +    "grant_type": bpm_grant_type,
    +    "client_id": bpm_client_id,
    +    "client_secret": bpm_client_secret,
    +}
    +headers = {"content-type": "application/x-www-form-urlencoded"}
     try:
         response = requests.post(
             bpm_token_api, headers=headers, data=payload, timeout=HTTP_TIMEOUT
         )
         data = json.loads(response.text)
         return {
             "Authorization": "Bearer " + data["access_token"],
             "Content-Type": "application/json",
         }
    Suggestion importance[1-10]: 8

    __

    Why: Defining payload and headers outside the try block prevents undefined variable errors and ensures all code paths can obtain a token.

    Medium
    Fix meta syntax

    Remove the extra '=' in the meta value so the viewport directive parses correctly.
    It should read viewport=width… rather than viewport==width….

    forms-flow-idm/keycloak/themes/multitenant/login/theme.properties [7]

    -meta=viewport==width=device-width,initial-scale=1
    +meta=viewport=width=device-width,initial-scale=1
    Suggestion importance[1-10]: 8

    __

    Why: Removing the extra = corrects the viewport directive syntax, which is critical for proper responsive rendering.

    Medium
    Avoid duplicate key

    Rename or remove the duplicate tenantName property to avoid overriding the earlier
    definition. Use a unique key (e.g., captureTenantName) for the tenant capture field.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [436]

    -tenantName=Tenant Name
    +captureTenantName=Tenant Name
    Suggestion importance[1-10]: 7

    __

    Why: Renaming the duplicate tenantName property prevents one from overriding the other and ensures unique keys for tenant capture fields.

    Medium
    Use unique action key

    Rename the generic submit key to avoid collision with the existing doSubmit entry.
    Use a more descriptive key such as captureSubmit.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [437]

    -submit=Submit
    +captureSubmit=Submit
    Suggestion importance[1-10]: 6

    __

    Why: Renaming submit avoids collision with doSubmit and clarifies purpose, improving maintainability with minimal impact.

    Low
    General
    Return explicit HTTP 201 response

    Return a Flask response with an explicit status code (e.g., 201) and JSON content
    instead of relying on the raw return value. Use jsonify() or make_response() to set
    the HTTP status.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [306-314]

     def post(definition_key: str):
    -    """Creates a new process instance using the specified definition key."""
    -    payload = request.get_json()
    -    tenant_key = request.args.get("tenantKey", default=None)
    -    camunda_start_task = BPMService.post_process_start_tenant(
    -                process_key=definition_key,
    -                payload=payload,
    -                token=None,
    -                tenant_key=tenant_key
    -            )
    -    return camunda_start_task
    +    ...
    +    camunda_start_task = BPMService.post_process_start_tenant(...)
    +    return jsonify(camunda_start_task), HTTPStatus.CREATED
    Suggestion importance[1-10]: 6

    __

    Why: Returning jsonify(camunda_start_task) with HTTPStatus.CREATED aligns the response with the documented 201 status and improves HTTP semantics.

    Low
    Validate JSON payload presence

    Validate that the JSON payload exists and return a 400 error if it is missing or
    malformed before invoking the BPM service.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [306]

    -payload = request.get_json()
    +payload = request.get_json(silent=True)
    +if payload is None:
    +    return {"message": "Invalid JSON payload"}, HTTPStatus.BAD_REQUEST
    Suggestion importance[1-10]: 5

    __

    Why: Early validation of payload guards against malformed or missing JSON, providing clearer client errors and preventing downstream exceptions.

    Low
    Add EOF newline

    Ensure the file ends with a single newline to comply with POSIX conventions and
    avoid potential parsing issues.

    forms-flow-idm/keycloak/themes/multitenant/login/theme.properties [135]

    +loginForm=capture-tenant-info.ftl
     
    -
    Suggestion importance[1-10]: 1

    __

    Why: Ensuring a trailing newline is a minor formatting issue with negligible impact on functionality.

    Low

    Previous suggestions

    Suggestions up to commit 5f00152
    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Add error handling and status code

    Wrap the call to BPMService.post_process_start_tenant in a try/except block and
    return a tuple of the JSON body with an explicit HTTP status code. This ensures
    errors are caught and that clients always receive a valid (201 or 500) response.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [314]

    -return camunda_start_task
    +try:
    +    result = BPMService.post_process_start_tenant(
    +        process_key=definition_key, payload=payload, token=None, tenant_key=tenant_key
    +    )
    +    return result, 201
    +except Exception as e:
    +    current_app.logger.error(f"Failed to start process: {e}")
    +    return {"error": "Failed to start process"}, 500
    Suggestion importance[1-10]: 6

    __

    Why: Wrapping BPMService.post_process_start_tenant in try/except improves robustness by returning explicit status codes, though implementation details (e.g., imports) may need adjustment.

    Low
    Remove duplicate locale key

    Remove the duplicate locale entry to prevent one from silently overriding the other
    at load time. Keep only a single consistent key format (e.g. locale_pt_BR).

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [332-333]

     locale_pt_BR=Portugu\u00EAs (Brasil)
    -locale_pt-BR=Portugu\u00EAs (Brasil)
    Suggestion importance[1-10]: 5

    __

    Why: Removing one of the duplicate locale entries (locale_pt-BR) prevents inconsistent overrides and keeps the file clean.

    Low
    General
    Ensure default credential fallback

    When multi-tenancy is enabled and no tenant‐key is provided, fall back to the
    default client credentials rather than allowing a None value. This prevents passing
    None to the token endpoint.

    forms-flow-api/src/formsflow_api/services/external/base_bpm.py [71-80]

     bpm_client_id = (
    -    current_app.config.get("MULTITENANT_BPM_CLIENT_ID")
    +    current_app.config.get("MULTITENANT_BPM_CLIENT_ID", current_app.config.get("BPM_CLIENT_ID"))
         if is_multitenant_client_secret
         else current_app.config.get("BPM_CLIENT_ID")
     )
     bpm_client_secret = (
    -    current_app.config.get("MULTITENANT_BPM_CLIENT_SECRET")
    +    current_app.config.get("MULTITENANT_BPM_CLIENT_SECRET", current_app.config.get("BPM_CLIENT_SECRET"))
         if is_multitenant_client_secret
         else current_app.config.get("BPM_CLIENT_SECRET")
     )
    Suggestion importance[1-10]: 5

    __

    Why: Providing a default in config.get avoids passing None to the token endpoint, a useful but minor enhancement in credential handling.

    Low
    Normalize Camunda endpoint URL

    Normalize URL concatenation to guarantee a single slash between
    PUBLIC_PROCESS_START_URL and PROCESS_KEY. This avoids malformed endpoints when the
    base URL does or does not end with a slash.

    forms-flow-idm/keycloak/keycloak-event-listener/src/main/java/com/formsflow/keycloak/listener/KeycloakEventListenerProvider.java [46]

    -String startUrl = camundaUrl + processKey + "/start?tenantKey=" + tenantKey;
    +String base = camundaUrl.endsWith("/") ? camundaUrl.substring(0, camundaUrl.length()-1) : camundaUrl;
    +String startUrl = String.format("%s/%s/start?tenantKey=%s", base, processKey, tenantKey);
    Suggestion importance[1-10]: 5

    __

    Why: Ensuring a single slash in startUrl prevents malformed URLs, but it’s a small improvement rather than a critical fix.

    Low
    Ensure newline at EOF

    Add a newline at the end of the file to ensure POSIX compliance and avoid potential
    parsing issues when loading this properties file.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [441]

    +registrationCustomSuccessMsg=Registration is successful. You will shortly receive an email with login URL and details.
     
    -
    Suggestion importance[1-10]: 2

    __

    Why: Adding a POSIX-compliant newline at EOF is good practice but carries very low impact, and the snippet is unchanged.

    Low
    Suggestions up to commit 146528d
    CategorySuggestion                                                                                                                                    Impact
    General
    Rename duplicate tenantName key

    There are two identical tenantName keys which will cause one to override the other.
    Rename the custom usage or remove the duplicate to prevent unexpected overrides.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [2-436]

     tenantName=Tenant Name
     ...
    -tenantName=Tenant Name
    +customTenantName=Tenant Name
    Suggestion importance[1-10]: 8

    __

    Why: The duplicate tenantName keys at lines 2 and 436 will override one another in the properties lookup, risking unexpected behavior.

    Medium
    Handle BPMService errors gracefully

    Wrap the external BPMService call in a try/except to catch network or service errors
    and return an appropriate HTTP error response instead of propagating raw exceptions.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [305-311]

    -camunda_start_task = BPMService.post_process_start_tenant(
    -            process_key=definition_key,
    -            payload=payload,
    -            token=None,
    -            tenant_key=tenant_key
    -        )
    -return camunda_start_task
    +try:
    +    camunda_start_task = BPMService.post_process_start_tenant(
    +        process_key=definition_key,
    +        payload=payload,
    +        token=None,
    +        tenant_key=tenant_key
    +    )
    +    return camunda_start_task
    +except Exception as e:
    +    current_app.logger.error(f"Failed to start process: {e}")
    +    return {"error": "Process start failed"}, HTTPStatus.BAD_GATEWAY
    Suggestion importance[1-10]: 6

    __

    Why: Wrapping the BPMService.post_process_start_tenant call in a try/except improves resilience by returning a controlled HTTP error instead of propagating raw exceptions.

    Low
    Validate HTTP response status

    Check for non-2xx responses and log an error or take recovery actions instead of
    treating all statuses as informational.

    forms-flow-idm/keycloak/keycloak-event-listener/src/main/java/com/formsflow/keycloak/listener/KeycloakEventListenerProvider.java [61-62]

     HttpResponse<String> startResponse = httpClient.send(startRequest, HttpResponse.BodyHandlers.ofString());
    -logger.info("Camunda response status: {}", startResponse.statusCode());
    +if (startResponse.statusCode() >= 400) {
    +    logger.error("Camunda start failed with status {} and body: {}", startResponse.statusCode(), startResponse.body());
    +} else {
    +    logger.info("Camunda response status: {}", startResponse.statusCode());
    +}
    Suggestion importance[1-10]: 5

    __

    Why: Adding a check on startResponse.statusCode() ensures non-2xx responses are logged as errors, improving observability and error handling.

    Low
    Add newline at end of file

    Ensure the properties file ends with a newline to comply with POSIX text file
    conventions and avoid parsing issues.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [441]

    -registrationCustomSuccessMsg=Registration is successful. You will shortly receive an email with login URL and details.\ No newline at end of file
    +registrationCustomSuccessMsg=Registration is successful. You will shortly receive an email with login URL and details.
    Suggestion importance[1-10]: 3

    __

    Why: Ending the file with a newline complies with POSIX conventions and avoids potential parsing issues, but has minimal functional impact.

    Low
    Possible issue
    Fix meta viewport syntax

    The meta entry has a double equals (==) which is invalid syntax. Remove the extra =
    so the viewport is parsed correctly.

    forms-flow-idm/keycloak/themes/multitenant/login/theme.properties [7]

    -meta=viewport==width=device-width,initial-scale=1
    +meta=viewport=width=device-width,initial-scale=1
    Suggestion importance[1-10]: 6

    __

    Why: The extra = in meta=viewport==... is invalid and will prevent the viewport setting from being parsed correctly.

    Low
    Suggestions up to commit 05f008e
    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Define payload and headers before token fetch

    Build and send the token‐request payload correctly by defining payload and headers
    before calling requests.post. This ensures the token endpoint receives the expected
    form data and content type.

    forms-flow-api/src/formsflow_api/services/external/base_bpm.py [95-103]

    +payload = {
    +    "grant_type": bpm_grant_type,
    +    "client_id": bpm_client_id,
    +    "client_secret": bpm_client_secret,
    +}
    +headers = {"Content-Type": "application/x-www-form-urlencoded"}
     try:
         response = requests.post(
             bpm_token_api, headers=headers, data=payload, timeout=HTTP_TIMEOUT
         )
    -    data = json.loads(response.text)
    +    response.raise_for_status()
    +    data = response.json()
         return {
             "Authorization": "Bearer " + data["access_token"],
             "Content-Type": "application/json",
         }
     except Exception as e:
    -    current_app.logger.error(f"Token fetch failed: {str(e)}")
    +    current_app.logger.error(f"Token fetch failed: {e}")
         raise
    Suggestion importance[1-10]: 9

    __

    Why: The call to requests.post uses undefined payload and headers, causing a runtime error; defining them upfront fixes a critical bug in token retrieval.

    High
    Validate auth and handle errors

    Require and validate an Authorization header and wrap the BPM call in try/except so
    errors map to proper HTTP status codes. Pass the extracted token to
    post_process_start_tenant.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [289-311]

     @cors_preflight("POST,OPTIONS")
     @API.route("/<string:definition_key>/start", methods=["POST", "OPTIONS"])
     class ProcessByDefinitionKeyResource(Resource):
         @staticmethod
    +    @API.response(201, "Created")
    +    @API.response(401, "Missing or invalid token")
    +    @API.response(502, "Upstream BPM error")
         def post(definition_key: str):
    +        token = request.headers.get("Authorization")
    +        if not token:
    +            API.abort(401, "Authorization header is required")
             payload = request.get_json()
    -        tenant_key = request.args.get("tenantKey", default=None)
    -        camunda_start_task = BPMService.post_process_start_tenant(
    -                    process_key=definition_key,
    -                    payload=payload,
    -                    token=None,
    -                    tenant_key=tenant_key
    -                )
    -        return camunda_start_task
    +        tenant_key = request.args.get("tenantKey")
    +        try:
    +            result = BPMService.post_process_start_tenant(
    +                process_key=definition_key,
    +                payload=payload,
    +                token=token,
    +                tenant_key=tenant_key
    +            )
    +            return result, 201
    +        except Exception as e:
    +            API.abort(502, f"BPM start failed: {e}")
    Suggestion importance[1-10]: 7

    __

    Why: Adding Authorization header validation and exception mapping improves security and error transparency without altering core functionality.

    Medium
    Encode URL query parameters

    URL‐encode processKey and tenantKey when building startUrl to prevent malformed
    requests or injection issues.

    forms-flow-idm/keycloak/keycloak-event-listener/src/main/java/com/formsflow/keycloak/listener/KeycloakEventListenerProvider.java [44]

    -String startUrl = camundaUrl + processKey + "/start?tenantKey=" + tenantKey;
    +String encodedKey = URLEncoder.encode(processKey, StandardCharsets.UTF_8);
    +String encodedTenant = URLEncoder.encode(tenantKey, StandardCharsets.UTF_8);
    +String startUrl = String.format("%s%s/start?tenantKey=%s", camundaUrl, encodedKey, encodedTenant);
    Suggestion importance[1-10]: 7

    __

    Why: URL-encoding processKey and tenantKey prevents malformed URLs or injection issues when building the request endpoint.

    Medium
    Remove duplicate key

    There is a duplicate tenantName entry in the file which will override the first one.
    Remove the second occurrence to avoid unexpected key collisions.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [436]

    -tenantName=Tenant Name
     
    +
    Suggestion importance[1-10]: 6

    __

    Why: The duplicate tenantName at line 436 overrides the earlier one at line 2 causing unexpected collisions; removing it prevents key duplication.

    Low
    General
    Consolidate duplicate locale

    These two keys represent the same locale and will conflict. Retain only one
    standardized key (preferably locale_pt-BR) to prevent overrides.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [332-333]

    -locale_pt_BR=Portugu\u00EAs (Brasil)
     locale_pt-BR=Portugu\u00EAs (Brasil)
    Suggestion importance[1-10]: 6

    __

    Why: Having both locale_pt_BR and locale_pt-BR causes one to override the other; consolidating to a single key avoids conflicts.

    Low
    Add script shebang line

    Add a shebang at the top so the script runs with the intended shell interpreter when
    executed.

    forms-flow-idm/keycloak/start-keycloak.sh [2-5]

    +#!/usr/bin/env bash
     # Ensure the directories exist
     mkdir -p /opt/keycloak/themes
     mkdir -p /opt/keycloak/data/import
     mkdir -p /opt/keycloak/providers
     ...
     exec $COMMAND
    Suggestion importance[1-10]: 1

    __

    Why: A shebang is a minor enhancement for script portability but does not impact the PR’s primary functionality.

    Low
    Suggestions up to commit 04a04d8
    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Define request headers and payload

    The variables headers and payload are not defined before use, causing a NameError.
    You should build the token request payload and headers from bpm_client_id,
    bpm_client_secret, and bpm_grant_type before calling requests.post. This ensures the
    request is formed correctly and avoids runtime errors.

    forms-flow-api/src/formsflow_api/services/external/base_bpm.py [95-107]

    +payload = {
    +    "grant_type": bpm_grant_type,
    +    "client_id": bpm_client_id,
    +    "client_secret": bpm_client_secret,
    +}
    +headers = {"Content-Type": "application/x-www-form-urlencoded"}
     try:
         response = requests.post(
             bpm_token_api, headers=headers, data=payload, timeout=HTTP_TIMEOUT
         )
    -    data = json.loads(response.text)
    +    response.raise_for_status()
    +    data = response.json()
         return {
             "Authorization": "Bearer " + data["access_token"],
             "Content-Type": "application/json",
         }
     except Exception as e:
         current_app.logger.error(f"Token fetch failed: {str(e)}")
         raise
    Suggestion importance[1-10]: 9

    __

    Why: The call to requests.post uses undefined headers and payload, causing a runtime NameError and blocking token retrieval.

    High
    Check HTTP status before parsing

    You should verify the HTTP status before parsing JSON to catch non-200 errors. Use
    response.raise_for_status() and response.json() to simplify parsing and handle
    unexpected responses gracefully.

    forms-flow-api/src/formsflow_api/services/external/base_bpm.py [96-103]

     response = requests.post(
         bpm_token_api, headers=headers, data=payload, timeout=HTTP_TIMEOUT
     )
    -data = json.loads(response.text)
    +response.raise_for_status()
    +data = response.json()
     return {
         "Authorization": "Bearer " + data["access_token"],
         "Content-Type": "application/json",
     }
    Suggestion importance[1-10]: 6

    __

    Why: Adding response.raise_for_status() and using response.json() improves error detection and simplifies parsing, enhancing robustness.

    Low
    General
    Consolidate Portuguese locale key

    Defining both locale_pt_BR and locale_pt-BR will cause one entry to override the
    other. Consolidate to a single standard variant to ensure consistent locale loading.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [332-333]

     locale_pt_BR=Portugu\u00EAs (Brasil)
    -locale_pt-BR=Portugu\u00EAs (Brasil)
    Suggestion importance[1-10]: 7

    __

    Why: Both locale_pt_BR and locale_pt-BR map to the same value and one will override the other; consolidating to a single key ensures consistent locale loading.

    Medium
    Use unique key for tenant name

    The key tenantName is defined twice and the second occurrence will override the
    first one, leading to potential confusion in other contexts. Rename this key to a
    more specific identifier for the capture-tenant-info form.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [436]

    -tenantName=Tenant Name
    +captureTenantInfo.tenantName=Tenant Name
    Suggestion importance[1-10]: 6

    __

    Why: The key tenantName is defined twice (lines 2 and 436), causing the first entry to be overridden; renaming the second entry avoids confusion and preserves both translations.

    Low
    Add endpoint error handling

    The endpoint directly returns the service result without error handling or HTTP
    status mapping. Wrap the call in a try/except, validate the service response, and
    return a proper Flask response tuple with status codes and error messages on
    failure.

    forms-flow-api/src/formsflow_api/resources/public_endpoints.py [305-311]

    -camunda_start_task = BPMService.post_process_start_tenant(
    -            process_key=definition_key,
    -            payload=payload,
    -            token=None,
    -            tenant_key=tenant_key
    -        )
    -return camunda_start_task
    +try:
    +    result = BPMService.post_process_start_tenant(
    +        process_key=definition_key,
    +        payload=payload,
    +        token=None,
    +        tenant_key=tenant_key
    +    )
    +    return result, HTTPStatus.CREATED
    +except SomeServiceError as err:
    +    current_app.logger.error(f"BPM start error: {err}")
    +    return {"error": str(err)}, HTTPStatus.BAD_GATEWAY
    Suggestion importance[1-10]: 4

    __

    Why: Wrapping BPMService.post_process_start_tenant in try/except adds proper status mapping, but it's an optional error-handling improvement.

    Low
    Normalize URL concatenation

    Concatenating the URL without ensuring a trailing slash on camundaUrl may produce
    malformed endpoints. Normalize the base URL by trimming any trailing slash and use
    String.format to build the final URL safely.

    forms-flow-idm/keycloak/keycloak-event-listener/src/main/java/com/formsflow/keycloak/listener/KeycloakEventListenerProvider.java [34-44]

    -String startUrl = System.getenv("PUBLIC_PROCESS_START_URL");
    -String processKey = System.getenv("PROCESS_KEY");
    -String tenantKey = System.getenv("PROCESS_TENANT_KEY");
    -...
    -String startUrl = camundaUrl + processKey + "/start?tenantKey=" + tenantKey;
    +String base = camundaUrl.replaceAll("/$", "");
    +String startUrl = String.format("%s/%s/start?tenantKey=%s", base, processKey, tenantKey);
    Suggestion importance[1-10]: 4

    __

    Why: Ensuring a trailing slash is trimmed and using String.format makes URL building safer, but impacts a non-critical logging listener path.

    Low
    Rename submit key to avoid collision

    The generic submit key collides with doSubmit and may override other submit
    translations. Prefix it to reflect its use in the tenant capture form.

    forms-flow-idm/keycloak/themes/multitenant/login/messages/messages_en.properties [437]

    -submit=Submit
    +captureTenantInfo.submit=Submit
    Suggestion importance[1-10]: 4

    __

    Why: The generic submit key can be ambiguous alongside other submit-related keys like doSubmit; prefixing it improves clarity but has low impact on functionality.

    Low

    Copy link

    Persistent review updated to latest commit 23cefa1

    Copy link

    Persistent review updated to latest commit 8f7f296

    Copy link

    Persistent review updated to latest commit e2c152b

    Copy link

    Persistent review updated to latest commit ff4709c

    Copy link

    Persistent review updated to latest commit 20b4750

    Copy link

    Persistent review updated to latest commit 8b04005

    Copy link

    Persistent review updated to latest commit 26dc435

    Copy link
    Contributor

    @auslin-aot auslin-aot left a comment

    Choose a reason for hiding this comment

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

    Please check the sonar issue

    Copy link

    Persistent review updated to latest commit 04a04d8

    Copy link

    Persistent review updated to latest commit 05f008e

    Copy link

    Persistent review updated to latest commit 146528d

    Copy link

    Persistent review updated to latest commit 5f00152

    Copy link

    Persistent review updated to latest commit 8129b1d

    @arun-s-aot
    Copy link
    Contributor

    arun-s-aot commented Jul 18, 2025

    ACTION ITEM from my side :

    • Change basebranch to a test branch so as to test this implementation without affecting the release activities.
    • Update the image version to 7.1.0-pilot
    • Merge this branch

    @arun-s-aot arun-s-aot changed the base branch from develop to poc/premium-pilot July 18, 2025 10:21
    Copy link

    @arun-s-aot arun-s-aot marked this pull request as draft September 10, 2025 07:40
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    4 participants