diff --git a/cmd/ragflow_server.go b/cmd/ragflow_server.go index eb855bfe36..1ca4614fbb 100644 --- a/cmd/ragflow_server.go +++ b/cmd/ragflow_server.go @@ -325,7 +325,7 @@ func selectedLogLevel(args *serverArgs, configured string) string { // CLI flag > environment variable > config file > default(1) and returns the // resolved ingestor worker count (K), validating it against the inclusive // range [MinIngestorWorkers, MaxIngestorWorkers]. An out-of-range or -// non-integer value at any layer is a fatal startup error. +// noninteger value at any layer is a fatal startup error. func resolveIngestorMaxConcurrentWorkers(args *serverArgs, configured int) (int, error) { val := config.MinIngestorWorkers if configured > 0 { @@ -352,7 +352,7 @@ func resolveIngestorMaxConcurrentWorkers(args *serverArgs, configured int) (int, // CLI flag > environment variable > config file > default(2) and returns the // resolved per-document page concurrency (N), validating it against the // inclusive range [MinPageConcurrency, MaxPageConcurrency]. An out-of-range or -// non-integer value at any layer is a fatal startup error. +// noninteger value at any layer is a fatal startup error. func resolveIngestorPageConcurrency(args *serverArgs, configured int) (int, error) { val := 2 // default page concurrency if configured > 0 { @@ -584,7 +584,7 @@ func main() { // stdout-only window. switch *arguments.mode { case "api", "ingestor": - if err := registerNativeDeepDoc(arguments); err != nil { + if err = registerNativeDeepDoc(arguments); err != nil { common.Error("Failed to register in-process DeepDoc backend", err) os.Exit(1) } @@ -622,7 +622,7 @@ func main() { } if err = checkDatabaseVersion(ctx); err != nil { - common.Fatal("Refusing to start: database was migrated by a newer version", zap.Error(err)) + common.Fatal("Database has a newer version", zap.Error(err)) } // Initialize doc engine @@ -944,7 +944,7 @@ func runIngestor(ctx context.Context, cancel context.CancelFunc, serverName stri // topic title and an existing cluster's description is fused with the joining // document. Passing an empty model ref resolves each tenant's default chat // model on demand; without one the nav service keeps its deterministic - // behaviour. + // behavior. navService.SetNavMergeLLM(service.NewNavMergeLLM(service.NewModelFactory(), "")) nav.SetNavService(navService) // Memory extraction runs on the Ingestor's shared NATS consumer + worker @@ -956,7 +956,7 @@ func runIngestor(ctx context.Context, cancel context.CancelFunc, serverName stri // goroutines and joins them via Stop); a provisioning failure here must // fail the server (main's os.Exit(1) path) instead of reporting a // healthy ingestor that can never consume. - if err := ingestor.Start(); err != nil { + if err = ingestor.Start(); err != nil { common.Error("Failed to initialize ingestor", err) return err } diff --git a/internal/agentic_rag/agent.go b/internal/agentic_rag/agent.go index fd5998a3ec..76418be10a 100644 --- a/internal/agentic_rag/agent.go +++ b/internal/agentic_rag/agent.go @@ -302,7 +302,7 @@ func Run(ctx context.Context, in Input) (string, error) { // Shared per-run duration tally: every tool invocation is timed and // accumulated here for per-question usage accounting. if in.ToolCallDurations == nil { - in.ToolCallDurations = NewDurationAccumulator() + in.ToolCallDurations = &durationAccumulator{dur: make(map[string]time.Duration)} } tools := in.Tools diff --git a/internal/server/config/environments.go b/internal/server/config/environments.go index 55c7811df2..3bd2a404d9 100644 --- a/internal/server/config/environments.go +++ b/internal/server/config/environments.go @@ -644,6 +644,8 @@ func (c *Config) GetMaxContentLength() int { return c.environments.MAXContentLen func (c *Config) GetHomePath() string { return c.environments.HomePath } +func (c *Config) GetMCPAllowPrivateHosts() bool { return c.environments.MCPAllowPrivateHosts } + func (c *Config) GetUserProfile() string { return c.environments.UserProfile } func (c *Config) GetHTTPProxy() string { return c.environments.HTTPProxy } diff --git a/internal/utility/mcp_ssrf.go b/internal/utility/mcp_ssrf.go index 389b7bed7f..fa227f492a 100644 --- a/internal/utility/mcp_ssrf.go +++ b/internal/utility/mcp_ssrf.go @@ -19,6 +19,7 @@ package utility import ( "net/url" "ragflow/internal/common" + "ragflow/internal/server" "strings" ) @@ -34,8 +35,9 @@ import ( // AssertMCPURLSafeSameOrigin so a malicious server cannot redirect POSTs to an // unrelated internal host. func AssertMCPURLSafe(rawURL string) (hostname, resolvedIP string, err error) { + globalConfig := server.GetConfig() hostname, resolvedIP, err = common.AssertURLSafe(rawURL) - if err == nil || !mcpPrivateHostsAllowed() { + if err == nil || !globalConfig.GetMCPAllowPrivateHosts() { return hostname, resolvedIP, err } strictErr := err @@ -64,7 +66,8 @@ func AssertMCPURLSafeSameOrigin(rawURL, originURL string) (hostname, resolvedIP if err == nil { return hostname, resolvedIP, nil } - if !mcpPrivateHostsAllowed() { + globalConfig := server.GetConfig() + if !globalConfig.GetMCPAllowPrivateHosts() { return "", "", err } origin, perr := url.Parse(strings.TrimSpace(originURL)) @@ -80,10 +83,3 @@ func AssertMCPURLSafeSameOrigin(rawURL, originURL string) (hostname, resolvedIP } return AssertMCPURLSafe(rawURL) } - -// mcpPrivateHostsAllowed reports whether RAGFLOW_MCP_ALLOW_PRIVATE_HOSTS is -// enabled (true/1/yes, case-insensitive). -func mcpPrivateHostsAllowed() bool { - v := strings.ToLower(strings.TrimSpace(common.GetEnv(common.EnvMCPAllowPrivateHosts))) - return v == "true" || v == "1" || v == "yes" -} diff --git a/internal/utility/mcp_ssrf_test.go b/internal/utility/mcp_ssrf_test.go index d07d85e60e..a8d92511f3 100644 --- a/internal/utility/mcp_ssrf_test.go +++ b/internal/utility/mcp_ssrf_test.go @@ -18,6 +18,7 @@ package utility import ( "ragflow/internal/common" + "ragflow/internal/server" "testing" ) @@ -26,11 +27,15 @@ func stubLookupHost(t *testing.T, ips []string) { original := common.LookupHost common.LookupHost = func(string) ([]string, error) { return ips, nil } t.Cleanup(func() { common.LookupHost = original }) + err := server.Init("") + if err != nil { + t.Fatalf("failed to init server: %v", err) + } } func TestAssertMCPURLSafePrivateHostAllowed(t *testing.T) { - stubLookupHost(t, []string{"172.18.0.5"}) t.Setenv(common.EnvMCPAllowPrivateHosts, "true") + stubLookupHost(t, []string{"172.18.0.5"}) host, ip, err := AssertMCPURLSafe("http://navigo-mcp:8765/mcp") if err != nil { @@ -42,8 +47,8 @@ func TestAssertMCPURLSafePrivateHostAllowed(t *testing.T) { } func TestAssertMCPURLSafeRejectsPrivateHostWhenDisabled(t *testing.T) { - stubLookupHost(t, []string{"172.18.0.5"}) t.Setenv(common.EnvMCPAllowPrivateHosts, "") + stubLookupHost(t, []string{"172.18.0.5"}) if _, _, err := AssertMCPURLSafe("http://navigo-mcp:8765/mcp"); err == nil { t.Fatal("expected private host to be rejected when disabled") @@ -63,8 +68,8 @@ func TestAssertMCPURLSafePublicHostUnaffected(t *testing.T) { } func TestAssertMCPURLSafeSameOriginAllowsPrivateAdvertisedURL(t *testing.T) { - stubLookupHost(t, []string{"172.18.0.5"}) t.Setenv(common.EnvMCPAllowPrivateHosts, "true") + stubLookupHost(t, []string{"172.18.0.5"}) host, ip, err := AssertMCPURLSafeSameOrigin("http://navigo-mcp:8765/mcp/messages", "http://navigo-mcp:8765/mcp/sse") if err != nil { @@ -76,8 +81,8 @@ func TestAssertMCPURLSafeSameOriginAllowsPrivateAdvertisedURL(t *testing.T) { } func TestAssertMCPURLSafeSameOriginRejectsCrossOriginPrivateAdvertisedURL(t *testing.T) { - stubLookupHost(t, []string{"172.18.0.6"}) t.Setenv(common.EnvMCPAllowPrivateHosts, "true") + stubLookupHost(t, []string{"172.18.0.6"}) if _, _, err := AssertMCPURLSafeSameOrigin("http://other-internal:8765/mcp/messages", "http://navigo-mcp:8765/mcp/sse"); err == nil { t.Fatal("expected cross-origin private advertised URL to be rejected")