os.WriteFile mode is masked by umask (022 in CI turns 0666 into 0644), making the writable-file rejection test environment-dependent; chmod the explicit bits after write
81 lines
2.5 KiB
Go
81 lines
2.5 KiB
Go
package config
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
)
|
||
|
||
func writeInstanceSettings(t *testing.T, root, body string) {
|
||
t.Helper()
|
||
if err := os.MkdirAll(root, 0o755); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(filepath.Join(root, "instance-settings.json"), []byte(body), 0o600); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func TestInstanceSettingsFinalLayerWins(t *testing.T) {
|
||
root := t.TempDir()
|
||
t.Setenv("CONFIG_ROOT", root)
|
||
writeInstanceSettings(t, root, `{"revision":3,"settings":{"http_port":9000,"agent_backend":"stub","agent_timeout":"15m"}}`)
|
||
|
||
cfg, src, err := LoadWithSources("", func(c *Config) { c.HTTPPort = 8888 }) // CLI 也被实例设置覆盖
|
||
if err != nil {
|
||
t.Fatalf("load: %v", err)
|
||
}
|
||
if cfg.HTTPPort != 9000 || cfg.AgentBackend != "stub" || cfg.AgentTimeout.String() != "15m0s" {
|
||
t.Fatalf("instance settings not applied: port=%d backend=%s timeout=%s", cfg.HTTPPort, cfg.AgentBackend, cfg.AgentTimeout)
|
||
}
|
||
if src["http_port"].Layer != "instance-settings" {
|
||
t.Fatalf("http_port layer=%s want instance-settings", src["http_port"].Layer)
|
||
}
|
||
if src["agent_timeout"].Layer != "instance-settings" {
|
||
t.Fatalf("agent_timeout layer=%s", src["agent_timeout"].Layer)
|
||
}
|
||
}
|
||
|
||
func TestInstanceSettingsIgnoredMode(t *testing.T) {
|
||
root := t.TempDir()
|
||
t.Setenv("CONFIG_ROOT", root)
|
||
t.Setenv("SETTINGS_MODE", "ignore")
|
||
writeInstanceSettings(t, root, `{"settings":{"http_port":9000}}`)
|
||
cfg, err := Load("")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if cfg.HTTPPort == 9000 {
|
||
t.Fatal("SETTINGS_MODE=ignore must skip the instance settings layer")
|
||
}
|
||
}
|
||
|
||
func TestInstanceSettingsBootstrapDeny(t *testing.T) {
|
||
root := t.TempDir()
|
||
t.Setenv("CONFIG_ROOT", root)
|
||
writeInstanceSettings(t, root, `{"settings":{"env":"main"}}`)
|
||
if _, err := Load(""); err == nil {
|
||
t.Fatal("bootstrap field override must fail closed")
|
||
}
|
||
}
|
||
|
||
func TestInstanceSettingsTypeMismatchFails(t *testing.T) {
|
||
root := t.TempDir()
|
||
t.Setenv("CONFIG_ROOT", root)
|
||
writeInstanceSettings(t, root, `{"settings":{"http_port":"not-a-number"}}`)
|
||
if _, err := Load(""); err == nil {
|
||
t.Fatal("type mismatch must fail closed")
|
||
}
|
||
}
|
||
|
||
func TestInstanceSettingsPermissiveFileRejected(t *testing.T) {
|
||
root := t.TempDir()
|
||
t.Setenv("CONFIG_ROOT", root)
|
||
p := filepath.Join(root, "instance-settings.json")
|
||
_ = os.WriteFile(p, []byte(`{"settings":{"http_port":9000}}`), 0o600)
|
||
_ = os.Chmod(p, 0o666) // 显式置位:WriteFile 的 mode 受 umask 侵蚀(CI 022 下 0666→0644)
|
||
if _, err := Load(""); err == nil {
|
||
t.Fatal("group/world writable instance settings must be rejected")
|
||
}
|
||
}
|