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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions api/internal/api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1501,8 +1501,6 @@ func (h *Handler) AddRepository(c *gin.Context) {

// SyncRepository triggers a sync for a repository
func (h *Handler) SyncRepository(c *gin.Context) {
// SECURITY FIX: Use request context for proper cancellation and timeout handling
ctx := c.Request.Context()
repoIDStr := c.Param("id")

// Convert repo ID to int
Expand Down
72 changes: 40 additions & 32 deletions api/internal/api/stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,45 +675,53 @@
func (h *Handler) GetMetrics(c *gin.Context) {
ctx := c.Request.Context()

// Get cluster nodes
nodes, err := h.k8sClient.GetNodes(ctx)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get cluster nodes"})
return
}

// Count ready nodes
// Initialize default values
totalNodes := 0
readyNodes := 0
totalCPU := int64(0)
totalMemory := int64(0)
usedPods := 0
totalPods := 0

for _, node := range nodes.Items {
// Check if node is ready
for _, condition := range node.Status.Conditions {
if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
readyNodes++
break
// Get cluster nodes (handle nil k8sClient gracefully)
if h.k8sClient != nil {
nodes, err := h.k8sClient.GetNodes(ctx)
if err != nil {
log.Printf("Failed to get cluster nodes: %v", err)
// Continue with default values instead of failing
} else {
totalNodes = len(nodes.Items)

// Count ready nodes and sum resources
for _, node := range nodes.Items {
// Check if node is ready
for _, condition := range node.Status.Conditions {
if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {
readyNodes++
break
}
}

// Sum up allocatable resources
if cpu, ok := node.Status.Allocatable[corev1.ResourceCPU]; ok {
totalCPU += cpu.MilliValue()
}
if memory, ok := node.Status.Allocatable[corev1.ResourceMemory]; ok {
totalMemory += memory.Value()
}
if pods, ok := node.Status.Allocatable[corev1.ResourcePods]; ok {
totalPods += int(pods.Value())
}
}
}

// Sum up allocatable resources
if cpu, ok := node.Status.Allocatable[corev1.ResourceCPU]; ok {
totalCPU += cpu.MilliValue()
}
if memory, ok := node.Status.Allocatable[corev1.ResourceMemory]; ok {
totalMemory += memory.Value()
}
if pods, ok := node.Status.Allocatable[corev1.ResourcePods]; ok {
totalPods += int(pods.Value())
// Get all pods to calculate resource usage
pods, err := h.k8sClient.GetPods(ctx, h.namespace)
if err == nil {
usedPods = len(pods.Items)
}
}
}

// Get all pods to calculate resource usage
pods, err := h.k8sClient.GetPods(ctx, h.namespace)
if err == nil {
usedPods = len(pods.Items)
} else {
log.Printf("Warning: k8sClient is nil, returning metrics without cluster data")
}

// Get session counts from database
Expand All @@ -724,7 +732,7 @@
Terminated int
}

err = h.db.DB().QueryRowContext(ctx, `

Check failure on line 735 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
SELECT
COUNT(*) as total,
COUNT(*) FILTER (WHERE state = 'running') as running,
Expand All @@ -733,8 +741,8 @@
FROM sessions
`).Scan(&sessionCounts.Total, &sessionCounts.Running, &sessionCounts.Hibernated, &sessionCounts.Terminated)

if err != nil {

Check failure on line 744 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
log.Printf("Failed to get session counts: %v", err)

Check failure on line 745 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
// Use zeros if query fails
sessionCounts = struct {
Total, Running, Hibernated, Terminated int
Expand All @@ -747,15 +755,15 @@
Active int
}

err = h.db.DB().QueryRowContext(ctx, `

Check failure on line 758 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
SELECT
COUNT(*) as total,
COUNT(*) FILTER (WHERE last_login > NOW() - INTERVAL '24 hours') as active
FROM users
`).Scan(&userCounts.Total, &userCounts.Active)

if err != nil {

Check failure on line 765 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
log.Printf("Failed to get user counts: %v", err)

Check failure on line 766 in api/internal/api/stubs.go

View workflow job for this annotation

GitHub Actions / Go Dependency Vulnerability Scan (api)

undefined: err
// Use zeros if query fails
userCounts = struct{ Total, Active int }{0, 0}
}
Expand Down Expand Up @@ -784,9 +792,9 @@
c.JSON(http.StatusOK, gin.H{
"cluster": gin.H{
"nodes": gin.H{
"total": len(nodes.Items),
"total": totalNodes,
"ready": readyNodes,
"notReady": len(nodes.Items) - readyNodes,
"notReady": totalNodes - readyNodes,
},
"sessions": gin.H{
"total": sessionCounts.Total,
Expand Down
1 change: 1 addition & 0 deletions api/internal/db/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import (
"regexp"
"strconv"
"strings"
"time"

"golang.org/x/crypto/bcrypt"
_ "github.com/lib/pq"
Expand Down
1 change: 1 addition & 0 deletions api/internal/handlers/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"
"net/smtp"
"os"
Expand Down
4 changes: 2 additions & 2 deletions ui/src/pages/admin/UserDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,15 @@ export default function UserDetail() {
Role
</Typography>
<Box sx={{ mt: 0.5 }}>
<Chip label={user.role.toUpperCase()} size="small" />
<Chip label={user.role?.toUpperCase() || 'N/A'} size="small" />
</Box>
</Box>
<Box>
<Typography variant="caption" color="text.secondary">
Provider
</Typography>
<Box sx={{ mt: 0.5 }}>
<Chip label={user.provider.toUpperCase()} size="small" variant="outlined" />
<Chip label={user.provider?.toUpperCase() || 'N/A'} size="small" variant="outlined" />
</Box>
</Box>
<Box>
Expand Down
Loading