Skip to content

Commit e7cb5a1

Browse files
committed
#128 | Added environment validation to prevent cross environments config read
- Added environment configuration (int_env) to GoonjConfig and RwbConfig - Changed default int_tasks from "all" to "none" in GoonjConfig and RWBConfig - Added avni.int.env property to integrator-application.properties with documentation - Implemented environment validation in IntegrationJobScheduler and AdhocTaskSchedulerService - Enhanced startup logging to show active and skipped modules with detailed reasons
1 parent 71b9b23 commit e7cb5a1

File tree

7 files changed

+261
-34
lines changed

7 files changed

+261
-34
lines changed

goonj/src/main/java/org/avni_integration_service/goonj/config/GoonjConfig.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public boolean getAuthEnabled() {
6464
}
6565

6666
public String getTasks() {
67-
return getStringConfigValue("int_tasks", "all");
67+
return getStringConfigValue("int_tasks", "none");
6868
}
6969

7070
public boolean getDeleteAndRecreateDispatchReceipt() {
@@ -80,4 +80,13 @@ public boolean getBypassErrors() {
8080
public String getS3Url(){
8181
return getStringConfigValue("avni_s3_url_prefix","dummy");
8282
}
83+
84+
/**
85+
* Gets the integration environment from DB config.
86+
* This should match the environment where the integration service is running.
87+
* @return environment string (e.g., "prod", "staging", "prerelease")
88+
*/
89+
public String getEnvironment() {
90+
return getStringConfigValue("int_env", null);
91+
}
8392
}

integrator/src/main/java/org/avni_integration_service/scheduler/AdhocTaskSchedulerService.java

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.avni_integration_service.integration_data.repository.IntegrationSystemRepository;
1414
import org.avni_integration_service.integration_data.repository.config.IntegrationSystemConfigRepository;
1515
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.beans.factory.annotation.Value;
1617
import org.springframework.scheduling.TaskScheduler;
1718
import org.springframework.scheduling.annotation.EnableScheduling;
1819
import org.springframework.stereotype.Service;
@@ -31,6 +32,9 @@ public class AdhocTaskSchedulerService {
3132
private final IntegrationSystemRepository integrationSystemRepository;
3233
private final AvniGoonjAdhocJob avniGoonjAdhocJob;
3334
private final GoonjAdhocTaskRepository goonjAdhocTaskRepository;
35+
@Value("${avni.int.env:#{null}}")
36+
private String currentEnvironment;
37+
3438
@Autowired
3539
public AdhocTaskSchedulerService(TaskScheduler taskScheduler, IntegrationSystemConfigRepository integrationSystemConfigRepository, IntegrationSystemRepository integrationSystemRepository, AvniGoonjAdhocJob avniGoonjAdhocJob, GoonjAdhocTaskRepository goonjAdhocTaskRepository) {
3640
this.taskScheduler = taskScheduler;
@@ -40,15 +44,33 @@ public AdhocTaskSchedulerService(TaskScheduler taskScheduler, IntegrationSystemC
4044
this.goonjAdhocTaskRepository = goonjAdhocTaskRepository;
4145
}
4246

43-
public void schedule(GoonjAdhocTask goonjAdhocTask){
44-
logger.info(String.format("scheduling start %s for %s",goonjAdhocTask.getIntegrationTask(),goonjAdhocTask.getUuid()));
47+
public void schedule(GoonjAdhocTask goonjAdhocTask, IntegrationSystem integrationSystem) {
48+
logger.info(String.format("scheduling start %s for %s (system: %s)",
49+
goonjAdhocTask.getIntegrationTask(), goonjAdhocTask.getUuid(), integrationSystem.getName()));
50+
51+
// Validate that the provided integration system is of type Goonj
52+
if (!IntegrationSystem.IntegrationSystemType.Goonj.equals(integrationSystem.getSystemType())) {
53+
logger.error(String.format("Goonj adhoc task SKIPPED: Invalid system type. Expected: Goonj, Actual: %s",
54+
integrationSystem.getSystemType()));
55+
goonjAdhocTask.setGoonjAdhocTaskSatus(GoonjAdhocTaskSatus.ERROR);
56+
goonjAdhocTaskRepository.save(goonjAdhocTask);
57+
return;
58+
}
59+
60+
GoonjConfig goonjConfig = getGoonjConfig(integrationSystem);
61+
62+
if (!isGoonjEnvironmentValid(goonjConfig)) {
63+
goonjAdhocTask.setGoonjAdhocTaskSatus(GoonjAdhocTaskSatus.ERROR);
64+
goonjAdhocTaskRepository.save(goonjAdhocTask);
65+
return;
66+
}
67+
4568
IntegrationTask integrationTask = goonjAdhocTask.getIntegrationTask();
4669
Map<String, Object> taskConfig = goonjAdhocTask.getTaskConfig();
4770
Map<String, Object> filters = getFilters(goonjAdhocTask, taskConfig);
48-
GoonjConfig goonjConfig = getGoonjConfig();
4971
taskScheduler.schedule(() -> {
5072
try {
51-
logger.info(String.format("running start for %s ", goonjAdhocTask));
73+
logger.info(String.format("running start for %s (system: %s)", goonjAdhocTask, integrationSystem.getName()));
5274
avniGoonjAdhocJob.execute(goonjConfig, integrationTask, filters);
5375
goonjAdhocTask.setGoonjAdhocTaskSatus(GoonjAdhocTaskSatus.COMPLETED);
5476
} catch (Exception e) {
@@ -60,11 +82,9 @@ public void schedule(GoonjAdhocTask goonjAdhocTask){
6082
}, goonjAdhocTask.getTriggerDateTime());
6183
}
6284

63-
private GoonjConfig getGoonjConfig() {
64-
List<IntegrationSystem> goonjSystems = integrationSystemRepository.findAllBySystemType(IntegrationSystem.IntegrationSystemType.Goonj);
65-
IntegrationSystem goonjSystem = goonjSystems.stream().findFirst().get();
66-
IntegrationSystemConfigCollection integrationSystemConfigs = integrationSystemConfigRepository.getInstanceConfiguration(goonjSystem);
67-
return new GoonjConfig(integrationSystemConfigs, goonjSystem);
85+
private GoonjConfig getGoonjConfig(IntegrationSystem integrationSystem) {
86+
IntegrationSystemConfigCollection integrationSystemConfigs = integrationSystemConfigRepository.getInstanceConfiguration(integrationSystem);
87+
return new GoonjConfig(integrationSystemConfigs, integrationSystem);
6888
}
6989

7090
private Map<String,Object> getFilters(GoonjAdhocTask goonjAdhocTask, Map<String, Object> taskConfig) {
@@ -76,4 +96,29 @@ private Map<String,Object> getFilters(GoonjAdhocTask goonjAdhocTask, Map<String,
7696
return filters;
7797
}
7898

99+
private boolean isGoonjEnvironmentValid(GoonjConfig goonjConfig) {
100+
String dbEnvironment = goonjConfig.getEnvironment();
101+
102+
if (currentEnvironment == null || currentEnvironment.isBlank()) {
103+
logger.warn("Goonj adhoc task SKIPPED: avni.int.env property not set. " +
104+
"Set this property to match the DB config int_env to enable Goonj integration.");
105+
return false;
106+
}
107+
108+
if (dbEnvironment == null || dbEnvironment.isBlank()) {
109+
logger.warn("Goonj adhoc task SKIPPED: int_env not configured in DB. " +
110+
"Configure int_env in integration_system_config table to enable Goonj integration.");
111+
return false;
112+
}
113+
114+
if (!currentEnvironment.equals(dbEnvironment)) {
115+
logger.error(String.format("Goonj adhoc task SKIPPED: Environment mismatch detected! " +
116+
"Current environment (from env): '%s', DB config environment: '%s'. " +
117+
"This likely indicates a non-prod environment using prod DB config.",
118+
currentEnvironment, dbEnvironment));
119+
return false;
120+
}
121+
122+
return true;
123+
}
79124
}

integrator/src/main/java/org/avni_integration_service/scheduler/IntegrationJobScheduler.java

Lines changed: 162 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@
2424
import org.springframework.scheduling.support.CronTrigger;
2525
import org.springframework.stereotype.Component;
2626

27+
import org.apache.log4j.Logger;
28+
2729
import javax.annotation.PostConstruct;
30+
import java.util.ArrayList;
2831
import java.util.List;
2932

3033
@Component
3134
@EnableScheduling
3235
@ConditionalOnProperty(value = "avni.int.auto.close", havingValue = "false")
3336
public class IntegrationJobScheduler {
37+
private static final Logger logger = Logger.getLogger(IntegrationJobScheduler.class);
38+
3439
private final AvniGoonjMainJob avniGoonjMainJob;
3540
private final AvniGoonjFullErrorJob avniGoonjFullErrorJob;
3641
private final AvniPowerMainJob avniPowerMainJob;
@@ -56,6 +61,8 @@ public class IntegrationJobScheduler {
5661
private String amritCron;
5762
@Value("${amrit.app.cron.full.error}")
5863
private String amritCronError;
64+
@Value("${avni.int.env:#{null}}")
65+
private String currentEnvironment;
5966

6067
@Autowired
6168
public IntegrationJobScheduler(AvniGoonjMainJob avniGoonjMainJob, AvniGoonjFullErrorJob avniGoonjFullErrorJob,
@@ -80,55 +87,188 @@ public IntegrationJobScheduler(AvniGoonjMainJob avniGoonjMainJob, AvniGoonjFullE
8087

8188
@PostConstruct
8289
public void scheduleAll() {
83-
schedulePower();
84-
scheduleLahi();
85-
scheduleRwb();
86-
scheduleAmrit();
87-
scheduleGoonj();
90+
logger.info("========== INTEGRATION SERVICE STARTUP - SCHEDULING JOBS ==========");
91+
List<String> activeModules = new ArrayList<>();
92+
List<String> skippedModules = new ArrayList<>();
93+
94+
if (schedulePower()) activeModules.add("Power"); else skippedModules.add("Power");
95+
if (scheduleLahi()) activeModules.add("Lahi"); else skippedModules.add("Lahi");
96+
if (scheduleRwb()) activeModules.add("RWB"); else skippedModules.add("RWB");
97+
if (scheduleAmrit()) activeModules.add("Amrit"); else skippedModules.add("Amrit");
98+
if (scheduleGoonj()) activeModules.add("Goonj"); else skippedModules.add("Goonj");
99+
100+
logStartupSummary(activeModules, skippedModules);
101+
}
102+
103+
private void logStartupSummary(List<String> activeModules, List<String> skippedModules) {
104+
logger.info("========== INTEGRATION SERVICE STARTUP SUMMARY ==========");
105+
logger.info(String.format("Active modules (%d): %s", activeModules.size(),
106+
activeModules.isEmpty() ? "NONE" : String.join(", ", activeModules)));
107+
logger.info(String.format("Skipped modules (%d): %s", skippedModules.size(),
108+
skippedModules.isEmpty() ? "NONE" : String.join(", ", skippedModules)));
109+
logger.info("==========================================================");
88110
}
89111

90-
private void scheduleGoonj() {
112+
private boolean scheduleGoonj() {
113+
logger.info("--- Goonj Module ---");
91114
List<IntegrationSystem> goonjSystems = integrationSystemRepository.findAllBySystemType(IntegrationSystem.IntegrationSystemType.Goonj);
92-
goonjSystems.forEach(goonjSystem -> {
115+
if (goonjSystems.isEmpty()) {
116+
logger.info("Goonj: No integration systems found in DB");
117+
return false;
118+
}
119+
120+
boolean anyScheduled = false;
121+
for (IntegrationSystem goonjSystem : goonjSystems) {
93122
IntegrationSystemConfigCollection integrationSystemConfigs = integrationSystemConfigRepository.getInstanceConfiguration(goonjSystem);
94123
GoonjConfig goonjConfig = new GoonjConfig(integrationSystemConfigs, goonjSystem);
124+
125+
if (!validateEnvironment(goonjSystem.getName(), goonjConfig.getEnvironment())) {
126+
continue;
127+
}
128+
95129
String mainScheduledJobCron = integrationSystemConfigs.getMainScheduledJobCron();
96130
String errorScheduledJobCron = integrationSystemConfigs.getErrorScheduledJobCron();
131+
String tasks = goonjConfig.getTasks();
132+
133+
logger.info(String.format("Goonj [%s]: Scheduling jobs - mainCron: %s, errorCron: %s, tasks: %s",
134+
goonjSystem.getName(), mainScheduledJobCron, errorScheduledJobCron, tasks));
97135

98-
if (CronExpression.isValidExpression(mainScheduledJobCron))
136+
if (CronExpression.isValidExpression(mainScheduledJobCron)) {
99137
taskScheduler.schedule(() -> avniGoonjMainJob.execute(goonjConfig), new CronTrigger(mainScheduledJobCron));
138+
logger.info(String.format("Goonj [%s]: Main job SCHEDULED with cron: %s", goonjSystem.getName(), mainScheduledJobCron));
139+
anyScheduled = true;
140+
} else {
141+
logger.info(String.format("Goonj [%s]: Main job SKIPPED - invalid cron: %s", goonjSystem.getName(), mainScheduledJobCron));
142+
}
100143

101-
if (CronExpression.isValidExpression(errorScheduledJobCron))
144+
if (CronExpression.isValidExpression(errorScheduledJobCron)) {
102145
taskScheduler.schedule(() -> avniGoonjFullErrorJob.execute(goonjConfig), new CronTrigger(errorScheduledJobCron));
103-
});
146+
logger.info(String.format("Goonj [%s]: Error job SCHEDULED with cron: %s", goonjSystem.getName(), errorScheduledJobCron));
147+
anyScheduled = true;
148+
} else {
149+
logger.info(String.format("Goonj [%s]: Error job SKIPPED - invalid cron: %s", goonjSystem.getName(), errorScheduledJobCron));
150+
}
151+
}
152+
return anyScheduled;
104153
}
105154

106-
private void scheduleAmrit() {
107-
if (CronExpression.isValidExpression(amritCron)) taskScheduler.schedule(avniAmritMainJob::execute, new CronTrigger(amritCron));
108-
if (CronExpression.isValidExpression(amritCronError)) taskScheduler.schedule(avniAmritFullErrorJob::execute, new CronTrigger(amritCronError));
155+
private boolean validateEnvironment(String systemName, String dbEnv) {
156+
if (currentEnvironment == null || currentEnvironment.isBlank()) {
157+
logger.warn(String.format("%s integration SKIPPED: avni.int.env property not set. " +
158+
"Set this property to match the DB config int_env to enable integration.", systemName));
159+
return false;
160+
}
161+
162+
if (dbEnv == null || dbEnv.isBlank()) {
163+
logger.warn(String.format("%s integration SKIPPED: int_env not configured in DB. " +
164+
"Configure int_env in integration_system_config table to enable integration.", systemName));
165+
return false;
166+
}
167+
168+
if (!currentEnvironment.equals(dbEnv)) {
169+
logger.error(String.format("%s integration SKIPPED: Environment mismatch detected! " +
170+
"Current environment (from env): '%s', DB config environment: '%s'. " +
171+
"This likely indicates a non-prod environment using prod DB config. " +
172+
"Either update the avni.int.env property or clean up the DB integration config.",
173+
systemName, currentEnvironment, dbEnv));
174+
return false;
175+
}
176+
177+
logger.info(String.format("%s environment validation passed. Environment: %s", systemName, currentEnvironment));
178+
return true;
109179
}
110180

111-
private void scheduleLahi() {
112-
if (CronExpression.isValidExpression(lahiCron)) taskScheduler.schedule(avniLahiMainJob::execute, new CronTrigger(lahiCron));
113-
if (CronExpression.isValidExpression(lahiCronError)) taskScheduler.schedule(avniLahiFullErrorJob::execute, new CronTrigger(lahiCronError));
181+
private boolean isRwbEnvironmentValid(RwbConfig rwbConfig) {
182+
return validateEnvironment(rwbConfig.getIntegrationSystem().getName(), rwbConfig.getEnvironment());
114183
}
115184

116-
private void schedulePower() {
117-
if (CronExpression.isValidExpression(powerCron)) taskScheduler.schedule(avniPowerMainJob::execute, new CronTrigger(powerCron));
118-
if (CronExpression.isValidExpression(powerCronError)) taskScheduler.schedule(avniPowerFullErrorJob::execute, new CronTrigger(powerCronError));
185+
private boolean scheduleAmrit() {
186+
logger.info("--- Amrit Module ---");
187+
boolean scheduled = false;
188+
if (CronExpression.isValidExpression(amritCron)) {
189+
taskScheduler.schedule(avniAmritMainJob::execute, new CronTrigger(amritCron));
190+
logger.info(String.format("Amrit: Main job SCHEDULED with cron: %s", amritCron));
191+
scheduled = true;
192+
} else {
193+
logger.info(String.format("Amrit: Main job SKIPPED - invalid cron: %s", amritCron));
194+
}
195+
if (CronExpression.isValidExpression(amritCronError)) {
196+
taskScheduler.schedule(avniAmritFullErrorJob::execute, new CronTrigger(amritCronError));
197+
logger.info(String.format("Amrit: Error job SCHEDULED with cron: %s", amritCronError));
198+
scheduled = true;
199+
} else {
200+
logger.info(String.format("Amrit: Error job SKIPPED - invalid cron: %s", amritCronError));
201+
}
202+
return scheduled;
119203
}
120204

205+
private boolean scheduleLahi() {
206+
logger.info("--- Lahi Module ---");
207+
boolean scheduled = false;
208+
if (CronExpression.isValidExpression(lahiCron)) {
209+
taskScheduler.schedule(avniLahiMainJob::execute, new CronTrigger(lahiCron));
210+
logger.info(String.format("Lahi: Main job SCHEDULED with cron: %s", lahiCron));
211+
scheduled = true;
212+
} else {
213+
logger.info(String.format("Lahi: Main job SKIPPED - invalid cron: %s", lahiCron));
214+
}
215+
if (CronExpression.isValidExpression(lahiCronError)) {
216+
taskScheduler.schedule(avniLahiFullErrorJob::execute, new CronTrigger(lahiCronError));
217+
logger.info(String.format("Lahi: Error job SCHEDULED with cron: %s", lahiCronError));
218+
scheduled = true;
219+
} else {
220+
logger.info(String.format("Lahi: Error job SKIPPED - invalid cron: %s", lahiCronError));
221+
}
222+
return scheduled;
223+
}
121224

122-
private void scheduleRwb() {
225+
private boolean schedulePower() {
226+
logger.info("--- Power Module ---");
227+
boolean scheduled = false;
228+
if (CronExpression.isValidExpression(powerCron)) {
229+
taskScheduler.schedule(avniPowerMainJob::execute, new CronTrigger(powerCron));
230+
logger.info(String.format("Power: Main job SCHEDULED with cron: %s", powerCron));
231+
scheduled = true;
232+
} else {
233+
logger.info(String.format("Power: Main job SKIPPED - invalid cron: %s", powerCron));
234+
}
235+
if (CronExpression.isValidExpression(powerCronError)) {
236+
taskScheduler.schedule(avniPowerFullErrorJob::execute, new CronTrigger(powerCronError));
237+
logger.info(String.format("Power: Error job SCHEDULED with cron: %s", powerCronError));
238+
scheduled = true;
239+
} else {
240+
logger.info(String.format("Power: Error job SKIPPED - invalid cron: %s", powerCronError));
241+
}
242+
return scheduled;
243+
}
244+
245+
private boolean scheduleRwb() {
246+
logger.info("--- RWB Module ---");
123247
List<IntegrationSystem> rwbSystems = integrationSystemRepository.findAllBySystemType(IntegrationSystem.IntegrationSystemType.rwb);
124-
rwbSystems.forEach(rwbSystem -> {
248+
if (rwbSystems.isEmpty()) {
249+
logger.info("RWB: No integration systems found in DB");
250+
return false;
251+
}
252+
253+
boolean anyScheduled = false;
254+
for (IntegrationSystem rwbSystem : rwbSystems) {
125255
IntegrationSystemConfigCollection integrationSystemConfigs = integrationSystemConfigRepository.getInstanceConfiguration(rwbSystem);
126256
RwbConfig rwbConfig = new RwbConfig(integrationSystemConfigs, rwbSystem);
257+
258+
if (!isRwbEnvironmentValid(rwbConfig)) {
259+
continue;
260+
}
261+
127262
String rwbCron = integrationSystemConfigs.getMainScheduledJobCron();
128263

129264
if (CronExpression.isValidExpression(rwbCron)) {
130265
taskScheduler.schedule(() -> avniRwbMainJob.execute(rwbConfig), new CronTrigger(rwbCron));
266+
logger.info(String.format("RWB [%s]: Main job SCHEDULED with cron: %s", rwbSystem.getName(), rwbCron));
267+
anyScheduled = true;
268+
} else {
269+
logger.info(String.format("RWB [%s]: Main job SKIPPED - invalid cron: %s", rwbSystem.getName(), rwbCron));
131270
}
132-
});
271+
}
272+
return anyScheduled;
133273
}
134274
}

0 commit comments

Comments
 (0)