mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 12:18:59 +00:00
fix(config): add GOCLAW_ALLOWED_ORIGINS env var for CORS config (#543)
Add env var support for gateway.allowed_origins so container deployments can set CORS origins reliably even if config file is overwritten by UI save cycles. Follows same pattern as GOCLAW_OWNER_IDS.
This commit is contained in:
1 parent
e27c2cc45e
commit
533ca44e99
3 files changed
+81
-2
No files matched your search
+4
-2
@@ -1140,8 +1140,10 @@ func runGateway() {
|
||||
if strings.Contains(cfg.Database.PostgresDSN, ":goclaw@") {
|
||||
slog.Warn("security.default_db_password: using default Postgres password — run ./prepare-env.sh to generate a strong one")
|
||||
}
|
||||
if len(cfg.Gateway.AllowedOrigins) == 0 && !edition.Current().IsLimited() {
|
||||
slog.Warn("security.cors_open: no allowed_origins configured — all WebSocket origins accepted. Set gateway.allowed_origins for production")
|
||||
if len(cfg.Gateway.AllowedOrigins) > 0 {
|
||||
slog.Info("cors: allowed_origins configured", "origins", cfg.Gateway.AllowedOrigins)
|
||||
} else if !edition.Current().IsLimited() {
|
||||
slog.Warn("security.cors_open: no allowed_origins configured — all WebSocket origins accepted. Set gateway.allowed_origins or GOCLAW_ALLOWED_ORIGINS for production")
|
||||
}
|
||||
|
||||
if err := server.Start(ctx); err != nil {
|
||||
|
||||
@@ -214,6 +214,17 @@ func (c *Config) applyEnvOverrides() {
|
||||
c.Gateway.OwnerIDs = ids
|
||||
}
|
||||
|
||||
// Allowed origins from env (comma-separated, whitespace-trimmed)
|
||||
if v := os.Getenv("GOCLAW_ALLOWED_ORIGINS"); v != "" {
|
||||
var origins []string
|
||||
for origin := range strings.SplitSeq(v, ",") {
|
||||
if trimmed := strings.TrimSpace(origin); trimmed != "" {
|
||||
origins = append(origins, trimmed)
|
||||
}
|
||||
}
|
||||
c.Gateway.AllowedOrigins = origins
|
||||
}
|
||||
|
||||
// Tailscale (tsnet)
|
||||
envStr("GOCLAW_TSNET_HOSTNAME", &c.Tailscale.Hostname)
|
||||
envStr("GOCLAW_TSNET_AUTH_KEY", &c.Tailscale.AuthKey)
|
||||
|
||||
@@ -132,6 +132,72 @@ func TestLoad_EnvVarAPIKeys(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Allowed origins from JSON5 ---
|
||||
|
||||
func TestLoad_AllowedOrigins_JSON5(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
cfgPath := filepath.Join(dir, "config.json5")
|
||||
|
||||
content := `{
|
||||
"gateway": {
|
||||
"allowed_origins": [
|
||||
"https://app.example.com",
|
||||
"https://admin.example.com",
|
||||
"http://localhost:3002",
|
||||
],
|
||||
},
|
||||
}`
|
||||
os.WriteFile(cfgPath, []byte(content), 0644)
|
||||
|
||||
cfg, err := Load(cfgPath)
|
||||
if err != nil {
|
||||
t.Fatalf("load error: %v", err)
|
||||
}
|
||||
if len(cfg.Gateway.AllowedOrigins) != 3 {
|
||||
t.Fatalf("expected 3 origins, got %d: %v", len(cfg.Gateway.AllowedOrigins), cfg.Gateway.AllowedOrigins)
|
||||
}
|
||||
if cfg.Gateway.AllowedOrigins[0] != "https://app.example.com" {
|
||||
t.Fatalf("first origin: got %q", cfg.Gateway.AllowedOrigins[0])
|
||||
}
|
||||
if cfg.Gateway.AllowedOrigins[2] != "http://localhost:3002" {
|
||||
t.Fatalf("third origin: got %q", cfg.Gateway.AllowedOrigins[2])
|
||||
}
|
||||
}
|
||||
|
||||
// --- Allowed origins from env var ---
|
||||
|
||||
func TestLoad_AllowedOrigins_EnvVar(t *testing.T) {
|
||||
t.Setenv("GOCLAW_ALLOWED_ORIGINS", " https://a.com , https://b.com ")
|
||||
|
||||
cfg, err := Load("/nonexistent/path")
|
||||
if err != nil {
|
||||
t.Fatalf("load error: %v", err)
|
||||
}
|
||||
if len(cfg.Gateway.AllowedOrigins) != 2 {
|
||||
t.Fatalf("expected 2 origins, got %d: %v", len(cfg.Gateway.AllowedOrigins), cfg.Gateway.AllowedOrigins)
|
||||
}
|
||||
if cfg.Gateway.AllowedOrigins[0] != "https://a.com" || cfg.Gateway.AllowedOrigins[1] != "https://b.com" {
|
||||
t.Fatalf("origins not parsed correctly: %v", cfg.Gateway.AllowedOrigins)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_AllowedOrigins_EnvVar_OverridesFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
cfgPath := filepath.Join(dir, "config.json5")
|
||||
os.WriteFile(cfgPath, []byte(`{"gateway":{"allowed_origins":["https://file.com"]}}`), 0644)
|
||||
|
||||
// Env var should override file value
|
||||
t.Setenv("GOCLAW_ALLOWED_ORIGINS", "https://env.com")
|
||||
|
||||
cfg, err := Load(cfgPath)
|
||||
if err != nil {
|
||||
t.Fatalf("load error: %v", err)
|
||||
}
|
||||
if len(cfg.Gateway.AllowedOrigins) != 1 || cfg.Gateway.AllowedOrigins[0] != "https://env.com" {
|
||||
t.Fatalf("env should override file: got %v", cfg.Gateway.AllowedOrigins)
|
||||
}
|
||||
}
|
||||
|
||||
// --- FlexibleStringSlice ---
|
||||
|
||||
func TestFlexibleStringSlice_StringArray(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user