Repository: kestra-io/kestra
Issue: A flow named `files` mixed up with namespace files
Labels: bug

### Explain the bug

Namespace files creates files inside the `/my/namespaces/files` directory.
Imagine the following flow:
```yaml
id: files
namespace: dev
tasks:
  - id: extract
    type: io.kestra.plugin.gcp.bigquery.Query
    sql: |
      SELECT DATETIME(datehour) as date, title, views FROM `bigquery-public-data.wikipedia.pageviews_2023` 
      WHERE DATE(datehour) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY) and wiki = 'fr' and title not in ('Cookie_(informatique)', 'Wikipédia:Accueil_principal', 'Spécial:Recherche')
      ORDER BY datehour desc, views desc
      LIMIT 10
    store: true
```

Its execution files will be visible inside the namespace files editor which is not a good idea for various reasons.

We discuss this issue internally and we will move namespace files prefix directory to `_files` ~and prevent starting a flow and a namespace by `_` which is a breaking change~.

EDIT: flows and namespace are slugify so we don't need to prevent starting a flow with `_`.

### Environment Information

- Kestra Version:
- Operating System and Java Version (if not using Kestra Docker image):


Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/core/src/main/java/io/kestra/core/storages/StorageInterface.java b/core/src/main/java/io/kestra/core/storages/StorageInterface.java
index bc88b14609..d19dd6e3b8 100644
--- a/core/src/main/java/io/kestra/core/storages/StorageInterface.java
+++ b/core/src/main/java/io/kestra/core/storages/StorageInterface.java
@@ -165,7 +165,7 @@ default String cachePrefix(String namespace, String flowId, String taskId, @Null
     default String namespaceFilePrefix(String namespace) {
         return fromParts(
             namespace.replace(".", "/"),
-            "files"
+            "_files"
         );
     }
 


Test patch:
diff --git a/core/src/test/java/io/kestra/core/storage/StorageInterfaceTest.java b/core/src/test/java/io/kestra/core/storage/StorageInterfaceTest.java
index dadf5c8eab..c19707ab37 100644
--- a/core/src/test/java/io/kestra/core/storage/StorageInterfaceTest.java
+++ b/core/src/test/java/io/kestra/core/storage/StorageInterfaceTest.java
@@ -86,6 +86,6 @@ void outputPrefix() {
     void namespaceFilePrefix() {
         var prefix = storageInterface.namespaceFilePrefix("io.namespace");
         assertThat(prefix, notNullValue());
-        assertThat(prefix, is("/io/namespace/files"));
+        assertThat(prefix, is("/io/namespace/_files"));
     }
 }
diff --git a/core/src/test/java/io/kestra/core/tasks/flows/VariablesTest.java b/core/src/test/java/io/kestra/core/tasks/flows/VariablesTest.java
index ea25468423..005bae08af 100644
--- a/core/src/test/java/io/kestra/core/tasks/flows/VariablesTest.java
+++ b/core/src/test/java/io/kestra/core/tasks/flows/VariablesTest.java
@@ -10,6 +10,7 @@
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
 
 import java.util.List;
 import java.util.Objects;
@@ -25,6 +26,8 @@ class VariablesTest extends AbstractMemoryRunnerTest {
     QueueInterface<LogEntry> workerTaskLogQueue;
 
     @Test
+    @EnabledIfEnvironmentVariable(named = "KESTRA_TEST1", matches = ".*")
+    @EnabledIfEnvironmentVariable(named = "KESTRA_TEST2", matches = ".*")
     void recursiveVars() throws TimeoutException {
         Execution execution = runnerUtils.runOne(null, "io.kestra.tests", "variables");
 
diff --git a/webserver/src/test/java/io/kestra/webserver/controllers/NamespaceFileControllerTest.java b/webserver/src/test/java/io/kestra/webserver/controllers/NamespaceFileControllerTest.java
index 9e839f2277..74c334e93a 100644
--- a/webserver/src/test/java/io/kestra/webserver/controllers/NamespaceFileControllerTest.java
+++ b/webserver/src/test/java/io/kestra/webserver/controllers/NamespaceFileControllerTest.java
@@ -90,7 +90,7 @@ void stats() throws IOException {
     @Test
     void namespaceRootStatsWithoutPreCreation() {
         FileAttributes res = client.toBlocking().retrieve(HttpRequest.GET("/api/v1/namespaces/" + NAMESPACE + "/files/stats"), TestFileAttributes.class);
-        assertThat(res.getFileName(), is("files"));
+        assertThat(res.getFileName(), is("_files"));
         assertThat(res.getType(), is(FileAttributes.FileType.Directory));
     }