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
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: '3.8'
services:
db:
image: mysql:8.0
container_name: amrit-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: amrit_common
ports:
- "3306:3306"
Comment on lines +8 to +11
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.

⚠️ Potential issue | 🟠 Major

Avoid committing fixed database root credentials.

Line 8 hardcodes a weak root password (password). This tends to leak into non-local usage and weakens default security posture.

Suggested change
 services:
   db:
     image: mysql:8.0
     container_name: amrit-mysql
     restart: always
     environment:
-      MYSQL_ROOT_PASSWORD: password
+      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD}
       MYSQL_DATABASE: amrit_common
+      MYSQL_USER: ${MYSQL_USER:amrit_user}
+      MYSQL_PASSWORD: ${MYSQL_PASSWORD:?set MYSQL_PASSWORD}
📝 Committable suggestion

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

Suggested change
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: amrit_common
ports:
- "3306:3306"
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: amrit_common
MYSQL_USER: ${MYSQL_USER:amrit_user}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?set MYSQL_PASSWORD}
ports:
- "3306:3306"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 8 - 11, The docker-compose service currently
hardcodes MYSQL_ROOT_PASSWORD ("password"), which is insecure; update the
docker-compose.yml to remove the fixed credential and instead read
MYSQL_ROOT_PASSWORD from an external source (e.g., a .env file or an environment
variable) and ensure a strong default is not committed—replace the literal
assignment with a variable reference (keep the key MYSQL_ROOT_PASSWORD) and
document that developers must supply a secure password via .env or CI secrets;
if necessary, add a note to ignore the .env in version control.

