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
1 change: 1 addition & 0 deletions .github/workflows/buildProjectFactory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- allValidations
- master
- project-factory-tenantId-fix

env:
DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,7 @@ async function handleResouceDetailsError(request: any, error: any) {
stringifiedError = error;
}
}

const tenantId = request?.body?.ResourceDetails?.tenantId;
logger.error("Error while processing after validation : " + error);
if (request?.body?.ResourceDetails) {
request.body.ResourceDetails.status = "failed";
Expand Down Expand Up @@ -1539,7 +1539,7 @@ async function handleResouceDetailsError(request: any, error: any) {
await produceModifiedMessages(
activityObject,
config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC,
activities?.tenantId || config.app.defaultTenantId
tenantId || config.app.defaultTenantId
)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import config from "../config";
import { throwError } from "../utils/genericUtils";
import { logger } from "../utils/logger";

export async function fetchProductVariants(pvarIds: string[]) {
export async function fetchProductVariants(pvarIds: string[] , tenantId?: string) {
const CHUNK_SIZE = 100;
const allProductVariants: any[] = [];
const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: defaultRequestInfo?.RequestInfo?.userInfo?.tenantId };
const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: tenantId };

Comment on lines +7 to 11
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Enforce tenantId; avoid sending undefined in query params

Passing tenantId: undefined can generate invalid requests. Fail fast if tenantId is missing.

-export async function fetchProductVariants(pvarIds: string[] , tenantId?: string) {
+export async function fetchProductVariants(pvarIds: string[] , tenantId?: string) {
     const CHUNK_SIZE = 100;
     const allProductVariants: any[] = [];
-    const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId: tenantId };
+    if (!tenantId) {
+      throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required to fetch product variants");
+    }
+    const params: any = { limit: CHUNK_SIZE, offset: 0, tenantId };

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In health-services/project-factory/src/server/api/healthApis.ts around lines 7
to 11, the function accepts tenantId as optional and then includes tenantId:
undefined in query params; enforce tenantId presence by making the parameter
required in the function signature (remove the optional ?) and/or add an early
runtime check (if tenantId is missing throw a clear Error like "tenantId is
required") so you never send undefined in params, and update any callers to pass
a valid tenantId.

for (let i = 0; i < pvarIds.length; i += CHUNK_SIZE) {
const chunk = pvarIds.slice(i, i + CHUNK_SIZE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const config = {
contextPath: process.env.CONTEXT_PATH || "/project-factory",
logLevel: process.env.APP_LOG_LEVEL || "debug",
debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000,
defaultTenantId: process.env.DEFAULT_TENANT_ID || "mz",
defaultTenantId: process.env.DEFAULT_TENANT_ID ,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Audit usages of defaultTenantId; it may now be undefined

Since there’s no fallback, ensure no code depends on a non-empty default. Prefer explicit tenantId everywhere; otherwise, add boot-time validation or remove fallbacks.

Run to find usages relying on defaultTenantId:


🏁 Script executed:

#!/bin/bash
rg -n -C2 --type=ts --type=tsx --type=js --type=jsx '\bdefaultTenantId\b'

Length of output: 27


🏁 Script executed:

#!/bin/bash
rg -n -C2 'defaultTenantId'

Length of output: 1556


🏁 Script executed:

#!/bin/bash
# Get context around coreApis.ts:15
echo "=== coreApis.ts context ==="
sed -n '1,30p' health-services/project-factory/src/server/api/coreApis.ts

echo -e "\n=== campaignApis.ts context around 1542 ==="
sed -n '1535,1550p' health-services/project-factory/src/server/api/campaignApis.ts

Length of output: 1601


🏁 Script executed:

#!/bin/bash
# Check if there's any git history showing what changed on line 97
echo "=== Checking git log for config/index.ts ==="
cd health-services/project-factory && git log -p --follow -S 'defaultTenantId' -- src/server/config/index.ts 2>/dev/null | head -50

echo -e "\n=== Searching for DEFAULT_TENANT_ID in .env or docs ==="
find . -name ".env*" -o -name "*.md" | xargs grep -l "DEFAULT_TENANT_ID" 2>/dev/null || echo "No env file references found"

echo -e "\n=== Checking produceModifiedMessages signature ==="
rg -n -A5 'function produceModifiedMessages|const produceModifiedMessages|export.*produceModifiedMessages' | head -30

Length of output: 1033


Enforce a non-empty DEFAULT_TENANT_ID or restore a fallback

  • coreApis.ts (src/server/api/coreApis.ts:15): defaultRequestInfo.RequestInfo.userInfo.tenantId may now be undefined, breaking MDMS calls.
  • campaignApis.ts (src/server/api/campaignApis.ts:1542): tenantId || config.app.defaultTenantId can pass undefined to produceModifiedMessages, causing tenantId.includes() to throw.
    Add a boot-time assertion that process.env.DEFAULT_TENANT_ID is set or reintroduce a safe default.
🤖 Prompt for AI Agents
In health-services/project-factory/src/server/config/index.ts around line 97,
the export for defaultTenantId currently assigns process.env.DEFAULT_TENANT_ID
which may be undefined at runtime; add a boot-time assertion that
DEFAULT_TENANT_ID is present and non-empty (throw a clear error and exit during
startup if missing) or explicitly set a safe fallback value before exporting
(e.g., a validated constant like 'default' or read from a secure config source)
so downstream code never receives undefined and functions like
tenantId.includes() are safe.

incomingRequestPayloadLimit: process.env.INCOMING_REQUEST_PAYLOAD_LIMIT || "2mb",
maxInFlight: process.env.MAX_INFLIGHT || "15",
maxEventLoopLagMs: process.env.MAX_EVENT_LOOP_LAG_MS || "100",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,10 @@ async function validateForRetry(request: any) {

async function validateProductVariant(request: any) {
const deliveryRules = request?.body?.CampaignDetails?.deliveryRules;
const tenantId = request?.body?.CampaignDetails?.tenantId;
if(tenantId === undefined){
logger.error("tenantId is undefined");
}

Comment on lines +1265 to 1269
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Require tenantId for product-variant validation; validate at both levels

Logging when tenantId is undefined but continuing leads to invalid downstream calls. Enforce presence and propagate explicitly.

-    const tenantId = request?.body?.CampaignDetails?.tenantId;
-    if(tenantId === undefined){
-        logger.error("tenantId is undefined");
-    }
+    const tenantId = request?.body?.CampaignDetails?.tenantId;
+    if (!tenantId) {
+        throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required to validate product variants");
+    }
...
-    await validatePvarIds(pvarIds as string[] ,tenantId);
+    await validatePvarIds(pvarIds as string[], tenantId);

Also guard inside validatePvarIds:

-async function validatePvarIds(pvarIds: string[] , tenantId?: string) {
+async function validatePvarIds(pvarIds: string[] , tenantId?: string) {
+    if (!tenantId) {
+        throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required to validate product variants");
+    }
     if (!pvarIds?.length || pvarIds.some((id:any) => !id)) {
         throwError("COMMON", 400, "VALIDATION_ERROR", "productVariantId is required in every delivery rule's resources");
     }
-    const allProductVariants = await fetchProductVariants(pvarIds ,tenantId);
+    const allProductVariants = await fetchProductVariants(pvarIds, tenantId);

Check for any other call sites that still use the old signature:

Also applies to: 1281-1283, 1285-1293


🏁 Script executed:

#!/bin/bash
rg -n -C2 --type=ts --type=tsx '\bvalidatePvarIds\s*\('

Length of output: 27


if (!Array.isArray(deliveryRules)) {
throwError("COMMON", 400, "VALIDATION_ERROR", "deliveryRules must be an array");
Expand All @@ -1274,18 +1278,18 @@ async function validateProductVariant(request: any) {
}
});
const pvarIds= getPvarIds(request?.body);
await validatePvarIds(pvarIds as string[]);
await validatePvarIds(pvarIds as string[] ,tenantId);
logger.info("Validated product variants successfully");
}

async function validatePvarIds(pvarIds: string[]) {
async function validatePvarIds(pvarIds: string[] , tenantId?: string) {
// Validate that pvarIds is not null, undefined, or empty, and that no element is null or undefined
if (!pvarIds?.length || pvarIds.some((id:any) => !id)) {
throwError("COMMON", 400, "VALIDATION_ERROR", "productVariantId is required in every delivery rule's resources");
}

// Fetch product variants using the fetchProductVariants function
const allProductVariants = await fetchProductVariants(pvarIds);
const allProductVariants = await fetchProductVariants(pvarIds ,tenantId);

// Extract the ids of the fetched product variants
const fetchedIds = new Set(allProductVariants.map((pvar: any) => pvar?.id));
Expand Down
Loading