@@ -117,9 +117,6 @@ func Load(
if err != nil {
return Config{}, err
}
- if err := validateHTTPListenerSafety(httpAddr, httpToken); err != nil {
- return Config{}, err
- }
return Config{
Username: username,
@@ -242,21 +239,6 @@ func httpToken(ctx context.Context, resolver *configvalue.Resolver, config *stri
return value, nil
}
-func validateHTTPListenerSafety(addr, token string) error {
- host, _, err := net.SplitHostPort(addr)
- if err != nil {
- return fmt.Errorf("invalid MCP HTTP listen address: %w", err)
- }
- if isLoopbackHost(host) {
- return nil
- }
- if token != "" {
- return nil
- }
-
- return fmt.Errorf("MCP HTTP token is required for non-loopback HTTP listen addresses")
-}
-
func isLoopbackHost(host string) bool {
if strings.EqualFold(host, "localhost") {
return true
@@ -233,8 +233,8 @@ http_token = ""
}
}
-// server.SECURITY.1
-func TestLoadACIDServerSecurity1AllowsLoopbackHTTPAddrWithoutToken(t *testing.T) {
+// server.SECURITY.1-1
+func TestLoadACIDServerSecurity1_1AllowsLoopbackHTTPAddrWithoutToken(t *testing.T) {
tests := []struct {
name string
addr string
@@ -269,69 +269,65 @@ http_addr = "`+tt.addr+`"
}
}
-// server.SECURITY.1
-func TestLoadACIDServerSecurity1RejectsNonLoopbackHTTPAddrWithoutToken(t *testing.T) {
- configPath := filepath.Join(t.TempDir(), "config.toml")
- writeConfig(t, configPath, `[user]
-name = "toml-user"
-password = "toml-password"
-
-[mcp]
-http_addr = "0.0.0.0:8123"
-`)
-
- _, err := Load(context.Background(), configPath, configvalue.NewResolver(), LoadOptions{})
- if err == nil {
- t.Fatal("Load() error = nil, want non-loopback HTTP token error")
- }
- if !strings.Contains(err.Error(), "MCP HTTP token is required") {
- t.Fatalf("Load() error = %v, want HTTP token required error", err)
+// server.SECURITY.1-1
+func TestLoadACIDServerSecurity1_1AllowsHTTPAddrWithoutToken(t *testing.T) {
+ tests := []struct {
+ name string
+ addr string
+ }{
+ {name: "all interfaces", addr: "0.0.0.0:8123"},
+ {name: "LAN", addr: "192.168.1.10:8123"},
+ {name: "Tailscale", addr: "100.64.0.1:8123"},
+ {name: "hostname-like LAN", addr: "192.168.1.blah:8123"},
}
-}
-// server.SECURITY.1
-func TestLoadACIDServerSecurity1AllowsNonLoopbackHTTPAddrWithToken(t *testing.T) {
- configPath := filepath.Join(t.TempDir(), "config.toml")
- writeConfig(t, configPath, `[user]
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ configPath := filepath.Join(t.TempDir(), "config.toml")
+ writeConfig(t, configPath, `[user]
name = "toml-user"
password = "toml-password"
[mcp]
-http_addr = "0.0.0.0:8123"
-http_token = "secret-token"
+http_addr = "`+tt.addr+`"
`)
- got, err := Load(context.Background(), configPath, configvalue.NewResolver(), LoadOptions{})
- if err != nil {
- t.Fatalf("Load() error = %v", err)
- }
- if got.HTTPAddr != "0.0.0.0:8123" {
- t.Fatalf("HTTPAddr = %q, want non-loopback address", got.HTTPAddr)
- }
- if got.HTTPToken != "secret-token" {
- t.Fatal("HTTPToken was not resolved")
+ got, err := Load(context.Background(), configPath, configvalue.NewResolver(), LoadOptions{})
+ if err != nil {
+ t.Fatalf("Load() error = %v", err)
+ }
+ if got.HTTPAddr != tt.addr {
+ t.Fatalf("HTTPAddr = %q, want %q", got.HTTPAddr, tt.addr)
+ }
+ if got.HTTPToken != "" {
+ t.Fatalf("HTTPToken = %q, want empty", got.HTTPToken)
+ }
+ })
}
}
-// server.SECURITY.1
-func TestLoadACIDServerSecurity1RejectsNonLoopbackHTTPAddrOverrideWithoutToken(t *testing.T) {
+// server.SECURITY.1-1
+func TestLoadACIDServerSecurity1_1AllowsHTTPAddrOverrideWithoutToken(t *testing.T) {
configPath := filepath.Join(t.TempDir(), "config.toml")
writeConfig(t, configPath, `[user]
name = "toml-user"
password = "toml-password"
`)
- _, err := Load(
+ got, err := Load(
context.Background(),
configPath,
configvalue.NewResolver(),
LoadOptions{HTTPAddr: "0.0.0.0:8123"},
)
- if err == nil {
- t.Fatal("Load() error = nil, want non-loopback HTTP token error")
+ if err != nil {
+ t.Fatalf("Load() error = %v", err)
+ }
+ if got.HTTPAddr != "0.0.0.0:8123" {
+ t.Fatalf("HTTPAddr = %q, want override", got.HTTPAddr)
}
- if !strings.Contains(err.Error(), "MCP HTTP token is required") {
- t.Fatalf("Load() error = %v, want HTTP token required error", err)
+ if got.HTTPToken != "" {
+ t.Fatalf("HTTPToken = %q, want empty", got.HTTPToken)
}
}