2 changes: 1 addition & 1 deletion src/main/java/com/iemr/common/config/CorsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
@Configuration
public class CorsConfig implements WebMvcConfigurer {

@Value("${cors.allowed-origins}")
@Value("${cors.allowed-origins:*}")
private String allowedOrigins;
@Override
public void addCorsMappings(CorsRegistry registry) {
Expand Down
24 changes: 17 additions & 7 deletions src/main/java/com/iemr/common/config/PrimaryDBConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
*/
package com.iemr.common.config;



import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
Expand All @@ -48,13 +46,13 @@
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", basePackages = { "com.iemr.common.repository",
"com.iemr.common.repo", "com.iemr.common.notification.agent", "com.iemr.common.covidVaccination", "com.iemr.common.repository.everwell.*", "com.iemr.common.data.grievance", "com.iemr.common.repository.users" })
"com.iemr.common.repo", "com.iemr.common.notification.agent", "com.iemr.common.covidVaccination",
"com.iemr.common.repository.everwell.*", "com.iemr.common.data.grievance", "com.iemr.common.repository.users" })
@Profile("!swagger")
public class PrimaryDBConfig {

Logger logger = LoggerFactory.getLogger(this.getClass().getName());


@Primary
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
Expand All @@ -74,8 +72,19 @@ public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource datasource = new org.apache.tomcat.jdbc.pool.DataSource();
datasource.setPoolProperties(p);

datasource.setUsername(ConfigProperties.getPropertyByName("spring.datasource.username"));
datasource.setPassword(ConfigProperties.getPropertyByName("spring.datasource.password"));

String dbUser = ConfigProperties.getPropertyByName("spring.datasource.username");
String dbPass = ConfigProperties.getPropertyByName("spring.datasource.password");


if (dbUser == null) {
logger.error("Critical Error: 'spring.datasource.username' is missing from configuration!");

dbUser = "root";
}

datasource.setUsername(dbUser);
datasource.setPassword(dbPass != null ? dbPass : "password");
Comment on lines +76 to +87
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.

⚠️ Potential issue | 🟠 Major

Do not mask datasource credential misconfiguration with root/password fallback.

Reading credentials via ConfigProperties + fallback defaults can hide broken env/secret injection and unintentionally connect with privileged local creds. Prefer required properties and fail fast.

Suggested change
-		String dbUser = ConfigProperties.getPropertyByName("spring.datasource.username");
-		String dbPass = ConfigProperties.getPropertyByName("spring.datasource.password");
-
-		if (dbUser == null) {
-			logger.error("Critical Error: 'spring.datasource.username' is missing from configuration!");
-			dbUser = "root";
-		}
-
-		datasource.setUsername(dbUser);
-		datasource.setPassword(dbPass != null ? dbPass : "password");
+		String dbUser = ConfigProperties.getPropertyByName("spring.datasource.username");
+		String dbPass = ConfigProperties.getPropertyByName("spring.datasource.password");
+		if (dbUser == null || dbUser.isBlank() || dbPass == null || dbPass.isBlank()) {
+			throw new IllegalStateException(
+				"Missing required primary datasource credentials (spring.datasource.username/password)");
+		}
+		datasource.setUsername(dbUser);
+		datasource.setPassword(dbPass);
📝 Committable suggestion

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

Suggested change
String dbUser = ConfigProperties.getPropertyByName("spring.datasource.username");
String dbPass = ConfigProperties.getPropertyByName("spring.datasource.password");
if (dbUser == null) {
logger.error("Critical Error: 'spring.datasource.username' is missing from configuration!");
dbUser = "root";
}
datasource.setUsername(dbUser);
datasource.setPassword(dbPass != null ? dbPass : "password");
String dbUser = ConfigProperties.getPropertyByName("spring.datasource.username");
String dbPass = ConfigProperties.getPropertyByName("spring.datasource.password");
if (dbUser == null || dbUser.isBlank() || dbPass == null || dbPass.isBlank()) {
throw new IllegalStateException(
"Missing required primary datasource credentials (spring.datasource.username/password)");
}
datasource.setUsername(dbUser);
datasource.setPassword(dbPass);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/iemr/common/config/PrimaryDBConfig.java` around lines 76 -
87, The code in PrimaryDBConfig currently masks missing datasource credentials
by defaulting dbUser/dbPass to "root"/"password"; remove these dangerous
fallbacks and make the configuration fail-fast: when
ConfigProperties.getPropertyByName("spring.datasource.username") or
"...password" returns null or blank, log a clear error and throw an
IllegalStateException (or propagate a configuration exception) rather than
calling datasource.setUsername/dbPass fallback; update the initialization around
dbUser, dbPass, and the datasource.setUsername/datasource.setPassword calls to
validate the values and abort startup if either credential is missing.


return datasource;
}
Expand All @@ -85,7 +94,8 @@ public DataSource dataSource() {
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
@Qualifier("dataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.iemr.common.data", "com.iemr.common.notification",
"com.iemr.common.model", "com.iemr.common.covidVaccination", "com.iemr.common.data.everwell", "com.iemr.common.data.grievance", "com.iemr.common.data.users").persistenceUnit("db_iemr").build();
"com.iemr.common.model", "com.iemr.common.covidVaccination", "com.iemr.common.data.everwell",
"com.iemr.common.data.grievance", "com.iemr.common.data.users").persistenceUnit("db_iemr").build();
}

@Primary
Expand Down
18 changes: 12 additions & 6 deletions src/main/java/com/iemr/common/config/SecondaryDBConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
*/
package com.iemr.common.config;



import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties;
Expand All @@ -48,7 +46,7 @@
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "secondaryEntityManagerFactory", transactionManagerRef = "secondaryTransactionManager", basePackages = {
"com.iemr.common.secondary.repository.callreport" })
"com.iemr.common.secondary.repository.callreport" })
@Profile("!swagger")
public class SecondaryDBConfig {

Expand All @@ -72,8 +70,16 @@ public DataSource dataSource() {
org.apache.tomcat.jdbc.pool.DataSource datasource = new org.apache.tomcat.jdbc.pool.DataSource();
datasource.setPoolProperties(p);

datasource.setUsername(ConfigProperties.getPropertyByName("secondary.datasource.username"));
datasource.setPassword(ConfigProperties.getPropertyByName("secondary.datasource.password"));
String secondaryUser = ConfigProperties.getPropertyByName("secondary.datasource.username");
String secondaryPass = ConfigProperties.getPropertyByName("secondary.datasource.password");

if (secondaryUser == null) {
logger.error("Critical Error: 'secondary.datasource.username' is missing!");
secondaryUser = "root"; // Defaulting to root prevents the crash
}

datasource.setUsername(secondaryUser);
datasource.setPassword(secondaryPass != null ? secondaryPass : "password");

Comment on lines +73 to 83
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.

⚠️ Potential issue | 🟠 Major

Fail fast instead of silently defaulting to root/password.

This change prevents an NPE, but it introduces risky behavior: misconfiguration now silently falls back to privileged credentials. That can mask environment issues and connect to the wrong database.

Suggested change
-		if (secondaryUser == null) {
-			logger.error("Critical Error: 'secondary.datasource.username' is missing!");
-			secondaryUser = "root"; // Defaulting to root prevents the crash
-		}
-
-		datasource.setUsername(secondaryUser);
-		datasource.setPassword(secondaryPass != null ? secondaryPass : "password");
+		if (secondaryUser == null || secondaryUser.isBlank() ||
+		    secondaryPass == null || secondaryPass.isBlank()) {
+			throw new IllegalStateException(
+				"Missing required secondary datasource credentials (secondary.datasource.username/password)");
+		}
+		datasource.setUsername(secondaryUser);
+		datasource.setPassword(secondaryPass);
📝 Committable suggestion

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

Suggested change
String secondaryUser = ConfigProperties.getPropertyByName("secondary.datasource.username");
String secondaryPass = ConfigProperties.getPropertyByName("secondary.datasource.password");
if (secondaryUser == null) {
logger.error("Critical Error: 'secondary.datasource.username' is missing!");
secondaryUser = "root"; // Defaulting to root prevents the crash
}
datasource.setUsername(secondaryUser);
datasource.setPassword(secondaryPass != null ? secondaryPass : "password");
String secondaryUser = ConfigProperties.getPropertyByName("secondary.datasource.username");
String secondaryPass = ConfigProperties.getPropertyByName("secondary.datasource.password");
if (secondaryUser == null || secondaryUser.isBlank() ||
secondaryPass == null || secondaryPass.isBlank()) {
throw new IllegalStateException(
"Missing required secondary datasource credentials (secondary.datasource.username/password)");
}
datasource.setUsername(secondaryUser);
datasource.setPassword(secondaryPass);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/iemr/common/config/SecondaryDBConfig.java` around lines 73
- 83, The code in SecondaryDBConfig currently falls back to hardcoded
"root"/"password" when
ConfigProperties.getPropertyByName("secondary.datasource.username"/"secondary.datasource.password")
is missing, which is unsafe; instead validate the configuration via
ConfigProperties in the SecondaryDBConfig initialization, log a clear error with
logger (include the missing property key), and fail fast by throwing an
unchecked exception (e.g., IllegalStateException) before calling
datasource.setUsername or datasource.setPassword; ensure you check both the
username and password (no silent defaults), and update the datasource only after
successful validation.

return datasource;
}
Expand All @@ -90,5 +96,5 @@ public PlatformTransactionManager barTransactionManager(
@Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) {
return new JpaTransactionManager((jakarta.persistence.EntityManagerFactory) secondaryEntityManagerFactory);
}

}
93 changes: 90 additions & 3 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,10 @@ grievancePassword = <Enter Grievance password>
grievanceUserAuthenticate = <Enter Grievance UserAuthenticate>
grievanceDataSyncDuration = <Enter Grievience Data Sync Duration>

