Repository: kestra-io/kestra (java)

Issue:
Able to determine the length of a secret in the logs
### Describe the issue

![Image](https://github.com/user-attachments/assets/5484e89c-5f18-4f74-b030-fd2a4f405b73)
While using a task that log a secret, while it is hidden behing some "****" and that there is a "masked" sentence inside the logged output : the exact number of char used in the secret is conserved while it should not be the case.

The mention of the "masked" work do not appear if their isn't more than 8 chars, a code like "bloup" will be showned as "*****", a code much more longer like "aaaaaaaaaaaaaaaaaaaaa" will be displayed with two stars + masked + the number of stars needed to match the total chars numbers of the secret.

Couldn't we replace this behavior by systematically replacing the display by a fixed nbr of stars ? Like "*********", whatever the secret may contain.

### Environment

- Kestra Version:

![Image](https://github.com/user-attachments/assets/a9bff668-8e6a-49c1-a3be-1d50802fed8e)


Pull request:
feat(core): use a fixed-size mask to mask secrets (#8131)
Fixes #8131

Patch:
diff --git a/core/src/main/java/io/kestra/core/runners/RunContextLogger.java b/core/src/main/java/io/kestra/core/runners/RunContextLogger.java
index e2f246637..ad829d2ec 100644
--- a/core/src/main/java/io/kestra/core/runners/RunContextLogger.java
+++ b/core/src/main/java/io/kestra/core/runners/RunContextLogger.java
@@ -234,8 +234,7 @@ public class RunContextLogger implements Supplier<org.slf4j.Logger> {
         private String replaceSecret(String data) {
             for (String s : runContextLogger.useSecrets) {
                 if (data.contains(s)) {
-                    data = data.replace(s, "*".repeat(s.length()));
-                    data = data.replaceFirst("[*]{9}", "**masked*");
+                    data = data.replace(s, "******");
                 }
             }
 
diff --git a/core/src/main/java/io/kestra/plugin/core/dashboard/chart/Bar.java b/core/src/main/java/io/kestra/plugin/core/dashboard/chart/Bar.java
index 255179f8c..f9ced2ee2 100644
--- a/core/src/main/java/io/kestra/plugin/core/dashboard/chart/Bar.java
+++ b/core/src/main/java/io/kestra/plugin/core/dashboard/chart/Bar.java
@@ -1,7 +1,6 @@
 package io.kestra.plugin.core.dashboard.chart;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonTypeName;
 
 import io.kestra.core.models.annotations.Example;
 import io.kestra.core.models.annotations.Plugin;
@@ -51,7 +50,7 @@ import lombok.experimental.SuperBuilder;
             }
         )
     }
-) 
+)
 public class Bar<F extends Enum<F>, D extends DataFilter<F, ? extends ColumnDescriptor<F>>> extends DataChart<BarOption, D> {
     @Override
     public Integer minNumberOfAggregations() {
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/Dag.java b/core/src/main/java/io/kestra/plugin/core/flow/Dag.java
index 2b48d08a4..e65dc63a8 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/Dag.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/Dag.java
@@ -10,6 +10,7 @@ import io.kestra.core.models.executions.NextTaskRun;
 import io.kestra.core.models.executions.TaskRun;
 import io.kestra.core.models.hierarchies.GraphCluster;
 import io.kestra.core.models.hierarchies.RelationType;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.*;
 import io.kestra.core.runners.FlowableUtils;
 import io.kestra.core.runners.RunContext;
@@ -93,8 +94,7 @@ public class Dag extends Task implements FlowableTask<VoidOutput> {
         title = "Number of concurrent parallel tasks that can be running at any point in time.",
         description = "If the value is `0`, no concurrency limit exists for the tasks in a DAG and all tasks that can run in parallel will start at the same time."
     )
-    @PluginProperty
-    private final Integer concurrent = 0;
+    private final Property<Integer> concurrent = Property.of(0);
 
     @Valid
     @NotEmpty
@@ -171,7 +171,7 @@ public class Dag extends Task implements FlowableTask<VoidOutput> {
             FlowableUtils.resolveTasks(this.errors, parentTaskRun),
             FlowableUtils.resolveTasks(this._finally, parentTaskRun),
             parentTaskRun,
-            this.concurrent,
+            runContext.render(this.concurrent).as(Integer.class).orElseThrow(),
             this.tasks
         );
     }
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/EachParallel.java b/core/src/main/java/io/kestra/plugin/core/flow/EachParallel.java
index 958340d81..149533f9b 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/EachParallel.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/EachParallel.java
@@ -10,6 +10,7 @@ import io.kestra.core.models.executions.TaskRun;
 import io.kestra.core.models.flows.State;
 import io.kestra.core.models.hierarchies.GraphCluster;
 import io.kestra.core.models.hierarchies.RelationType;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.FlowableTask;
 import io.kestra.core.models.tasks.ResolvedTask;
 import io.kestra.core.models.tasks.VoidOutput;
@@ -128,8 +129,7 @@ public class EachParallel extends Parallel implements FlowableTask<VoidOutput> {
         title = "Number of concurrent parallel tasks that can be running at any point in time.",
         description = "If the value is `0`, no limit exist and all the tasks will start at the same time."
     )
-    @PluginProperty
-    private final Integer concurrent = 0;
+    private final Property<Integer> concurrent = Property.of(0);
 
     @NotNull
     @PluginProperty(dynamic = true)
@@ -191,7 +191,7 @@ public class EachParallel extends Parallel implements FlowableTask<VoidOutput> {
             FlowableUtils.resolveTasks(this.errors, parentTaskRun),
             FlowableUtils.resolveTasks(this._finally, parentTaskRun),
             parentTaskRun,
-            this.concurrent
+            runContext.render(this.concurrent).as(Integer.class).orElseThrow()
         );
     }
 }
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/If.java b/core/src/main/java/io/kestra/plugin/core/flow/If.java
index 8083175b5..d262bca92 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/If.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/If.java
@@ -11,6 +11,7 @@ import io.kestra.core.models.executions.TaskRun;
 import io.kestra.core.models.flows.State;
 import io.kestra.core.models.hierarchies.GraphCluster;
 import io.kestra.core.models.hierarchies.RelationType;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.FlowableTask;
 import io.kestra.core.models.tasks.ResolvedTask;
 import io.kestra.core.models.tasks.Task;
