Repository: kestra-io/kestra
Issue: Template properties should not be return by webserver
Labels: bug
backend

This [property](https://github.com/kestra-io/kestra/blob/d1837d17a649b1d5a844fe23a36a9543478d1465/core/src/main/java/io/kestra/core/tasks/flows/Template.java#L119) is need by serialization internaly for executor but for now this property is returned by webserver and should not (diff in terraform plan).
Find a way to hide it only on webserver

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/core/src/main/java/io/kestra/core/tasks/flows/Template.java b/core/src/main/java/io/kestra/core/tasks/flows/Template.java
index b9e9cc3524..0e882a23e6 100644
--- a/core/src/main/java/io/kestra/core/tasks/flows/Template.java
+++ b/core/src/main/java/io/kestra/core/tasks/flows/Template.java
@@ -1,6 +1,5 @@
 package io.kestra.core.tasks.flows;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.kestra.core.exceptions.IllegalVariableEvaluationException;
 import io.kestra.core.exceptions.InternalException;
 import io.kestra.core.models.annotations.Example;
@@ -18,6 +17,7 @@
 import io.kestra.core.repositories.TemplateRepositoryInterface;
 import io.kestra.core.runners.FlowableUtils;
 import io.kestra.core.runners.RunContext;
+import io.kestra.core.serializers.JacksonMapper;
 import io.kestra.core.services.GraphService;
 import io.micronaut.context.ApplicationContext;
 import io.micronaut.context.event.StartupEvent;
@@ -40,6 +40,7 @@
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 
+import static io.kestra.core.utils.Rethrow.throwConsumer;
 import static io.kestra.core.utils.Rethrow.throwFunction;
 
 @SuperBuilder(toBuilder = true)
@@ -116,29 +117,15 @@ public class Template extends Task implements FlowableTask<Template.Output> {
     @PluginProperty(dynamic = true, additionalProperties = String.class)
     private Map<String, String> args;
 
-    private transient io.kestra.core.models.templates.Template template;
-
-    private io.kestra.core.models.templates.Template template() throws IllegalVariableEvaluationException {
-        if (this.template == null) {
-            this.template = this.findTemplate(ContextHelper.context());
-        }
-
-        return this.template;
-    }
-
-    @JsonIgnore
-    public boolean isExecutorReady() {
-        return this.template != null;
-    }
-
     @Override
     public GraphCluster tasksTree(Execution execution, TaskRun taskRun, List<String> parentValues) throws IllegalVariableEvaluationException {
         GraphCluster subGraph = new GraphCluster(this, taskRun, parentValues, RelationType.SEQUENTIAL);
+        io.kestra.core.models.templates.Template template = this.findTemplate(ContextHelper.context());
 
         GraphService.sequential(
             subGraph,
-            this.template().getTasks(),
-            this.template().getErrors(),
+            template.getTasks(),
+            template.getErrors(),
             taskRun,
             execution
         );
@@ -149,11 +136,12 @@ public GraphCluster tasksTree(Execution execution, TaskRun taskRun, List<String>
     @Override
     public List<Task> allChildTasks() {
         try {
+            io.kestra.core.models.templates.Template template = this.findTemplate(ContextHelper.context());
 
             return Stream
                 .concat(
-                    this.template().getTasks() != null ? this.template().getTasks().stream() : Stream.empty(),
-                    this.template().getErrors() != null ? this.template().getErrors().stream() : Stream.empty()
+                    template.getTasks() != null ? template.getTasks().stream() : Stream.empty(),
+                    template.getErrors() != null ? template.getErrors().stream() : Stream.empty()
                 )
                 .collect(Collectors.toList());
         } catch (IllegalVariableEvaluationException e) {
@@ -163,16 +151,19 @@ public List<Task> allChildTasks() {
 
     @Override
     public List<ResolvedTask> childTasks(RunContext runContext, TaskRun parentTaskRun) throws IllegalVariableEvaluationException {
+        io.kestra.core.models.templates.Template template = this.findTemplate(ContextHelper.context());
 
-        return FlowableUtils.resolveTasks(this.template().getTasks(), parentTaskRun);
+        return FlowableUtils.resolveTasks(template.getTasks(), parentTaskRun);
     }
 
     @Override
     public List<NextTaskRun> resolveNexts(RunContext runContext, Execution execution, TaskRun parentTaskRun) throws IllegalVariableEvaluationException {
+        io.kestra.core.models.templates.Template template = this.findTemplate(ContextHelper.context());
+
         return FlowableUtils.resolveSequentialNexts(
             execution,
             this.childTasks(runContext, parentTaskRun),
-            FlowableUtils.resolveTasks(this.template().getErrors(), parentTaskRun),
+            FlowableUtils.resolveTasks(template.getErrors(), parentTaskRun),
             parentTaskRun
         );
     }
@@ -196,7 +187,7 @@ public Template.Output outputs(RunContext runContext, Execution execution, TaskR
         return builder.build();
     }
 
-    private io.kestra.core.models.templates.Template findTemplate(ApplicationContext applicationContext) throws IllegalVariableEvaluationException {
+    protected io.kestra.core.models.templates.Template findTemplate(ApplicationContext applicationContext) throws IllegalVariableEvaluationException {
         TemplateExecutorInterface templateExecutor = applicationContext.getBean(TemplateExecutorInterface.class);
 
         io.kestra.core.models.templates.Template template = templateExecutor.findById(this.namespace, this.templateId);
@@ -207,7 +198,32 @@ private io.kestra.core.models.templates.Template findTemplate(ApplicationContext
         return template;
     }
 
-    public static Flow injectTemplate(Flow flow, Execution execution, BiFunction<String, String, io.kestra.core.models.templates.Template> provider) {
+    @SuperBuilder(toBuilder = true)
+    @ToString
+    @EqualsAndHashCode
+    @Getter
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ExecutorTemplate extends Template {
+        private io.kestra.core.models.templates.Template template;
+
+        @Override
+        protected io.kestra.core.models.templates.Template findTemplate(ApplicationContext applicationContext) throws IllegalVariableEvaluationException {
+            return this.template;
+        }
+
+        public static ExecutorTemplate of(Template templateTask, io.kestra.core.models.templates.Template template) {
+            Map<String, Object> map = JacksonMapper.toMap(templateTask);
+            map.put("type", ExecutorTemplate.class.getName());
+
+            ExecutorTemplate executorTemplate = JacksonMapper.toMap(map, ExecutorTemplate.class);
+            executorTemplate.template = template;
+
+            return executorTemplate;
+        }
+    }
+
+    public static Flow injectTemplate(Flow flow, Execution execution, BiFunction<String, String, io.kestra.core.models.templates.Template> provider) throws InternalException {
         AtomicReference<Flow> flowReference = new AtomicReference<>(flow);
 
         boolean haveTemplate = true;
@@ -215,32 +231,26 @@ public static Flow injectTemplate(Flow flow, Execution execution, BiFunction<Str
             List<Template> templates = flowReference.get().allTasks()
                 .filter(task -> task.getType().equals(Template.class.getName()))
                 .map(task -> (Template) task)
-                .filter(t -> !t.isExecutorReady())
+                .filter(t -> !(t instanceof ExecutorTemplate))
                 .collect(Collectors.toList());
 
             templates
-                .forEach(templateTask -> {
+                .forEach(throwConsumer(templateTask -> {
                     io.kestra.core.models.templates.Template template = provider.apply(
                         templateTask.getNamespace(),
                         templateTask.getTemplateId()
                     );
 
-                    if (template!= null) {
-                        try {
-                            flowReference.set(
-                                flowReference.get().updateTask(
-                                    templateTask.getId(),
-                                    templateTask.toBuilder()
-                                        .template(template)
-                                        .build()
-                                )
-                            );
-                        } catch (InternalException e) {
-                            log.warn("Unable to update task for execution {}", execution.getId(), e);
-                        }
+                    if (template != null) {
+                        flowReference.set(
+                            flowReference.get().updateTask(
+                                templateTask.getId(),
+                                ExecutorTemplate.of(templateTask, template)
+                            )
+                        );
                     }
 
-                });
+                }));
 
             haveTemplate = templates.size() > 0;
         }
diff --git a/core/src/main/java/io/kestra/core/tasks/scripts/AbstractPython.java b/core/src/main/java/io/kestra/core/tasks/scripts/AbstractPython.java
index 8d0a139f88..918e34b518 100644
--- a/core/src/main/java/io/kestra/core/tasks/scripts/AbstractPython.java
+++ b/core/src/main/java/io/kestra/core/tasks/scripts/AbstractPython.java
@@ -72,7 +72,7 @@
     }
 )
 @Slf4j
-public class AbstractPython extends AbstractBash {
+public abstract class AbstractPython extends AbstractBash {
     @Builder.Default
     @Schema(
         title = "The python interpreter to use",
diff --git a/runner-kafka/src/main/java/io/kestra/runner/kafka/streams/FlowJoinerTransformer.java b/runner-kafka/src/main/java/io/kestra/runner/kafka/streams/FlowJoinerTransformer.java
index 057145b72d..16ffa19f08 100644
--- a/runner-kafka/src/main/java/io/kestra/runner/kafka/streams/FlowJoinerTransformer.java
+++ b/runner-kafka/src/main/java/io/kestra/runner/kafka/streams/FlowJoinerTransformer.java
@@ -1,5 +1,6 @@
 package io.kestra.runner.kafka.streams;
 
+import io.kestra.core.exceptions.InternalException;
 import io.kestra.core.models.flows.Flow;
 import io.kestra.core.runners.Executor;
 import io.kestra.core.services.TaskDefaultService;
@@ -50,14 +51,18 @@ public Executor transform(String key, Executor executor) {
             return executor.withFlow(flow);
         }
 
-        flow = Template.injectTemplate(flow, executor.getExecution(), (namespace, id) -> {
-            String templateUid = io.kestra.core.models.templates.Template.uid(
-                namespace,
-                id
-            );
-
-            return this.templateStore.get(templateUid).map(ValueAndTimestamp::value).orElse(null);
-        });
+        try {
+            flow = Template.injectTemplate(flow, executor.getExecution(), (namespace, id) -> {
+                String templateUid = io.kestra.core.models.templates.Template.uid(
+                    namespace,
+                    id
+                );
+
+                return this.templateStore.get(templateUid).map(ValueAndTimestamp::value).orElse(null);
+            });
+        } catch (InternalException e) {
+            log.warn("Failed to inject template",  e);
+        }
 
         Flow flowWithDefaults = taskDefaultService.injectDefaults(flow, executor.getExecution());
 
diff --git a/runner-memory/src/main/java/io/kestra/runner/memory/MemoryExecutor.java b/runner-memory/src/main/java/io/kestra/runner/memory/MemoryExecutor.java
index b92937905c..91c2139b8d 100644
--- a/runner-memory/src/main/java/io/kestra/runner/memory/MemoryExecutor.java
+++ b/runner-memory/src/main/java/io/kestra/runner/memory/MemoryExecutor.java
@@ -1,5 +1,6 @@
 package io.kestra.runner.memory;
 
+import io.kestra.core.exceptions.InternalException;
 import io.kestra.core.metrics.MetricRegistry;
 import io.kestra.core.models.executions.Execution;
 import io.kestra.core.models.executions.LogEntry;
@@ -84,11 +85,15 @@ private void executionQueue(Execution message) {
     }
 
     private Flow transform(Flow flow, Execution execution) {
-        flow = Template.injectTemplate(
-            flow,
-            execution,
-            templateExecutorInterface::findById
-        );
+        try {
+            flow = Template.injectTemplate(
+                flow,
+                execution,
+                templateExecutorInterface::findById
+            );
+        } catch (InternalException e) {
+            log.warn("Failed to inject template",  e);
+        }
 
         return taskDefaultService.injectDefaults(flow, execution);
     }


Test patch: