Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -112,6 +113,7 @@ public class WorkflowApplication implements AutoCloseable {
private final AllStrategyCorrelationInfoFactory allStrategyCorrelationInfoFactory;
private final WorkflowLifeCycleCloudEventFactory lifeCycleCloudEventFactory;
private final ScheduledExecutorService schedulerExecutorService;
private final Set<String> allowedCommands;

private WorkflowApplication(Builder builder) {
this.taskFactory = builder.taskFactory;
Expand Down Expand Up @@ -147,6 +149,7 @@ private WorkflowApplication(Builder builder) {
this.allStrategyCorrelationInfoFactory = builder.allStrategyCorrelationInfoFactory;
this.lifeCycleCloudEventFactory = builder.lifeCycleCloudEventFactory;
this.schedulerExecutorService = builder.schedulerExecutorService;
this.allowedCommands = Collections.unmodifiableSet(builder.allowedCommands);
}

public TaskExecutorFactory taskFactory() {
Expand Down Expand Up @@ -274,6 +277,7 @@ public SchemaValidator getValidator(SchemaInline inline) {
private WorkflowLifeCycleCloudEventFactory lifeCycleCloudEventFactory;
private CronResolverFactory cronResolverFactory;
private ScheduledExecutorService schedulerExecutorService;
private Set<String> allowedCommands = new HashSet<>();

private Builder() {
ServiceLoader.load(NamedWorkflowAdditionalObject.class)
Expand Down Expand Up @@ -396,6 +400,16 @@ public Builder withModelFactory(WorkflowModelFactory modelFactory) {
return this;
}

public Builder withAllowedCommand(String command) {
this.allowedCommands.add(command);
return this;
}

public Builder withAllowedCommands(Collection<String> commands) {
this.allowedCommands.addAll(commands);
return this;
}

public Builder withContextFactory(WorkflowModelFactory contextFactory) {
this.contextFactory = contextFactory;
return this;
Expand Down Expand Up @@ -690,4 +704,8 @@ public AllStrategyCorrelationInfoFactory allStrategyCorrelationInfoFactory() {
public WorkflowLifeCycleCloudEventFactory lifeCycleCloudEventFactory() {
return lifeCycleCloudEventFactory;
}

public Set<String> allowedCommands() {
return allowedCommands;
Comment thread
fjtirado marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@
import io.serverlessworkflow.impl.WorkflowModel;
import io.serverlessworkflow.impl.WorkflowValueResolver;
import io.serverlessworkflow.impl.scripts.ScriptUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public class RunShellExecutor implements CallableTask {
private final WorkflowValueResolver<String> shellCommand;
private final Map<WorkflowValueResolver<String>, Optional<WorkflowValueResolver<String>>>
shellArguments;
private final List<WorkflowValueResolver<String>> shellArguments;
private final Optional<WorkflowValueResolver<Map<String, Object>>> shellEnv;
private final Optional<ProcessReturnType> returnType;

public RunShellExecutor(
WorkflowValueResolver<String> shellCommand,
Map<WorkflowValueResolver<String>, Optional<WorkflowValueResolver<String>>> shellArguments,
List<WorkflowValueResolver<String>> shellArguments,
Optional<WorkflowValueResolver<Map<String, Object>>> shellEnv,
Optional<ProcessReturnType> returnType) {
super();
this.shellCommand = shellCommand;
this.shellArguments = shellArguments;
this.shellEnv = shellEnv;
Expand All @@ -49,16 +49,21 @@ public RunShellExecutor(
@Override
public CompletableFuture<WorkflowModel> apply(
WorkflowContext workflowContext, TaskContext taskContext, WorkflowModel model) {
StringBuilder commandBuilder =
new StringBuilder(shellCommand.apply(workflowContext, taskContext, model));
for (var entry : shellArguments.entrySet()) {
commandBuilder.append(" ").append(entry.getKey().apply(workflowContext, taskContext, model));
entry
.getValue()
.ifPresent(
v -> commandBuilder.append("=").append(v.apply(workflowContext, taskContext, model)));

String command = shellCommand.apply(workflowContext, taskContext, model);
if (!workflowContext.definition().application().allowedCommands().contains(command)) {
return CompletableFuture.failedFuture(
new SecurityException(
"Command "
+ command
+ " is not allowed. Please verify the set of allowed commands passed to the application"));
}
ProcessBuilder builder = new ProcessBuilder("sh", "-c", commandBuilder.toString());

List<String> commandAndArgs = new ArrayList<>();
commandAndArgs.add(command);
shellArguments.forEach(f -> commandAndArgs.add(f.apply(workflowContext, taskContext, model)));

ProcessBuilder builder = new ProcessBuilder(commandAndArgs);
shellEnv.ifPresent(
map -> ScriptUtils.addEnviromment(builder, map.apply(workflowContext, taskContext, model)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@
import io.serverlessworkflow.api.types.Shell;
import io.serverlessworkflow.impl.WorkflowDefinition;
import io.serverlessworkflow.impl.WorkflowUtils;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class RunShellExecutorBuilder implements RunnableTaskBuilder<RunShell> {

Expand All @@ -37,19 +35,10 @@ public CallableTask build(RunShell taskConfiguration, WorkflowDefinition definit
WorkflowUtils.buildStringFilter(
definition.application(), taskConfiguration.getShell().getCommand()),
shell.getArguments() != null
? shell.getArguments().getAdditionalProperties().entrySet().stream()
.collect(
Collectors.toMap(
e -> WorkflowUtils.buildStringFilter(definition.application(), e.getKey()),
e ->
e.getValue() != null
? Optional.of(
WorkflowUtils.buildStringFilter(
definition.application(), e.getValue().toString()))
: Optional.empty(),
(x, y) -> y,
LinkedHashMap::new))
: Map.of(),
? shell.getArguments().stream()
.map(s -> WorkflowUtils.buildStringFilter(definition.application(), s))
.toList()
: List.of(),
shell.getEnvironment() != null
? Optional.of(
WorkflowUtils.buildMapResolver(
Expand Down
Loading
Loading