springdoc.api-docs.enabled=@env.SWAGGER_DOC_ENABLED@
springdoc.swagger-ui.enabled=@env.SWAGGER_UI_ENABLED@
#springdoc.api-docs.enabled=@env.SWAGGER_DOC_ENABLED@
#springdoc.swagger-ui.enabled=@env.SWAGGER_UI_ENABLED@
springdoc.swagger-ui.enabled=true
springdoc.api-docs.enabled=true
Comment on lines +358 to +359
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What are the recommended production defaults for springdoc.swagger-ui.enabled and springdoc.api-docs.enabled in Spring Boot applications?

💡 Result:

Recommended Springdoc production defaults (i.e., what you should set to in production) for Spring Boot are: 1) springdoc.swagger-ui.enabled=false This disables the Swagger UI endpoint (default is /swagger-ui.html). 2) springdoc.api-docs.enabled=false This disables the OpenAPI JSON endpoint (default is /v3/api-docs). If you do not set these properties, both are enabled by default (their documented default value is true).

Citations:


Don't hard-enable Swagger/docs in shared defaults.

Setting both springdoc flags to true in application.properties exposes Swagger UI and API documentation endpoints across all environments by default. Production deployments should disable these unless explicitly needed. Use environment-driven configuration with safe defaults (false).

