diff --git a/config.go b/config.go index 35055dc..4ac32d8 100644 --- a/config.go +++ b/config.go @@ -253,6 +253,13 @@ func Load(m coreio.Medium, path string) (map[string]any, error) { // Save writes configuration data to a YAML file at the given path. // It ensures the parent directory exists before writing. func Save(m coreio.Medium, path string, data map[string]any) error { + switch ext := strings.ToLower(filepath.Ext(path)); ext { + case "", ".yaml", ".yml": + // These paths are safe to treat as YAML destinations. + default: + return coreerr.E("config.Save", "unsupported config file type: "+path, nil) + } + out, err := yaml.Marshal(data) if err != nil { return coreerr.E("config.Save", "failed to marshal config", err) diff --git a/config_test.go b/config_test.go index 317c80b..981ed83 100644 --- a/config_test.go +++ b/config_test.go @@ -312,6 +312,28 @@ func TestSave_Good(t *testing.T) { assert.Contains(t, content, "key: value") } +func TestSave_UnsupportedPath_Bad(t *testing.T) { + m := coreio.NewMockMedium() + + err := Save(m, "/tmp/test/config.json", map[string]any{"key": "value"}) + assert.Error(t, err) + assert.Contains(t, err.Error(), "unsupported config file type") +} + +func TestConfig_Commit_UnsupportedPath_Bad(t *testing.T) { + m := coreio.NewMockMedium() + + cfg, err := New(WithMedium(m), WithPath("/tmp/test/config.json")) + assert.NoError(t, err) + + err = cfg.Set("key", "value") + assert.NoError(t, err) + + err = cfg.Commit() + assert.Error(t, err) + assert.Contains(t, err.Error(), "unsupported config file type") +} + func TestConfig_LoadFile_Env(t *testing.T) { m := coreio.NewMockMedium() m.Files["/.env"] = "FOO=bar\nBAZ=qux"