Skip to content

Sync release-3.8.3 with vb/trace: role grant - #155

Merged
SauravBizbRolly merged 4 commits into
release-3.8.3from
vb/release-3.8.3-sync
Jul 14, 2026
Merged

Sync release-3.8.3 with vb/trace: role grant#155
SauravBizbRolly merged 4 commits into
release-3.8.3from
vb/release-3.8.3-sync

Conversation

@vishwab1

@vishwab1 vishwab1 commented Jul 14, 2026

Copy link
Copy Markdown
Member

📋 Description

JIRA ID:

Please provide a summary of the change and the motivation behind it. Include relevant context and details.


✅ Type of Change

  • 🐞 Bug fix (non-breaking change which resolves an issue)
  • New feature (non-breaking change which adds functionality)
  • 🔥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 🛠 Refactor (change that is neither a fix nor a new feature)
  • ⚙️ Config change (configuration file or build script updates)
  • 📚 Documentation (updates to docs or readme)
  • 🧪 Tests (adding new or updating existing tests)
  • 🎨 UI/UX (changes that affect the user interface)
  • 🚀 Performance (improves performance)
  • 🧹 Chore (miscellaneous changes that don't modify src or test files)

ℹ️ Additional Information

Please describe how the changes were tested, and include any relevant screenshots, logs, or other information that provides additional context.

Summary by CodeRabbit

  • New Features

    • Added role-based access controls across clinical, registration, laboratory, teleconsultation, and data-sync workflows.
    • Added health and version endpoints with service status and build information.
    • Added ECG abnormal-finding master data and support for displaying ECG findings.
    • Added doctor signature tracking across supported clinical workflows.
    • Added improved authentication, authorization, CORS handling, and standardized 401/403 responses.
  • Bug Fixes

    • Improved beneficiary registration endpoint handling and optional camp/van ID enforcement.
    • Expanded medication frequency support and improved referral details processing.
    • Improved document URL parsing and response handling.

vishwab1 and others added 4 commits July 14, 2026 13:55
Allow users with the new Volunteer role (Stop TB serviceline) to authenticate
via /user login endpoints and to register new beneficiaries via
/registrarBeneficaryRegistrationNew. Mirrors existing ASHA access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Confirmed via role trace that userId 4408 (and likely other
Registration Officer accounts) was hitting 403 on
registrarBeneficaryRegistrationNew because REGISTRATION_OFFICER
wasn't in the allowed-roles whitelist. Mirrors the existing
ASHA/VOLUNTEER access.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The pull request adds stateless Spring Security authentication with role-based controller authorization, authenticated-principal validation, CORS enforcement, and custom 401/403 responses. It also adds health and version endpoints, ECG abnormal-finding support, doctor-signature flow tracking, registration validation, and medication-frequency handling updates.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • PSMRI/TM-API#104: Implements closely related Spring Security RBAC infrastructure and controller authorization changes.

Suggested reviewers: vanitha1822, drtechie

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.37% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and related to the merge/sync and role-grant changes in the PR.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
13.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@vishwab1
vishwab1 changed the base branch from main to release-3.8.3 July 14, 2026 08:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java (1)

557-601: 🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Potential IDOR on OpenKM file download. getOpenKMDocURL resolves a caller-supplied fileID straight to a fileUUID with no beneficiary/visit ownership check, and getKMFile has no method-level role restriction. Any authenticated user can vary fileID and fetch another beneficiary’s OpenKM URL. Add a record-level access check before resolving the URL, and put a @PreAuthorize guard on getKMFile as defense in depth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`
around lines 557 - 601, The getOpenKMDocURL flow must enforce record-level
beneficiary/visit ownership before benVisitDetailRepo.getFileUUID resolves the
caller-supplied fileID; reuse the project’s existing authorization check and
return or reject unauthorized requests. In WorklistController.java lines
806-824, add a method-level `@PreAuthorize` guard to getKMFile using the
appropriate role expression, preserving existing behavior for authorized
callers.
src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java (1)

417-466: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

NullPointerException vulnerability when processing partially-populated payloads.

The overarching conditional ensures execution if either labResultsList OR radiologyTestResults has items. However, if the payload contains one but omits the other, the omitted list will be null. The code attempts to iterate over both lists unconditionally, which will trigger a NullPointerException (e.g., when labResultsList is null but radiologyTestResults has elements, or vice versa).

Safeguard both for loops by explicitly validating that the target list is not null before iteration.

🐛 Proposed fix structure

Wrap each loop block with a null check:

 		if ((null != labResultsList && labResultsList.size() > 0)
 				|| (null != wrapperLabResults.getRadiologyTestResults()
 				&& wrapperLabResults.getRadiologyTestResults().size() > 0)) {
 			List<LabResultEntry> labResultsListNew = new ArrayList<LabResultEntry>();
-			for (LabResultEntry labResult : labResultsList) {
+			if (labResultsList != null) {
+				for (LabResultEntry labResult : labResultsList) {
 					List<Map<String, String>> compResult = labResult.getCompList();
 					if (null != compResult && compResult.size() > 0) {
 						// ... existing lab components loop ...
 					}
 				}
+			}
-			for (LabResultEntry labResultEntry : wrapperLabResults.getRadiologyTestResults()) {
+			if (wrapperLabResults.getRadiologyTestResults() != null) {
+				for (LabResultEntry labResultEntry : wrapperLabResults.getRadiologyTestResults()) {
 					labResultEntry.setBeneficiaryRegID(wrapperLabResults.getBeneficiaryRegID());
 					// ... existing radiology items loop ...
 					labResultsListNew.add(labResultEntry);
 				}
+			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java`
around lines 417 - 466, Guard both list iterations in the result-processing
block: only iterate labResultsList when it is non-null, and only iterate
wrapperLabResults.getRadiologyTestResults() when that list is non-null. Preserve
the existing processing logic and outer condition while preventing partially
populated payloads from reaching either enhanced for loop with a null list.
src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java (2)

152-169: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Duplicated isOriginAllowed origin-matching logic in two files, both flagged for a non-literal-regex ReDoS risk.

The exact same pattern-to-regex conversion and origin.matches(regex) call is copy-pasted into JwtUserIdValidationFilter and HTTPRequestInterceptor (the latter's own javadoc says it mirrors the former "for consistency"). Static analysis flags both call sites since the regex is built dynamically from config and matched against attacker-influenced Origin input, risking catastrophic backtracking if the configured allow-list pattern is complex. Extracting one shared, hardened matcher fixes both the duplication and the ReDoS exposure in a single place instead of two.

  • src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java#L152-L169: extract this method into a shared component (e.g., CorsOriginMatcher), and harden it (e.g., precompile/cache patterns once at startup instead of rebuilding regex per call, and/or validate configured patterns to avoid pathological wildcard combinations).
  • src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java#L149-L163: delete this duplicate copy and delegate to the same shared matcher used by JwtUserIdValidationFilter.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java` around lines
152 - 169, Extract the origin-pattern conversion and matching from
isOriginAllowed in
src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java lines 152-169
into one shared, hardened CorsOriginMatcher component, validating or safely
precompiling configured patterns to prevent pathological regex backtracking
while preserving current allow-list behavior. Remove the duplicate matching
logic from src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java
lines 149-163 and make its origin validation delegate to the shared matcher;
both callers must retain their existing null and empty-configuration handling.

Source: Linters/SAST tools


40-104: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Short-circuit allowed OPTIONS requests before JWT validation. This filter is registered on /* with Ordered.HIGHEST_PRECEDENCE, so preflight requests hit it first. For allowed origins, return a 2xx immediately after setting the CORS headers; otherwise browser requests to protected endpoints will fail on preflight with 401 and never reach the API.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java` around lines
40 - 104, Update the OPTIONS branch in JwtUserIdValidationFilter to
short-circuit allowed preflight requests after CORS headers are configured,
returning a successful 2xx response without continuing into JWT validation.
Preserve the existing rejection behavior for missing or unauthorized origins,
and ensure non-OPTIONS requests continue through the current filter flow.
🧹 Nitpick comments (8)
src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java (1)

38-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unused imports and injected fields across controllers.

Both TeleConsultationController and VideoConsultationController declare imports for CookieUtil, JwtUtil (and HttpServletRequest) and inject a JwtUtil bean. Since the endpoint authentication logic has been refactored to rely exclusively on the Authentication principal passed as a method parameter, these utilities are no longer used.

  • src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java#L38-L40: Remove the CookieUtil and JwtUtil imports.
  • src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java#L58-L60: Remove the unused @Autowired private JwtUtil jwtUtil; field.
  • src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java#L37-L40: Remove the HttpServletRequest, CookieUtil, and JwtUtil imports.
  • src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java#L53-L54: Remove the unused @Autowired private JwtUtil jwtUtil; field.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java`
around lines 38 - 40, Remove the unused CookieUtil and JwtUtil imports and
injected JwtUtil field from TeleConsultationController at
src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java
lines 38-40 and 58-60. In VideoConsultationController, remove the unused
HttpServletRequest, CookieUtil, and JwtUtil imports plus the injected JwtUtil
field at
src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java
lines 37-40 and 53-54; keep authentication based on the Authentication method
parameter.
src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java (1)

143-143: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify @PreAuthorize role checks with hasAnyRole.

Using Spring Security's native hasAnyRole('ROLE1', 'ROLE2') provides a more concise and idiomatic expression than chaining multiple hasRole(...) || hasRole(...) blocks. Consider updating the authorization logic across the controller endpoints to improve readability.

  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L143-L143: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L173-L173: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L203-L203: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L233-L233: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L263-L263: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L295-L295: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L327-L327: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L359-L359: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L390-L390: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L417-L417: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L469-L469: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L508-L508: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java#L544-L544: use hasAnyRole('NURSE', 'DOCTOR', 'ONCOLOGIST').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L143-L143: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L169-L169: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L198-L198: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L226-L226: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L253-L253: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L279-L279: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L306-L306: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L369-L369: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L398-L398: use hasAnyRole('NURSE', 'DOCTOR').
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java#L427-L427: use hasAnyRole('NURSE', 'DOCTOR').
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java`
at line 143, Replace the chained hasRole authorization expressions on the
affected endpoints with hasAnyRole expressions. In CancerScreeningController at
lines 143, 173, 203, 233, 263, 295, 327, 359, 390, 417, 469, and 508, use NURSE
and DOCTOR; at line 544, include ONCOLOGIST as well. Apply the same NURSE/DOCTOR
hasAnyRole expression in NCDScreeningController at lines 143, 169, 198, 226,
253, 279, 306, 369, 398, and 427, preserving the existing access rules.
src/main/java/com/iemr/tm/service/health/HealthService.java (1)

90-90: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider externalizing ADVANCED_HEALTH_CHECKS_ENABLED.

It's hardcoded true; advanced checks add extra INFORMATION_SCHEMA queries per (throttled) health check. Exposing this via @Value with a sane default would allow disabling the extra DB load without a redeploy if it ever becomes a concern in production.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/health/HealthService.java` at line 90,
Externalize ADVANCED_HEALTH_CHECKS_ENABLED instead of hardcoding it to true,
injecting it through the service’s configuration mechanism (such as `@Value`) with
a default of true. Preserve the existing advanced health-check behavior while
allowing operators to disable the extra database queries through configuration.
src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java (1)

757-761: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated doctorSignatureFlag parsing logic.

The same 4-line null-safe boolean extraction is repeated in both saveDoctorData and updateGeneralOPDDoctorData. Consider extracting a small private helper (e.g. parseDoctorSignatureFlag(JsonObject requestOBJ)) to keep the two call sites in sync if the field name or semantics change.

Also applies to: 1368-1372

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java`
around lines 757 - 761, Extract the repeated null-safe doctorSignatureFlag
parsing from saveDoctorData and updateGeneralOPDDoctorData into a private helper
such as parseDoctorSignatureFlag(JsonObject requestOBJ). Replace both inline
extraction blocks with calls to the helper, preserving the current false default
and boolean conversion behavior.
src/main/java/com/iemr/tm/service/common/master/CommonMasterServiceImpl.java (1)

39-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inject the interface instead of the concrete implementation class.

Injecting the concrete implementation (LabTechnicianServiceImpl) instead of its interface (LabTechnicianService) violates the Dependency Inversion Principle. It may also lead to BeanNotOfRequiredTypeException failures if Spring utilizes JDK dynamic proxies for transaction or security interception on the target bean.

Prefer injecting the LabTechnicianService interface.

♻️ Proposed refactor
-	private LabTechnicianServiceImpl labTechnicianServiceImpl;
+	private LabTechnicianService labTechnicianService;
 
 	`@Autowired`
 	public void setNcdCareMasterDataServiceImpl(NCDCareMasterDataServiceImpl ncdCareMasterDataServiceImpl) {
 		this.ncdCareMasterDataServiceImpl = ncdCareMasterDataServiceImpl;
 	}
 
 	`@Autowired`
-	public void setLabTechnicianServiceImpl(LabTechnicianServiceImpl labTechnicianServiceImpl) {
-		this.labTechnicianServiceImpl = labTechnicianServiceImpl;
+	public void setLabTechnicianService(LabTechnicianService labTechnicianService) {
+		this.labTechnicianService = labTechnicianService;
 	}

Make sure to update the usage on line 234:

 	`@Override`
 	public String getECGAbnormalFindings() {
-		return labTechnicianServiceImpl.getECGAbnormalFindings();
+		return labTechnicianService.getECGAbnormalFindings();
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/master/CommonMasterServiceImpl.java`
around lines 39 - 49, Update CommonMasterServiceImpl to depend on the
LabTechnicianService interface instead of LabTechnicianServiceImpl: change the
field and setLabTechnicianServiceImpl setter parameter accordingly, while
preserving the existing setter wiring. Also update the usage around the
referenced call site to use the interface-typed dependency.
src/main/java/com/iemr/tm/utils/IntegerListConverter.java (1)

35-51: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Cache the TypeToken type to prevent unnecessary object churn.

Using new TypeToken<List<Integer>>(){}.getType() recreates an anonymous inner class and executes reflection on every invocation of convertToEntityAttribute. Moving it to a static final constant is better for performance and memory allocation.

♻️ Proposed refactor
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
 
 `@Converter`
 public class IntegerListConverter implements AttributeConverter<List<Integer>, String> {
 
     private final Gson gson = new Gson();
+    private static final Type LIST_TYPE = new TypeToken<List<Integer>>(){}.getType();
 
     `@Override`
     public String convertToDatabaseColumn(List<Integer> attribute) {
         if (attribute == null || attribute.isEmpty()) {
             return null;
         }
-        return gson.toJson(attribute);
+        return gson.toJson(attribute, LIST_TYPE);
     }
 
     `@Override`
     public List<Integer> convertToEntityAttribute(String dbData) {
         if (dbData == null || dbData.trim().isEmpty()) {
             return null;
         }
-        return gson.fromJson(dbData, new TypeToken<List<Integer>>(){}.getType());
+        return gson.fromJson(dbData, LIST_TYPE);
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/IntegerListConverter.java` around lines 35 -
51, Cache the Gson type metadata used by IntegerListConverter in a static final
Type field, initialized once from the List<Integer> TypeToken. Update
convertToEntityAttribute to reuse this constant instead of creating a new
TypeToken on each invocation, while preserving the existing null and blank-input
behavior.
src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java (1)

117-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider depending on RedisConnectionFactory instead of the concrete LettuceConnectionFactory.

Coding to the RedisConnectionFactory interface (which is all that's used here via getConnection()) improves testability and decouples this class from the specific Redis client implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java` around
lines 117 - 118, Change the injected field in RegistrarServiceImpl from
LettuceConnectionFactory to the RedisConnectionFactory interface, retaining the
existing getConnection() usage and removing the concrete-client dependency.
src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java (1)

774-778: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix indentation for readability.

The assignment statement inside the if block is missing an indentation level. Correcting the indentation ensures the code remains clean and visually clear.

  • src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java#L774-L778: indent doctorSignatureFlag = ... correctly.
  • src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java#L1211-L1215: indent doctorSignatureFlag = ... correctly.
🧹 Proposed fixes

For lines 774-778:

 			Boolean doctorSignatureFlag = false;
 			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
-			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
+				doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
 			}

For lines 1211-1215:

 			Boolean doctorSignatureFlag = false;
 			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
-			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
+				doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java` around
lines 774 - 778, Correct the indentation of the doctorSignatureFlag assignment
inside the if block at
src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java lines 774-778
and lines 1211-1215, without changing its behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/iemr/tm/controller/common/main/WorklistController.java`:
- Around line 710-731: Add the same `@PreAuthorize` role restriction used by
neighboring worklist handlers to getTCSpecialistWorkListNew and the other two TC
specialist worklist endpoint methods. Preserve their existing authentication and
response logic while applying the established role guard consistently to all
three endpoints.

In `@src/main/java/com/iemr/tm/controller/health/HealthController.java`:
- Around line 73-82: Update the catch-all error response in HealthController to
include a components map matching the success schema, including the mysql status
entry, while preserving the existing DOWN status, timestamp, and
SERVICE_UNAVAILABLE response.
- Around line 40-43: Update the error response construction in HealthController
to include the same top-level keys as the successful health response,
specifically adding components alongside the existing status fields. Preserve
the current failure status and error details while ensuring both response paths
share a consistent shape.

In
`@src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java`:
- Line 30: Remove the unused org.checkerframework.checker.units.qual.s import
from CommonBenStatusFlowServiceImpl, leaving the remaining imports and class
implementation unchanged.

In `@src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java`:
- Around line 814-819: Update the doctorSignatureFlag initialization block in
CSServiceImpl to guard requestOBJ before calling has or get; only read
doctorSignatureFlag when requestOBJ is non-null and the property is present and
non-null, preserving false as the default for a null requestOBJ.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`:
- Around line 583-593: The file URL extraction logic in CommonServiceImpl must
not return dataVal.toString() when a JSONObject lacks the response key. Update
this fallback to signal that no usable URL was found, matching the existing
error or empty-result contract consumed by WorklistController.getKMFile, while
preserving response extraction and URL normalization for valid objects.
- Around line 566-595: Update the response logging in the OpenKM exchange flow
before parsing responseBody: remove raw response-body logging at INFO level, or
log only a redacted version at DEBUG level by stripping embedded credentials
before “@”. Preserve the existing response parsing and URL normalization in the
surrounding fileUUID handling.

In `@src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java`:
- Around line 134-147: Update getUserRoles so the intentionally thrown
IEMRException for a missing role is not caught and re-wrapped by the general
exception handler. Preserve its original message, while continuing to wrap
unexpected exceptions with the original exception as the cause when constructing
the failure IEMRException.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java`:
- Around line 68-78: Update the allowed-origin branch in
JwtUserIdValidationFilter so it restores the Vary response header with the value
Origin alongside Access-Control-Allow-Origin. Keep this header limited to
responses where isOriginAllowed(origin) succeeds.

In `@src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java`:
- Around line 150-165: Update resolveAuthToken in RoleAuthenticationFilter to
remove the leading “Bearer ” scheme prefix before returning the token, matching
HTTPRequestInterceptor.preHandle and preserving raw-token Redis session lookup.
Apply this normalization to the resolved Authorization token while leaving other
header and cookie fallback behavior unchanged.

In `@src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java`:
- Around line 38-40: Update the SecurityConfig HTTP security chain to retain
CSRF protection for requests authenticated through the Jwttoken cookie, using
the existing JwtUserIdValidationFilter/CookieUtil authentication path as the
reference. Do not leave csrf globally disabled; configure an appropriate CSRF
token repository and cookie-based request handling while preserving stateless
session management and header-token behavior.

In `@src/main/java/com/iemr/tm/utils/redis/RedisStorage.java`:
- Around line 102-112: Update cacheUserRoles and the role-assignment mutation
flow to prevent stale authorities: shorten the current 30-minute TTL and add
explicit deletion of the user’s "roles:" cache key whenever roles are assigned,
revoked, or changed. Ensure RoleAuthenticationFilter observes the updated roles
after mutation while preserving the existing cache write behavior.

---

Outside diff comments:
In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`:
- Around line 557-601: The getOpenKMDocURL flow must enforce record-level
beneficiary/visit ownership before benVisitDetailRepo.getFileUUID resolves the
caller-supplied fileID; reuse the project’s existing authorization check and
return or reject unauthorized requests. In WorklistController.java lines
806-824, add a method-level `@PreAuthorize` guard to getKMFile using the
appropriate role expression, preserving existing behavior for authorized
callers.

In
`@src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java`:
- Around line 417-466: Guard both list iterations in the result-processing
block: only iterate labResultsList when it is non-null, and only iterate
wrapperLabResults.getRadiologyTestResults() when that list is non-null. Preserve
the existing processing logic and outer condition while preventing partially
populated payloads from reaching either enhanced for loop with a null list.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java`:
- Around line 152-169: Extract the origin-pattern conversion and matching from
isOriginAllowed in
src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java lines 152-169
into one shared, hardened CorsOriginMatcher component, validating or safely
precompiling configured patterns to prevent pathological regex backtracking
while preserving current allow-list behavior. Remove the duplicate matching
logic from src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java
lines 149-163 and make its origin validation delegate to the shared matcher;
both callers must retain their existing null and empty-configuration handling.
- Around line 40-104: Update the OPTIONS branch in JwtUserIdValidationFilter to
short-circuit allowed preflight requests after CORS headers are configured,
returning a successful 2xx response without continuing into JWT validation.
Preserve the existing rejection behavior for missing or unauthorized origins,
and ensure non-OPTIONS requests continue through the current filter flow.

---

Nitpick comments:
In
`@src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java`:
- Line 143: Replace the chained hasRole authorization expressions on the
affected endpoints with hasAnyRole expressions. In CancerScreeningController at
lines 143, 173, 203, 233, 263, 295, 327, 359, 390, 417, 469, and 508, use NURSE
and DOCTOR; at line 544, include ONCOLOGIST as well. Apply the same NURSE/DOCTOR
hasAnyRole expression in NCDScreeningController at lines 143, 169, 198, 226,
253, 279, 306, 369, 398, and 427, preserving the existing access rules.

In
`@src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java`:
- Around line 38-40: Remove the unused CookieUtil and JwtUtil imports and
injected JwtUtil field from TeleConsultationController at
src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java
lines 38-40 and 58-60. In VideoConsultationController, remove the unused
HttpServletRequest, CookieUtil, and JwtUtil imports plus the injected JwtUtil
field at
src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java
lines 37-40 and 53-54; keep authentication based on the Authentication method
parameter.

In
`@src/main/java/com/iemr/tm/service/common/master/CommonMasterServiceImpl.java`:
- Around line 39-49: Update CommonMasterServiceImpl to depend on the
LabTechnicianService interface instead of LabTechnicianServiceImpl: change the
field and setLabTechnicianServiceImpl setter parameter accordingly, while
preserving the existing setter wiring. Also update the usage around the
referenced call site to use the interface-typed dependency.

In `@src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java`:
- Around line 757-761: Extract the repeated null-safe doctorSignatureFlag
parsing from saveDoctorData and updateGeneralOPDDoctorData into a private helper
such as parseDoctorSignatureFlag(JsonObject requestOBJ). Replace both inline
extraction blocks with calls to the helper, preserving the current false default
and boolean conversion behavior.

In `@src/main/java/com/iemr/tm/service/health/HealthService.java`:
- Line 90: Externalize ADVANCED_HEALTH_CHECKS_ENABLED instead of hardcoding it
to true, injecting it through the service’s configuration mechanism (such as
`@Value`) with a default of true. Preserve the existing advanced health-check
behavior while allowing operators to disable the extra database queries through
configuration.

In `@src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java`:
- Around line 774-778: Correct the indentation of the doctorSignatureFlag
assignment inside the if block at
src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java lines 774-778
and lines 1211-1215, without changing its behavior.

In `@src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java`:
- Around line 117-118: Change the injected field in RegistrarServiceImpl from
LettuceConnectionFactory to the RedisConnectionFactory interface, retaining the
existing getConnection() usage and removing the concrete-client dependency.

In `@src/main/java/com/iemr/tm/utils/IntegerListConverter.java`:
- Around line 35-51: Cache the Gson type metadata used by IntegerListConverter
in a static final Type field, initialized once from the List<Integer> TypeToken.
Update convertToEntityAttribute to reuse this constant instead of creating a new
TypeToken on each invocation, while preserving the existing null and blank-input
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd8740c7-861f-4f11-867e-a403654fdd98

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8fdd2 and 1e5bf1f.

📒 Files selected for processing (67)
  • pom.xml
  • src/main/environment/common_ci.properties
  • src/main/environment/common_docker.properties
  • src/main/environment/common_example.properties
  • src/main/java/com/iemr/tm/controller/anc/AntenatalCareController.java
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java
  • src/main/java/com/iemr/tm/controller/common/main/WorklistController.java
  • src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
  • src/main/java/com/iemr/tm/controller/covid19/CovidController.java
  • src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java
  • src/main/java/com/iemr/tm/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java
  • src/main/java/com/iemr/tm/controller/foetalmonitor/FoetalMonitorController.java
  • src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.java
  • src/main/java/com/iemr/tm/controller/health/HealthController.java
  • src/main/java/com/iemr/tm/controller/labtechnician/LabtechnicianController.java
  • src/main/java/com/iemr/tm/controller/location/LocationController.java
  • src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java
  • src/main/java/com/iemr/tm/controller/ncdCare/NCDCareController.java
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java
  • src/main/java/com/iemr/tm/controller/nurse/vitals/AnthropometryVitalsController.java
  • src/main/java/com/iemr/tm/controller/patientApp/master/PatientAppCommonMasterController.java
  • src/main/java/com/iemr/tm/controller/pnc/PostnatalCareController.java
  • src/main/java/com/iemr/tm/controller/quickconsult/QuickConsultController.java
  • src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
  • src/main/java/com/iemr/tm/controller/report/CRMReportController.java
  • src/main/java/com/iemr/tm/controller/snomedct/SnomedController.java
  • src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java
  • src/main/java/com/iemr/tm/controller/version/VersionController.java
  • src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java
  • src/main/java/com/iemr/tm/data/benFlowStatus/BeneficiaryFlowStatus.java
  • src/main/java/com/iemr/tm/data/labModule/ECGAbnormalFindingMaster.java
  • src/main/java/com/iemr/tm/data/labModule/LabResultEntry.java
  • src/main/java/com/iemr/tm/data/ncdcare/NCDCareDiagnosis.java
  • src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
  • src/main/java/com/iemr/tm/repo/labModule/ECGAbnormalFindingMasterRepo.java
  • src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java
  • src/main/java/com/iemr/tm/repo/nurse/ncdcare/NCDCareDiagnosisRepo.java
  • src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java
  • src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java
  • src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/master/CommonMasterServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/master/CommonMaterService.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java
  • src/main/java/com/iemr/tm/service/covid19/Covid19ServiceImpl.java
  • src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java
  • src/main/java/com/iemr/tm/service/health/HealthService.java
  • src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdscreening/NCDSCreeningDoctorServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdscreening/NCDScreeningServiceImpl.java
  • src/main/java/com/iemr/tm/service/pnc/PNCServiceImpl.java
  • src/main/java/com/iemr/tm/service/quickConsultation/QuickConsultationServiceImpl.java
  • src/main/java/com/iemr/tm/service/registrar/RegistrarServiceImpl.java
  • src/main/java/com/iemr/tm/utils/CookieUtil.java
  • src/main/java/com/iemr/tm/utils/IntegerListConverter.java
  • src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java
  • src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
  • src/main/java/com/iemr/tm/utils/JwtUtil.java
  • src/main/java/com/iemr/tm/utils/StringListConverter.java
  • src/main/java/com/iemr/tm/utils/exception/CustomAccessDeniedHandler.java
  • src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java
  • src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java
  • src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java
  • src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java
  • src/main/java/com/iemr/tm/utils/redis/RedisStorage.java

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

🛑 Comments failed to post (12)
src/main/java/com/iemr/tm/controller/common/main/WorklistController.java (1)

710-731: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Add the same role guard to the three TC specialist worklist endpoints.
They only check authentication.isAuthenticated(), while the neighboring worklist handlers require a role. Add the same @PreAuthorize(...) restriction here so access control stays consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/common/main/WorklistController.java`
around lines 710 - 731, Add the same `@PreAuthorize` role restriction used by
neighboring worklist handlers to getTCSpecialistWorkListNew and the other two TC
specialist worklist endpoint methods. Preserve their existing authentication and
response logic while applying the established role guard consistently to all
three endpoints.
src/main/java/com/iemr/tm/controller/health/HealthController.java (2)

40-43: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

git ls-files | rg 'src/main/java/.*/(HealthController|HealthService|SecurityConfig)\.java$'

Repository: PSMRI/TM-API

Length of output: 335


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files | rg 'src/main/java/.*/(HealthController|HealthService|SecurityConfig)\.java$'

printf '\n== controller outline ==\n'
ast-grep outline src/main/java/com/iemr/tm/controller/health/HealthController.java --view expanded || true

printf '\n== security config outline ==\n'
ast-grep outline src/main/java/com/iemr/tm/config/SecurityConfig.java --view expanded || true

printf '\n== health service outline ==\n'
ast-grep outline src/main/java/com/iemr/tm/service/HealthService.java --view expanded || true

Repository: PSMRI/TM-API

Length of output: 828


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== HealthController.java ==\n'
sed -n '1,220p' src/main/java/com/iemr/tm/controller/health/HealthController.java

printf '\n== HealthService.java ==\n'
sed -n '1,260p' src/main/java/com/iemr/tm/service/health/HealthService.java

printf '\n== SecurityConfig.java ==\n'
sed -n '1,260p' src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java

Repository: PSMRI/TM-API

Length of output: 17377


Keep the failure response shape consistent
HealthController.java:76-79 omits components, while the success path always returns it. Add the same top-level keys on the error path so callers don’t fail only when health checks break.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/health/HealthController.java` around
lines 40 - 43, Update the error response construction in HealthController to
include the same top-level keys as the successful health response, specifically
adding components alongside the existing status fields. Preserve the current
failure status and error details while ensuring both response paths share a
consistent shape.

73-82: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Error-path response omits components, unlike the success schema.

The catch-all fallback returns only {status, timestamp}, while the normal path always includes a components map. A client that unconditionally reads components.mysql.status will fail specifically when the health check itself throws — the scenario where a reliable response matters most.

🩹 Suggested fix
             Map<String, Object> errorResponse = Map.of(
                 "status", "DOWN",
-                "timestamp", Instant.now().toString()
+                "timestamp", Instant.now().toString(),
+                "components", Map.of()
             );
📝 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.

        } catch (Exception e) {
            logger.error("Unexpected error during health check", e);
            
            Map<String, Object> errorResponse = Map.of(
                "status", "DOWN",
                "timestamp", Instant.now().toString(),
                "components", Map.of()
            );
            
            return new ResponseEntity<>(errorResponse, HttpStatus.SERVICE_UNAVAILABLE);
        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/health/HealthController.java` around
lines 73 - 82, Update the catch-all error response in HealthController to
include a components map matching the success schema, including the mysql status
entry, while preserving the existing DOWN status, timestamp, and
SERVICE_UNAVAILABLE response.
src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java (1)

30-30: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the unresolved and unused import.

This import appears to be an accidental inclusion (e.g., from an IDE auto-import). It is entirely unused within the class and will cause javac compilation failures if the checker-qual package is not available on the classpath.

🧹 Proposed fix
-import org.checkerframework.checker.units.qual.s;
📝 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.


🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java`
at line 30, Remove the unused org.checkerframework.checker.units.qual.s import
from CommonBenStatusFlowServiceImpl, leaving the remaining imports and class
implementation unchanged.
src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java (1)

814-819: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Add a null check for requestOBJ to prevent a potential NullPointerException.

The code unconditionally invokes requestOBJ.has(...), but the downstream logic (e.g., the null guard at line 820) indicates that requestOBJ can legitimately be null. If a null object is provided, this block will crash the request execution.

🛡️ Proposed fix to add the null guard and correct the indentation
 		Boolean doctorSignatureFlag = false;
-			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
-			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
-			}
+		if (requestOBJ != null && requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
+			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
+		}
📝 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.

		Boolean doctorSignatureFlag = false;
		if (requestOBJ != null && requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java` around
lines 814 - 819, Update the doctorSignatureFlag initialization block in
CSServiceImpl to guard requestOBJ before calling has or get; only read
doctorSignatureFlag when requestOBJ is non-null and the property is present and
non-null, preserving false as the default for a null requestOBJ.
src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java (2)

566-595: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Logging the raw OpenKM response can leak embedded credentials.

The method's own comment documents that the extracted URL can look like https://user:pass@https://host, meaning the response body legitimately contains Basic-Auth-style credentials embedded in a URL. logger.info("Response=" + response.getBody()) writes that entire body — credentials included — into application logs before any redaction happens.

🔒 Suggested fix
-				logger.info("Response=" + response.getBody());

 				String responseBody = response.getBody();

If response-body logging is needed for debugging, redact the credentials portion (e.g. strip anything before @) before logging, and drop it to DEBUG level.

📝 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.

			logger.info("fileUUID for fileID " + obj.getInt("fileID") + " is " + fileUUID);
			logger.info("openkmDocUrl is " + openkmDocUrl);
			
			if (fileUUID != null) {
				Map<String, Object> requestBody = new HashMap<>();
				requestBody.put("fileUID", fileUUID);

				HttpEntity<Object> request = RestTemplateUtil.createRequestEntity(requestBody, Authorization);
				ResponseEntity<String> response = restTemplate.exchange(openkmDocUrl, HttpMethod.POST, request,
						String.class);

				String responseBody = response.getBody();
				if (responseBody != null) {
					JSONObject responseObj = new JSONObject(responseBody);
					if (responseObj.has("data")) {
						Object dataVal = responseObj.get("data");
						if (dataVal instanceof JSONObject) {
							JSONObject dataObj = (JSONObject) dataVal;
							if (dataObj.has("response")) {
								String fileUrl = dataObj.getString("response");
								// Fix malformed URL: https://user:pass@https://host -> https://user:pass@host
								fileUrl = fileUrl.replaceAll("`@https`?://", "@");
								return fileUrl;
							}
						}
						return dataVal.toString();
					}
				}
				return responseBody;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`
around lines 566 - 595, Update the response logging in the OpenKM exchange flow
before parsing responseBody: remove raw response-body logging at INFO level, or
log only a redacted version at DEBUG level by stripping embedded credentials
before “@”. Preserve the existing response parsing and URL normalization in the
surrounding fileUUID handling.

583-593: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Silent fallback returns a stringified JSON object as the "file URL".

When data is a JSONObject without a response key, dataVal.toString() is returned as if it were the download URL. The caller (WorklistController.getKMFile) puts this directly into the client response via response.setResponse(s), so the client would receive an unusable JSON blob instead of a URL, with no error signal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`
around lines 583 - 593, The file URL extraction logic in CommonServiceImpl must
not return dataVal.toString() when a JSONObject lacks the response key. Update
this fallback to signal that no usable URL was found, matching the existing
error or empty-result contract consumed by WorklistController.getKMFile, while
preserving response extraction and URL normalization for valid objects.
src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java (1)

134-147: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Catch block re-wraps its own thrown IEMRException, losing message clarity and cause.

The throw new IEMRException("No role found...") at Line 141 is caught by the catch (Exception e) below it and re-wrapped into a confusing nested message ("Failed to retrieverole... error : No role found..."). The original exception's cause is also dropped since e isn't passed to the new IEMRException.

🐛 Proposed fix
 public List<String> getUserRoles(Long userId) throws IEMRException {
 		if (null == userId || userId <= 0) {
 			throw new IEMRException("Invalid User ID : " + userId);
 		}
 		try {
 			List<String> role = userLoginRepo.getRoleNamebyUserId(userId);
 			if (null == role || role.isEmpty()) {
 				throw new IEMRException("No role found for userId : " + userId);
 			}
 			return role;
+		} catch (IEMRException e) {
+			throw e;
 		} catch (Exception e) {
-			throw new IEMRException("Failed to retrieverole for usedId : " + userId + " error : " + e.getMessage());
+			throw new IEMRException("Failed to retrieve role for userId : " + userId + " error : " + e.getMessage(), e);
 		}
 	}
📝 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.

	public List<String> getUserRoles(Long userId) throws IEMRException {
		if (null == userId || userId <= 0) {
			throw new IEMRException("Invalid User ID : " + userId);
		}
		try {
			List<String> role = userLoginRepo.getRoleNamebyUserId(userId);
			if (null == role || role.isEmpty()) {
				throw new IEMRException("No role found for userId : " + userId);
			}
			return role;
		} catch (IEMRException e) {
			throw e;
		} catch (Exception e) {
			throw new IEMRException("Failed to retrieve role for userId : " + userId + " error : " + e.getMessage(), e);
		}
	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java` around lines 134
- 147, Update getUserRoles so the intentionally thrown IEMRException for a
missing role is not caught and re-wrapped by the general exception handler.
Preserve its original message, while continuing to wrap unexpected exceptions
with the original exception as the cause when constructing the failure
IEMRException.
src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java (1)

68-78: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Vary: Origin header dropped when echoing the allowed origin.

Previously the allowed-origin response set Vary: Origin; this block no longer sets it. Without it, caches/CDNs sitting in front of this service could serve one origin's CORS-enabled response to a different origin.

🛡️ Proposed fix
 			response.setHeader("Access-Control-Allow-Credentials", "true");
 			response.setHeader("Access-Control-Max-Age", "3600");
+			response.setHeader("Vary", "Origin");
 			logger.info("Origin Validated | Origin: {} | Method: {} | URI: {}", origin, method, uri);
📝 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.

		if (origin != null && isOriginAllowed(origin)) {
			response.setHeader("Access-Control-Allow-Origin", origin); // Never use wildcard
			response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
			response.setHeader("Access-Control-Allow-Headers",
					"Authorization, Content-Type, Accept, Jwttoken, serverAuthorization, ServerAuthorization, serverauthorization, Serverauthorization");
			response.setHeader("Access-Control-Allow-Credentials", "true");
			response.setHeader("Access-Control-Max-Age", "3600");
			response.setHeader("Vary", "Origin");
			logger.info("Origin Validated | Origin: {} | Method: {} | URI: {}", origin, method, uri);
		} else {
			logger.warn("Origin [{}] is NOT allowed. CORS headers NOT added.", origin);
		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java` around lines
68 - 78, Update the allowed-origin branch in JwtUserIdValidationFilter so it
restores the Vary response header with the value Origin alongside
Access-Control-Allow-Origin. Keep this header limited to responses where
isOriginAllowed(origin) succeeds.
src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java (1)

150-165: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

resolveAuthToken doesn't strip the "Bearer " prefix, breaking the legacy Redis session lookup for standard clients.

HTTPRequestInterceptor.preHandle strips "Bearer " before using the token as a Redis key (preAuth.replace("Bearer ", "")). This method doesn't, so a client sending Authorization: Bearer <token> will have authToken = "Bearer <token>" passed to redisService.getObject(...), which won't find the session stored under the raw token — silently failing the legacy fallback path for standard Bearer-scheme clients.

🐛 Proposed fix
 private String resolveAuthToken(HttpServletRequest request) {

         String token = request.getHeader("Authorization");
+        if (token != null && token.startsWith("Bearer ")) {
+            token = token.substring(7);
+        }

         if (token == null || token.isBlank()) {
             token = request.getHeader("AuthToken");
📝 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.

    private String resolveAuthToken(HttpServletRequest request) {

        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }

        if (token == null || token.isBlank()) {
            token = request.getHeader("AuthToken");
        }
        if (token == null || token.isBlank()) {
            token = request.getHeader("X-Auth-Token");
        }
        if (token == null || token.isBlank()) {
            token = CookieUtil.getCookieValue(request, "Authorization")
                    .orElse(null);
        }
        return token;
    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java` around
lines 150 - 165, Update resolveAuthToken in RoleAuthenticationFilter to remove
the leading “Bearer ” scheme prefix before returning the token, matching
HTTPRequestInterceptor.preHandle and preserving raw-token Redis session lookup.
Apply this normalization to the resolved Authorization token while leaving other
header and cookie fallback behavior unchanged.
src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java (1)

38-40: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

CSRF protection disabled while the app also authenticates via a cookie (Jwttoken).

CSRF is safe to disable only for stateless, header-only token auth with no browser-auto-submitted cookie. This codebase's JwtUserIdValidationFilter/CookieUtil treat the Jwttoken cookie as a first-class auth path, so state-changing requests authenticated via that cookie are not protected against forged cross-site requests with csrf().disable().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java` around lines 38 -
40, Update the SecurityConfig HTTP security chain to retain CSRF protection for
requests authenticated through the Jwttoken cookie, using the existing
JwtUserIdValidationFilter/CookieUtil authentication path as the reference. Do
not leave csrf globally disabled; configure an appropriate CSRF token repository
and cookie-based request handling while preserving stateless session management
and header-token behavior.

Source: Linters/SAST tools

src/main/java/com/iemr/tm/utils/redis/RedisStorage.java (1)

102-112: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

30-minute role cache creates a stale-privilege window after role changes/revocations.

cacheUserRoles sets a flat 30-minute TTL with no invalidation hook tied to role mutation elsewhere. Since RoleAuthenticationFilter treats this cache as authoritative for SecurityContextHolder authorities, a revoked or downgraded role can remain effectively granted for up to 30 minutes after the change.

Consider a shorter TTL and/or invalidating (redisTemplate.delete("roles:" + userId)) the cache entry whenever a user's role assignment changes, rather than relying solely on time-based expiry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/redis/RedisStorage.java` around lines 102 -
112, Update cacheUserRoles and the role-assignment mutation flow to prevent
stale authorities: shorten the current 30-minute TTL and add explicit deletion
of the user’s "roles:" cache key whenever roles are assigned, revoked, or
changed. Ensure RoleAuthenticationFilter observes the updated roles after
mutation while preserving the existing cache write behavior.

@SauravBizbRolly
SauravBizbRolly merged commit 4f41a0b into release-3.8.3 Jul 14, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants