package configkit_test import ( "errors" "os" "path/filepath" "testing" configkit "gitea.maximumdirect.net/eric/ConfigKit" ) func TestFacadeNativeDiscoveryWithNestedRoot(t *testing.T) { root := t.TempDir() parts := filepath.Join(root, "nested/root/parts") if err := os.MkdirAll(parts, 0o700); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(parts, "value.yml"), []byte("value: 1\n"), 0o600); err != nil { t.Fatal(err) } if err := os.Symlink("parts", filepath.Join(root, "nested/root/linked")); err != nil { t.Skipf("symlinks unavailable: %v", err) } filesystem := configkit.NewFilesystem("nested", os.DirFS(root)) context := &configkit.FilesystemContext{FS: &filesystem, Root: "nested/root", BaseDir: "nested/root"} for _, selector := range []string{ "dir: parts", "glob: 'parts/*.yml'", "dir: linked", "glob: 'lin*/*.yml'", } { t.Run(selector, func(t *testing.T) { result, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n")), configkit.Options[map[string]any]{Imports: true, Filesystem: context}) if err != nil { t.Fatal(err) } if result.Config["value"] != int64(1) { t.Fatalf("configuration = %#v", result.Config) } }) } if err := os.WriteFile(filepath.Join(root, "nested/outside.yml"), []byte("value: outside\n"), 0o600); err != nil { t.Fatal(err) } if err := os.Symlink("../../outside.yml", filepath.Join(parts, "escape.yml")); err != nil { t.Fatal(err) } for _, selector := range []string{"dir: parts", "glob: 'parts/*.yml'"} { _, err := configkit.Load(configkit.Bytes("main", []byte("configkit:\n imports:\n - "+selector+"\n")), configkit.Options[map[string]any]{Imports: true, Filesystem: context}) var loadError *configkit.LoadError if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 || loadError.Diagnostics()[0].Code != configkit.CodeImportOutsideRoot { t.Fatalf("escaping %s: %v", selector, err) } } }