Suggested change
-springdoc.swagger-ui.enabled=true
-springdoc.api-docs.enabled=true
+springdoc.swagger-ui.enabled=${SPRINGDOC_SWAGGER_UI_ENABLED:false}
+springdoc.api-docs.enabled=${SPRINGDOC_API_DOCS_ENABLED:false}
📝 Committable suggestion

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

Suggested change
springdoc.swagger-ui.enabled=true
springdoc.api-docs.enabled=true
springdoc.swagger-ui.enabled=${SPRINGDOC_SWAGGER_UI_ENABLED:false}
springdoc.api-docs.enabled=${SPRINGDOC_API_DOCS_ENABLED:false}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.properties` around lines 358 - 359, The file
currently forces springdoc.swagger-ui.enabled=true and
springdoc.api-docs.enabled=true which enables Swagger/docs in all environments;
change these defaults to false and make them environment-configurable so
production remains safe: set springdoc.swagger-ui.enabled=false and
springdoc.api-docs.enabled=false in the shared defaults, and document/expect
overrides via environment properties or Spring profiles (e.g. override with
JVM/env vars or profile-specific application-*.properties) when you want to
enable Swagger; update any README or deployment configs to show how to set
springdoc.swagger-ui.enabled=true for non-production environments.


isProduction=false
grievanceAllocationRetryConfiguration=3
Expand All @@ -371,4 +373,89 @@ video-call-url =
allowed.file.extensions=msg,pdf,png,jpeg,doc,docx,xlsx,xls,csv,txt

##sms details for beneficiary otp cosent
sms-template-name = otp_consent
sms-template-name = otp_consent

cors.allowed-origins=*
jwt.secret=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890
jwt.expiration=3600000



# Primary Database Settings
spring.datasource.url=jdbc:mysql://localhost:3306/amrit_common?useSSL=false&serverTimezone=UTC
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.

⚠️ Potential issue | 🟠 Major

Consolidate duplicate property keys to avoid last-value-wins surprises.

spring.datasource.url and send-message-url are each declared multiple times in the same file. The later entry silently overrides earlier values and makes behavior harder to reason about.

Also applies to: 444-445, 441-441, 452-453

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.properties` at line 385, There are duplicate
property keys (spring.datasource.url and send-message-url) defined multiple
times causing last-value-wins behavior; open the properties file and consolidate
each duplicated key into a single canonical declaration (or move
environment/profile-specific variants into proper spring profiles or
externalized config), remove or merge the redundant entries referencing
spring.datasource.url and send-message-url, and ensure any intended different
values are placed under distinct profiles (e.g., application-dev.properties) or
renamed so the correct value is explicit and unambiguous.

spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Comment on lines +379 to +388
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.

⚠️ Potential issue | 🟠 Major

