aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/yaml_util.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/yaml_util.go')
-rw-r--r--internal/admin/yaml_util.go22
1 files changed, 20 insertions, 2 deletions
diff --git a/internal/admin/yaml_util.go b/internal/admin/yaml_util.go
index 6ea6692..c042248 100644
--- a/internal/admin/yaml_util.go
+++ b/internal/admin/yaml_util.go
@@ -226,8 +226,26 @@ func renameEntityFile(dataDir, subdir, oldID, newID string) (string, string, []b
if oldPath == newPath {
return "", "", nil, fmt.Errorf("new name is same as current")
}
- if _, err := os.Stat(newPath); err == nil {
- return "", "", nil, fmt.Errorf("entity %s already exists", newID)
+ // The ID namespace is global across the entity type's subdirectory tree
+ // (findEntityPath and the runtime path indexes resolve by filename
+ // anywhere under data/<subdir>), so the collision check must cover the
+ // whole tree, not just the file's own directory — otherwise renaming
+ // into an ID that exists in ANOTHER directory creates a duplicate ID
+ // shadowed by whichever file the index happens to find first.
+ target := newID + ".yaml"
+ var clash string
+ filepath.WalkDir(filepath.Join(dataDir, subdir), func(path string, d os.DirEntry, err error) error {
+ if err != nil || d.IsDir() {
+ return nil
+ }
+ if d.Name() == target {
+ clash = path
+ return filepath.SkipAll
+ }
+ return nil
+ })
+ if clash != "" {
+ return "", "", nil, fmt.Errorf("entity %s already exists at %s", newID, clash)
}
data, err := os.ReadFile(oldPath)
if err != nil {