Use secure temporary config files

This commit is contained in:
Brandon McGinty (chatgpt)
2026-08-10 08:44:58 -04:00
committed by Brandon McGinty
parent 3ba5e03208
commit dcffa1efa1
2 changed files with 35 additions and 5 deletions
+15 -5
View File
@@ -8,6 +8,7 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
"os" "os"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@@ -61,15 +62,24 @@ func (c *Config) saveConfigLocked() error {
if err != nil { if err != nil {
return err return err
} }
tmp := c.fn + ".tmp" file, err := os.CreateTemp(filepath.Dir(c.fn), filepath.Base(c.fn)+".tmp-")
if err := ioutil.WriteFile(tmp, data, 0600); err != nil { if err != nil {
return err return err
} }
if err := os.Rename(tmp, c.fn); err != nil { tmp := file.Name()
_ = os.Remove(tmp) defer os.Remove(tmp)
if err := file.Chmod(0600); err != nil {
file.Close()
return err return err
} }
return nil if _, err := file.Write(data); err != nil {
file.Close()
return err
}
if err := file.Close(); err != nil {
return err
}
return os.Rename(tmp, c.fn)
} }
func key(k uiterm.Key) *uiterm.Key { func key(k uiterm.Key) *uiterm.Key {
+20
View File
@@ -1,6 +1,7 @@
package config package config
import ( import (
"os"
"path/filepath" "path/filepath"
"sync" "sync"
"testing" "testing"
@@ -16,6 +17,25 @@ func TestSaveConfigReturnsWriteError(t *testing.T) {
} }
} }
func TestSaveConfigDoesNotUsePredictableTemporaryPath(t *testing.T) {
path := filepath.Join(t.TempDir(), "barnard.toml")
legacyTemp := path + ".tmp"
if err := os.WriteFile(legacyTemp, []byte("sentinel"), 0600); err != nil {
t.Fatal(err)
}
cfg := NewConfig(&path)
if err := cfg.SaveConfig(); err != nil {
t.Fatal(err)
}
contents, err := os.ReadFile(legacyTemp)
if err != nil {
t.Fatal(err)
}
if string(contents) != "sentinel" {
t.Fatalf("predictable temporary file was modified: %q", contents)
}
}
func TestConcurrentConfigurationUpdatesAndWrites(t *testing.T) { func TestConcurrentConfigurationUpdatesAndWrites(t *testing.T) {
path := filepath.Join(t.TempDir(), "barnard.toml") path := filepath.Join(t.TempDir(), "barnard.toml")
cfg := NewConfig(&path) cfg := NewConfig(&path)