Remove committed plaintext secrets/credentials from shared properties.

This block includes sensitive defaults (jwt.secret, DB passwords, mail/sms passwords, encryption-key). These should be externalized to env/secret stores and not committed as active values.

Suggested change
-jwt.secret=AbCdEfGhIjKlMnOpQrStUvWxYz1234567890
-spring.datasource.username=root
-spring.datasource.password=password
+jwt.secret=${JWT_SECRET}
+spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
+spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}
...
-sms-password=password
-mail-password=password
+sms-password=${SMS_PASSWORD:}
+mail-password=${MAIL_PASSWORD:}
...
-secondary.datasource.username=root
-secondary.datasource.password=password
+secondary.datasource.username=${SECONDARY_DATASOURCE_USERNAME}
+secondary.datasource.password=${SECONDARY_DATASOURCE_PASSWORD}
...
-encryption-key=dummy_key_12345
+encryption-key=${ENCRYPTION_KEY}

Also applies to: 424-426, 431-432, 437-438, 461-461

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.properties` around lines 379 - 388, The
properties file currently contains committed plaintext secrets (jwt.secret,
spring.datasource.username, spring.datasource.password, encryption-key, mail/sms
passwords and similar keys) — replace these concrete values with
environment-backed placeholders (e.g. ${JWT_SECRET:},
${SPRING_DATASOURCE_USERNAME:}, ${SPRING_DATASOURCE_PASSWORD:}) or remove them
entirely, and load actual secrets from environment variables/secret store at
runtime; ensure default empty or non-sensitive fallbacks are not used, update
any references to jwt.secret, spring.datasource.*, encryption-key, and mail/sms
credentials to use the placeholders so secrets are not present in the repo.


# Connection Pool Settings
spring.datasource.tomcat.max-active=30
spring.datasource.tomcat.max-idle=15
spring.datasource.tomcat.min-idle=5

# Secondary Database Settings
spring.second-datasource.url=jdbc:mysql://localhost:3306/amrit_secondary?useSSL=false&serverTimezone=UTC
spring.second-datasource.username=root
spring.second-datasource.password=password
spring.second-datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# In case the code uses these specific names:
secondary.db.username=root
secondary.db.password=password


# Secondary Database Credentials
spring.second-datasource.username=root
spring.second-datasource.password=password
# Add these in case the @Value annotation uses a different key
secondary.db.username=root
secondary.db.password=password

# Scheduler Settings
start-grievancedatasync-scheduler=false
start-registration-cleanup-scheduler=false
start-notification-scheduler=false

# SMS and Communication Defaults
sms-consent-source-address=123456
sms-template-id=default
sms-enabled=false
beneficiary-sms-enabled=false
welcome-sms-enabled=false
sms-username=admin
sms-password=password
sms-auth-key=dummy
sms-sender-id=AMRIT
sms-url=http://localhost:8080/sms

# Often required alongside SMS: Email/General Comm settings
mail-username=admin
mail-password=password

# Secondary Database Defaults (Prevents the URL cannot be null error)
secondary.datasource.url=jdbc:mysql://localhost:3306/amrit_common
secondary.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
secondary.datasource.username=root
secondary.datasource.password=password

# Final SMS Placeholder
send-message-url=http://localhost:8080/sms/send

# MySQL Connection Security Fix
spring.datasource.url=jdbc:mysql://localhost:3306/amrit_common?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
secondary.datasource.url=jdbc:mysql://localhost:3306/amrit_common?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true

# Redis Settings (Point to dummy or local if not using)
spring.redis.host=localhost
spring.redis.port=6379

# Final URL Placeholders (Double check these)
send-message-url=http://localhost:8080/sms/send
sms-url=http://localhost:8080/sms

# File Management Settings
tempFilePath=/tmp/
uploadDir=/tmp/uploads/
file-delete-scheduler=false

# Security/Encryption (Often required for KMFileManager)
encryption-key=dummy_key_12345