Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion core/http/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func API(application *application.Application) (*fiber.App, error) {
router.Use(recover.New())
}

// OpenTelemetry metrics for Prometheus export
if !application.ApplicationConfig().DisableMetrics {
metricsService, err := services.NewLocalAIMetricsService()
if err != nil {
Expand All @@ -141,6 +142,7 @@ func API(application *application.Application) (*fiber.App, error) {
})
}
}

// Health Checks should always be exempt from auth, so register these first
routes.HealthRoutes(router)

Expand Down Expand Up @@ -202,12 +204,28 @@ func API(application *application.Application) (*fiber.App, error) {
routes.RegisterElevenLabsRoutes(router, requestExtractor, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig())
routes.RegisterLocalAIRoutes(router, requestExtractor, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig(), application.GalleryService())
routes.RegisterOpenAIRoutes(router, requestExtractor, application)

if !application.ApplicationConfig().DisableWebUI {

// Create metrics store for tracking usage (before API routes registration)
metricsStore := services.NewInMemoryMetricsStore()

// Add metrics middleware BEFORE API routes so it can intercept them
router.Use(middleware.MetricsMiddleware(metricsStore))
Comment on lines +213 to +214

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional High

The metrics middleware is registered after API routes (RegisterElevenLabsRoutes, RegisterLocalAIRoutes, RegisterOpenAIRoutes) are already added to the router, so it will not intercept those routes despite the comment claiming it runs 'BEFORE API routes'.

Also reported at: core/http/app.go L208–L221

Suggested fix
		// Create metrics store for tracking usage (before API routes registration)
		metricsStore := services.NewInMemoryMetricsStore()

		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

		// Register cleanup on shutdown
		router.Hooks().OnShutdown(func() error {
			metricsStore.Stop()
			log.Info().Msg("Metrics store stopped")
			return nil
		})

		// Health Checks should always be exempt from auth, so register these first
		routes.HealthRoutes(router)

		routes.RegisterElevenLabsRoutes(...)
		routes.RegisterLocalAIRoutes(...)
		routes.RegisterOpenAIRoutes(...)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/app.go
Lines: 213-214
Issue Type: functional-high
Severity: high

Issue Description:
The metrics middleware is registered after API routes (RegisterElevenLabsRoutes, RegisterLocalAIRoutes, RegisterOpenAIRoutes) are already added to the router, so it will not intercept those routes despite the comment claiming it runs 'BEFORE API routes'.

_Also reported at: `core/http/app.go` L208–L221_

Current Code:
		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional High

The MetricsMiddleware is registered via router.Use() AFTER RegisterElevenLabsRoutes, RegisterLocalAIRoutes, and RegisterOpenAIRoutes have already been called, so it will not intercept those routes in Fiber; move the router.Use(middleware.MetricsMiddleware(metricsStore)) call to before the route registrations.

Suggested fix
		// Create metrics store for tracking usage
		metricsStore := services.NewInMemoryMetricsStore()

		// Register cleanup on shutdown
		router.Hooks().OnShutdown(func() error {
			metricsStore.Stop()
			log.Info().Msg("Metrics store stopped")
			return nil
		})

		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

		// ... then register API routes ...
		routes.RegisterElevenLabsRoutes(...)
		routes.RegisterLocalAIRoutes(...)
		routes.RegisterOpenAIRoutes(...)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/app.go
Lines: 214-214
Issue Type: functional-high
Severity: high

Issue Description:
The MetricsMiddleware is registered via router.Use() AFTER RegisterElevenLabsRoutes, RegisterLocalAIRoutes, and RegisterOpenAIRoutes have already been called, so it will not intercept those routes in Fiber; move the router.Use(middleware.MetricsMiddleware(metricsStore)) call to before the route registrations.

Current Code:
		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Register cleanup on shutdown
router.Hooks().OnShutdown(func() error {
metricsStore.Stop()
log.Info().Msg("Metrics store stopped")
return nil
})
Comment on lines 208 to +221

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Medium

The metricsStore and MetricsMiddleware are created inside the DisableWebUI guard block, so metrics collection is silently skipped when the Web UI is disabled, even though the metrics store is presumably useful for API-level tracking regardless of UI state.

Suggested fix
	// Create metrics store for tracking usage (before API routes registration)
	metricsStore := services.NewInMemoryMetricsStore()

	// Add metrics middleware BEFORE API routes so it can intercept them
	router.Use(middleware.MetricsMiddleware(metricsStore))

	// Register cleanup on shutdown
	router.Hooks().OnShutdown(func() error {
		metricsStore.Stop()
		log.Info().Msg("Metrics store stopped")
		return nil
	})

	// ... register API routes ...

	if !application.ApplicationConfig().DisableWebUI {
		opcache := services.NewOpCache(application.GalleryService())
		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.GalleryService(), opcache, metricsStore)
		routes.RegisterUIRoutes(router, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig(), application.GalleryService())
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/app.go
Lines: 208-221
Issue Type: functional-medium
Severity: medium

Issue Description:
The metricsStore and MetricsMiddleware are created inside the DisableWebUI guard block, so metrics collection is silently skipped when the Web UI is disabled, even though the metrics store is presumably useful for API-level tracking regardless of UI state.

Current Code:
	if !application.ApplicationConfig().DisableWebUI {

		// Create metrics store for tracking usage (before API routes registration)
		metricsStore := services.NewInMemoryMetricsStore()

		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

		// Register cleanup on shutdown
		router.Hooks().OnShutdown(func() error {
			metricsStore.Stop()
			log.Info().Msg("Metrics store stopped")
			return nil
		})
		...
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Create opcache for tracking UI operations
opcache := services.NewOpCache(application.GalleryService())
routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.GalleryService(), opcache)
routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.GalleryService(), opcache, metricsStore)
Comment on lines +207 to +225

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional High

The metrics middleware is registered AFTER the API routes (ElevenLabs, LocalAI, OpenAI, JINA), so it will never intercept requests to those routes; move router.Use(middleware.MetricsMiddleware(metricsStore)) to before the route registrations.

Suggested fix
	// Create metrics store for tracking usage (before API routes registration)
	var metricsStore services.MetricsStore
	if !application.ApplicationConfig().DisableWebUI {
		metricsStore = services.NewInMemoryMetricsStore()
		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))
		// Register cleanup on shutdown
		router.Hooks().OnShutdown(func() error {
			metricsStore.Stop()
			log.Info().Msg("Metrics store stopped")
			return nil
		})
	}

	routes.RegisterElevenLabsRoutes(router, ...)
	routes.RegisterLocalAIRoutes(router, ...)
	routes.RegisterOpenAIRoutes(router, ...)

	if !application.ApplicationConfig().DisableWebUI {
		opcache := services.NewOpCache(application.GalleryService())
		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.GalleryService(), opcache, metricsStore)
		routes.RegisterUIRoutes(router, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig(), application.GalleryService())
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/app.go
Lines: 207-225
Issue Type: functional-high
Severity: high