@@ -69,12 +70,11 @@ import java.util.stream.Stream;
     aliases = "io.kestra.core.tasks.flows.If"
 )
 public class If extends Task implements FlowableTask<If.Output> {
-    @PluginProperty(dynamic = true)
     @Schema(
         title = "The `If` condition which can be any expression that evaluates to a boolean value.",
         description = "Boolean coercion allows 0, -0, null and '' to evaluate to false, all other values will evaluate to true."
     )
-    private String condition;
+    private Property<String> condition;
 
     @Valid
     @PluginProperty
@@ -205,7 +205,7 @@ public class If extends Task implements FlowableTask<If.Output> {
     }
 
     private Boolean isTrue(RunContext runContext) throws IllegalVariableEvaluationException {
-        String rendered = runContext.render(condition);
+        String rendered = runContext.render(condition).as(String.class).orElse(null);
         return TruthUtils.isTruthy(rendered);
     }
 
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/LoopUntil.java b/core/src/main/java/io/kestra/plugin/core/flow/LoopUntil.java
index 0b3dae6e2..a76fbdbc2 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/LoopUntil.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/LoopUntil.java
@@ -12,6 +12,7 @@ import io.kestra.core.models.flows.State;
 import io.kestra.core.models.hierarchies.AbstractGraph;
 import io.kestra.core.models.hierarchies.GraphCluster;
 import io.kestra.core.models.hierarchies.RelationType;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.FlowableTask;
 import io.kestra.core.models.tasks.ResolvedTask;
 import io.kestra.core.models.tasks.Task;
@@ -90,19 +91,17 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
     private List<Task> tasks;
 
     @NotNull
-    @PluginProperty(dynamic = true)
     @Schema(
         title = "The condition expression that should evaluate to `true` or `false`.",
         description = "Boolean coercion allows 0, -0, null and '' to evaluate to false; all other values will evaluate to true."
     )
-    private String condition;
+    private Property<String> condition;
 
     @Schema(
         title = "If set to `true`, the task run will end in a failed state once the `maxIterations` or `maxDuration` are reached."
     )
     @Builder.Default
-    @PluginProperty
-    private Boolean failOnMaxReached = false;
+    private Property<Boolean> failOnMaxReached = Property.of(false);
 
     @Schema(
         title = "Check the frequency configuration."
@@ -159,16 +158,16 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
 
     public Instant nextExecutionDate(RunContext runContext, Execution execution, TaskRun parentTaskRun) throws IllegalVariableEvaluationException {
         if (!this.reachedMaximums(runContext, execution, parentTaskRun, false)) {
-            String continueLoop = runContext.render(this.condition);
+            String continueLoop = runContext.render(this.condition).as(String.class).orElse(null);
             if (!TruthUtils.isTruthy(continueLoop)) {
-                return Instant.now().plus(this.checkFrequency.interval);
+                return Instant.now().plus(runContext.render(this.getCheckFrequency().getInterval()).as(Duration.class).orElseThrow());
             }
         }
 
         return null;
     }
 
-    private boolean reachedMaximums(RunContext runContext, Execution execution, TaskRun parentTaskRun, Boolean printLog) {
+    private boolean reachedMaximums(RunContext runContext, Execution execution, TaskRun parentTaskRun, Boolean printLog) throws IllegalVariableEvaluationException {
         Logger logger = runContext.logger();
 
         if (!this.childTaskRunExecuted(execution, parentTaskRun)) {
@@ -178,14 +177,18 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
         Integer iterationCount = Optional.ofNullable(parentTaskRun.getOutputs())
             .map(outputs -> (Integer) outputs.get("iterationCount"))
             .orElse(0);
-        if (this.checkFrequency.maxIterations != null && iterationCount != null && iterationCount > this.checkFrequency.maxIterations) {
+        
+        Optional<Integer> maxIterations = runContext.render(this.getCheckFrequency().getMaxIterations()).as(Integer.class);
+        if (maxIterations.isPresent() && iterationCount != null && iterationCount > maxIterations.get()) {
             if (printLog) {logger.warn("Max iterations reached");}
             return true;
         }
 
         Instant creationDate = parentTaskRun.getState().getHistories().getFirst().getDate();
-        if (this.checkFrequency.maxDuration != null &&
-            creationDate != null && creationDate.plus(this.checkFrequency.maxDuration).isBefore(Instant.now())) {
+        Optional<Duration> maxDuration = runContext.render(this.getCheckFrequency().getMaxDuration()).as(Duration.class);
+        if (maxDuration.isPresent() 
+            && creationDate != null 
+            && creationDate.plus(maxDuration.get()).isBefore(Instant.now())) {
             if (printLog) {logger.warn("Max duration reached");}
 
             return true;
@@ -201,7 +204,10 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
             return Optional.empty();
         }
 
-        if (childTaskExecuted && this.reachedMaximums(runContext, execution, parentTaskRun, true) && this.failOnMaxReached) {
+        if (childTaskExecuted 
+            && this.reachedMaximums(runContext, execution, parentTaskRun, true) 
+            && Boolean.TRUE.equals(runContext.render(this.failOnMaxReached).as(Boolean.class).orElseThrow())
+        ) {
             return Optional.of(State.Type.FAILED);
         }
 
@@ -269,21 +275,18 @@ public class LoopUntil extends Task implements FlowableTask<LoopUntil.Output> {
             title = "Maximum count of iterations."
         )
         @Builder.Default
-        @PluginProperty
-        private Integer maxIterations = 100;
+        private Property<Integer> maxIterations = Property.of(100);
 
         @Schema(
             title = "Maximum duration of the task."
         )
         @Builder.Default
-        @PluginProperty
-        private Duration maxDuration = Duration.ofHours(1);
+        private Property<Duration> maxDuration = Property.of(Duration.ofHours(1));
 
         @Schema(
             title = "Interval between each iteration."
         )
         @Builder.Default
-        @PluginProperty
-        private Duration interval = Duration.ofSeconds(1);
+        private Property<Duration> interval = Property.of(Duration.ofSeconds(1));
     }
 }
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/Parallel.java b/core/src/main/java/io/kestra/plugin/core/flow/Parallel.java
index d2414df4c..bf768ba71 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/Parallel.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/Parallel.java
@@ -2,6 +2,7 @@ package io.kestra.plugin.core.flow;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import io.kestra.core.models.annotations.PluginProperty;
+import io.kestra.core.models.property.Property;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import lombok.experimental.SuperBuilder;
@@ -110,8 +111,7 @@ public class Parallel extends Task implements FlowableTask<VoidOutput> {
         title = "Number of concurrent parallel tasks that can be running at any point in time.",
         description = "If the value is `0`, no limit exist and all tasks will start at the same time."
     )
-    @PluginProperty
-    private final Integer concurrent = 0;
+    private final Property<Integer> concurrent = Property.of(0);
 
     @Valid
     @PluginProperty
@@ -173,7 +173,7 @@ public class Parallel extends Task implements FlowableTask<VoidOutput> {
             FlowableUtils.resolveTasks(this.errors, parentTaskRun),
             FlowableUtils.resolveTasks(this._finally, parentTaskRun),
             parentTaskRun,
-            this.concurrent
+            runContext.render(this.concurrent).as(Integer.class).orElseThrow()
         );
     }
 }
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/Sleep.java b/core/src/main/java/io/kestra/plugin/core/flow/Sleep.java
index 38d4feac8..71885998a 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/Sleep.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/Sleep.java
@@ -2,7 +2,7 @@ package io.kestra.plugin.core.flow;
 
 import io.kestra.core.models.annotations.Example;
 import io.kestra.core.models.annotations.Plugin;
-import io.kestra.core.models.annotations.PluginProperty;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.RunnableTask;
 import io.kestra.core.models.tasks.Task;
 import io.kestra.core.models.tasks.VoidOutput;
@@ -42,15 +42,15 @@ public class Sleep extends Task implements RunnableTask<VoidOutput> {
         title = "Duration to sleep",
         description = "The time duration in ISO-8601 format (e.g., `PT5S` for 5 seconds)."
     )
-    @PluginProperty
     @NotNull
-    private Duration duration;
+    private Property<Duration> duration;
 
     public VoidOutput run(RunContext runContext) throws Exception {
-        runContext.logger().info("Waiting for {}", duration);
+        Duration durationRendered = runContext.render(this.duration).as(Duration.class).orElseThrow();
+        runContext.logger().info("Waiting for {}", durationRendered);
 
         // Wait for the specified duration
-        TimeUnit.MILLISECONDS.sleep(duration.toMillis());
+        TimeUnit.MILLISECONDS.sleep(durationRendered.toMillis());
 
         return null;
     }
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/Subflow.java b/core/src/main/java/io/kestra/plugin/core/flow/Subflow.java
index 1e7ec7ca6..8a7e1409d 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/Subflow.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/Subflow.java
@@ -2,6 +2,7 @@ package io.kestra.plugin.core.flow;
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import io.kestra.core.exceptions.IllegalVariableEvaluationException;
 import io.kestra.core.exceptions.InternalException;
 import io.kestra.core.models.Label;
 import io.kestra.core.models.annotations.Example;
@@ -136,8 +137,7 @@ public class Subflow extends Task implements ExecutableTask<Subflow.Output>, Chi
         title = "Whether the subflow should inherit labels from this execution that triggered it.",
         description = "By default, labels are not passed to the subflow execution. If you set this option to `true`, the child flow execution will inherit all labels from the parent execution."
     )
-    @PluginProperty
-    private final Boolean inheritLabels = false;
+    private final Property<Boolean> inheritLabels = Property.of(false);
 
     /**
      * @deprecated Output value should now be defined part of the Flow definition.
@@ -187,7 +187,7 @@ public class Subflow extends Task implements ExecutableTask<Subflow.Output>, Chi
             currentTaskRun,
             inputs,
             labels,
-            inheritLabels,
+            runContext.render(inheritLabels).as(Boolean.class).orElseThrow(),
             scheduleDate
         )
             .<List<SubflowExecution<?>>>map(subflowExecution -> List.of(subflowExecution))
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/Switch.java b/core/src/main/java/io/kestra/plugin/core/flow/Switch.java
index 5df677d92..7d2b9bd4b 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/Switch.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/Switch.java
@@ -12,6 +12,7 @@ import io.kestra.core.models.executions.TaskRun;
 import io.kestra.core.models.flows.State;
 import io.kestra.core.models.hierarchies.GraphCluster;
 import io.kestra.core.models.hierarchies.RelationType;
+import io.kestra.core.models.property.Property;
 import io.kestra.core.models.tasks.FlowableTask;
 import io.kestra.core.models.tasks.ResolvedTask;
 import io.kestra.core.models.tasks.Task;
@@ -90,13 +91,11 @@ import static io.kestra.core.utils.Rethrow.throwPredicate;
 @Introspected
 @SwitchTaskValidation
 public class Switch extends Task implements FlowableTask<Switch.Output> {
-    @NotBlank
     @NotNull
     @Schema(
         title = "The value to be evaluated."
     )
-    @PluginProperty(dynamic = true)
-    private String value;
+    private Property<String> value;
 
     // @FIXME: @Valid break on io.micronaut.validation.validator.DefaultValidator#cascadeToOne with "Cannot validate java.util.ArrayList"
     // @Valid
@@ -124,7 +123,7 @@ public class Switch extends Task implements FlowableTask<Switch.Output> {
     }
 
     private String rendererValue(RunContext runContext) throws IllegalVariableEvaluationException {
-        return runContext.render(this.value);
+        return runContext.render(this.value).as(String.class).orElseThrow();
     }
 
     @Override
diff --git a/core/src/main/java/io/kestra/plugin/core/flow/WorkingDirectory.java b/core/src/main/java/io/kestra/plugin/core/flow/WorkingDirectory.java
index ff854a476..df995d8fd 100644
--- a/core/src/main/java/io/kestra/plugin/core/flow/WorkingDirectory.java
+++ b/core/src/main/java/io/kestra/plugin/core/flow/WorkingDirectory.java
@@ -234,7 +234,7 @@ public class WorkingDirectory extends Sequential implements NamespaceFilesInterf
     public void preExecuteTasks(RunContext runContext, TaskRun taskRun) throws Exception {
         if (cache != null) {
             // May download cached file if it exists and is not expired, and extract its content
-            var maybeCacheFile = runContext.storage().getCacheFile(getId(), taskRun.getValue(), cache.ttl);
+            var maybeCacheFile = runContext.storage().getCacheFile(getId(), taskRun.getValue(), runContext.render(cache.ttl).as(Duration.class).orElse(null));
             if (maybeCacheFile.isPresent()) {
                 runContext.logger().debug("Cache exist, downloading it");
                 // download the cache if exist and unzip all entries
@@ -291,7 +291,7 @@ public class WorkingDirectory extends Sequential implements NamespaceFilesInterf
         }
         try {
             // This is monolithic, maybe a cache entry by pattern would be better.
-            List<Path> matchesList = runContext.workingDir().findAllFilesMatching(cache.getPatterns());
+            List<Path> matchesList = runContext.workingDir().findAllFilesMatching(runContext.render(cache.getPatterns()).asList(String.class));
 
             // Check that some files has been updated since the start of the task
             // TODO we may need to allow excluding files as some files always changed for dependencies (for ex .package-log.json)
@@ -373,15 +373,13 @@ public class WorkingDirectory extends Sequential implements NamespaceFilesInterf
     @NoArgsConstructor
     public static class Cache {
         @Schema(title = "Cache TTL (Time To Live), after this duration the cache will be deleted.")
-        @PluginProperty
-        private Duration ttl;
+        private Property<Duration> ttl;
 
         @Schema(
             title = "List of file [glob](https://en.wikipedia.org/wiki/Glob_(programming)) patterns to include in the cache.",
             description = "For example, 'node_modules/**' will include all files of the node_modules directory including sub-directories."
         )
-        @PluginProperty
         @NotNull
-        private List<String> patterns;
+        private Property<List<String>> patterns;
     }
 }
diff --git a/ui/src/components/flows/useCodePanels.ts b/ui/src/components/flows/useCodePanels.ts
index 6df11fa35..bc6917cc6 100644
--- a/ui/src/components/flows/useCodePanels.ts
+++ b/ui/src/components/flows/useCodePanels.ts
@@ -100,6 +100,14 @@ export function useCodePanels(panels: Ref<Panel[]>) {
     watch(codeEditorTabs, (newVal) => {
         const codeTabs = getPanelsFromCodeEditorTabs(newVal)
 
+        // Loop through tabs to see if any code tab should be removed due to file deletion
+        const openedTabs = new Set(codeTabs.tabs.map(tab => tab.value))
+        panels.value.forEach((panel) => {
+            panel.tabs = panel.tabs.filter(tab => {
+                return !tab.value.startsWith("code-") || openedTabs.has(tab.value)
+            })
+        })
+        
         // get all the tabs to add since they are not already part of the panels tabs
         const toAdd = codeTabs.tabs.filter(t => !panels.value.some(p => p.tabs.some(pt => t.value === pt.value)))
 
diff --git a/ui/src/stores/namespaces.js b/ui/src/stores/namespaces.js
index 27a96f6fe..ca442d582 100644
--- a/ui/src/stores/namespaces.js
+++ b/ui/src/stores/namespaces.js
@@ -152,7 +152,17 @@ export default {
             if (!payload.path) return;
 
             const URL = `${base.call(this, payload.namespace)}/files?path=${slashPrefix(safePath(payload.path))}`;
-            const request = await this.$http.get(URL, {transformResponse: response => response, responseType: "json"})
+            const request = await this.$http.get(URL, {
+                validateStatus: (status) => status === 200 || status === 404,
+                transformResponse: response => response, responseType: "json"
+            })
+
+            if(request.status === 404) {
+                const message = JSON.parse(request.data)?.message;
+                this.$toast.bind({$t: this.$i18n.t})().error(message ?? "File not found");
+
+                return [];
+            }
 
             return request.data ?? [];
         },


Test patch:
diff --git a/core/src/test/java/io/kestra/core/runners/InputsTest.java b/core/src/test/java/io/kestra/core/runners/InputsTest.java
index cb5aba209..713dc92e7 100644
--- a/core/src/test/java/io/kestra/core/runners/InputsTest.java
+++ b/core/src/test/java/io/kestra/core/runners/InputsTest.java
@@ -386,6 +386,6 @@ public class InputsTest {
 
         var logEntry = receive.blockLast();
         assertThat(logEntry).isNotNull();
-        assertThat(logEntry.getMessage()).isEqualTo("This is my secret: ********");
+        assertThat(logEntry.getMessage()).isEqualTo("This is my secret: ******");
     }
 }
diff --git a/core/src/test/java/io/kestra/core/runners/RunContextLoggerTest.java b/core/src/test/java/io/kestra/core/runners/RunContextLoggerTest.java
index 3434a61e1..4cc09ec00 100644
--- a/core/src/test/java/io/kestra/core/runners/RunContextLoggerTest.java
+++ b/core/src/test/java/io/kestra/core/runners/RunContextLoggerTest.java
@@ -27,10 +27,6 @@ class RunContextLoggerTest {
     @Named(QueueFactoryInterface.WORKERTASKLOG_NAMED)
     QueueInterface<LogEntry> logQueue;
 
-    @Inject
-    RunContextFactory runContextFactory;
-
-
     @Test
     void logs() {
         List<LogEntry> logs = new CopyOnWriteArrayList<>();
@@ -116,9 +112,9 @@ class RunContextLoggerTest {
 
         matchingLog = TestsUtils.awaitLogs(logs, 3);
         receive.blockLast();
-        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElseThrow().getMessage()).isEqualTo("test john@******* test");
+        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElseThrow().getMessage()).isEqualTo("test john@****** test");
         assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.TRACE)).findFirst().orElseThrow().getMessage()).contains("exception from doe.com");
-        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElseThrow().getMessage()).isEqualTo("test **masked****************** ************* **************************");
-        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.WARN)).findFirst().orElseThrow().getMessage()).isEqualTo("test **masked**********");
+        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElseThrow().getMessage()).isEqualTo("test ************ ****** ************");
+        assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.WARN)).findFirst().orElseThrow().getMessage()).isEqualTo("test ******");
     }
 }
\ No newline at end of file
diff --git a/core/src/test/java/io/kestra/core/runners/RunContextTest.java b/core/src/test/java/io/kestra/core/runners/RunContextTest.java
index 2140d910f..b48deefa7 100644
--- a/core/src/test/java/io/kestra/core/runners/RunContextTest.java
+++ b/core/src/test/java/io/kestra/core/runners/RunContextTest.java
@@ -319,7 +319,7 @@ class RunContextTest {
 
         matchingLog = TestsUtils.awaitLogs(logs, 3);
         receive.blockLast();
-        assertThat(Objects.requireNonNull(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElse(null)).getMessage()).isEqualTo("john ******** doe");
+        assertThat(Objects.requireNonNull(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElse(null)).getMessage()).isEqualTo("john ****** doe");
     }
 
     @Test
diff --git a/core/src/test/java/io/kestra/core/runners/WorkerTest.java b/core/src/test/java/io/kestra/core/runners/WorkerTest.java
index 55afa8726..38f351021 100644
--- a/core/src/test/java/io/kestra/core/runners/WorkerTest.java
+++ b/core/src/test/java/io/kestra/core/runners/WorkerTest.java
@@ -204,7 +204,7 @@ class WorkerTest {
         Sleep bash = Sleep.builder()
             .type(Sleep.class.getName())
             .id("unit-test")
-            .duration(Duration.ofMillis(sleepDuration))
+            .duration(Property.of(Duration.ofMillis(sleepDuration)))
             .build();
 
         Flow flow = Flow.builder()
diff --git a/core/src/test/java/io/kestra/core/schedulers/AbstractSchedulerTest.java b/core/src/test/java/io/kestra/core/schedulers/AbstractSchedulerTest.java
index c1f05ce08..755c43d6d 100644
--- a/core/src/test/java/io/kestra/core/schedulers/AbstractSchedulerTest.java
+++ b/core/src/test/java/io/kestra/core/schedulers/AbstractSchedulerTest.java
@@ -116,7 +116,7 @@ abstract public class AbstractSchedulerTest {
             .toBuilder()
             .tasks(
                 Collections.singletonList(
-                    Sleep.builder().id("sleep").type(Sleep.class.getName()).duration(Duration.ofSeconds(125)).build()
+                    Sleep.builder().id("sleep").type(Sleep.class.getName()).duration(Property.of(Duration.ofSeconds(125))).build()
                 )
             )
             .build();
diff --git a/core/src/test/java/io/kestra/plugin/core/flow/ForEachItemCaseTest.java b/core/src/test/java/io/kestra/plugin/core/flow/ForEachItemCaseTest.java
index 879fbc026..301b7638a 100644
--- a/core/src/test/java/io/kestra/plugin/core/flow/ForEachItemCaseTest.java
+++ b/core/src/test/java/io/kestra/plugin/core/flow/ForEachItemCaseTest.java
@@ -130,7 +130,7 @@ public class ForEachItemCaseTest {
 
         Flux<Execution> receive = TestsUtils.receive(executionQueue, either -> {
             Execution execution = either.getLeft();
-            if (execution.getFlowId().equals("for-each-item-subflow")) {
+            if (execution.getFlowId().equals("for-each-item-subflow-sleep")) {
                 if (execution.getState().getCurrent().isTerminated()) {
                     triggered.set(execution);
                     countDownLatch.countDown();
@@ -167,9 +167,9 @@ public class ForEachItemCaseTest {
 
         // assert on the last subflow execution
         assertThat(triggered.get().getState().getCurrent()).isEqualTo(State.Type.SUCCESS);
-        assertThat(triggered.get().getFlowId()).isEqualTo("for-each-item-subflow");
+        assertThat(triggered.get().getFlowId()).isEqualTo("for-each-item-subflow-sleep");
         assertThat((String) triggered.get().getInputs().get("items")).matches("kestra:///io/kestra/tests/for-each-item-no-wait/executions/.*/tasks/each-split/.*\\.txt");
-        assertThat(triggered.get().getTaskRunList()).hasSize(1);
+        assertThat(triggered.get().getTaskRunList()).hasSize(2);
     }
 
     @SuppressWarnings("unchecked")
diff --git a/core/src/test/java/io/kestra/plugin/core/flow/SubflowTest.java b/core/src/test/java/io/kestra/plugin/core/flow/SubflowTest.java
index 1abe3a794..f546b1afd 100644
--- a/core/src/test/java/io/kestra/plugin/core/flow/SubflowTest.java
+++ b/core/src/test/java/io/kestra/plugin/core/flow/SubflowTest.java
@@ -10,7 +10,6 @@ import io.kestra.core.models.flows.State.History;
 import io.kestra.core.runners.DefaultRunContext;
 import io.kestra.core.runners.SubflowExecutionResult;
 import io.micronaut.context.ApplicationContext;
-import org.hamcrest.Matchers;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -29,8 +28,6 @@ import java.util.Map;
 import java.util.Optional;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.Matchers.hasProperty;
-import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @ExtendWith(MockitoExtension.class)
@@ -68,7 +65,7 @@ class SubflowTest {
             Execution.builder().build()
         );
 
-        assertThat(result).isEqualTo(Optional.empty());
+        assertThat(result).isEmpty();
     }
 
     @SuppressWarnings("deprecation")
diff --git a/core/src/test/java/io/kestra/plugin/core/flow/TimeoutTest.java b/core/src/test/java/io/kestra/plugin/core/flow/TimeoutTest.java
index 7908a756d..c846e2cc5 100644
--- a/core/src/test/java/io/kestra/plugin/core/flow/TimeoutTest.java
+++ b/core/src/test/java/io/kestra/plugin/core/flow/TimeoutTest.java
@@ -51,7 +51,7 @@ class TimeoutTest {
             .tasks(Collections.singletonList(Sleep.builder()
                 .id("test")
                 .type(Sleep.class.getName())
-                .duration(Duration.ofSeconds(100))
+                .duration(Property.of(Duration.ofSeconds(100)))
                 .timeout(Property.of(Duration.ofNanos(100000)))
                 .build()))
             .build();
diff --git a/core/src/test/resources/flows/valids/for-each-item-no-wait.yaml b/core/src/test/resources/flows/valids/for-each-item-no-wait.yaml
index 93725f43e..27ee8f7ad 100644
--- a/core/src/test/resources/flows/valids/for-each-item-no-wait.yaml
+++ b/core/src/test/resources/flows/valids/for-each-item-no-wait.yaml
@@ -12,7 +12,7 @@ tasks:
     batch:
       rows: 4
     namespace: io.kestra.tests
-    flowId: for-each-item-subflow
+    flowId: for-each-item-subflow-sleep
     wait: false
     transmitFailed: true
     inputs:
diff --git a/core/src/test/resources/flows/valids/for-each-item-subflow-sleep.yaml b/core/src/test/resources/flows/valids/for-each-item-subflow-sleep.yaml
new file mode 100644
index 000000000..bacd13575
--- /dev/null
+++ b/core/src/test/resources/flows/valids/for-each-item-subflow-sleep.yaml
@@ -0,0 +1,15 @@
+id: for-each-item-subflow-sleep
+namespace: io.kestra.tests
+
+inputs:
+  - id: items
+    type: STRING
+
+tasks:
+  - type: io.kestra.plugin.core.flow.Sleep
+    id: sleep
+    duration: PT0.2S
+
+  - id: per-item
+    type: io.kestra.plugin.core.log.Log
+    message: "{{ inputs.items }}"
\ No newline at end of file
diff --git a/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcRunnerTest.java b/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcRunnerTest.java
index ad880a293..4f5703bf5 100644
--- a/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcRunnerTest.java
+++ b/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcRunnerTest.java
@@ -144,7 +144,7 @@ public abstract class JdbcRunnerTest extends AbstractRunnerTest {
     }
 
     @RetryingTest(5)
-    @LoadFlows({"flows/valids/for-each-item-subflow.yaml",
+    @LoadFlows({"flows/valids/for-each-item-subflow-sleep.yaml",
         "flows/valids/for-each-item-no-wait.yaml"})
     protected void forEachItemNoWait() throws Exception {
         forEachItemCaseTest.forEachItemNoWait();
diff --git a/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcServiceLivenessCoordinatorTest.java b/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcServiceLivenessCoordinatorTest.java
index 0ca984735..cfa3c1ec5 100644
--- a/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcServiceLivenessCoordinatorTest.java
+++ b/jdbc/src/test/java/io/kestra/jdbc/runner/JdbcServiceLivenessCoordinatorTest.java
@@ -311,7 +311,7 @@ public abstract class JdbcServiceLivenessCoordinatorTest {
         Sleep bash = Sleep.builder()
             .type(Sleep.class.getName())
             .id("unit-test")
-            .duration(sleep)
+            .duration(io.kestra.core.models.property.Property.of(sleep))
             .workerGroup(workerGroupKey != null ? new WorkerGroup(workerGroupKey, null) : null)
             .build();
 
@@ -351,7 +351,7 @@ public abstract class JdbcServiceLivenessCoordinatorTest {
         Sleep bash = Sleep.builder()
             .type(Sleep.class.getName())
             .id("unit-test")
-            .duration(sleep)
+            .duration(io.kestra.core.models.property.Property.of(sleep))
             .build();
 
         SleepTrigger trigger = SleepTrigger.builder()