-
Notifications
You must be signed in to change notification settings - Fork 56
Fix: Resolved startup NullPointerException and environmental placeholders #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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" | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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") | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not mask datasource credential misconfiguration with Reading credentials via 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return datasource; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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 | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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 { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fail fast instead of silently defaulting to 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
| return datasource; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,5 +96,5 @@ public PlatformTransactionManager barTransactionManager( | |||||||||||||||||||||||||||||||||||||||||
| @Qualifier("secondaryEntityManagerFactory") EntityManagerFactory secondaryEntityManagerFactory) { | ||||||||||||||||||||||||||||||||||||||||||
| return new JpaTransactionManager((jakarta.persistence.EntityManagerFactory) secondaryEntityManagerFactory); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 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 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| isProduction=false | ||||||||||
| grievanceAllocationRetryConfiguration=3 | ||||||||||
|
|
@@ -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 | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consolidate duplicate property keys to avoid last-value-wins surprises.
Also applies to: 444-445, 441-441, 452-453 🤖 Prompt for AI Agents |
||||||||||
| spring.datasource.username=root | ||||||||||
| spring.datasource.password=password | ||||||||||
| spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver | ||||||||||
|
Comment on lines
+379
to
+388
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove committed plaintext secrets/credentials from shared properties. This block includes sensitive defaults ( 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 |
||||||||||
|
|
||||||||||
| # 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 | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
🤖 Prompt for AI Agents