Issue Description:
The metrics middleware is registered AFTER the API routes (ElevenLabs, LocalAI, OpenAI, JINA), so it will never intercept requests to those routes; move `router.Use(middleware.MetricsMiddleware(metricsStore))` to before the route registrations.

Current Code:
	routes.RegisterElevenLabsRoutes(router, ...)
	routes.RegisterLocalAIRoutes(router, ...)
	routes.RegisterOpenAIRoutes(router, ...)

	if !application.ApplicationConfig().DisableWebUI {
		metricsStore := services.NewInMemoryMetricsStore()
		router.Use(middleware.MetricsMiddleware(metricsStore))
		...
		routes.RegisterUIAPIRoutes(router, ..., metricsStore)
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +207 to +225

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional High

The MetricsMiddleware is registered after RegisterOpenAIRoutes, RegisterLocalAIRoutes, and RegisterElevenLabsRoutes, so it will never intercept those API requests; the comment on line 213 states it should be added BEFORE API routes.

Also reported at: core/http/app.go L208–L221

Suggested fix
	if !application.ApplicationConfig().DisableWebUI {

		// Create metrics store for tracking usage (before API routes registration)
		metricsStore := services.NewInMemoryMetricsStore()

		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

		// Register cleanup on shutdown
		router.Hooks().OnShutdown(func() error {
			metricsStore.Stop()
			log.Info().Msg("Metrics store stopped")
			return nil
		})
	}

	routes.RegisterElevenLabsRoutes(...)
	routes.RegisterLocalAIRoutes(...)
	routes.RegisterOpenAIRoutes(...)

	if !application.ApplicationConfig().DisableWebUI {
		opcache := services.NewOpCache(application.GalleryService())
		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.GalleryService(), opcache, metricsStore)
		routes.RegisterUIRoutes(...)
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/app.go
Lines: 207-225
Issue Type: functional-high
Severity: high

Issue Description:
The MetricsMiddleware is registered after RegisterOpenAIRoutes, RegisterLocalAIRoutes, and RegisterElevenLabsRoutes, so it will never intercept those API requests; the comment on line 213 states it should be added BEFORE API routes.

_Also reported at: `core/http/app.go` L208–L221_

Current Code:
	routes.RegisterOpenAIRoutes(router, requestExtractor, application)

	if !application.ApplicationConfig().DisableWebUI {

		// Create metrics store for tracking usage (before API routes registration)
		metricsStore := services.NewInMemoryMetricsStore()

		// Add metrics middleware BEFORE API routes so it can intercept them
		router.Use(middleware.MetricsMiddleware(metricsStore))

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

routes.RegisterUIRoutes(router, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig(), application.GalleryService())
Comment on lines 208 to 226

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Metrics middleware registered after API routes — will never fire

In Fiber v2, routes are matched in registration order. The MetricsMiddleware is added via router.Use() at line 214, but RegisterElevenLabsRoutes, RegisterLocalAIRoutes, and RegisterOpenAIRoutes are all registered at lines 204–206 — before the middleware. When a request arrives for /v1/chat/completions, Fiber matches the OpenAI handler first; that handler returns a response without calling c.Next(), so the metrics middleware is never reached. The comment on line 213 even acknowledges this must run "BEFORE API routes," but the placement is after them. The result is that the dashboard will always show 0 total requests and empty endpoint/model charts, making the entire feature non-functional. The metricsStore initialization block needs to move to before the three Register*Routes calls.

}

routes.RegisterJINARoutes(router, requestExtractor, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig())

// Define a custom 404 handler
Expand Down
61 changes: 61 additions & 0 deletions core/http/endpoints/localai/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package localai

import (
"github.com/gofiber/fiber/v2"
"github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/gallery"
"github.com/mudler/LocalAI/core/http/utils"
"github.com/mudler/LocalAI/core/services"
"github.com/mudler/LocalAI/internal"
"github.com/mudler/LocalAI/pkg/model"
)

// SettingsEndpoint handles the settings page which shows detailed model/backend management
func SettingsEndpoint(appConfig *config.ApplicationConfig,
cl *config.ModelConfigLoader, ml *model.ModelLoader, opcache *services.OpCache) func(*fiber.Ctx) error {
return func(c *fiber.Ctx) error {
modelConfigs := cl.GetAllModelsConfigs()
galleryConfigs := map[string]*gallery.ModelConfig{}

installedBackends, err := gallery.ListSystemBackends(appConfig.SystemState)
if err != nil {
return err
}

for _, m := range modelConfigs {
cfg, err := gallery.GetLocalModelConfiguration(ml.ModelPath, m.Name)
if err != nil {
continue
}
galleryConfigs[m.Name] = cfg
}

loadedModels := ml.ListLoadedModels()
loadedModelsMap := map[string]bool{}
for _, m := range loadedModels {
loadedModelsMap[m.ID] = true
}

modelsWithoutConfig, _ := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

The error from services.ListModels is silently discarded with _; a failure here would silently render the page with an empty model list instead of surfacing the error to the caller.

Suggested fix
		modelsWithoutConfig, err := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)
		if err != nil {
			return err
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 39-39
Issue Type: robustness-medium
Severity: medium

Issue Description:
The error from `services.ListModels` is silently discarded with `_`; a failure here would silently render the page with an empty model list instead of surfacing the error to the caller.

Current Code:
		modelsWithoutConfig, _ := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

The error from services.ListModels is silently discarded with _; if it fails, modelsWithoutConfig will be nil/empty and the UI will silently show no models instead of surfacing the error.

Suggested fix
		modelsWithoutConfig, err := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)
		if err != nil {
			return err
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 39-39
Issue Type: robustness-medium
Severity: medium

Issue Description:
The error from `services.ListModels` is silently discarded with `_`; if it fails, `modelsWithoutConfig` will be nil/empty and the UI will silently show no models instead of surfacing the error.

Current Code:
		modelsWithoutConfig, _ := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

The error from services.ListModels is silently discarded with _; a failure here would silently produce an empty model list with no indication of the error.

Suggested fix
		modelsWithoutConfig, err := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)
		if err != nil {
			log.Error().Err(err).Msg("error listing models")
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 39-39
Issue Type: robustness-medium
Severity: medium

Issue Description:
The error from `services.ListModels` is silently discarded with `_`; a failure here would silently produce an empty model list with no indication of the error.

Current Code:
		modelsWithoutConfig, _ := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness High

The error from ListModels is ignored and should be handled to avoid rendering a partial or misleading settings page.

Suggested fix
		modelsWithoutConfig, err := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)
		if err != nil {
			return err
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 39-39
Issue Type: robustness-high
Severity: high

Issue Description:
The error from ListModels is ignored and should be handled to avoid rendering a partial or misleading settings page.

Current Code:
		modelsWithoutConfig, _ := services.ListModels(cl, ml, config.NoFilterFn, services.LOOSE_ONLY)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Get model statuses to display in the UI the operation in progress
processingModels, taskTypes := opcache.GetStatus()

summary := fiber.Map{
"Title": "LocalAI - Settings & Management",
"Version": internal.PrintableVersion(),
"BaseURL": utils.BaseURL(c),
"Models": modelsWithoutConfig,
"ModelsConfig": modelConfigs,
"GalleryConfig": galleryConfigs,
"ApplicationConfig": appConfig,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

The full appConfig (ApplicationConfig) is passed directly into the template map and rendered to the UI; this may expose sensitive configuration fields (API keys, secrets, internal paths) to the browser.

Suggested fix
			// Only expose the specific fields the template actually needs, not the entire config struct.
			// e.g. "DebugMode": appConfig.Debug,
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 51-51
Issue Type: security-high
Severity: high

Issue Description:
The full `appConfig` (ApplicationConfig) is passed directly into the template map and rendered to the UI; this may expose sensitive configuration fields (API keys, secrets, internal paths) to the browser.

Current Code:
			"ApplicationConfig": appConfig,

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

appConfig (the full application configuration) is passed directly into the template map and rendered to the UI, potentially exposing sensitive internal configuration fields (API keys, secrets, paths) to end users.

Suggested fix
			// Only expose the specific fields needed by the template rather than the full appConfig struct
			"ApplicationConfig": appConfig,  // TODO: replace with a safe DTO containing only UI-relevant fields
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 51-51
Issue Type: security-high
Severity: high

Issue Description:
`appConfig` (the full application configuration) is passed directly into the template map and rendered to the UI, potentially exposing sensitive internal configuration fields (API keys, secrets, paths) to end users.

Current Code:
			"ApplicationConfig": appConfig,

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

The full appConfig (ApplicationConfig) is passed directly to the template in the "ApplicationConfig" key, potentially exposing sensitive fields (API keys, secrets, internal paths) to the rendered HTML view.

Suggested change
"ApplicationConfig": appConfig,
"ApplicationConfig": appConfig.Redacted(), // expose only safe/non-sensitive fields
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 51-51
Issue Type: security-high
Severity: high

Issue Description:
The full `appConfig` (ApplicationConfig) is passed directly to the template in the `"ApplicationConfig"` key, potentially exposing sensitive fields (API keys, secrets, internal paths) to the rendered HTML view.

Current Code:
			"ApplicationConfig": appConfig,

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

Passing the entire application config into the template exposes all server settings to the UI, so only include the specific non-sensitive fields the view needs.

Suggested fix
			"ApplicationConfig": fiber.Map{
				"SomeSafeField": appConfig.SomeSafeField,
			},
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 51-51
Issue Type: security-high
Severity: high

Issue Description:
Passing the entire application config into the template exposes all server settings to the UI, so only include the specific non-sensitive fields the view needs.

Current Code:
			"ApplicationConfig": appConfig,

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

"ProcessingModels": processingModels,
"TaskTypes": taskTypes,
"LoadedModels": loadedModelsMap,
"InstalledBackends": installedBackends,
}
Comment on lines +44 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

Passing the entire application config into the view exposes server configuration to the UI, so send only the specific fields the template needs.

Suggested fix
		summary := fiber.Map{
			"Title":             "LocalAI - Settings & Management",
			"Version":           internal.PrintableVersion(),
			"BaseURL":           utils.BaseURL(c),
			"Models":            modelsWithoutConfig,
			"ModelsConfig":      modelConfigs,
			"GalleryConfig":     galleryConfigs,
			"ProcessingModels":  processingModels,
			"TaskTypes":         taskTypes,
			"LoadedModels":      loadedModelsMap,
			"InstalledBackends": installedBackends,
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/endpoints/localai/settings.go
Lines: 44-56
Issue Type: security-high
Severity: high

Issue Description:
Passing the entire application config into the view exposes server configuration to the UI, so send only the specific fields the template needs.

Current Code:
		summary := fiber.Map{
			"Title":             "LocalAI - Settings & Management",
			"Version":           internal.PrintableVersion(),
			"BaseURL":           utils.BaseURL(c),
			"Models":            modelsWithoutConfig,
			"ModelsConfig":      modelConfigs,
			"GalleryConfig":     galleryConfigs,
			"ApplicationConfig": appConfig,
			"ProcessingModels":  processingModels,
			"TaskTypes":         taskTypes,
			"LoadedModels":      loadedModelsMap,
			"InstalledBackends": installedBackends,
		}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Render settings page
return c.Render("views/settings", summary)
}
}
174 changes: 174 additions & 0 deletions core/http/middleware/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package middleware

import (
"encoding/json"
"strings"
"time"

"github.com/gofiber/fiber/v2"
"github.com/mudler/LocalAI/core/services"
"github.com/rs/zerolog/log"
)

// MetricsMiddleware creates a middleware that tracks API usage metrics
// Note: Uses CONTEXT_LOCALS_KEY_MODEL_NAME constant defined in request.go
func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler {
return func(c *fiber.Ctx) error {
path := c.Path()

// Skip tracking for UI routes, static files, and non-API endpoints
if shouldSkipMetrics(path) {
return c.Next()
}

// Record start time
start := time.Now()

// Get endpoint category
endpoint := categorizeEndpoint(path)

// Continue with the request
err := c.Next()

// Record metrics after request completes
duration := time.Since(start)
success := err == nil && c.Response().StatusCode() < 400

// Extract model name from context (set by RequestExtractor middleware)
// Use the same constant as RequestExtractor
model := "unknown"
if modelVal, ok := c.Locals(CONTEXT_LOCALS_KEY_MODEL_NAME).(string); ok && modelVal != "" {
model = modelVal
log.Debug().Str("model", model).Str("endpoint", endpoint).Msg("Recording metrics for request")
} else {
// Fallback: try to extract from path params or query
model = extractModelFromRequest(c)
log.Debug().Str("model", model).Str("endpoint", endpoint).Msg("Recording metrics for request (fallback)")
}

// Extract backend from response headers if available
backend := string(c.Response().Header.Peek("X-LocalAI-Backend"))

// Record the request
metricsStore.RecordRequest(endpoint, model, backend, success, duration)

return err
}
}

// shouldSkipMetrics determines if a request should be excluded from metrics
func shouldSkipMetrics(path string) bool {
// Skip UI routes
skipPrefixes := []string{
"/views/",
"/static/",
"/browse/",
"/chat/",
"/text2image/",
"/tts/",
"/talk/",
"/models/edit/",
"/import-model",
"/settings",
"/api/models", // UI API endpoints
"/api/backends", // UI API endpoints
"/api/operations", // UI API endpoints
"/api/p2p", // UI API endpoints
"/api/metrics", // Metrics API itself
}
Comment on lines +62 to +78

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Medium

shouldSkipMetrics skips /api/metrics but the Prometheus metrics endpoint is registered at /metrics (not /api/metrics); requests to /metrics will be tracked by this middleware, creating a recursive/noisy metrics loop. Add /metrics to the skip list.

Suggested fix
	skipPrefixes := []string{
		"/views/",
		"/static/",
		"/browse/",
		"/chat/",
		"/text2image/",
		"/tts/",
		"/talk/",
		"/models/edit/",
		"/import-model",
		"/settings",
		"/metrics",        // Prometheus metrics endpoint
		"/api/models",     // UI API endpoints
		"/api/backends",   // UI API endpoints
		"/api/operations", // UI API endpoints
		"/api/p2p",        // UI API endpoints
		"/api/metrics",    // Metrics API itself
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 62-78
Issue Type: functional-medium
Severity: medium

Issue Description:
`shouldSkipMetrics` skips `/api/metrics` but the Prometheus metrics endpoint is registered at `/metrics` (not `/api/metrics`); requests to `/metrics` will be tracked by this middleware, creating a recursive/noisy metrics loop. Add `/metrics` to the skip list.

Current Code:
	skipPrefixes := []string{
		"/views/",
		"/static/",
		"/browse/",
		"/chat/",
		"/text2image/",
		"/tts/",
		"/talk/",
		"/models/edit/",
		"/import-model",
		"/settings",
		"/api/models",     // UI API endpoints
		"/api/backends",   // UI API endpoints
		"/api/operations", // UI API endpoints
		"/api/p2p",        // UI API endpoints
		"/api/metrics",    // Metrics API itself
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


for _, prefix := range skipPrefixes {
if strings.HasPrefix(path, prefix) {
return true
}
}

// Also skip root path and other UI pages
if path == "/" || path == "/index" {
return true
}

return false
}

// categorizeEndpoint maps request paths to friendly endpoint categories
func categorizeEndpoint(path string) string {
// OpenAI-compatible endpoints
if strings.HasPrefix(path, "/v1/chat/completions") || strings.HasPrefix(path, "/chat/completions") {
return "chat"
}
if strings.HasPrefix(path, "/v1/completions") || strings.HasPrefix(path, "/completions") {
return "completions"
}
if strings.HasPrefix(path, "/v1/embeddings") || strings.HasPrefix(path, "/embeddings") {
return "embeddings"
}
if strings.HasPrefix(path, "/v1/images/generations") || strings.HasPrefix(path, "/images/generations") {
return "image-generation"
}
if strings.HasPrefix(path, "/v1/audio/transcriptions") || strings.HasPrefix(path, "/audio/transcriptions") {
return "transcriptions"
}
if strings.HasPrefix(path, "/v1/audio/speech") || strings.HasPrefix(path, "/audio/speech") {
return "text-to-speech"
}
if strings.HasPrefix(path, "/v1/models") || strings.HasPrefix(path, "/models") {
return "models"
}

// LocalAI-specific endpoints
if strings.HasPrefix(path, "/v1/internal") {
return "internal"
}
if strings.Contains(path, "/tts") {
return "text-to-speech"
}
if strings.Contains(path, "/stt") || strings.Contains(path, "/whisper") {
return "speech-to-text"
}
if strings.Contains(path, "/sound-generation") {
return "sound-generation"
}

// Default to the first path segment
parts := strings.Split(strings.Trim(path, "/"), "/")
if len(parts) > 0 {
return parts[0]
}
Comment on lines +134 to +137

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

strings.Split on an empty string after strings.Trim returns a slice with one empty-string element, so parts[0] returns "" rather than "unknown" for a bare / path that somehow bypasses the earlier check.

Suggested fix
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 && parts[0] != "" {
		return parts[0]
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 134-137
Issue Type: robustness-medium
Severity: medium

Issue Description:
`strings.Split` on an empty string after `strings.Trim` returns a slice with one empty-string element, so `parts[0]` returns `""` rather than `"unknown"` for a bare `/` path that somehow bypasses the earlier check.

Current Code:
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 {
		return parts[0]
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


return "unknown"
Comment on lines +134 to +139

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Medium

strings.Split on an empty string after strings.Trim returns a slice with one empty-string element, so parts[0] returns "" instead of "unknown" for the root path; however the root path is already excluded by shouldSkipMetrics, so the real risk is any path that trims to empty (e.g. "/"). The guard len(parts) > 0 never triggers the fallback "unknown" return. Replace with an explicit empty-string check.

Suggested fix
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 && parts[0] != "" {
		return parts[0]
	}

	return "unknown"
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 134-139
Issue Type: functional-medium
Severity: medium

Issue Description:
`strings.Split` on an empty string after `strings.Trim` returns a slice with one empty-string element, so `parts[0]` returns `""` instead of `"unknown"` for the root path; however the root path is already excluded by `shouldSkipMetrics`, so the real risk is any path that trims to empty (e.g. `"/"`). The guard `len(parts) > 0` never triggers the fallback `"unknown"` return. Replace with an explicit empty-string check.

Current Code:
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 {
		return parts[0]
	}

	return "unknown"

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +134 to +139

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Medium

strings.Split(strings.Trim(path, "/"), "/") always produces a slice with at least one element (even for an empty string it returns [""]), so the len(parts) > 0 guard never prevents returning an empty string as the endpoint category; the fallback return "unknown" is dead code and an empty path segment can be recorded as a metric key.

Suggested fix
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 && parts[0] != "" {
		return parts[0]
	}

	return "unknown"
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 134-139
Issue Type: functional-medium
Severity: medium

Issue Description:
`strings.Split(strings.Trim(path, "/"), "/")` always produces a slice with at least one element (even for an empty string it returns `[""]`), so the `len(parts) > 0` guard never prevents returning an empty string as the endpoint category; the fallback `return "unknown"` is dead code and an empty path segment can be recorded as a metric key.

Current Code:
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 {
		return parts[0]
	}

	return "unknown"

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +134 to +139

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional Medium

strings.Split(strings.Trim(path, "/"), "/") always returns a slice with at least one element (even for an empty string it returns [""]), so the len(parts) > 0 guard never triggers the return "unknown" fallback and an empty first segment can be returned as the category. The guard should check parts[0] != "".

Suggested fix
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 && parts[0] != "" {
		return parts[0]
	}

	return "unknown"
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 134-139
Issue Type: functional-medium
Severity: medium

Issue Description:
`strings.Split(strings.Trim(path, "/"), "/")` always returns a slice with at least one element (even for an empty string it returns `[""]`), so the `len(parts) > 0` guard never triggers the `return "unknown"` fallback and an empty first segment can be returned as the category. The guard should check `parts[0] != ""`.

Current Code:
	parts := strings.Split(strings.Trim(path, "/"), "/")
	if len(parts) > 0 {
		return parts[0]
	}

	return "unknown"

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}

// extractModelFromRequest attempts to extract the model name from the request
func extractModelFromRequest(c *fiber.Ctx) string {
// Try query parameter first
model := c.Query("model")
if model != "" {
return model
}

// Try to extract from JSON body for POST requests
if c.Method() == fiber.MethodPost {
// Read body
bodyBytes := c.Body()
if len(bodyBytes) > 0 {
// Parse JSON
var reqBody map[string]interface{}
if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
if modelVal, ok := reqBody["model"]; ok {
if modelStr, ok := modelVal.(string); ok {
return modelStr
}
}
}
Comment on lines +145 to +163

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Medium

Model name extracted from user-controlled query parameters and JSON body is stored in metrics without sanitization, allowing arbitrary strings to pollute metric labels and potentially cause cardinality explosion in the metrics store.

Suggested fix
	const maxModelNameLen = 256

	sanitize := func(s string) string {
		if len(s) > maxModelNameLen {
			return "unknown"
		}
		return s
	}

	model := c.Query("model")
	if model != "" {
		return sanitize(model)
	}

	if c.Method() == fiber.MethodPost {
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return sanitize(modelStr)
					}
				}
			}
		}
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 145-163
Issue Type: security-medium
Severity: medium

Issue Description:
Model name extracted from user-controlled query parameters and JSON body is stored in metrics without sanitization, allowing arbitrary strings to pollute metric labels and potentially cause cardinality explosion in the metrics store.

Current Code:
	model := c.Query("model")
	if model != "" {
		return model
	}

	if c.Method() == fiber.MethodPost {
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +150 to +163

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance Medium

Parsing the full request body again in middleware adds avoidable CPU and memory cost on every POST request, so prefer reusing the model already extracted by earlier middleware or gate this fallback behind endpoint checks and content type validation.

Suggested fix
	// Try to extract from JSON body only for JSON POST requests on known model-carrying endpoints
	if c.Method() == fiber.MethodPost && strings.HasPrefix(c.Get("Content-Type"), fiber.MIMEApplicationJSON) {
		if shouldInspectBodyForModel(c.Path()) {
			bodyBytes := c.Body()
			if len(bodyBytes) > 0 {
				var reqBody struct {
					Model string `json:"model"`
				}
				if err := json.Unmarshal(bodyBytes, &reqBody); err == nil && reqBody.Model != "" {
					return reqBody.Model
				}
			}
		}
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 150-163
Issue Type: performance-medium
Severity: medium

Issue Description:
Parsing the full request body again in middleware adds avoidable CPU and memory cost on every POST request, so prefer reusing the model already extracted by earlier middleware or gate this fallback behind endpoint checks and content type validation.

Current Code:
	// Try to extract from JSON body for POST requests
	if c.Method() == fiber.MethodPost {
		// Read body
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			// Parse JSON
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}
}
Comment on lines +151 to +165

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

In extractModelFromRequest, c.Body() is called after c.Next() has already been called in the middleware chain; Fiber may have consumed or reset the body by this point, making the body read unreliable for metrics extraction.

Suggested fix
	// NOTE: c.Body() is only reliable before c.Next() is called.
	// This fallback path is only reached when the context local was not set by
	// RequestExtractor, so body-based extraction here may return empty.
	if c.Method() == fiber.MethodPost {
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 151-165
Issue Type: robustness-medium
Severity: medium

Issue Description:
In `extractModelFromRequest`, `c.Body()` is called after `c.Next()` has already been called in the middleware chain; Fiber may have consumed or reset the body by this point, making the body read unreliable for metrics extraction.

Current Code:
	if c.Method() == fiber.MethodPost {
		// Read body
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			// Parse JSON
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +151 to +165

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

In extractModelFromRequest, c.Body() is called after c.Next() has already been invoked in the middleware chain; depending on the Fiber version and body-parser configuration, the body may have been consumed or reset, making this read unreliable. The model should be extracted before calling c.Next(), or the context-local value set by RequestExtractor should be relied upon exclusively.

Suggested fix
	// Try to extract from JSON body for POST requests
	// Note: c.Body() is safe to call multiple times in Fiber (body is cached),
	// but model extraction should ideally happen before c.Next() to avoid
	// relying on post-handler body state. Consider moving extraction pre-Next.
	if c.Method() == fiber.MethodPost {
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 151-165
Issue Type: robustness-medium
Severity: medium

Issue Description:
In `extractModelFromRequest`, `c.Body()` is called after `c.Next()` has already been invoked in the middleware chain; depending on the Fiber version and body-parser configuration, the body may have been consumed or reset, making this read unreliable. The model should be extracted before calling `c.Next()`, or the context-local value set by `RequestExtractor` should be relied upon exclusively.

Current Code:
	// Try to extract from JSON body for POST requests
	if c.Method() == fiber.MethodPost {
		// Read body
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			// Parse JSON
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +151 to +165

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness Medium

In extractModelFromRequest, c.Body() is called after c.Next() has already been called in the middleware chain; Fiber may have consumed or reset the body by this point, making body parsing unreliable in a post-handler middleware context. The model should be extracted before calling c.Next(), or the context-local value should be relied upon exclusively.

Suggested fix
	// Move model extraction to before c.Next() is called, storing the result in a local variable,
	// so the body is still available. For example:
	//
	//   modelName := extractModelFromRequest(c)  // called before c.Next()
	//   err := c.Next()
	//   // use modelName after c.Next()
	//
	// Alternatively, rely solely on the CONTEXT_LOCALS_KEY_MODEL_NAME set by RequestExtractor.
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/metrics.go
Lines: 151-165
Issue Type: robustness-medium
Severity: medium

Issue Description:
In `extractModelFromRequest`, `c.Body()` is called after `c.Next()` has already been called in the middleware chain; Fiber may have consumed or reset the body by this point, making body parsing unreliable in a post-handler middleware context. The model should be extracted before calling `c.Next()`, or the context-local value should be relied upon exclusively.

Current Code:
	// Try to extract from JSON body for POST requests
	if c.Method() == fiber.MethodPost {
		// Read body
		bodyBytes := c.Body()
		if len(bodyBytes) > 0 {
			// Parse JSON
			var reqBody map[string]interface{}
			if err := json.Unmarshal(bodyBytes, &reqBody); err == nil {
				if modelVal, ok := reqBody["model"]; ok {
					if modelStr, ok := modelVal.(string); ok {
						return modelStr
					}
				}
			}
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Try path parameter for endpoints like /models/:model
model = c.Params("model")
if model != "" {
return model
}

return "unknown"
}
4 changes: 4 additions & 0 deletions core/http/middleware/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ func (re *RequestExtractor) SetModelAndConfig(initializer func() schema.LocalAIR
log.Debug().Str("context localModelName", localModelName).Msg("overriding empty model name in request body with value found earlier in middleware chain")
input.ModelName(&localModelName)
}
} else {
// Update context locals with the model name from the request body
// This ensures downstream middleware (like metrics) can access it
ctx.Locals(CONTEXT_LOCALS_KEY_MODEL_NAME, input.ModelName(nil))
Comment on lines +130 to +133

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

The request body can overwrite the trusted model selected earlier in middleware, so only set the local when it is empty or validate it against the authorized model.

Suggested fix
		} else {
			// Preserve the model selected earlier in the middleware chain.
			if localModelName, ok := ctx.Locals(CONTEXT_LOCALS_KEY_MODEL_NAME).(string); !ok || localModelName == "" {
				ctx.Locals(CONTEXT_LOCALS_KEY_MODEL_NAME, input.ModelName(nil))
			}
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/middleware/request.go
Lines: 130-133
Issue Type: security-high
Severity: high

Issue Description:
The request body can overwrite the trusted model selected earlier in middleware, so only set the local when it is empty or validate it against the authorized model.

Current Code:
		} else {
			// Update context locals with the model name from the request body
			// This ensures downstream middleware (like metrics) can access it
			ctx.Locals(CONTEXT_LOCALS_KEY_MODEL_NAME, input.ModelName(nil))
		}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}

cfg, err := re.modelConfigLoader.LoadModelConfigFileByNameDefaultOptions(input.ModelName(nil), re.applicationConfig)
Expand Down
3 changes: 3 additions & 0 deletions core/http/routes/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func RegisterUIRoutes(app *fiber.App,

app.Get("/", localai.WelcomeEndpoint(appConfig, cl, ml, processingOps))

// Settings page - detailed model/backend management
app.Get("/settings", localai.SettingsEndpoint(appConfig, cl, ml, processingOps))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security High

The new settings UI exposes ApplicationConfig to the template, which likely includes sensitive fields such as P2P tokens, so gate this route with authentication or pass only a sanitized view model.

Suggested change
app.Get("/settings", localai.SettingsEndpoint(appConfig, cl, ml, processingOps))
app.Get("/settings", middleware.RequireAuth(), localai.SettingsEndpoint(sanitizedConfig, cl, ml, processingOps))
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/http/routes/ui.go
Lines: 27-27
Issue Type: security-high
Severity: high

Issue Description:
The new settings UI exposes `ApplicationConfig` to the template, which likely includes sensitive fields such as P2P tokens, so gate this route with authentication or pass only a sanitized view model.

Current Code:
	app.Get("/settings", localai.SettingsEndpoint(appConfig, cl, ml, processingOps))

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// P2P
app.Get("/p2p", func(c *fiber.Ctx) error {
summary := fiber.Map{
Expand Down
Loading