diff --git a/config.go b/config.go index 4ac32d8..33f3ac4 100644 --- a/config.go +++ b/config.go @@ -106,6 +106,9 @@ func configTypeForPath(path string) (string, error) { if ext == "" && filepath.Base(path) == ".env" { return "env", nil } + if ext == "" { + return "yaml", nil + } switch ext { case ".yaml", ".yml": @@ -236,6 +239,13 @@ func (c *Config) Path() string { // Returns the parsed data as a map, or an error if the file cannot be read or parsed. // Deprecated: Use Config.LoadFile instead. func Load(m coreio.Medium, path string) (map[string]any, error) { + switch ext := strings.ToLower(filepath.Ext(path)); ext { + case "", ".yaml", ".yml": + // These paths are safe to treat as YAML sources. + default: + return nil, coreerr.E("config.Load", "unsupported config file type: "+path, nil) + } + content, err := m.Read(path) if err != nil { return nil, coreerr.E("config.Load", "failed to read config file: "+path, err) diff --git a/config_test.go b/config_test.go index 981ed83..b3c24e6 100644 --- a/config_test.go +++ b/config_test.go @@ -239,6 +239,15 @@ func TestLoad_Bad(t *testing.T) { assert.Contains(t, err.Error(), "failed to read config file") } +func TestLoad_UnsupportedPath_Bad(t *testing.T) { + m := coreio.NewMockMedium() + m.Files["/tmp/test/config.json"] = `{"app":{"name":"core"}}` + + _, err := Load(m, "/tmp/test/config.json") + assert.Error(t, err) + assert.Contains(t, err.Error(), "unsupported config file type") +} + func TestLoad_InvalidYAML_Bad(t *testing.T) { m := coreio.NewMockMedium() m.Files["/tmp/test/config.yaml"] = "invalid: yaml: content: [[[[" @@ -261,6 +270,19 @@ func TestConfig_LoadFile_JSON_Good(t *testing.T) { assert.Equal(t, "core", name) } +func TestConfig_LoadFile_Extensionless_Good(t *testing.T) { + m := coreio.NewMockMedium() + m.Files["/tmp/test/config"] = "app:\n name: core\n" + + cfg, err := New(WithMedium(m), WithPath("/tmp/test/config")) + assert.NoError(t, err) + + var name string + err = cfg.Get("app.name", &name) + assert.NoError(t, err) + assert.Equal(t, "core", name) +} + func TestConfig_LoadFile_TOML_Good(t *testing.T) { m := coreio.NewMockMedium() m.Files["/tmp/test/config.toml"] = "app = { name = \"core\" }\n" @@ -312,6 +334,17 @@ func TestSave_Good(t *testing.T) { assert.Contains(t, content, "key: value") } +func TestSave_Extensionless_Good(t *testing.T) { + m := coreio.NewMockMedium() + + err := Save(m, "/tmp/test/config", map[string]any{"key": "value"}) + assert.NoError(t, err) + + content, readErr := m.Read("/tmp/test/config") + assert.NoError(t, readErr) + assert.Contains(t, content, "key: value") +} + func TestSave_UnsupportedPath_Bad(t *testing.T) { m := coreio.NewMockMedium()