Skip to content

feat(ui): add front-page stats#4

Open
DhirenMhatre wants to merge 1 commit into
masterfrom
feat/stats
Open

feat(ui): add front-page stats#4
DhirenMhatre wants to merge 1 commit into
masterfrom
feat/stats

Conversation

@DhirenMhatre

Copy link
Copy Markdown

No description provided.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory metrics collection via MetricsMiddleware to track API requests and expose /api/metrics/* endpoints for summaries and time-series data.
  • Introduced a new Settings page (/settings) with model/backend management UI, including status badges, detected models, and backend monitoring.
  • Redesigned the dashboard (index.html) to show real-time stats and charts, and refactored related views for consistent UX and feedback.

Key Changes by Area

Metrics & Monitoring: Added middleware to track requests, a metrics service with pruning, and Prometheus export via OpenTelemetry. Backend CPU/memory monitoring is now available.
Settings UI: Created a dedicated settings page with model and backend grids, status indicators, and actions like reload/delete.
Dashboard & Navigation: Replaced the old landing page with a metrics-driven dashboard; updated navbar and partials to support the new flow.

Files Changed

File Changes Summary
core/http/app.go Registered metrics middleware and new routes
core/http/endpoints/localai/settings.go Added SettingsEndpoint for model/backend management UI
core/http/middleware/metrics.go Implemented MetricsMiddleware to track request stats
core/http/middleware/request.go Added IsUIRoute helper to exclude UI routes from metrics
core/http/routes/ui.go Added /settings route and updated navigation
core/http/routes/ui_api.go Added /api/metrics/* endpoints
core/http/views/index.html Redesigned dashboard with metrics charts; fixed quick start guide
core/http/views/partials/navbar.html Added Settings link to navigation
core/http/views/settings.html New settings page with models/backends grids and notifications
core/services/metrics.go Implemented in-memory metrics store with pruning and Prometheus export

Review Focus Areas

  • Chart.js color handling in updateEndpointChart (index.html:316) may cause invisible chart entries for >5 endpoints.
  • External links in index.html and settings.html lack rel="noopener noreferrer" on target="_blank" attributes.

Architecture

Design Decisions: Metrics are stored in-memory with configurable limits and periodic pruning to prevent unbounded growth. Prometheus export uses OpenTelemetry for compatibility with existing tooling. Backend monitoring samples resource usage without modifying backend processes.

Scalability & Extensibility: Metrics service supports time-series queries and breakdowns by model/backend. Backend monitoring is lightweight and non-intrusive. Out-of-scope: persistent storage or distributed aggregation.

Risks: In-memory metrics may be lost on restart (intentional for simplicity). The chart color array issue (review finding) is unintentional and should be fixed. Missing rel="noopener noreferrer" is a security risk and should be addressed.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 5 HIGH-severity inline review findings need resolution (threshold: 3)
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

@greptile-apps

greptile-apps Bot commented May 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR redesigns the LocalAI home page into a split dashboard/welcome experience and introduces an in-memory metrics store backed by a new middleware and five API endpoints that power live Chart.js charts showing request counts, endpoint usage, and model usage.

  • A new /settings page absorbs all the model and backend management UI from the old index page, keeping the home page focused on the stats dashboard.
  • InMemoryMetricsStore tracks per-endpoint, per-model, and per-backend counters with a background pruning goroutine and exposes them via /api/metrics/* routes.
  • The metrics middleware is registered via router.Use() after the three main API route groups, which causes it to be skipped for every real API request in Fiber's ordered route-matching model — the dashboard will always show zeros until the registration order is corrected.

Confidence Score: 3/5

The UI and settings page changes are safe to merge, but the core feature — live API stats on the dashboard — will not work because the metrics middleware cannot intercept the existing API routes.

The middleware registration happens after the three main API route groups in app.go, so no real API request will ever be counted. Every chart on the new dashboard will display 'No data yet' regardless of actual traffic. The structural changes (new settings page, redesigned home page, new routes) are independently correct, but the feature the PR is named for is broken at the wiring layer. Two additional robustness concerns — an unguarded metrics-reset endpoint and a double-close risk in Stop() — sit on top of that central defect.

core/http/app.go needs the metricsStore initialization and router.Use() call moved above the RegisterElevenLabsRoutes/RegisterLocalAIRoutes/RegisterOpenAIRoutes calls. core/http/routes/ui_api.go needs an auth check on the reset endpoint. core/services/metrics.go needs a sync.Once guard in Stop().

Important Files Changed

Filename Overview
core/http/app.go Registers MetricsMiddleware via router.Use() after the three main API route groups, so the middleware will never intercept those requests in Fiber's ordered route-matching model.
core/services/metrics.go New in-memory metrics store with background pruning goroutine; Stop() has no double-close guard (can panic), and the bubble-sort used for map pruning is O(n²) but acceptable at the 1000-key limit.
core/http/middleware/metrics.go New middleware that captures endpoint/model/backend stats after each request; logic is sound but becomes a no-op for existing API routes due to the registration-order bug in app.go.
core/http/routes/ui_api.go Adds five metrics API endpoints; POST /api/metrics/reset lacks any authentication check, allowing unauthenticated callers to wipe all collected metrics.
core/http/views/index.html Redesigned dashboard with live Chart.js charts; Chart.js loaded from CDN without SRI hash, and the dashboard view depends on API data that will always be empty due to the middleware ordering bug.
core/http/endpoints/localai/settings.go New settings endpoint that renders the settings page with model/backend management data; closely mirrors WelcomeEndpoint and looks correct.
core/http/middleware/request.go Small addition to propagate the model name from the request body into Fiber context locals so the MetricsMiddleware can read it downstream.
core/http/routes/ui.go Registers the new /settings route backed by the new SettingsEndpoint; straightforward addition.
core/http/views/settings.html New settings page extracted from the old index.html, with full model/backend management UI; content looks correct and consistent with the existing patterns.
core/http/views/partials/navbar.html Adds 'Settings' link to both desktop and mobile nav menus; no issues.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Fiber Router
    participant ElevenLabs/LocalAI/OpenAI Routes
    participant MetricsMiddleware
    participant InMemoryMetricsStore
    participant Dashboard

    Note over Fiber Router: Registration order in app.go
    Note over Fiber Router: 1. ElevenLabs/LocalAI/OpenAI routes registered
    Note over Fiber Router: 2. MetricsMiddleware registered (too late!)
    Note over Fiber Router: 3. UI API + UI routes registered

    Client->>Fiber Router: POST /v1/chat/completions
    Fiber Router->>ElevenLabs/LocalAI/OpenAI Routes: Matched first (registered earlier)
    ElevenLabs/LocalAI/OpenAI Routes-->>Client: Response (no c.Next() call)
    Note over MetricsMiddleware: Never reached

    Client->>Fiber Router: GET /api/metrics/summary
    Fiber Router->>MetricsMiddleware: Runs (UI routes registered after)
    MetricsMiddleware->>InMemoryMetricsStore: GetTotalRequests(), GetEndpointStats()...
    InMemoryMetricsStore-->>MetricsMiddleware: All zeros (no data recorded)
    MetricsMiddleware-->>Client: "{totalRequests: 0, ...}"

    Client->>Fiber Router: GET /
    Fiber Router->>Dashboard: Render dashboard
    Dashboard-->>Client: Charts showing empty data
Loading

Comments Outside Diff (1)

  1. core/http/routes/ui_api.go, line 436-442 (link)

    P2 Unauthenticated metrics-reset endpoint

    POST /api/metrics/reset performs a destructive, state-mutating operation (wiping all collected metrics) with no authentication check. Any client that can reach the LocalAI instance — including unauthenticated HTTP callers — can silently zero out all dashboard data. The other GET metrics endpoints are read-only, but this one permanently destroys state. If the DisableWebUI guard is the only intended access control, that isn't sufficient because the WebUI is typically network-accessible.

Reviews (1): Last reviewed commit: "feat(ui): add front-page stats" | Re-trigger Greptile

Comment thread core/http/app.go
Comment on lines 208 to 226
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
})

// 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)
routes.RegisterUIRoutes(router, application.ModelConfigLoader(), application.ModelLoader(), application.ApplicationConfig(), application.GalleryService())

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.

Comment thread core/services/metrics.go
Comment on lines +168 to +170
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Stop() panics on double-close

close(m.stopChan) will panic with "close of closed channel" if called more than once. Fiber's OnShutdown hook is the only registered caller today, but there is no guard preventing a second invocation (e.g., if the hook fires twice during ungraceful shutdown, or a future caller adds another cleanup path). Wrapping the close in a sync.Once is the idiomatic Go protection for this pattern.

</div>

<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Chart.js is loaded from a CDN without a Subresource Integrity (SRI) hash. If the CDN is compromised or the package is updated unexpectedly, malicious JavaScript could be served to every user who opens the dashboard. Adding the integrity and crossorigin attributes pins the exact bytes that are allowed to execute.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js" integrity="sha256-oVuCFqrvkPCjkEiMGj3eaEJHXjFHNOa8CMEF8z1KFMY=" crossorigin="anonymous"></script>

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

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

Comment on lines +811 to +817
app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
metricsStore.Reset()
return c.JSON(fiber.Map{
"success": true,
"message": "Metrics reset successfully",
})
})

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 /api/metrics/reset endpoint is a state-mutating POST route with no authentication, authorization check, or CSRF protection guard beyond whatever global middleware applies, allowing any user or script with network access to silently wipe all metrics data.

Suggested fix
		// Reset metrics - restrict to admin/local access only
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			// Guard: only allow if caller has admin privileges or remove endpoint entirely in production
			if !appConfig.Debug {
				return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
					"error": "endpoint disabled in production",
				})
			}
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})
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_api.go
Lines: 811-817
Issue Type: security-high
Severity: high

Issue Description:
The `/api/metrics/reset` endpoint is a state-mutating POST route with no authentication, authorization check, or CSRF protection guard beyond whatever global middleware applies, allowing any user or script with network access to silently wipe all metrics data.

Current Code:
		// Reset metrics (optional - for testing/admin purposes)
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})

---

### 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 thread core/services/metrics.go
Comment on lines +168 to +170
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)
}

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

Stop() closes stopChan without guarding against double-close; calling Stop() twice will panic with 'close of closed channel'.

Suggested fix
func (m *InMemoryMetricsStore) Stop() {
	m.mu.Lock()
	defer m.mu.Unlock()
	select {
	case <-m.stopChan:
		// already closed
	default:
		close(m.stopChan)
	}
}
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/services/metrics.go
Lines: 168-170
Issue Type: robustness-high
Severity: high

Issue Description:
Stop() closes stopChan without guarding against double-close; calling Stop() twice will panic with 'close of closed channel'.

Current Code:
func (m *InMemoryMetricsStore) Stop() {
	close(m.stopChan)
}

---

### 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 thread core/services/metrics.go
Comment on lines +108 to +115
if len(newTimeSeries) > m.maxRecords {
// Keep the most recent maxRecords entries
newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
log.Warn().
Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
Int("kept", len(newTimeSeries)).
Msg("Metrics store exceeded maximum records, dropping oldest entries")
}

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 'dropped' count in the log message is computed after newTimeSeries has already been re-sliced, so len(m.timeSeries)-len(newTimeSeries) compares the original full slice against the already-truncated slice, producing an incorrect (inflated) dropped count.

Suggested fix
	if len(newTimeSeries) > m.maxRecords {
		beforeLen := len(newTimeSeries)
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", beforeLen-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")
	}
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/services/metrics.go
Lines: 108-115
Issue Type: functional-high
Severity: high

Issue Description:
The 'dropped' count in the log message is computed after newTimeSeries has already been re-sliced, so len(m.timeSeries)-len(newTimeSeries) compares the original full slice against the already-truncated slice, producing an incorrect (inflated) dropped count.

Current Code:
	if len(newTimeSeries) > m.maxRecords {
		// Keep the most recent maxRecords entries
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")
	}

---

### 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 thread core/services/metrics.go
Comment on lines +60 to +76
func NewInMemoryMetricsStore() *InMemoryMetricsStore {
store := &InMemoryMetricsStore{
endpoints: make(map[string]int64),
models: make(map[string]int64),
backends: make(map[string]int64),
timeSeries: make([]RequestRecord, 0),
stopChan: make(chan struct{}),
maxRecords: 10000, // Limit to 10k records (~1-2MB of memory)
maxMapKeys: 1000, // Limit to 1000 unique keys per map (~50KB per map)
pruneEvery: 5 * time.Minute, // Prune every 5 minutes instead of every request
}

// Start background pruning goroutine
go store.pruneLoop()

return store
}

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

NewInMemoryMetricsStore starts a goroutine (pruneLoop) that holds a reference to the store, but there is no way for callers to know they must call Stop(); if the store is abandoned without Stop(), the goroutine leaks for the lifetime of the process.

Suggested fix
// NewInMemoryMetricsStore creates a new in-memory metrics store.
// Callers MUST call Stop() when the store is no longer needed to release the background goroutine.
func NewInMemoryMetricsStore() *InMemoryMetricsStore {
	store := &InMemoryMetricsStore{
		endpoints:  make(map[string]int64),
		models:     make(map[string]int64),
		backends:   make(map[string]int64),
		timeSeries: make([]RequestRecord, 0),
		stopChan:   make(chan struct{}),
		maxRecords: 10000,
		maxMapKeys: 1000,
		pruneEvery: 5 * time.Minute,
	}

	go store.pruneLoop()

	return store
}
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/services/metrics.go
Lines: 60-76
Issue Type: robustness-high
Severity: high

Issue Description:
NewInMemoryMetricsStore starts a goroutine (pruneLoop) that holds a reference to the store, but there is no way for callers to know they must call Stop(); if the store is abandoned without Stop(), the goroutine leaks for the lifetime of the process.

Current Code:
func NewInMemoryMetricsStore() *InMemoryMetricsStore {
	store := &InMemoryMetricsStore{
		...
	}

	// Start background pruning goroutine
	go store.pruneLoop()

	return store
}

---

### 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

{{ if gt (len .ModelsConfig) 0 }}
this.fetchMetrics();
// Auto-refresh every 30 seconds
setInterval(() => this.fetchMetrics(), 30000);

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 setInterval at line 289 is never cleared; if the component is destroyed or re-initialized (e.g., via Alpine.js hot-reload or navigation), the interval leaks and continues firing, causing redundant fetches and potential errors on stale DOM references.

Suggested fix
            this._metricsInterval = setInterval(() => this.fetchMetrics(), 30000);
            // In a destroy/cleanup hook:
            // clearInterval(this._metricsInterval);
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 289-289
Issue Type: robustness-medium
Severity: medium

Issue Description:
The `setInterval` at line 289 is never cleared; if the component is destroyed or re-initialized (e.g., via Alpine.js hot-reload or navigation), the interval leaks and continues firing, causing redundant fetches and potential errors on stale DOM references.

Current Code:
            setInterval(() => this.fetchMetrics(), 30000);

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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 +166 to +170
<img {{ if and $cfg $cfg.Icon }}
src="{{$cfg.Icon}}"
{{ else }}
src="{{$noicon}}"
{{ end }}

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

The model icon URL from gallery config is rendered directly as an img src without validation, allowing the server-side data to cause the browser to make arbitrary outbound requests to attacker-controlled hosts if gallery config is compromised.

Suggested fix
                                <!-- Validate icon URLs server-side to only allow https:// scheme before passing to the template, or proxy images through a local endpoint -->
                                <!-- In the Go handler, sanitize $cfg.Icon to ensure it starts with https:// before rendering -->
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 166-170
Issue Type: security-medium
Severity: medium

Issue Description:
The model icon URL from gallery config is rendered directly as an img src without validation, allowing the server-side data to cause the browser to make arbitrary outbound requests to attacker-controlled hosts if gallery config is compromised.

Current Code:
                                <img {{ if and $cfg $cfg.Icon }}
                                    src="{{$cfg.Icon}}"
                                    {{ else }}
                                    src="{{$noicon}}"
                                    {{ end }}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 thread core/services/metrics.go
Comment on lines +143 to +149
for i := 0; i < len(entries); i++ {
for j := i + 1; j < len(entries); j++ {
if entries[i].value < entries[j].value {
entries[i], entries[j] = entries[j], entries[i]
}
}
}

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

pruneMapIfNeeded uses a hand-rolled O(n²) bubble sort; for maps that can grow to maxMapKeys (1000 entries) this is unnecessarily slow and should use sort.Slice instead.

Also reported at: core/services/metrics.go L276–L282

Suggested fix
	// Sort by value descending (keep highest counts)
	sort.Slice(entries, func(i, j int) bool {
		return entries[i].value > entries[j].value
	})
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/services/metrics.go
Lines: 143-149
Issue Type: performance-medium
Severity: medium

Issue Description:
pruneMapIfNeeded uses a hand-rolled O(n²) bubble sort; for maps that can grow to maxMapKeys (1000 entries) this is unnecessarily slow and should use sort.Slice instead.

_Also reported at: `core/services/metrics.go` L276–L282_

Current Code:
	// Sort by value descending (keep highest counts)
	for i := 0; i < len(entries); i++ {
		for j := i + 1; j < len(entries); j++ {
			if entries[i].value < entries[j].value {
				entries[i], entries[j] = entries[j], entries[i]
			}
		}
	}

---

### 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 thread core/services/metrics.go
Comment on lines +250 to +254
func (m *InMemoryMetricsStore) GetRequestsOverTime(hours int) []TimeSeriesPoint {
m.mu.RLock()
defer m.mu.RUnlock()

cutoff := time.Now().Add(-time.Duration(hours) * time.Hour)

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

GetRequestsOverTime accepts an unbounded positive integer for 'hours'; a caller passing a very large value (e.g., math.MaxInt) causes time.Duration overflow in the cutoff calculation, returning incorrect results instead of an error or a capped value.

Suggested fix
func (m *InMemoryMetricsStore) GetRequestsOverTime(hours int) []TimeSeriesPoint {
	const maxHours = 24 * 365 // cap at one year
	if hours <= 0 {
		hours = 24
	} else if hours > maxHours {
		hours = maxHours
	}
	m.mu.RLock()
	defer m.mu.RUnlock()

	cutoff := time.Now().Add(-time.Duration(hours) * time.Hour)
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/services/metrics.go
Lines: 250-254
Issue Type: robustness-medium
Severity: medium

Issue Description:
GetRequestsOverTime accepts an unbounded positive integer for 'hours'; a caller passing a very large value (e.g., math.MaxInt) causes time.Duration overflow in the cutoff calculation, returning incorrect results instead of an error or a capped value.

Current Code:
func (m *InMemoryMetricsStore) GetRequestsOverTime(hours int) []TimeSeriesPoint {
	m.mu.RLock()
	defer m.mu.RUnlock()

	cutoff := time.Now().Add(-time.Duration(hours) * time.Hour)

---

### 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 thread core/services/metrics.go
Comment on lines +173 to +211
func (m *InMemoryMetricsStore) RecordRequest(endpoint, model, backend string, success bool, duration time.Duration) {
m.mu.Lock()
defer m.mu.Unlock()

// Record endpoint
if endpoint != "" {
m.endpoints[endpoint]++
}

// Record model
if model != "" {
m.models[model]++
}

// Record backend
if backend != "" {
m.backends[backend]++
}

// Record success/failure
if success {
m.successCount++
} else {
m.failureCount++
}

// Add to time series
record := RequestRecord{
Timestamp: time.Now(),
Endpoint: endpoint,
Model: model,
Backend: backend,
Success: success,
Duration: duration,
}
m.timeSeries = append(m.timeSeries, record)

// Note: Pruning is done periodically by pruneLoop() to avoid overhead on every request
}

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

Endpoint, model, and backend strings supplied by HTTP callers are stored as map keys without length or character validation; an attacker can craft arbitrarily long strings that consume memory before the periodic pruner runs.

Suggested fix
const maxKeyLen = 256

func truncateKey(s string) string {
	if len(s) > maxKeyLen {
		return s[:maxKeyLen]
	}
	return s
}

func (m *InMemoryMetricsStore) RecordRequest(endpoint, model, backend string, success bool, duration time.Duration) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if endpoint != "" {
		m.endpoints[truncateKey(endpoint)]++
	}
	if model != "" {
		m.models[truncateKey(model)]++
	}
	if backend != "" {
		m.backends[truncateKey(backend)]++
	}
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/services/metrics.go
Lines: 173-211
Issue Type: security-medium
Severity: medium

Issue Description:
Endpoint, model, and backend strings supplied by HTTP callers are stored as map keys without length or character validation; an attacker can craft arbitrarily long strings that consume memory before the periodic pruner runs.

Current Code:
func (m *InMemoryMetricsStore) RecordRequest(endpoint, model, backend string, success bool, duration time.Duration) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if endpoint != "" {
		m.endpoints[endpoint]++
	}
	if model != "" {
		m.models[model]++
	}
	if backend != "" {
		m.backends[backend]++
	}

---

### 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

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

Nitpicks (Low Priority)

Found 2 low-priority suggestions for code improvement

Click to expand nitpicks

core/http/views/index.html (lines 37-238)

Security Low

External links to https://localai.io open with target="_blank" but are missing rel="noopener noreferrer", which allows the opened page to access window.opener and potentially redirect the parent page.

Also reported at: core/http/views/settings.html L60–L65

Code Suggestion or Comments
<a href="https://localai.io/basics/getting_started/" target="_blank" rel="noopener noreferrer" class="...">
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 37-238
Issue Type: security-low
Severity: low

Issue Description:
External links to `https://localai.io` open with `target="_blank"` but are missing `rel="noopener noreferrer"`, which allows the opened page to access `window.opener` and potentially redirect the parent page.

_Also reported at: `core/http/views/settings.html` L60–L65_

Current Code:
<a href="https://localai.io/basics/getting_started/" target="_blank" class="...">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

---



core/http/views/index.html (line 316)

Robustness Low

In updateEndpointChart, the colors array has only 5 entries but endpoints may contain more items; endpoints beyond index 4 will receive undefined as their background color, rendering them invisible in the chart.

Code Suggestion or Comments
const palette = ['#38BDF8', '#8B5CF6', '#10B981', '#F59E0B', '#EF4444'];
            const colors = endpoints.map((_, i) => palette[i % palette.length]);
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 316-316
Issue Type: robustness-low
Severity: low

Issue Description:
In `updateEndpointChart`, the `colors` array has only 5 entries but `endpoints` may contain more items; endpoints beyond index 4 will receive `undefined` as their background color, rendering them invisible in the chart.

Current Code:
            const colors = ['#38BDF8', '#8B5CF6', '#10B981', '#F59E0B', '#EF4444'];

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Clean
Files Scanned 10

No critical security issues detected

Scan completed in 32.7s

Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 283
Unknown License 51

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 51 packages
  • github.com/docker/docker 28.5.1+incompatible
  • github.com/docker/distribution 2.8.2+incompatible
  • github.com/docker/docker-credential-helpers 0.7.0
  • github.com/docker/go-connections 0.6.0
  • github.com/docker/go-units 0.5.0
  • github.com/dsnet/compress 0.0.2-0.20210315054119-f66993602bf5
  • github.com/flynn/noise 1.1.0
  • github.com/go-audio/audio 1.0.0
  • github.com/go-audio/riff 1.0.0
  • github.com/go-logr/logr 1.4.3
  • github.com/go-logr/stdr 1.2.2
  • github.com/go-openapi/jsonpointer 0.21.0
  • github.com/go-openapi/jsonreference 0.21.0
  • github.com/go-openapi/spec 0.21.0
  • github.com/go-openapi/swag 0.23.0
  • github.com/gogo/protobuf 1.3.2
  • github.com/golang/groupcache 0.0.0-20210331224755-41bb18bfe9da
  • github.com/golang/snappy 0.0.4
  • github.com/google/btree 1.1.3
  • github.com/google/go-cmp 0.7.0

...and 31 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 16, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-16 21:59 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 4
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:30 (Error_Handling · HIGH)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed and not logged, which can lead to silent failures.
Suggestion: Log the error before continuing to ensure visibility of issues.

if err != nil { continue }

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics, health routes, and UI routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-003] core/http/endpoints/localai/settings.go:1 (Documentation · MEDIUM)

Issue: The SettingsEndpoint function lacks a docstring explaining its parameters and return values.
Suggestion: Add a docstring to describe the function's purpose, parameters, and return values.

func SettingsEndpoint(appConfig *config.ApplicationConfig, ...

[CQ-LLM-004] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function directly depends on services.MetricsStore, making it hard to test in isolation.
Suggestion: Consider using dependency injection to pass the metrics store, allowing for easier testing with mocks.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler { ... }

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-LLM-005] core/http/middleware/metrics.go:10 (Maintainability · LOW)

Issue: The use of magic strings in the skipPrefixes array can lead to maintenance issues.
Suggestion: Define constants for the skip prefixes to improve readability and maintainability.

skipPrefixes := []string{ "/views/", "/static/", ... }

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

[CQ-008] core/http/routes/ui_api.go:796 (Maintainability · LOW)

Issue: Magic number 24 in code
Suggestion: Extract to a named constant

hours := 24

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 1 0 2
core/http/middleware/metrics.go 0 0 1 2 3
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory metrics tracking for API usage with automatic pruning and REST endpoints for dashboard visualization.
  • Redesigned the web UI to separate dashboard (metrics/monitoring) from settings (model/backend management).
  • Added Chart.js visualizations for endpoint usage, model requests, and 24-hour timelines with 30-second auto-refresh.

Key Changes by Area

Metrics System: New MetricsStore interface with InMemoryMetricsStore implementation tracking endpoint/model/backend usage, success rates, and request duration with 5-minute pruning.

API: New /api/metrics/ endpoints for summary stats, breakdowns, time series data, and reset functionality. MetricsMiddleware intercepts requests and skips UI/static routes.

UI/Dashboard: Complete index.html redesign with conditional welcome wizard vs. metrics dashboard, 4 stat cards, and 3 Chart.js visualizations.

UI/Settings: New settings.html with dedicated model/backend management, hero navigation, toast notifications, and action buttons (Chat/Image/TTS/Stop/Edit/Delete).

Navigation: Added Settings link to desktop and mobile navbars.

Files Changed

File Changes Summary
core/http/app.go Initializes InMemoryMetricsStore with graceful shutdown hook
core/http/endpoints/localai/settings.go New endpoint for model/backend management details
core/http/middleware/metrics.go MetricsMiddleware for API request tracking with skip logic
core/http/middleware/request.go Exposes model name to context locals for metrics consumption
core/http/routes/ui.go New /settings route registration
core/http/routes/ui_api.go New /api/metrics/* REST endpoints
core/http/views/index.html Redesigned with conditional dashboard, stat cards, Chart.js visualizations
core/http/views/partials/navbar.html Added Settings navigation link
core/http/views/settings.html New settings page with model/backend grids and action buttons
core/services/metrics.go MetricsStore interface and InMemoryMetricsStore implementation

Review Focus Areas

  • HTML structure validation in core/http/views/index.html:226-236 (misindented closing tag).
  • Memory usage of InMemoryMetricsStore under high load (10k record limit, 24h retention).
  • Thread safety of metrics collection during concurrent API requests.

Architecture

Design Decisions: In-memory metrics chosen for simplicity and low latency. Prometheus/OpenTelemetry remain for external monitoring. UI routes excluded from metrics to reduce noise. Auto-pruning (5 min interval) balances granularity with memory.

Scalability & Extensibility: Metrics system is intentionally single-node. Out of scope: distributed metrics aggregation, persistent storage, or horizontal scaling. Token metrics endpoint stubbed but not wired.

Risks:

  • Intentional: In-memory storage loses data on restart. Acceptable for dashboard trends, not billing.
  • Unintentional: Chart.js and Alpine.js dependencies add client-side weight. Auto-refresh every 30 seconds may stress low-power clients.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 10 HIGH-severity inline review findings need resolution (threshold: 3)
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

Comment thread core/http/app.go
Comment on lines +207 to +225

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
})

// 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)

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

"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

Comment on lines +811 to +817
app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
metricsStore.Reset()
return c.JSON(fiber.Map{
"success": true,
"message": "Metrics reset successfully",
})
})

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 /api/metrics/reset endpoint is unauthenticated and unguarded, allowing any user or unauthenticated request to wipe all metrics data; it should require admin authorization or be removed from production.

Suggested fix
		// Reset metrics - admin only
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			// TODO: add admin/role check before allowing reset
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})
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_api.go
Lines: 811-817
Issue Type: security-high
Severity: high

Issue Description:
The `/api/metrics/reset` endpoint is unauthenticated and unguarded, allowing any user or unauthenticated request to wipe all metrics data; it should require admin authorization or be removed from production.

Current Code:
		// Reset metrics (optional - for testing/admin purposes)
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})

---

### 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


<body class="bg-[#101827] text-[#E5E7EB]">
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">
<div class="flex flex-col min-h-screen" x-data="dashboardMetrics()">

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 x-data attribute references dashboardMetrics() (line 6) but the old code used indexDashboard(), and the charts/stats cards rely on Alpine.js properties (totalRequests, successRate, hasEndpointData, hasModelData, hasTimelineData) that must be defined in this new component; if dashboardMetrics() is not defined or missing these properties, all dynamic stat cards and charts will silently show stale/zero values or throw Alpine errors.

Also reported at: core/http/views/index.html L6

Suggested fix
<!-- Ensure dashboardMetrics() is defined in a <script> block and exposes:
     totalRequests, successRate, hasEndpointData, hasModelData, hasTimelineData
     and initialises Chart.js instances for endpointChart, modelChart, timelineChart -->
<div class="flex flex-col min-h-screen" x-data="dashboardMetrics()">
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 6-6
Issue Type: functional-high
Severity: high

Issue Description:
The `x-data` attribute references `dashboardMetrics()` (line 6) but the old code used `indexDashboard()`, and the charts/stats cards rely on Alpine.js properties (`totalRequests`, `successRate`, `hasEndpointData`, `hasModelData`, `hasTimelineData`) that must be defined in this new component; if `dashboardMetrics()` is not defined or missing these properties, all dynamic stat cards and charts will silently show stale/zero values or throw Alpine errors.

_Also reported at: `core/http/views/index.html` L6_

Current Code:
<div class="flex flex-col min-h-screen" x-data="dashboardMetrics()">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 thread core/services/metrics.go
Comment on lines +168 to +170
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)
}

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

Calling Stop() more than once panics because close on an already-closed channel causes a runtime panic; guard with a sync.Once to make it safe.

Suggested fix
func (m *InMemoryMetricsStore) Stop() {
	m.mu.Lock()
	defer m.mu.Unlock()
	select {
	case <-m.stopChan:
		// already closed
	default:
		close(m.stopChan)
	}
}
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/services/metrics.go
Lines: 168-170
Issue Type: robustness-high
Severity: high

Issue Description:
Calling `Stop()` more than once panics because `close` on an already-closed channel causes a runtime panic; guard with a `sync.Once` to make it safe.

Current Code:
func (m *InMemoryMetricsStore) Stop() {
	close(m.stopChan)
}

---

### 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 +476 to +486
const data = await response.json();

if (response.ok && data.success) {
this.addNotification(`Backend "${backendName}" deleted successfully!`, 'success');
// Reload page after short delay
setTimeout(() => {
window.location.reload();
}, 1500);
} else {
this.addNotification(`Failed to delete backend: ${data.error || 'Unknown error'}`, 'error');
}

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 deleteBackend function calls /api/backends/system/delete/ but response.json() is called unconditionally before checking response.ok; if the server returns a non-JSON error body (e.g., 404 HTML), this will throw and the catch block will surface a confusing parse error instead of the real HTTP error.

Also reported at: core/http/views/settings.html L562–L588

Suggested fix
                let data = {};
                try { data = await response.json(); } catch (_) {}
                
                if (response.ok && data.success) {
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 476-486
Issue Type: functional-medium
Severity: medium

Issue Description:
The `deleteBackend` function calls `/api/backends/system/delete/` but `response.json()` is called unconditionally before checking `response.ok`; if the server returns a non-JSON error body (e.g., 404 HTML), this will throw and the catch block will surface a confusing parse error instead of the real HTTP error.

_Also reported at: `core/http/views/settings.html` L562–L588_

Current Code:
                const data = await response.json();
                
                if (response.ok && data.success) {

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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 +548 to +553
const icon = button.querySelector('i');

// Show loading state
button.disabled = true;
button.querySelector('span').textContent = 'Updating...';
icon.classList.add('fa-spin');

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 icon variable is captured before the button is disabled; if the button has multiple <i> elements (it has two: fa-sync-alt and fa-refresh), querySelector('i') only returns the first one, so the second icon never gets the spin class and the visual feedback is incomplete.

Suggested fix
            const icons = button.querySelectorAll('i');
            const icon = icons[0]; // primary icon

            // Show loading state
            button.disabled = true;
            button.querySelector('span').textContent = 'Updating...';
            icon.classList.add('fa-spin');
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 548-553
Issue Type: robustness-medium
Severity: medium

Issue Description:
The `icon` variable is captured before the button is disabled; if the button has multiple `<i>` elements (it has two: `fa-sync-alt` and `fa-refresh`), `querySelector('i')` only returns the first one, so the second icon never gets the spin class and the visual feedback is incomplete.

Current Code:
            const icon = button.querySelector('i');

            // Show loading state
            button.disabled = true;
            button.querySelector('span').textContent = 'Updating...';
            icon.classList.add('fa-spin');

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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 +195 to +199
{{ if and $backendCfg (or (ne $backendCfg.MCP.Servers "") (ne $backendCfg.MCP.Stdio "")) }}
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold bg-[#8B5CF6]/20 text-[#8B5CF6] border border-[#8B5CF6]/30">
<i class="fas fa-plug mr-1"></i>MCP
</span>
{{ end }}

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 MCP badge condition uses ne $backendCfg.MCP.Servers "" and ne $backendCfg.MCP.Stdio "" but if these fields are slices or structs rather than plain strings, the Go template ne comparison against "" will always evaluate to true (non-empty interface), showing the MCP badge incorrectly for every model.

Suggested change
{{ if and $backendCfg (or (ne $backendCfg.MCP.Servers "") (ne $backendCfg.MCP.Stdio "")) }}
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold bg-[#8B5CF6]/20 text-[#8B5CF6] border border-[#8B5CF6]/30">
<i class="fas fa-plug mr-1"></i>MCP
</span>
{{ end }}
{{ if and $backendCfg (or $backendCfg.MCP.Servers $backendCfg.MCP.Stdio) }}
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 195-199
Issue Type: functional-medium
Severity: medium

Issue Description:
The MCP badge condition uses `ne $backendCfg.MCP.Servers ""` and `ne $backendCfg.MCP.Stdio ""` but if these fields are slices or structs rather than plain strings, the Go template `ne` comparison against `""` will always evaluate to true (non-empty interface), showing the MCP badge incorrectly for every model.

Current Code:
{{ if and $backendCfg (or (ne $backendCfg.MCP.Servers "") (ne $backendCfg.MCP.Stdio ""))  }}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 thread core/services/metrics.go
Comment on lines +108 to +115
if len(newTimeSeries) > m.maxRecords {
// Keep the most recent maxRecords entries
newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
log.Warn().
Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
Int("kept", len(newTimeSeries)).
Msg("Metrics store exceeded maximum records, dropping oldest entries")
}

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 dropped count in the log warning is computed after newTimeSeries has already been re-sliced to maxRecords, so len(m.timeSeries) - len(newTimeSeries) equals original_count - maxRecords and incorrectly includes records already removed by the 24-hour cutoff filter; capture the pre-slice length before line 110 to log the accurate count.

Suggested fix
	if len(newTimeSeries) > m.maxRecords {
		// Keep the most recent maxRecords entries
		preSliceLen := len(newTimeSeries)
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", preSliceLen-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")
	}
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/services/metrics.go
Lines: 108-115
Issue Type: functional-medium
Severity: medium

Issue Description:
The `dropped` count in the log warning is computed after `newTimeSeries` has already been re-sliced to `maxRecords`, so `len(m.timeSeries) - len(newTimeSeries)` equals `original_count - maxRecords` and incorrectly includes records already removed by the 24-hour cutoff filter; capture the pre-slice length before line 110 to log the accurate count.

Current Code:
	if len(newTimeSeries) > m.maxRecords {
		// Keep the most recent maxRecords entries
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")
	}

---

### 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 thread core/services/metrics.go
Comment on lines +143 to +149
for i := 0; i < len(entries); i++ {
for j := i + 1; j < len(entries); j++ {
if entries[i].value < entries[j].value {
entries[i], entries[j] = entries[j], entries[i]
}
}
}

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

Both pruneMapIfNeeded (lines 143-149) and GetRequestsOverTime (lines 276-282) use O(n²) bubble sort; replace with sort.Slice to avoid quadratic time on large inputs.

Also reported at: core/services/metrics.go L276–L282

Suggested fix
	// Sort by value descending (keep highest counts)
	sort.Slice(entries, func(i, j int) bool {
		return entries[i].value > entries[j].value
	})
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/services/metrics.go
Lines: 143-149
Issue Type: performance-medium
Severity: medium

Issue Description:
Both `pruneMapIfNeeded` (lines 143-149) and `GetRequestsOverTime` (lines 276-282) use O(n²) bubble sort; replace with `sort.Slice` to avoid quadratic time on large inputs.

_Also reported at: `core/services/metrics.go` L276–L282_

Current Code:
	// Sort by value descending (keep highest counts)
	for i := 0; i < len(entries); i++ {
		for j := i + 1; j < len(entries); j++ {
			if entries[i].value < entries[j].value {
				entries[i], entries[j] = entries[j], entries[i]
			}
		}
	}

---

### 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

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Nitpicks (Low Priority)

Found 1 low-priority suggestions for code improvement

Click to expand nitpicks

core/http/views/index.html (lines 226-236)

Maintainability Low

The closing </div> at line 235 is misindented and placed before the closing </a> at line 236, breaking the visual nesting of the Gallery quick-link card and making the HTML structure misleading.

Code Suggestion or Comments
<a href="/browse" class="group bg-[#1E293B] border border-[#8B5CF6]/20 rounded-2xl p-6 transition-all duration-300 hover:shadow-[0_0_15px_rgba(139,92,246,0.2)] hover:-translate-y-1">
                <div class="flex items-center space-x-4">
                    <div class="w-12 h-12 rounded-xl bg-[#8B5CF6]/20 flex items-center justify-center group-hover:scale-110 transition-transform">
                        <i class="fas fa-images text-xl text-[#8B5CF6]"></i>
                    </div>
                    <div>
                        <h4 class="font-semibold text-[#E5E7EB] group-hover:text-[#8B5CF6] transition-colors">Gallery</h4>
                        <p class="text-sm text-[#94A3B8]">Browse Models</p>
                    </div>
                </div>
            </a>
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 226-236
Issue Type: maintainability-low
Severity: low

Issue Description:
The closing `</div>` at line 235 is misindented and placed before the closing `</a>` at line 236, breaking the visual nesting of the Gallery quick-link card and making the HTML structure misleading.

Current Code:
            <a href="/browse" class="group bg-[#1E293B] border border-[#8B5CF6]/20 rounded-2xl p-6 ...">
                <div class="flex items-center space-x-4">
                    ...
              </div>
                </div>
            </a>

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Clean
Files Scanned 10

No critical security issues detected

Scan completed in 34.1s

Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 288
Unknown License 46

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 46 packages
  • github.com/docker/docker 28.5.1+incompatible
  • github.com/davidlazar/go-crypto 0.0.0-20200604182044-b73af7476f6c
  • github.com/docker/go-connections 0.6.0
  • github.com/dsnet/compress 0.0.2-0.20210315054119-f66993602bf5
  • github.com/docker/docker-credential-helpers 0.7.0
  • github.com/docker/go-units 0.5.0
  • github.com/flynn/noise 1.1.0
  • github.com/go-audio/riff 1.0.0
  • github.com/go-audio/audio 1.0.0
  • github.com/go-logr/stdr 1.2.2
  • github.com/go-logr/logr 1.4.3
  • github.com/go-openapi/jsonpointer 0.21.0
  • github.com/go-openapi/spec 0.21.0
  • github.com/go-openapi/jsonreference 0.21.0
  • github.com/go-openapi/swag 0.23.0
  • github.com/gogo/protobuf 1.3.2
  • github.com/golang/groupcache 0.0.0-20210331224755-41bb18bfe9da
  • github.com/google/btree 1.1.3
  • github.com/golang/snappy 0.0.4
  • github.com/google/go-cmp 0.7.0

...and 26 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-17 16:21 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 4
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:30 (Error_Handling · HIGH)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed, which can lead to silent failures.
Suggestion: Log the error or return it to the caller to handle appropriately.

cfg, err := gallery.GetLocalModelConfiguration(ml.ModelPath, m.Name)
if err != nil {
    continue
}

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics, health routes, and UI routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-005] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function directly depends on services.MetricsStore, making it hard to test in isolation.
Suggestion: Consider using dependency injection to pass in the metrics store, allowing for easier mocking in tests.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler {

[CQ-LLM-003] core/http/middleware/metrics.go:45 (Performance · MEDIUM)

Issue: The shouldSkipMetrics function iterates over a list of prefixes for each request, which can be inefficient if the list grows.
Suggestion: Consider using a more efficient data structure, such as a map, for faster lookups.

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

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-LLM-004] core/http/endpoints/localai/settings.go:1 (Documentation · LOW)

Issue: The SettingsEndpoint function lacks a docstring explaining its parameters and return values.
Suggestion: Add a docstring to describe the function's purpose, parameters, and return values.

func SettingsEndpoint(appConfig *config.ApplicationConfig, cl *config.ModelConfigLoader, ml *model.ModelLoader, opcache *services.OpCache) func(*fiber.Ctx) error {

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

[CQ-008] core/http/routes/ui_api.go:796 (Maintainability · LOW)

Issue: Magic number 24 in code
Suggestion: Extract to a named constant

hours := 24

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 0 1 2
core/http/middleware/metrics.go 0 0 2 1 3
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added a complete usage metrics system that tracks API requests by endpoint, model, and backend with automatic memory pruning.
  • Redesigned the dashboard with a dual-state view: welcome wizard for new users, metrics dashboard with Chart.js visualizations for existing deployments.
  • Moved model and backend management to a new dedicated Settings page with toast notifications and reload capabilities.

Key Changes by Area

Metrics Infrastructure: In-memory store with 24-hour data retention and 5-minute background pruning to prevent memory bloat. Thread-safe with sync.RWMutex.

API: New endpoints for metrics summary, timeseries data, and admin reset. Settings endpoint aggregates model configs, gallery configs, and operation statuses.

UI/UX: Chart.js integration with auto-refreshing dashboards. Consistent gradient styling across all pages. Toast notification system for async operation feedback.

Files Changed

File Changes Summary
core/http/app.go Metrics middleware registration and store lifecycle management
core/http/endpoints/localai/settings.go New settings page handler aggregating configs and model states
core/http/middleware/metrics.go Request tracking middleware with model/backend extraction
core/http/middleware/request.go Expose model name to context for metrics correlation
core/http/routes/ui.go Settings page route registration
core/http/routes/ui_api.go Metrics API endpoints (summary, timeseries, reset)
core/http/views/index.html Dual-state dashboard with Chart.js metrics visualization
core/http/views/partials/navbar.html Settings navigation link added
core/http/views/settings.html New management page with notifications and backend deletion
core/services/metrics.go In-memory metrics store with pruning and thread-safe operations

Review Focus Areas

  • Memory pruning logic in core/services/metrics.go: verify 10k record limits and 24-hour retention behave correctly under load.
  • DOM nesting in core/http/views/index.html:233-236: closing </div> appears outside <a> tag, may cause layout issues.
  • Metrics middleware exclusion rules: confirm UI/static routes are properly skipped to avoid noise.

Architecture

Design Decisions: In-memory storage chosen for simplicity with explicit pruning instead of persistence. Interface-based design (MetricsStore) allows future persistent backends. Pruning runs asynchronously to avoid request latency impact. Map size limits keep highest-count entries on overflow, favoring recent activity over completeness.

Scalability & Extensibility: Current implementation is single-node only. Out of scope: distributed metrics aggregation, persistent storage, or external metrics export (Prometheus/OpenTelemetry scaffolding exists but not wired).

Risks: Memory usage can spike between pruning intervals under heavy load. Intentional: data loss on restart (acceptable for usage stats). Unintentional: pruning may drop useful historical data if request patterns are bursty.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 1 CRITICAL inline review finding need resolution
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

Comment thread core/services/metrics.go
Comment on lines +110 to +114
newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
log.Warn().
Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
Int("kept", len(newTimeSeries)).
Msg("Metrics store exceeded maximum records, dropping oldest entries")

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 Critical

The dropped count in the log message is computed as len(m.timeSeries)-len(newTimeSeries) AFTER newTimeSeries has already been sliced down to maxRecords, so len(newTimeSeries) is always maxRecords and the logged drop count is wrong; capture the pre-slice length before reassigning.

Suggested fix
		originalLen := len(newTimeSeries)
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", originalLen-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")
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/services/metrics.go
Lines: 110-114
Issue Type: functional-critical
Severity: critical

Issue Description:
The `dropped` count in the log message is computed as `len(m.timeSeries)-len(newTimeSeries)` AFTER `newTimeSeries` has already been sliced down to `maxRecords`, so `len(newTimeSeries)` is always `maxRecords` and the logged drop count is wrong; capture the pre-slice length before reassigning.

Current Code:
		newTimeSeries = newTimeSeries[len(newTimeSeries)-m.maxRecords:]
		log.Warn().
			Int("dropped", len(m.timeSeries)-len(newTimeSeries)).
			Int("kept", len(newTimeSeries)).
			Msg("Metrics store exceeded maximum records, dropping oldest entries")

---

### 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 thread core/http/app.go
Comment on lines +207 to +225

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
})

// 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)

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

"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

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

Comment on lines +811 to +817
app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
metricsStore.Reset()
return c.JSON(fiber.Map{
"success": true,
"message": "Metrics reset successfully",
})
})

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 /api/metrics/reset endpoint is unauthenticated and unprotected, allowing any user or anonymous caller to wipe all metrics data; it should require admin authorization or be removed from production.

Suggested fix
		// Reset metrics - admin only
		app.Post("/api/metrics/reset", adminAuthMiddleware, func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})
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_api.go
Lines: 811-817
Issue Type: security-high
Severity: high

Issue Description:
The `/api/metrics/reset` endpoint is unauthenticated and unprotected, allowing any user or anonymous caller to wipe all metrics data; it should require admin authorization or be removed from production.

Current Code:
		// Reset metrics (optional - for testing/admin purposes)
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})

---

### 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


<body class="bg-[#101827] text-[#E5E7EB]">
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">
<div class="flex flex-col min-h-screen" x-data="dashboardMetrics()">

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 notification system (x-for="notification in notifications", dismissNotification, etc.) was removed along with the indexDashboard() Alpine.js component, but the root element now references dashboardMetrics() instead; if dashboardMetrics does not expose notifications/dismissNotification, any code elsewhere that still triggers notifications will silently fail or throw a JS error.

Suggested fix
<!-- Ensure dashboardMetrics() in the companion JS file exposes all properties
     previously provided by indexDashboard() that are still needed (e.g. notifications),
     or restore a separate notification container driven by a shared Alpine store. -->
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 6-6
Issue Type: functional-high
Severity: high

Issue Description:
The notification system (`x-for="notification in notifications"`, `dismissNotification`, etc.) was removed along with the `indexDashboard()` Alpine.js component, but the root element now references `dashboardMetrics()` instead; if `dashboardMetrics` does not expose `notifications`/`dismissNotification`, any code elsewhere that still triggers notifications will silently fail or throw a JS error.

Current Code:
<div class="flex flex-col min-h-screen" x-data="dashboardMetrics()">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 +476 to +486
const data = await response.json();

if (response.ok && data.success) {
this.addNotification(`Backend "${backendName}" deleted successfully!`, 'success');
// Reload page after short delay
setTimeout(() => {
window.location.reload();
}, 1500);
} else {
this.addNotification(`Failed to delete backend: ${data.error || 'Unknown error'}`, 'error');
}

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 deleteBackend function calls /api/backends/system/delete/ but response.json() is called unconditionally before checking response.ok; if the server returns a non-JSON error body (e.g., 404 HTML), this will throw and the catch block will surface a confusing parse error instead of the real HTTP error.

Suggested fix
                let data = {};
                try { data = await response.json(); } catch (_) {}
                
                if (response.ok && data.success) {
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 476-486
Issue Type: functional-medium
Severity: medium

Issue Description:
The `deleteBackend` function calls `/api/backends/system/delete/` but `response.json()` is called unconditionally before checking `response.ok`; if the server returns a non-JSON error body (e.g., 404 HTML), this will throw and the catch block will surface a confusing parse error instead of the real HTTP error.

Current Code:
                const data = await response.json();
                
                if (response.ok && data.success) {

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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

{{template "views/partials/head" .}}

<body class="bg-[#101827] text-[#E5E7EB]">
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">

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 x-data attribute on the root <div> uses indexDashboard() (line 6), but this is a settings page; the Alpine component is named indexDashboard which is semantically misleading and could conflict if index.html also defines a global indexDashboard function in the same page scope.

Suggested change
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">
<div class="flex flex-col min-h-screen" x-data="settingsDashboard()">
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 6-6
Issue Type: functional-medium
Severity: medium

Issue Description:
The `x-data` attribute on the root `<div>` uses `indexDashboard()` (line 6), but this is a settings page; the Alpine component is named `indexDashboard` which is semantically misleading and could conflict if `index.html` also defines a global `indexDashboard` function in the same page scope.

Current Code:
<div class="flex flex-col min-h-screen" x-data="indexDashboard()">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 thread core/services/metrics.go
Comment on lines +143 to +149
for i := 0; i < len(entries); i++ {
for j := i + 1; j < len(entries); j++ {
if entries[i].value < entries[j].value {
entries[i], entries[j] = entries[j], entries[i]
}
}
}

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

The bubble-sort in pruneMapIfNeeded is O(n²) over up to maxMapKeys (1000) entries; replace with sort.Slice for O(n log n) performance.

Also reported at: core/services/metrics.go L276–L282

Suggested fix
	// Sort by value descending (keep highest counts)
	sort.Slice(entries, func(i, j int) bool {
		return entries[i].value > entries[j].value
	})
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/services/metrics.go
Lines: 143-149
Issue Type: performance-medium
Severity: medium

Issue Description:
The bubble-sort in `pruneMapIfNeeded` is O(n²) over up to `maxMapKeys` (1000) entries; replace with `sort.Slice` for O(n log n) performance.

_Also reported at: `core/services/metrics.go` L276–L282_

Current Code:
	// Sort by value descending (keep highest counts)
	for i := 0; i < len(entries); i++ {
		for j := i + 1; j < len(entries); j++ {
			if entries[i].value < entries[j].value {
				entries[i], entries[j] = entries[j], entries[i]
			}
		}
	}

---

### 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 thread core/services/metrics.go
Comment on lines +43 to +44

// InMemoryMetricsStore implements MetricsStore with in-memory storage

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

LocalAIMetricsAPIMiddleware calls cfg.metricsService.ObserveAPICall unconditionally even when metrics is nil, which will panic at runtime if the service is not initialised; add a nil guard before calling.

Suggested fix
		elapsed := float64(time.Since(start)) / float64(time.Second)
		if cfg.metricsService != nil {
			cfg.metricsService.ObserveAPICall(method, path, elapsed)
		}
		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/services/metrics.go
Lines: 43-44
Issue Type: robustness-medium
Severity: medium

Issue Description:
`LocalAIMetricsAPIMiddleware` calls `cfg.metricsService.ObserveAPICall` unconditionally even when `metrics` is nil, which will panic at runtime if the service is not initialised; add a nil guard before calling.

Current Code:
		elapsed := float64(time.Since(start)) / float64(time.Second)
		cfg.metricsService.ObserveAPICall(method, path, elapsed)
		return err

---

### 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 thread core/services/metrics.go
Duration time.Duration
}

// InMemoryMetricsStore implements MetricsStore with in-memory storage

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 get_token_metrics.go, log.Err(err) does not send the log entry (missing .Msg() or .Send()), so the error is silently swallowed; replace with log.Err(err).Msg("failed to load model config") or use log.Error().Err(err).Msg(...).

Suggested change
// InMemoryMetricsStore implements MetricsStore with in-memory storage
log.Error().Err(err).Msg("failed to load model config")
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/services/metrics.go
Lines: 44-44
Issue Type: robustness-medium
Severity: medium

Issue Description:
In `get_token_metrics.go`, `log.Err(err)` does not send the log entry (missing `.Msg()` or `.Send()`), so the error is silently swallowed; replace with `log.Err(err).Msg("failed to load model config")` or use `log.Error().Err(err).Msg(...)`.

Current Code:
			log.Err(err)

---

### 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

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Nitpicks (Low Priority)

Found 1 low-priority suggestions for code improvement

Click to expand nitpicks

core/http/views/index.html (lines 233-236)

Maintainability Low

The closing </div> for the Gallery quick-link card is misplaced outside the <a> tag, breaking the intended DOM nesting and potentially causing layout issues.

Code Suggestion or Comments
</div>
                </div>
            </a>
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 233-236
Issue Type: maintainability-low
Severity: low

Issue Description:
The closing `</div>` for the Gallery quick-link card is misplaced outside the `<a>` tag, breaking the intended DOM nesting and potentially causing layout issues.

Current Code:
              </div>
        </div>
            </a>

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Clean
Files Scanned 10

No critical security issues detected

Scan completed in 29.1s

Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 276
Unknown License 58

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 58 packages
  • go.yaml.in/yaml/v2 2.4.2
  • go.yaml.in/yaml/v3 3.0.4
  • github.com/rymdport/portal 0.4.2
  • github.com/prometheus/otlptranslator 0.0.2
  • github.com/savsgio/gotils 0.0.0-20240303185622-093b76447511
  • github.com/srwiley/rasterx 0.0.0-20220730225603-2ab79fcdd4ef
  • github.com/srwiley/oksvg 0.0.0-20221011165216-be6e8873101c
  • github.com/wlynxg/anet 0.0.5
  • github.com/yosida95/uritemplate/v3 3.0.2
  • github.com/containerd/errdefs 1.0.0
  • github.com/Masterminds/goutils 1.1.1
  • github.com/Masterminds/semver/v3 3.4.0
  • github.com/andybalholm/brotli 1.1.0
  • github.com/alecthomas/chroma/v2 2.14.0
  • github.com/beorn7/perks 1.0.1
  • github.com/containerd/cgroups 1.1.0
  • github.com/containerd/continuity 0.4.4
  • github.com/containerd/log 0.1.0
  • github.com/containerd/stargz-snapshotter/estargz 0.14.3
  • github.com/creachadair/otp 0.5.0

...and 38 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 17, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-17 17:02 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 4
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:30 (Error_Handling · HIGH)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed and not logged, which can lead to silent failures.
Suggestion: Log the error or handle it appropriately to ensure visibility into issues.

if err != nil { continue }

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics, health routes, and UI routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-003] core/http/endpoints/localai/settings.go:1 (Documentation · MEDIUM)

Issue: The SettingsEndpoint function lacks a docstring explaining its parameters and return values.
Suggestion: Add a docstring to describe the function's purpose, parameters, and return values.

func SettingsEndpoint(appConfig *config.ApplicationConfig, ...

[CQ-LLM-004] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function directly depends on services.MetricsStore, making it hard to test in isolation.
Suggestion: Consider using dependency injection to allow for easier testing with mock implementations.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler { ... }

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-LLM-005] core/http/middleware/metrics.go:174 (Maintainability · LOW)

Issue: The use of magic strings in the shouldSkipMetrics function can lead to maintenance issues.
Suggestion: Define constants for the skip prefixes to improve maintainability.

skipPrefixes := []string{ "/views/", "/static/", ... }

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

[CQ-008] core/http/routes/ui_api.go:796 (Maintainability · LOW)

Issue: Magic number 24 in code
Suggestion: Extract to a named constant

hours := 24

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 1 0 2
core/http/middleware/metrics.go 0 0 1 2 3
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory API metrics tracking with time-series data and a new dashboard visualization in the web UI.
  • Reorganized the navigation to separate dashboard usage stats from model/backend management via a new settings page.
  • Added backend lifecycle management endpoints and UI controls for stopping and deleting backends.

Key Changes by Area

Metrics System

  • Metrics Collection: New MetricsStore interface with InMemoryMetricsStore implementation tracking endpoint usage, model names, backends, success rates, and request duration with 24h retention.
  • Middleware: MetricsMiddleware intercepts API requests and extracts model names from context for downstream aggregation.

Web UI

  • Dashboard: index.html now conditionally shows a welcome wizard (no models) or metrics dashboard with Chart.js visualizations (models installed). Auto-refreshes every 30 seconds.
  • Settings Page: New settings.html consolidates model management, backend grid with metadata, and system configuration. Added toast notifications across management pages.
  • Navigation: Added Settings link to navbar; moved model/backend controls from index to settings.

API

  • Metrics Endpoints: New /api/metrics/* routes exposing summary stats, top models/endpoints, backend usage, and time-series data.
  • Settings Endpoint: New endpoint aggregating model configs, gallery configs, loaded models, installed backends, and operation statuses.
  • Backend Lifecycle: Added BackendShutdownEndpoint and BackendMonitorEndpoint for process management and resource sampling.

Files Changed

File Changes Summary
core/http/app.go Injected metrics middleware before API routes; passed metrics store to UI API routes; added shutdown cleanup hook
core/http/endpoints/localai/settings.go New endpoint aggregating model configs, gallery configs, loaded models, backends, and operation statuses
core/http/middleware/metrics.go New middleware capturing request metrics after completion; filters UI/static routes
core/http/middleware/request.go Ensures model name is set in context locals for metrics consumption
core/http/routes/ui.go Added route registration for /settings page
core/http/routes/ui_api.go New /api/metrics/* endpoints for summary stats, top models/endpoints, backend usage, and time-series data
core/http/views/index.html Conditional two-state UI: welcome wizard vs. metrics dashboard with Chart.js; switched to dashboardMetrics() controller
core/http/views/partials/navbar.html Added Settings link with cog icon to desktop and mobile navigation
core/http/views/settings.html New template with hero section, model/backend management grid, toast notifications, and action controls
core/services/metrics.go New MetricsStore interface and InMemoryMetricsStore with time-series support, automatic pruning every 5 minutes, 24h retention, 10k record limit

Review Focus Areas

  • Memory usage of InMemoryMetricsStore under high request volume. Check pruning logic and goroutine lifecycle in core/services/metrics.go.
  • Correctness of model name extraction in core/http/middleware/request.go:130-132. Verify all API paths populate this context value.
  • Alpine.js state management in dashboardMetrics() controller. Ensure proper cleanup of Chart.js instances and polling intervals on page navigation.

Architecture

Design Decisions

  • In-memory metrics store chosen over persistent storage for simplicity and low latency. 24h retention with hard 10k record limit is an intentional tradeoff favoring recent data over historical accuracy.
  • Metrics middleware runs after request completion to capture actual duration and status. This adds minimal overhead but means failed requests mid-flight are not recorded.
  • UI state split between dashboard (usage) and settings (management) to reduce cognitive load. This duplicates some backend data fetching but improves perceived performance via separate page loads.

Scalability & Extensibility

  • Metrics store is interface-based (MetricsStore) allowing future swap to persistent or external implementation without middleware changes.
  • Time-series bucketing uses fixed 5-minute intervals. Out of scope: configurable granularity or aggregation windows.
  • Chart.js loaded via CDN. Out of scope: bundling or offline support.

Risks

  • Intentional: Memory growth if pruning fails or interval misconfigures. Acceptable for non-production monitoring; Prometheus remains source of truth.
  • Intentional: Metrics data lost on process restart. Documented limitation of in-memory approach.
  • Unintentional: Backend monitor service samples local processes but may miss resource spikes between intervals. Review sampling frequency appropriateness.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 4 CRITICAL inline review findings need resolution
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 6 HIGH-severity security findings

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Medium
Files Scanned 10

Consider addressing security findings before merging

Scan completed in 64.5s

View vulnerability details (2 items)

1. SEC-001 (CWE-79) HIGH

File: core/http/views/settings.html (line 240)
Category: Injection

onclick="handleStopModel('{{.Name}}')"

User-controlled model names are interpolated directly into an inline JavaScript handler without JavaScript string escaping (onclick="handleStopModel('{{.Name}}')"). If an attacker can supply a model name containing quotes or script, the entity will be decoded before execution and can break out of the string, leading to arbitrary script execution when the button is clicked (stored XSS).

Fix: Do not embed untrusted data directly into inline JavaScript. Pass the model name via a data attribute and retrieve it in the handler, or ensure it is properly JavaScript-escaped (e.g. by using printf "%q" to JSON-encode it) before insertion.


2. SEC-001 (CWE-79) HIGH

File: core/http/views/settings.html (line 256)
Category: Injection

onclick="handleDeleteModel('{{.Name}}')"

Model names are inserted into an inline JavaScript handler without JS-safe escaping (onclick="handleDeleteModel('{{.Name}}')"). A crafted model name containing quotes can break out of the string literal after entity decoding and inject JavaScript, resulting in cross-site scripting when a user clicks the delete button.

Fix: Avoid embedding untrusted values in inline JS. Move the name into a data-name attribute and read it in the handler, or JSON/JS-escape the value before use so it cannot break out of the string.


Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 310
Unknown License 24

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 24 packages
  • github.com/moby/docker-image-spec 1.3.1
  • github.com/docker/cli 27.0.3+incompatible
  • github.com/docker/distribution 2.8.2+incompatible
  • github.com/docker/docker-credential-helpers 0.7.0
  • github.com/docker/go-connections 0.6.0
  • github.com/dsnet/compress 0.0.2-0.20210315054119-f66993602bf5
  • github.com/docker/docker 28.5.1+incompatible
  • github.com/docker/go-units 0.5.0
  • github.com/flynn/noise 1.1.0
  • github.com/go-audio/riff 1.0.0
  • github.com/go-audio/audio 1.0.0
  • github.com/go-logr/logr 1.4.3
  • github.com/go-logr/stdr 1.2.2
  • github.com/go-openapi/jsonpointer 0.21.0
  • github.com/go-openapi/spec 0.21.0
  • github.com/go-openapi/swag 0.23.0
  • github.com/go-openapi/jsonreference 0.21.0
  • github.com/gogo/protobuf 1.3.2
  • github.com/golang/groupcache 0.0.0-20210331224755-41bb18bfe9da
  • github.com/golang/snappy 0.0.4

...and 4 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-19 15:29 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 6
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:20 (Error_Handling · HIGH)

Issue: Errors from gallery.ListSystemBackends are returned directly without any logging or handling.
Suggestion: Log the error or handle it appropriately to avoid silent failures.

installedBackends, err := gallery.ListSystemBackends(appConfig.SystemState)

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics and routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-003] core/http/endpoints/localai/settings.go:34 (Error_Handling · MEDIUM)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed, leading to potential issues without feedback.
Suggestion: Consider logging the error or returning it to the caller for better error visibility.

cfg, err := gallery.GetLocalModelConfiguration(ml.ModelPath, m.Name)

[CQ-LLM-006] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function has a hard dependency on services.MetricsStore, making it difficult to test in isolation.
Suggestion: Consider using dependency injection to allow for easier testing and mocking of the metrics store.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler {

[CQ-LLM-007] core/http/middleware/metrics.go:10 (Maintainability · MEDIUM)

Issue: The use of magic strings for endpoint categorization can lead to maintenance issues if the paths change.
Suggestion: Define constants for the endpoint paths to improve maintainability and reduce the risk of errors.

if strings.HasPrefix(path, "/v1/chat/completions") || strings.HasPrefix(path, "/chat/completions") {

[CQ-LLM-004] core/http/middleware/metrics.go:45 (Performance · MEDIUM)

Issue: The metrics middleware may introduce performance overhead due to logging and metrics recording on every request.
Suggestion: Evaluate the necessity of logging at the debug level and consider conditional logging based on the environment.

log.Debug().Str("model", model).Str("endpoint", endpoint).Msg("Recording metrics for request")

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-LLM-005] core/http/endpoints/localai/settings.go:1 (Documentation · LOW)

Issue: The SettingsEndpoint function lacks a detailed docstring explaining its parameters and return values.
Suggestion: Add a comprehensive docstring to the SettingsEndpoint function to improve code documentation.

func SettingsEndpoint(appConfig *config.ApplicationConfig, cl *config.ModelConfigLoader, ml *model.ModelLoader, opcache *services.OpCache) func(*fiber.Ctx) error {

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 1 1 3
core/http/middleware/metrics.go 0 0 3 1 4
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory metrics collection for API usage tracking (endpoints, models, backends, duration, success rates) with configurable retention and automatic pruning.
  • Redesigned dashboard UI with conditional welcome wizard for new users and metrics visualization (Chart.js) for existing users.
  • Consolidated model/backend management into a dedicated Settings page with toast notifications and improved status indicators.

Key Changes by Area

Metrics Infrastructure: New MetricsStore interface with memory-safe in-memory implementation, HTTP middleware for automatic request recording, and REST API endpoints for summary stats and time-series data.

Dashboard UI: Split index view into welcome flow (no models) vs. metrics dashboard (with models). Added Chart.js visualizations with 30-second auto-refresh.

Settings Page: New dedicated management interface with model cards, backend grid, MCP badges, and notification system for async operations.

Navigation: Added Settings link to navbar, reordered menu: Home → Settings → Models → Backends.

Files Changed

File Changes Summary
core/http/app.go Registered metrics middleware and graceful shutdown hook
core/http/endpoints/localai/settings.go New backend logic aggregating model/gallery configs and operation statuses
core/http/middleware/metrics.go New middleware intercepting API requests for metrics recording
core/http/middleware/request.go Added model name propagation to context
core/http/routes/ui.go Added /settings route handler
core/http/routes/ui_api.go New /api/metrics/* endpoints for stats, time-series, and reset
core/http/views/index.html Redesigned with conditional welcome wizard and metrics dashboard
core/http/views/partials/navbar.html Added Settings navigation link
core/http/views/settings.html New management page with notifications and backend/model grids
core/services/metrics.go New MetricsStore interface and InMemoryMetricsStore implementation

Review Focus Areas

  • Memory limits in InMemoryMetricsStore (10k records, 1k keys) and 5-minute pruning interval. Check if these suit expected load.
  • Metrics middleware excludes UI/static routes. Verify this covers all non-API paths.
  • Alpine.js component dashboardMetrics() handles both metrics display and notifications. Check for state conflicts.

Architecture

Design Decisions: In-memory store chosen for simplicity and zero external dependencies. Limits are hardcoded (acceptable for initial rollout). Token metrics endpoint exists but is unused (marked TODO). Backend monitoring uses gRPC where available, falls back to process stats.

Scalability & Extensibility: Metrics system is intentionally single-node. Out of scope: persistence, distributed aggregation, or external metrics export beyond existing Prometheus/OpenTelemetry.

Risks: Intentional: Data loss on restart (in-memory only), fixed retention windows. Unintentional: Potential memory pressure under high load if limits prove insufficient. Review pruning logic and goroutine cleanup on shutdown.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 4 CRITICAL inline review findings need resolution
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

Comment thread core/services/metrics.go
Comment on lines +168 to +169
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)

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 Critical

Stop closes stopChan without guarding against repeated calls, so a second shutdown path will panic; make Stop idempotent with sync.Once or a non-blocking close guard.

Suggested fix
type InMemoryMetricsStore struct {
	endpoints    map[string]int64
	models       map[string]int64
	backends     map[string]int64
	timeSeries   []RequestRecord
	successCount int64
	failureCount int64
	mu           sync.RWMutex
	stopChan     chan struct{}
	stopOnce     sync.Once
	maxRecords   int
	maxMapKeys   int
	pruneEvery   time.Duration
}

func (m *InMemoryMetricsStore) Stop() {
	m.stopOnce.Do(func() {
		close(m.stopChan)
	})
}
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/services/metrics.go
Lines: 168-169
Issue Type: functional-critical
Severity: critical

Issue Description:
Stop closes stopChan without guarding against repeated calls, so a second shutdown path will panic; make Stop idempotent with sync.Once or a non-blocking close guard.

Current Code:
func (m *InMemoryMetricsStore) Stop() {
	close(m.stopChan)
}

---

### 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 +44 to +56
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,
}

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

Comment on lines +130 to +133
} 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))

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

Comment on lines +810 to +817
// Reset metrics (optional - for testing/admin purposes)
app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
metricsStore.Reset()
return c.JSON(fiber.Map{
"success": true,
"message": "Metrics reset successfully",
})
})

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 reset endpoint performs a state-changing administrative action without any local authorization check, so gate it behind an admin-only middleware or remove it from the UI API.

Suggested fix
		// Reset metrics (optional - for testing/admin purposes)
		app.Post("/api/metrics/reset", adminOnlyMiddleware, func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})
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_api.go
Lines: 810-817
Issue Type: security-high
Severity: high

Issue Description:
The reset endpoint performs a state-changing administrative action without any local authorization check, so gate it behind an admin-only middleware or remove it from the UI API.

Current Code:
		// Reset metrics (optional - for testing/admin purposes)
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})

---

### 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 +472 to +474
const response = await fetch(`/api/backends/system/delete/${encodeURIComponent(backendName)}`, {
method: 'POST'
});

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

State-changing POST requests are sent without any CSRF token or same-site validation header, so add CSRF protection to each fetch call.

Also reported at: core/http/views/settings.html L501–L507, L526–L528, L556–L561

Suggested fix
                const response = await fetch(`/api/backends/system/delete/${encodeURIComponent(backendName)}`, {
                    method: 'POST',
                    headers: {
                        'X-CSRF-Token': window.csrfToken
                    },
                    credentials: 'same-origin'
                });
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 472-474
Issue Type: security-high
Severity: high

Issue Description:
State-changing POST requests are sent without any CSRF token or same-site validation header, so add CSRF protection to each fetch call.

_Also reported at: `core/http/views/settings.html` L501–L507, L526–L528, L556–L561_

Current Code:
                const response = await fetch(`/api/backends/system/delete/${encodeURIComponent(backendName)}`, {
                    method: 'POST'
                });

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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

<i class="fas fa-plus mr-3 text-lg"></i>
<span>Import Model</span>
<i class="fas fa-upload ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

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

Links opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

Also reported at: core/http/views/index.html L238, L250

Suggested change
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
<a href="https://localai.io/basics/getting_started/" target="_blank" rel="noopener noreferrer" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 37-37
Issue Type: security-medium
Severity: medium

Issue Description:
Links opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

_Also reported at: `core/http/views/index.html` L238, L250_

Current Code:
                    <a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

</div>

<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

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

The CDN script should use Subresource Integrity and crossorigin attributes or be self-hosted to reduce supply chain risk.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js" integrity="YOUR_SRI_HASH" crossorigin="anonymous"></script>
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 270-270
Issue Type: security-medium
Severity: medium

Issue Description:
The CDN script should use Subresource Integrity and crossorigin attributes or be self-hosted to reduce supply chain risk.

Current Code:
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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
// 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
}
}
}

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

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Medium
Files Scanned 10

Consider addressing security findings before merging

Scan completed in 35.5s

View vulnerability details (1 items)

1. VAR_IN_HREF (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) HIGH

File: core/http/views/settings.html (line 407)
Category: Other

Detected a template variable used in an anchor tag with the 'href' attribute. This allows a malicious actor to input the 'javascript:' URI and is subject to cross- site scripting (XSS) attacks. If using Flask, use 'url_for()' to safely generate a URL. If using Django, use the 'url' filter to safely generate a URL. If using Mustache, use a URL encoding library, or prepend a slash '/' to the variable for relative links (href="/{{link}}"). You may also consider setting the Content Security Policy (CSP) header.

Fix: Review and fix the security issue following OWASP guidelines.


Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 280
Unknown License 54

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 54 packages
  • packaging 24.1
  • github.com/docker/distribution 2.8.2+incompatible
  • github.com/docker/docker 28.5.1+incompatible
  • github.com/docker/docker-credential-helpers 0.7.0
  • github.com/dsnet/compress 0.0.2-0.20210315054119-f66993602bf5
  • github.com/docker/go-units 0.5.0
  • github.com/docker/go-connections 0.6.0
  • github.com/flynn/noise 1.1.0
  • github.com/go-audio/audio 1.0.0
  • github.com/go-audio/riff 1.0.0
  • github.com/go-logr/logr 1.4.3
  • github.com/go-logr/stdr 1.2.2
  • github.com/go-openapi/jsonpointer 0.21.0
  • github.com/go-openapi/swag 0.23.0
  • github.com/go-openapi/spec 0.21.0
  • github.com/go-openapi/jsonreference 0.21.0
  • github.com/gogo/protobuf 1.3.2
  • github.com/golang/groupcache 0.0.0-20210331224755-41bb18bfe9da
  • github.com/golang/snappy 0.0.4
  • github.com/google/btree 1.1.3

...and 34 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-19 16:08 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 4
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:30 (Error_Handling · HIGH)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed, which can lead to silent failures.
Suggestion: Handle the error appropriately, either by logging it or returning a meaningful response.

if err != nil { continue }

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics, health routes, and UI routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-003] core/http/endpoints/localai/settings.go:1 (Documentation · MEDIUM)

Issue: The SettingsEndpoint function lacks a docstring explaining its parameters and return values.
Suggestion: Add a docstring to the SettingsEndpoint function to improve documentation.

func SettingsEndpoint(appConfig *config.ApplicationConfig, ...

[CQ-LLM-004] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function has a hard dependency on services.MetricsStore, making it difficult to test in isolation.
Suggestion: Consider using dependency injection to allow for easier testing.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler { ... }

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-LLM-005] core/http/middleware/metrics.go:10 (Maintainability · LOW)

Issue: The use of magic strings in the skipPrefixes array can lead to maintenance issues.
Suggestion: Define constants for the skip prefixes to improve maintainability.

skipPrefixes := []string{ "/views/", "/static/", ... }

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

[CQ-008] core/http/routes/ui_api.go:796 (Maintainability · LOW)

Issue: Magic number 24 in code
Suggestion: Extract to a named constant

hours := 24

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 1 0 2
core/http/middleware/metrics.go 0 0 1 2 3
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory metrics collection and dashboard visualization for API usage tracking (endpoints, models, backends, time-series).
  • Split the web UI into two distinct experiences: a metrics dashboard for existing installations and a simplified welcome wizard for new users.
  • Moved model and backend management from the index page to a new dedicated Settings page.

Key Changes by Area

Metrics & Monitoring

  • Metrics Store: In-memory time-series storage with 24h retention and automatic pruning (core/services/metrics.go).
  • Middleware: Request interception to track endpoint, model, and backend usage (core/http/middleware/metrics.go).
  • API: Five new REST endpoints for metrics data (/api/metrics/*) and Prometheus-compatible endpoint via OpenTelemetry.

UI/UX

  • Dashboard: New metrics view with Chart.js visualizations (stats cards, endpoint/model usage charts, 24h timeline) when models are installed.
  • Settings Page: New dedicated page for model/backend management with toast notifications and improved card designs.
  • Navigation: Added Settings link to navbar; removed management UI from index page.

Files Changed

File Changes Summary
core/http/app.go Registered metrics middleware with graceful shutdown hook
core/http/endpoints/localai/settings.go New settings page handler for model/backend management
core/http/middleware/metrics.go New middleware for tracking API request metrics
core/http/middleware/request.go Exposed model name in context for metrics consumption
core/http/routes/ui.go Updated route handling for new dashboard/settings split
core/http/routes/ui_api.go Added five new /api/metrics/* REST endpoints
core/http/views/index.html Complete redesign with dashboard vs. welcome wizard views
core/http/views/partials/navbar.html Added Settings navigation link
core/http/views/settings.html New dedicated settings/management page (609 lines)
core/services/metrics.go New in-memory metrics store with time-series collection and pruning

Review Focus Areas

  • Memory usage of unbounded metrics store: 10k record limit with 5-minute pruning. Verify this is acceptable for your deployment scale.
  • Error handling in handleDeleteModel() and handleStopModel() JavaScript functions. Check that failures surface user-visible feedback.
  • Metrics middleware skips UI/static routes. Confirm this filtering matches your observability needs.

Architecture

Design Decisions

  • In-memory storage chosen for simplicity and zero external dependencies. This is intentional: no Redis/database required for single-node deployments.
  • 24h retention and 10k record cap are deliberate tradeoffs to bound memory. Not designed for long-term analytics or multi-node aggregation.
  • Dashboard/Settings split separates monitoring (frequent use) from management (infrequent use) to reduce cognitive load.

Scalability & Extensibility

  • Metrics store interface allows swapping implementation. Current in-memory version is not horizontally scalable.
  • Prometheus endpoint provides escape hatch for production monitoring if built-in dashboard insufficient.

Risks

  • Intentional: Data loss on process restart (in-memory only). Acceptable for operational telemetry, not billing/auditing.
  • Intentional: No authentication on metrics endpoints. Assumes deployment has network-level access control.
  • Unintentional: Background pruning goroutine has no panic recovery. Crash would take down entire application.

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 5 CRITICAL inline review findings need resolution
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

Comment thread core/services/metrics.go
Comment on lines +167 to +169
// Stop gracefully shuts down the metrics store
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)

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 Critical

Stop closes stopChan unconditionally, so a second Stop call will panic; guard the close with sync.Once or a non-blocking select.

Suggested fix
type InMemoryMetricsStore struct {
	endpoints    map[string]int64
	models       map[string]int64
	backends     map[string]int64
	timeSeries   []RequestRecord
	successCount int64
	failureCount int64
	mu           sync.RWMutex
	stopChan     chan struct{}
	stopOnce     sync.Once
	maxRecords   int
	maxMapKeys   int
	pruneEvery   time.Duration
}

func (m *InMemoryMetricsStore) Stop() {
	m.stopOnce.Do(func() {
		close(m.stopChan)
	})
}
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/services/metrics.go
Lines: 167-169
Issue Type: functional-critical
Severity: critical

Issue Description:
Stop closes stopChan unconditionally, so a second Stop call will panic; guard the close with sync.Once or a non-blocking select.

Current Code:
func (m *InMemoryMetricsStore) Stop() {
	close(m.stopChan)
}

---

### 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

"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

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

Comment thread core/http/routes/ui.go
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

Comment on lines +796 to +803
hours := 24
if hoursParam := c.Query("hours"); hoursParam != "" {
if h, err := strconv.Atoi(hoursParam); err == nil && h > 0 {
hours = h
}
}

timeSeries := metricsStore.GetRequestsOverTime(hours)

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 hours query parameter is accepted without an upper bound, so clamp it to a sane maximum before querying the metrics store.

Suggested fix
			hours := 24
			if hoursParam := c.Query("hours"); hoursParam != "" {
				if h, err := strconv.Atoi(hoursParam); err == nil && h > 0 {
					if h > 168 {
						h = 168
					}
					hours = h
				}
			}

			timeSeries := metricsStore.GetRequestsOverTime(hours)
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_api.go
Lines: 796-803
Issue Type: robustness-medium
Severity: medium

Issue Description:
The hours query parameter is accepted without an upper bound, so clamp it to a sane maximum before querying the metrics store.

Current Code:
			hours := 24
			if hoursParam := c.Query("hours"); hoursParam != "" {
				if h, err := strconv.Atoi(hoursParam); err == nil && h > 0 {
					hours = h
				}
			}

			timeSeries := metricsStore.GetRequestsOverTime(hours)

---

### 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

<i class="fas fa-plus mr-3 text-lg"></i>
<span>Import Model</span>
<i class="fas fa-upload ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

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

External links opened with target="_blank" should also set rel="noopener noreferrer" to prevent reverse tabnabbing.

Also reported at: core/http/views/index.html L238, L250

Suggested change
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
<a href="https://localai.io/basics/getting_started/" target="_blank" rel="noopener noreferrer" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 37-37
Issue Type: security-medium
Severity: medium

Issue Description:
External links opened with target="_blank" should also set rel="noopener noreferrer" to prevent reverse tabnabbing.

_Also reported at: `core/http/views/index.html` L238, L250_

Current Code:
                    <a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

</div>

<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

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

Loading Chart.js from a CDN without an integrity attribute weakens script supply chain protection, so add SRI and crossorigin or self-host the asset.

Suggested change
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js" integrity="<SRI_HASH>" crossorigin="anonymous"></script>
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 270-270
Issue Type: security-medium
Severity: medium

Issue Description:
Loading Chart.js from a CDN without an integrity attribute weakens script supply chain protection, so add SRI and crossorigin or self-host the asset.

Current Code:
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Clean
Files Scanned 10

No critical security issues detected

Scan completed in 46.4s

Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in:

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 297
Unknown License 37

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 37 packages
  • go.yaml.in/yaml/v2 2.4.2
  • go.yaml.in/yaml/v3 3.0.4
  • github.com/wlynxg/anet 0.0.5
  • github.com/srwiley/oksvg 0.0.0-20221011165216-be6e8873101c
  • github.com/prometheus/otlptranslator 0.0.2
  • github.com/savsgio/gotils 0.0.0-20240303185622-093b76447511
  • github.com/yosida95/uritemplate/v3 3.0.2
  • github.com/srwiley/rasterx 0.0.0-20220730225603-2ab79fcdd4ef
  • github.com/rymdport/portal 0.4.2
  • github.com/containerd/errdefs 1.0.0
  • github.com/alecthomas/chroma/v2 2.14.0
  • github.com/Masterminds/goutils 1.1.1
  • github.com/Masterminds/semver/v3 3.4.0
  • github.com/andybalholm/brotli 1.1.0
  • github.com/containerd/stargz-snapshotter/estargz 0.14.3
  • github.com/containerd/cgroups 1.1.0
  • github.com/beorn7/perks 1.0.1
  • github.com/containerd/continuity 0.4.4
  • github.com/containerd/log 0.1.0
  • github.com/docker/cli 27.0.3+incompatible

...and 17 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 19, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-19 16:45 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 5
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:30 (Error_Handling · HIGH)

Issue: Errors from gallery.ListSystemBackends are returned directly without any logging or handling, which may lead to silent failures.
Suggestion: Log the error or handle it appropriately to avoid silent failures.

installedBackends, err := gallery.ListSystemBackends(appConfig.SystemState)

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics, health routes, and UI routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-005] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function directly depends on services.MetricsStore, making it hard to test in isolation.
Suggestion: Consider using dependency injection to pass the metrics store, allowing for easier testing.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler { ... }

[CQ-LLM-003] core/http/middleware/metrics.go:45 (Performance · MEDIUM)

Issue: The shouldSkipMetrics function uses a loop to check against multiple prefixes, which could be optimized.
Suggestion: Consider using a map for skip prefixes to improve lookup performance.

for _, prefix := range skipPrefixes { ... }

[CQ-LLM-006] core/http/middleware/metrics.go:174 (Maintainability · MEDIUM)

Issue: The categorizeEndpoint function has multiple if statements that could be refactored for better maintainability.
Suggestion: Consider using a map or a switch statement to improve readability and maintainability.

if strings.HasPrefix(path, "/v1/chat/completions") || ...

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-LLM-004] core/http/endpoints/localai/settings.go:1 (Documentation · LOW)

Issue: The SettingsEndpoint function lacks a detailed docstring explaining its parameters and return values.
Suggestion: Add a docstring to the SettingsEndpoint function to describe its parameters and return values.

func SettingsEndpoint(appConfig *config.ApplicationConfig, ...

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 0 1 2
core/http/middleware/metrics.go 0 0 3 1 4
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

@DhirenMhatre

Copy link
Copy Markdown
Author

@codity review

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

Policy Check Failed

✗ 3/3 policy checks failed:

• Need 2 more approval(s) (0/2) — comment LGTM or approve via review
• Missing ticket reference (expected: JIRA-, ENG-, #*)
• 7 code file(s) changed but no test files added


To merge this PR:

  1. Address the failed checks listed above
  2. Ensure branch protection requires the codity/policy-check status

Configure policies in your dashboard

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

PR Summary

What Changed

  • Added in-memory API metrics tracking with time-series data and automatic pruning for system health monitoring.
  • Built a new Settings page for model/backend management and redesigned the dashboard with real-time metrics visualizations.
  • Integrated Chart.js for endpoint usage, model popularity, and request timeline charts with 30-second auto-refresh.

Key Changes by Area

Metrics System: MetricsMiddleware captures API requests with model/backend attribution. InMemoryMetricsStore bounds memory at 10k records with 5-minute background pruning.

API Endpoints: New /api/metrics/* routes expose summary stats, endpoint breakdowns, model usage, backend stats, time-series data, and admin reset.

UI/UX: Dashboard now shows conditional welcome wizard vs. metrics view. Settings page consolidates model management with toast notifications, backend deletion, and reload functionality.

Navigation: Added Settings link to navbar; standardized Alpine.js component names across views.

Files Changed

File Changes Summary
core/http/app.go Registered metrics middleware with shutdown cleanup hook
core/http/endpoints/localai/settings.go New route handler for Settings page
core/http/middleware/metrics.go Request metrics capture middleware
core/http/middleware/request.go Minor adjustments for metrics context
core/http/routes/ui.go Added Settings route registration
core/http/routes/ui_api.go New /api/metrics/* endpoints (summary, endpoints, models, backends, timeseries, reset)
core/http/views/index.html Dashboard redesign with Chart.js metrics and conditional welcome wizard
core/http/views/partials/navbar.html Added Settings navigation link
core/http/views/settings.html New dedicated settings page with model/backend management
core/services/metrics.go In-memory metrics store with time-series pruning

Review Focus Areas

  • Memory bounds in InMemoryMetricsStore: verify 10k record limit handles your expected load.
  • Metrics middleware placement: confirm it captures all API routes without double-counting.
  • Chart.js auto-refresh: check for memory leaks in long-running dashboard sessions.

Architecture

Design Decisions: In-memory storage keeps metrics simple and avoids external dependencies. Time-series pruning trades historical precision for bounded memory. UI routes excluded from metrics to focus on actual API usage.

Scalability & Extensibility: Metrics store is interface-based (MetricsStore) for future persistence implementations. Current in-memory approach is intentionally not distributed across instances.

Risks: Metrics data is lost on restart (intentional, acceptable for monitoring). Background pruning goroutine adds minimal overhead but could delay shutdown if stuck. No authentication on /api/metrics/reset endpoint (review if admin-only).

Merge Status

NOT MERGEABLE — PR Score 3/100, below threshold (50)

  • [H4] PR quality score (3) is below merge floor (50)
  • [H5] 5 CRITICAL inline review findings need resolution
  • [H6] Code quality raw score (5) is below merge floor (40)
  • [H7] 4 HIGH-severity security findings

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 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

Comment on lines +811 to +816
app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
metricsStore.Reset()
return c.JSON(fiber.Map{
"success": true,
"message": "Metrics reset successfully",
})

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 metrics reset endpoint performs a state-changing administrative action without any route-level authorization check, so add an explicit admin guard or remove this endpoint from the UI API.

Suggested fix
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			if !isAdminRequest(c) {
				return c.SendStatus(fiber.StatusForbidden)
			}

			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})
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_api.go
Lines: 811-816
Issue Type: security-high
Severity: high

Issue Description:
The metrics reset endpoint performs a state-changing administrative action without any route-level authorization check, so add an explicit admin guard or remove this endpoint from the UI API.

Current Code:
		app.Post("/api/metrics/reset", func(c *fiber.Ctx) error {
			metricsStore.Reset()
			return c.JSON(fiber.Map{
				"success": true,
				"message": "Metrics reset successfully",
			})
		})

---

### 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

<i class="fas fa-arrow-left ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
</a>

<a href="https://localai.io" target="_blank"

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

Links opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

Also reported at: core/http/views/settings.html L407

Suggested fix
                    <a href="https://localai.io" target="_blank" rel="noopener noreferrer"
Prompt for AI assistance

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

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

### Context

File: core/http/views/settings.html
Lines: 60-60
Issue Type: security-high
Severity: high

Issue Description:
Links opened with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

_Also reported at: `core/http/views/settings.html` L407_

Current Code:
                    <a href="https://localai.io" target="_blank" 

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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 thread core/services/metrics.go
Comment on lines +167 to +169
// Stop gracefully shuts down the metrics store
func (m *InMemoryMetricsStore) Stop() {
close(m.stopChan)

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

Stop closes stopChan unconditionally and will panic if called more than once, so guard the close with sync.Once or a non-blocking select.

Suggested fix
type InMemoryMetricsStore struct {
	endpoints    map[string]int64
	models       map[string]int64
	backends     map[string]int64
	timeSeries   []RequestRecord
	successCount int64
	failureCount int64
	mu           sync.RWMutex
	stopChan     chan struct{}
	stopOnce     sync.Once
	maxRecords   int
	maxMapKeys   int
	pruneEvery   time.Duration
}

func (m *InMemoryMetricsStore) Stop() {
	m.stopOnce.Do(func() {
		close(m.stopChan)
	})
}
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/services/metrics.go
Lines: 167-169
Issue Type: robustness-high
Severity: high

Issue Description:
Stop closes stopChan unconditionally and will panic if called more than once, so guard the close with sync.Once or a non-blocking select.

Current Code:
func (m *InMemoryMetricsStore) Stop() {
	close(m.stopChan)
}

---

### 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 +723 to +807
app.Get("/api/metrics/summary", func(c *fiber.Ctx) error {
endpointStats := metricsStore.GetEndpointStats()
modelStats := metricsStore.GetModelStats()
backendStats := metricsStore.GetBackendStats()

// Get top 5 models
type modelStat struct {
Name string `json:"name"`
Count int64 `json:"count"`
}
topModels := make([]modelStat, 0)
for model, count := range modelStats {
topModels = append(topModels, modelStat{Name: model, Count: count})
}
sort.Slice(topModels, func(i, j int) bool {
return topModels[i].Count > topModels[j].Count
})
if len(topModels) > 5 {
topModels = topModels[:5]
}

// Get top 5 endpoints
type endpointStat struct {
Name string `json:"name"`
Count int64 `json:"count"`
}
topEndpoints := make([]endpointStat, 0)
for endpoint, count := range endpointStats {
topEndpoints = append(topEndpoints, endpointStat{Name: endpoint, Count: count})
}
sort.Slice(topEndpoints, func(i, j int) bool {
return topEndpoints[i].Count > topEndpoints[j].Count
})
if len(topEndpoints) > 5 {
topEndpoints = topEndpoints[:5]
}

return c.JSON(fiber.Map{
"totalRequests": metricsStore.GetTotalRequests(),
"successRate": metricsStore.GetSuccessRate(),
"topModels": topModels,
"topEndpoints": topEndpoints,
"topBackends": backendStats,
})
})

// Get endpoint statistics
app.Get("/api/metrics/endpoints", func(c *fiber.Ctx) error {
stats := metricsStore.GetEndpointStats()
return c.JSON(fiber.Map{
"endpoints": stats,
})
})

// Get model statistics
app.Get("/api/metrics/models", func(c *fiber.Ctx) error {
stats := metricsStore.GetModelStats()
return c.JSON(fiber.Map{
"models": stats,
})
})

// Get backend statistics
app.Get("/api/metrics/backends", func(c *fiber.Ctx) error {
stats := metricsStore.GetBackendStats()
return c.JSON(fiber.Map{
"backends": stats,
})
})

// Get time series data
app.Get("/api/metrics/timeseries", func(c *fiber.Ctx) error {
// Default to last 24 hours
hours := 24
if hoursParam := c.Query("hours"); hoursParam != "" {
if h, err := strconv.Atoi(hoursParam); err == nil && h > 0 {
hours = h
}
}

timeSeries := metricsStore.GetRequestsOverTime(hours)
return c.JSON(fiber.Map{
"timeseries": timeSeries,
"hours": hours,
})

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

These endpoints expose aggregate usage and backend metadata through the web UI API, so restrict them to privileged users or omit sensitive fields.

Suggested fix
		app.Get("/api/metrics/summary", func(c *fiber.Ctx) error {
			if !isAdminRequest(c) {
				return c.SendStatus(fiber.StatusForbidden)
			}

			endpointStats := metricsStore.GetEndpointStats()
			modelStats := metricsStore.GetModelStats()
			backendStats := metricsStore.GetBackendStats()
			...
		})
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_api.go
Lines: 723-807
Issue Type: security-medium
Severity: medium

Issue Description:
These endpoints expose aggregate usage and backend metadata through the web UI API, so restrict them to privileged users or omit sensitive fields.

Current Code:
		app.Get("/api/metrics/summary", func(c *fiber.Ctx) error {
			endpointStats := metricsStore.GetEndpointStats()
			modelStats := metricsStore.GetModelStats()
			backendStats := metricsStore.GetBackendStats()
			...
		})
		...
		app.Get("/api/metrics/endpoints", func(c *fiber.Ctx) error {
			stats := metricsStore.GetEndpointStats()
			return c.JSON(fiber.Map{
				"endpoints": stats,
			})
		})
		...
		app.Get("/api/metrics/models", func(c *fiber.Ctx) error {
			stats := metricsStore.GetModelStats()
			return c.JSON(fiber.Map{
				"models": stats,
			})
		})
		...
		app.Get("/api/metrics/backends", func(c *fiber.Ctx) error {
			stats := metricsStore.GetBackendStats()
			return c.JSON(fiber.Map{
				"backends": stats,
			})
		})
		...
		app.Get("/api/metrics/timeseries", func(c *fiber.Ctx) error {
			...
			return c.JSON(fiber.Map{
				"timeseries": timeSeries,
				"hours":      hours,
			})
		})

---

### 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

<i class="fas fa-plus mr-3 text-lg"></i>
<span>Import Model</span>
<i class="fas fa-upload ml-3 opacity-70 group-hover:opacity-100 transition-opacity"></i>
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

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

Opening a new tab with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

Also reported at: core/http/views/index.html L238, L250

Suggested change
<a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
<a href="https://localai.io/basics/getting_started/" target="_blank" rel="noopener noreferrer" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 37-37
Issue Type: security-medium
Severity: medium

Issue Description:
Opening a new tab with target="_blank" should include rel="noopener noreferrer" to prevent reverse tabnabbing.

_Also reported at: `core/http/views/index.html` L238, L250_

Current Code:
                    <a href="https://localai.io/basics/getting_started/" target="_blank" class="group inline-flex items-center bg-[#1E293B] hover:bg-[#1E293B]/80 border border-[#38BDF8]/20 text-[#E5E7EB] py-4 px-8 rounded-xl font-semibold text-lg transition-all duration-300 transform hover:scale-105">

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow html 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

{{ if gt (len .ModelsConfig) 0 }}
this.fetchMetrics();
// Auto-refresh every 30 seconds
setInterval(() => this.fetchMetrics(), 30000);

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

The polling interval created in init() is never cleaned up, so repeated component mounts can leak timers; store the interval ID and clear it on teardown.

Suggested fix
            this.metricsInterval = setInterval(() => this.fetchMetrics(), 30000);
Prompt for AI assistance

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

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

### Context

File: core/http/views/index.html
Lines: 289-289
Issue Type: performance-medium
Severity: medium

Issue Description:
The polling interval created in init() is never cleaned up, so repeated component mounts can leak timers; store the interval ID and clear it on teardown.

Current Code:
            setInterval(() => this.fetchMetrics(), 30000);

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow javascript 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

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

Security Scan Summary

Metric Value
Vulnerabilities Critical: 0
Overall Risk Clean
Files Scanned 10

No critical security issues detected

Scan completed in 43.8s

Security scan powered by Codity.ai

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

Dependency vulnerability scanning

Metric Value
Vulnerabilities Found 4
Scanner pip-audit
View vulnerability details (4 items)

1. pip 24.0

CVE: GHSA-4xh5-x5gv-qwph
Fixed in: 25.3

When extracting a tar archive pip may not check symbolic links point into the extraction directory if the tarfile module doesn't implement PEP 706. Note that upgrading pip to a "fixed" version for thi


2. pip 24.0

CVE: GHSA-6vgw-5pg2-w6jp
Fixed in: 26.0

When pip is installing and extracting a maliciously crafted wheel archive, files may be extracted outside the installation directory. The path traversal is limited to prefixes of the installation dire


3. pip 24.0

CVE: GHSA-58qw-9mgm-455v
Fixed in: 26.1

pip handles concatenated tar and ZIP files as ZIP files regardless of filename or whether a file is both a tar and ZIP file. This behavior could result in confusing installation behavior, such as inst


4. pip 24.0

CVE: GHSA-jp4c-xjxw-mgf9
Fixed in: 26.1

pip prior to version 26.1 would run self-update check functionality after installing wheel files which required importing well-known Python modules names. These module imports were intentionally defer

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

License Compliance Scan

Metric Value
Packages Scanned 338
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 261
Unknown License 73

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 73 packages
  • github.com/docker/docker 28.5.1+incompatible
  • github.com/docker/docker-credential-helpers 0.7.0
  • github.com/docker/go-connections 0.6.0
  • github.com/docker/go-units 0.5.0
  • github.com/dsnet/compress 0.0.2-0.20210315054119-f66993602bf5
  • github.com/flynn/noise 1.1.0
  • github.com/go-audio/audio 1.0.0
  • github.com/go-audio/riff 1.0.0
  • github.com/go-logr/logr 1.4.3
  • github.com/go-openapi/jsonpointer 0.21.0
  • github.com/go-logr/stdr 1.2.2
  • github.com/go-openapi/spec 0.21.0
  • github.com/go-openapi/jsonreference 0.21.0
  • github.com/go-openapi/swag 0.23.0
  • github.com/golang/groupcache 0.0.0-20210331224755-41bb18bfe9da
  • github.com/gogo/protobuf 1.3.2
  • github.com/golang/snappy 0.0.4
  • github.com/google/btree 1.1.3
  • github.com/google/go-cmp 0.7.0
  • github.com/gorilla/css 1.0.1

...and 53 more

Powered by Codity.ai · Docs

@codity-dm

codity-dm Bot commented May 21, 2026

Copy link
Copy Markdown

Code Quality Report — test-org-codity/LocalAI · PR #4

Scanned: 2026-05-21 12:35 UTC | Score: 5/100 | Provider: github

Executive Summary

Severity Count
Critical 0
High 1
Medium 5
Low 777
Top Findings

[CQ-LLM-002] core/http/endpoints/localai/settings.go:20 (Error_Handling · HIGH)

Issue: Errors from gallery.ListSystemBackends are returned directly without any logging or handling.
Suggestion: Log the error or handle it appropriately to avoid silent failures.

installedBackends, err := gallery.ListSystemBackends(appConfig.SystemState)

[CQ-LLM-001] core/http/app.go:142 (Complexity · MEDIUM)

Issue: The function API has multiple responsibilities, including setting up metrics and routes, which increases its cyclomatic complexity.
Suggestion: Consider breaking the API function into smaller, more focused functions to reduce complexity.

func API(application *application.Application) (*fiber.App, error) { ... }

[CQ-LLM-004] core/http/endpoints/localai/settings.go:1 (Documentation · MEDIUM)

Issue: The SettingsEndpoint function lacks a docstring explaining its parameters and return values.
Suggestion: Add a docstring to describe the function's purpose, parameters, and return values.

func SettingsEndpoint(appConfig *config.ApplicationConfig, cl *config.ModelConfigLoader, ml *model.ModelLoader, opcache *services.OpCache) func(*fiber.Ctx) error {

[CQ-LLM-003] core/http/endpoints/localai/settings.go:34 (Error_Handling · MEDIUM)

Issue: Errors from gallery.GetLocalModelConfiguration are swallowed and not logged.
Suggestion: Log the error or handle it to provide visibility into potential issues.

cfg, err := gallery.GetLocalModelConfiguration(ml.ModelPath, m.Name)

[CQ-LLM-005] core/http/middleware/metrics.go:1 (Testability · MEDIUM)

Issue: The MetricsMiddleware function has a hard dependency on services.MetricsStore, making it difficult to test in isolation.
Suggestion: Consider using dependency injection to allow for easier testing with mock implementations.

func MetricsMiddleware(metricsStore services.MetricsStore) fiber.Handler {

[CQ-001] core/http/views/index.html:273 (Complexity · MEDIUM)

Issue: Function/method has 211 added lines, exceeding 200-line threshold
Suggestion: Break into smaller, single-responsibility functions

[CQ-009] core/http/app.go:225 (Style · LOW)

Issue: Line exceeds 120 characters (155 chars)
Suggestion: Break long lines into multiple lines for readability

		routes.RegisterUIAPIRoutes(router, application.ModelConfigLoader(), application.ApplicationConfig(), application.Galle...

[CQ-008] core/http/middleware/metrics.go:35 (Maintainability · LOW)

Issue: Magic number 400 in code
Suggestion: Extract to a named constant

success := err == nil && c.Response().StatusCode() < 400

[CQ-LLM-006] core/http/middleware/metrics.go:174 (Maintainability · LOW)

Issue: The use of magic strings in the skipPrefixes array can lead to maintenance issues.
Suggestion: Consider defining these strings as constants to improve maintainability.

skipPrefixes := []string{ ... }

[CQ-009] core/http/routes/ui_api.go:21 (Style · LOW)

Issue: Line exceeds 120 characters (213 chars)
Suggestion: Break long lines into multiple lines for readability

func RegisterUIAPIRoutes(app *fiber.App, cl *config.ModelConfigLoader, appConfig *config.ApplicationConfig, galleryServi...

Per-File Breakdown

File Critical High Medium Low Total
core/http/app.go 0 0 1 1 2
core/http/endpoints/localai/settings.go 0 1 2 0 3
core/http/middleware/metrics.go 0 0 1 2 3
core/http/routes/ui_api.go 0 0 0 2 2
core/http/views/index.html 0 0 1 309 310
core/http/views/partials/navbar.html 0 0 0 7 7
core/http/views/settings.html 0 0 0 454 454
core/services/metrics.go 0 0 0 2 2

Recommendations

  1. Resolve High severity issues, especially error handling gaps and performance bottlenecks.
  • Run automated tests after applying fixes to verify no regressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants