Skip to content

Commit 7925410

Browse files
authored
Merge branch 'dev' into dev-datavines
2 parents 57a3efd + 008e6e5 commit 7925410

File tree

11 files changed

+519
-0
lines changed

11 files changed

+519
-0
lines changed

docs/docs/en/contribute/join/security-model.md

+4
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,8 @@ The following are some erroneous vulnerabilities raised by users and developers
8787
There are multiple input boxes in Apache DolphinScheduler, allowing users to customize configurations as needed. As an open source task scheduling system, Apache DolphinScheduler requires administrators to fully trust all authorized operations of the target user in the process of deployment, authorization, and other security-related processes. If the user's behavior of adding and modifying configurations through pages or calling interfaces is within the scope of permissions, then the behavior of attacking or other operations in this way does not belong to security vulnerabilities.
8888
5. Attack or other operations by modifying the image or providing an unsafe image to run
8989
Apache DolphinScheduler itself and task operations both support k8s clusters. Before the service or task runs, the user needs to ensure the image's functions and configured parameters, and trust all operations during the service and task running process. Therefore, modifying tasks or parameters by any means before the image runs to attack or complete other operations does not constitute a security vulnerability.
90+
6. Attacks by obtaining certain sensitive information printed in service logs
91+
Apache DolphinScheduler prints some sensitive information in its service logs, which can be used by service deployers to view detailed information about the program's operation. Service deployers are considered trusted users, and we do not believe that service deployers will attack the program, so this type of issue is not a vulnerability.
92+
7. Security problems caused by system administrators accessing untrusted third-party websites
93+
System administrators using Apache DolphinScheduler may access untrusted third-party websites, resulting in system attacks; such issues are not considered security vulnerabilities. System administrators are considered to be trusted users, and we believe that system administrators have a basic awareness of security precautions. Problems caused by weak security precautions on the part of system administrators are not considered vulnerabilities.
9094

docs/docs/zh/contribute/join/security-model.md

+4
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,7 @@ Apache DolphinScheduler的部署和使用认为用户网络是安全和值得信
8585
在Apache DolphinScheduler有多个输入框,允许用户按需进行自定义配置,Apache DolphinScheduler作为开源任务调度系统,管理员用户在部署、授权等涉及安全的过程中需要完全信任目标用户的所有授权范围内的操作,用户通过页面或调用接口增加、修改配置的行为如果属于权限范围内的操作,则通过该方式进行攻击或其他操作的行为不属于安全漏洞。
8686
5.通过修改镜像或提供不安全的镜像运行进行攻击或其他操作
8787
Apache DolphinScheduler的本身和任务运行均支持k8s集群,在服务或任务运行之前,用户需要确保镜像的功能和所配置参数,信任服务、任务运行过程中的所有操作。所以在镜像运行之前通过任何途径将任务或参数进行修改进行攻击或其他完成其他操作的行为不属于安全漏洞。
88+
6.通过获取服务日志中打印的某些敏感信息进行攻击
89+
Apache DolphinScheduler的服务日志中会打印部分敏感信息,服务部署人员可以通过日志查看程序运行的详细信息。服务部署人员被认为是可信任的用户,我们认为服务部署人员不会攻击程序,所以该类型问题不属于漏洞。
90+
7.系统管理员通过访问不受信任的三方网站导致的安全问题
91+
系统管理员在使用Apache DolphinScheduler的过程中,可能会访问不受信任的三方网站,导致系统被攻击,这种问题不属于安全漏洞。系统管理员被认为是可信任的用户,我们认为系统管理员具备基本的安全防范意识,由于系统管理员的安全防范意识薄弱所引发的问题不属于漏洞。

dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/command/handler/RecoverFailureTaskCommandHandler.java

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.dolphinscheduler.dao.repository.TaskInstanceDao;
2626
import org.apache.dolphinscheduler.dao.repository.WorkflowInstanceDao;
2727
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
28+
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
2829
import org.apache.dolphinscheduler.server.master.engine.graph.IWorkflowGraph;
2930
import org.apache.dolphinscheduler.server.master.engine.graph.WorkflowExecutionGraph;
3031
import org.apache.dolphinscheduler.server.master.engine.graph.WorkflowGraphTopologyLogicalVisitor;
@@ -67,6 +68,9 @@ public class RecoverFailureTaskCommandHandler extends AbstractCommandHandler {
6768
@Autowired
6869
private TaskInstanceFactories taskInstanceFactories;
6970

71+
@Autowired
72+
private MasterConfig masterConfig;
73+
7074
/**
7175
* Generate the recover workflow instance.
7276
* <p> Will use the origin workflow instance, but will update the following fields. Need to note we cannot not
@@ -90,6 +94,7 @@ protected void assembleWorkflowInstance(
9094
workflowInstance.setVarPool(null);
9195
workflowInstance.setStateWithDesc(WorkflowExecutionStatus.RUNNING_EXECUTION, command.getCommandType().name());
9296
workflowInstance.setCommandType(command.getCommandType());
97+
workflowInstance.setHost(masterConfig.getMasterAddress());
9398
workflowInstanceDao.updateById(workflowInstance);
9499

95100
workflowExecuteContextBuilder.setWorkflowInstance(workflowInstance);

dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/command/handler/WorkflowFailoverCommandHandler.java

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.dolphinscheduler.dao.entity.WorkflowInstance;
2525
import org.apache.dolphinscheduler.dao.repository.WorkflowInstanceDao;
2626
import org.apache.dolphinscheduler.extract.master.command.WorkflowFailoverCommandParam;
27+
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
2728
import org.apache.dolphinscheduler.server.master.engine.ITaskGroupCoordinator;
2829
import org.apache.dolphinscheduler.server.master.engine.graph.IWorkflowGraph;
2930
import org.apache.dolphinscheduler.server.master.engine.graph.WorkflowExecutionGraph;
@@ -58,6 +59,9 @@ public class WorkflowFailoverCommandHandler extends AbstractCommandHandler {
5859
@Autowired
5960
private ApplicationContext applicationContext;
6061

62+
@Autowired
63+
private MasterConfig masterConfig;
64+
6165
/**
6266
* Generate the recover workflow instance.
6367
* <p> Will use the origin workflow instance, but will update the following fields. Need to note we cannot not
@@ -86,6 +90,7 @@ protected void assembleWorkflowInstance(
8690
"The WorkflowFailoverCommandParam: " + command.getCommandParam() + " is invalid");
8791
}
8892
workflowInstance.setState(workflowFailoverCommandParam.getWorkflowExecutionStatus());
93+
workflowInstance.setHost(masterConfig.getMasterAddress());
8994
workflowInstanceDao.updateById(workflowInstance);
9095

9196
workflowExecuteContextBuilder.setWorkflowInstance(workflowInstance);

dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/AbstractMasterIntegrationTestCase.java

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
package org.apache.dolphinscheduler.server.master;
1919

2020
import org.apache.dolphinscheduler.dao.DaoConfiguration;
21+
import org.apache.dolphinscheduler.registry.api.RegistryClient;
22+
import org.apache.dolphinscheduler.server.master.config.MasterConfig;
2123
import org.apache.dolphinscheduler.server.master.integration.MasterContainer;
2224
import org.apache.dolphinscheduler.server.master.integration.Repository;
2325
import org.apache.dolphinscheduler.server.master.integration.WorkflowOperator;
@@ -52,4 +54,10 @@ public abstract class AbstractMasterIntegrationTestCase {
5254

5355
@Autowired
5456
protected MasterContainer masterContainer;
57+
58+
@Autowired
59+
protected RegistryClient registryClient;
60+
61+
@Autowired
62+
protected MasterConfig masterConfig;
5563
}

dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceFailoverTestCase.java

+60
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@
2424
import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus;
2525
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
2626
import org.apache.dolphinscheduler.dao.entity.WorkflowDefinition;
27+
import org.apache.dolphinscheduler.extract.base.client.Clients;
28+
import org.apache.dolphinscheduler.extract.master.IWorkflowControlClient;
29+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopRequest;
30+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopResponse;
2731
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
32+
import org.apache.dolphinscheduler.registry.api.utils.RegistryUtils;
2833
import org.apache.dolphinscheduler.server.master.AbstractMasterIntegrationTestCase;
2934
import org.apache.dolphinscheduler.server.master.engine.system.SystemEventBus;
3035
import org.apache.dolphinscheduler.server.master.engine.system.event.GlobalMasterFailoverEvent;
@@ -555,4 +560,59 @@ public void testGlobalFailover_readyStopWorkflow_withKilledTasks() {
555560
masterContainer.assertAllResourceReleased();
556561
}
557562

563+
@Test
564+
public void testGlobalFailover_runningWorkflow_fromAnotherMaster() {
565+
final String yaml = "/it/failover/running_workflowInstance_from_another_master.yaml";
566+
final WorkflowTestCaseContext context = workflowTestCaseContextFactory.initializeContextFromYaml(yaml);
567+
final WorkflowDefinition workflow = context.getOneWorkflow();
568+
569+
systemEventBus.publish(GlobalMasterFailoverEvent.of(new Date()));
570+
571+
final String masterFailoverNodePath = RegistryUtils.getFailoveredNodePathWhichStartupTimeIsUnknown(
572+
"127.0.0.1:15678");
573+
// wait failover process
574+
await()
575+
.atMost(Duration.ofMinutes(3))
576+
.untilAsserted(() -> {
577+
assertThat(registryClient.exists(masterFailoverNodePath)).isTrue();
578+
});
579+
580+
// check workflow's status and can stop it
581+
await()
582+
.atMost(Duration.ofMinutes(1))
583+
.untilAsserted(() -> {
584+
assertThat(repository.queryWorkflowInstance(workflow))
585+
.hasSize(1)
586+
.anySatisfy(workflowInstance -> {
587+
assertThat(workflowInstance.getState())
588+
.isEqualTo(WorkflowExecutionStatus.RUNNING_EXECUTION);
589+
assertThat(workflowInstance.getName())
590+
.isEqualTo("workflow_with_one_fake_task_running-20250322201900000");
591+
592+
final WorkflowInstanceStopResponse stopResponse = Clients
593+
.withService(IWorkflowControlClient.class)
594+
.withHost(workflowInstance.getHost())
595+
.stopWorkflowInstance(
596+
new WorkflowInstanceStopRequest(workflowInstance.getId()));
597+
598+
assertThat((stopResponse != null && stopResponse.isSuccess())).isTrue();
599+
});
600+
});
601+
602+
await()
603+
.atMost(Duration.ofMinutes(1))
604+
.untilAsserted(() -> {
605+
assertThat(repository.queryWorkflowInstance(workflow))
606+
.hasSize(1)
607+
.anySatisfy(workflowInstance -> {
608+
assertThat(workflowInstance.getState())
609+
.isEqualTo(WorkflowExecutionStatus.STOP);
610+
assertThat(workflowInstance.getName())
611+
.isEqualTo("workflow_with_one_fake_task_running-20250322201900000");
612+
});
613+
});
614+
615+
masterContainer.assertAllResourceReleased();
616+
617+
}
558618
}

dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceRecoverFailureTaskTestCase.java

+51
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
import org.apache.dolphinscheduler.common.enums.Flag;
2424
import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus;
2525
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
26+
import org.apache.dolphinscheduler.dao.entity.WorkflowDefinition;
2627
import org.apache.dolphinscheduler.dao.entity.WorkflowInstance;
28+
import org.apache.dolphinscheduler.extract.base.client.Clients;
29+
import org.apache.dolphinscheduler.extract.master.IWorkflowControlClient;
30+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopRequest;
31+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopResponse;
2732
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
2833
import org.apache.dolphinscheduler.server.master.AbstractMasterIntegrationTestCase;
2934
import org.apache.dolphinscheduler.server.master.integration.WorkflowTestCaseContext;
@@ -89,4 +94,50 @@ public void testRepeatRunningWorkflow_with_taskOnly() {
8994
masterContainer.assertAllResourceReleased();
9095
}
9196

97+
@Test
98+
@DisplayName("Test recover a failure workflow from another master")
99+
public void testRecoverFailureWorkflow_from_another_master() {
100+
final String yaml = "/it/recover_failure_tasks/failure_workflow_from_another_master.yaml";
101+
final WorkflowTestCaseContext context = workflowTestCaseContextFactory.initializeContextFromYaml(yaml);
102+
final WorkflowDefinition workflow = context.getOneWorkflow();
103+
104+
final Integer workflowInstanceId = context.getWorkflowInstance().getId();
105+
workflowOperator.recoverFailureTasks(workflowInstanceId);
106+
107+
await()
108+
.atMost(Duration.ofMinutes(1))
109+
.untilAsserted(() -> {
110+
assertThat(repository.queryWorkflowInstance(workflow))
111+
.hasSize(1)
112+
.anySatisfy(workflowInstance -> {
113+
assertThat(workflowInstance.getState())
114+
.isEqualTo(WorkflowExecutionStatus.RUNNING_EXECUTION);
115+
assertThat(workflowInstance.getName())
116+
.isEqualTo("workflow_with_one_fake_task_killed-20250322201900000");
117+
118+
final WorkflowInstanceStopResponse stopResponse = Clients
119+
.withService(IWorkflowControlClient.class)
120+
.withHost(workflowInstance.getHost())
121+
.stopWorkflowInstance(
122+
new WorkflowInstanceStopRequest(workflowInstance.getId()));
123+
124+
assertThat(stopResponse != null && stopResponse.isSuccess()).isTrue();
125+
});
126+
});
127+
128+
await()
129+
.atMost(Duration.ofMinutes(1))
130+
.untilAsserted(() -> {
131+
assertThat(repository.queryWorkflowInstance(workflow))
132+
.hasSize(1)
133+
.anySatisfy(workflowInstance -> {
134+
assertThat(workflowInstance.getState())
135+
.isEqualTo(WorkflowExecutionStatus.STOP);
136+
assertThat(workflowInstance.getName())
137+
.isEqualTo("workflow_with_one_fake_task_killed-20250322201900000");
138+
});
139+
});
140+
141+
masterContainer.assertAllResourceReleased();
142+
}
92143
}

dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/integration/cases/WorkflowInstanceRecoverStopTestCase.java

+50
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424
import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus;
2525
import org.apache.dolphinscheduler.dao.entity.WorkflowDefinition;
2626
import org.apache.dolphinscheduler.dao.entity.WorkflowInstance;
27+
import org.apache.dolphinscheduler.extract.base.client.Clients;
28+
import org.apache.dolphinscheduler.extract.master.IWorkflowControlClient;
2729
import org.apache.dolphinscheduler.extract.master.command.RunWorkflowCommandParam;
30+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopRequest;
31+
import org.apache.dolphinscheduler.extract.master.transportor.workflow.WorkflowInstanceStopResponse;
2832
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
2933
import org.apache.dolphinscheduler.server.master.AbstractMasterIntegrationTestCase;
3034
import org.apache.dolphinscheduler.server.master.integration.WorkflowOperator;
@@ -121,4 +125,50 @@ public void testRecoverStoppedWorkflow_with_subWorkflowTask_success() {
121125
masterContainer.assertAllResourceReleased();
122126
}
123127

128+
@Test
129+
@DisplayName("Test recover a stopped workflow from another master")
130+
public void testRecoverStoppedWorkflow_from_another_master() {
131+
final String yaml = "/it/recover_stopped/stopped_workflow_from_another_master.yaml";
132+
final WorkflowTestCaseContext context = workflowTestCaseContextFactory.initializeContextFromYaml(yaml);
133+
final WorkflowDefinition workflow = context.getOneWorkflow();
134+
135+
final Integer workflowInstanceId = context.getWorkflowInstance().getId();
136+
assertThat(workflowOperator.recoverSuspendWorkflowInstance(workflowInstanceId).isSuccess()).isTrue();
137+
138+
await()
139+
.atMost(Duration.ofMinutes(1))
140+
.untilAsserted(() -> {
141+
assertThat(repository.queryWorkflowInstance(workflow))
142+
.hasSize(1)
143+
.anySatisfy(workflowInstance -> {
144+
assertThat(workflowInstance.getState())
145+
.isEqualTo(WorkflowExecutionStatus.RUNNING_EXECUTION);
146+
assertThat(workflowInstance.getName())
147+
.isEqualTo("workflow_with_one_fake_task_killed-20250322201900000");
148+
149+
final WorkflowInstanceStopResponse stopResponse = Clients
150+
.withService(IWorkflowControlClient.class)
151+
.withHost(workflowInstance.getHost())
152+
.stopWorkflowInstance(
153+
new WorkflowInstanceStopRequest(workflowInstance.getId()));
154+
155+
assertThat(stopResponse != null && stopResponse.isSuccess()).isTrue();
156+
});
157+
});
158+
159+
await()
160+
.atMost(Duration.ofMinutes(1))
161+
.untilAsserted(() -> {
162+
assertThat(repository.queryWorkflowInstance(workflow))
163+
.hasSize(1)
164+
.anySatisfy(workflowInstance -> {
165+
assertThat(workflowInstance.getState())
166+
.isEqualTo(WorkflowExecutionStatus.STOP);
167+
assertThat(workflowInstance.getName())
168+
.isEqualTo("workflow_with_one_fake_task_killed-20250322201900000");
169+
});
170+
});
171+
172+
masterContainer.assertAllResourceReleased();
173+
}
124174
}

0 commit comments

Comments
 (0)