diff --git a/cmd/uptop/main.go b/cmd/uptop/main.go index b58cb8d..71a280d 100644 --- a/cmd/uptop/main.go +++ b/cmd/uptop/main.go @@ -603,7 +603,9 @@ func seedKeysFromEnv(s store.Store) { if path := os.Getenv("UPTOP_KEYS"); path != "" { f, err := os.Open(filepath.Clean(path)) - if err == nil { + if err != nil { + slog.Warn("failed to open UPTOP_KEYS file", "path", path, "err", err) //nolint:gosec // structured slog, not format string + } else { scanner := bufio.NewScanner(f) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) diff --git a/internal/monitor/checker.go b/internal/monitor/checker.go index cbb7fdb..b5e9235 100644 --- a/internal/monitor/checker.go +++ b/internal/monitor/checker.go @@ -3,6 +3,7 @@ package monitor import ( "context" "fmt" + "io" "net" "net/http" "strconv" @@ -103,7 +104,10 @@ func runHTTPCheck(ctx context.Context, site models.SiteConfig, strict, insecure result.ErrorReason = truncateError(err.Error(), maxErrorLength) return result } - defer resp.Body.Close() + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() result.StatusCode = resp.StatusCode if !isCodeAccepted(resp.StatusCode, site.AcceptedCodes) { diff --git a/internal/monitor/monitor.go b/internal/monitor/monitor.go index de3ac27..c02af39 100644 --- a/internal/monitor/monitor.go +++ b/internal/monitor/monitor.go @@ -864,6 +864,9 @@ func (e *Engine) handleStatusChange(snap models.Site, rawStatus string, code int } func (e *Engine) triggerAlert(alertID int, title, message string) { + if alertID <= 0 { + return + } cfg, err := e.db.GetAlert(context.Background(), alertID) if err != nil { e.AddLog(fmt.Sprintf("Failed to load alert config %d: %v", alertID, err)) diff --git a/internal/server/server.go b/internal/server/server.go index 1ebc7b0..0e6ebf1 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -64,7 +64,7 @@ func Start(cfg ServerConfig, s store.Store, eng *monitor.Engine) *http.Server { func (s *Server) Start() *http.Server { if s.cfg.ClusterKey == "" { - slog.Warn("no UPTOP_CLUSTER_SECRET set, cluster API endpoints are unauthenticated") + slog.Warn("no UPTOP_CLUSTER_SECRET set, cluster API endpoints will reject all requests") } if s.cfg.ClusterMode != "" && s.cfg.ClusterMode != "leader" && s.cfg.TLSCert == "" { @@ -168,6 +168,10 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { } func (s *Server) handleExport(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } if !s.requireAuth(r) { http.Error(w, "Unauthorized: UPTOP_CLUSTER_SECRET required", http.StatusUnauthorized) return diff --git a/internal/tui/format.go b/internal/tui/format.go index 591371a..6614f60 100644 --- a/internal/tui/format.go +++ b/internal/tui/format.go @@ -34,6 +34,9 @@ func (m Model) emptyState(message, hint string) string { } func limitStr(text string, max int) string { + if max < 3 { + return text + } runes := []rune(text) if len(runes) > max { return string(runes[:max-3]) + "..." diff --git a/internal/tui/update.go b/internal/tui/update.go index 63f019b..12c0ea2 100644 --- a/internal/tui/update.go +++ b/internal/tui/update.go @@ -336,8 +336,8 @@ func (m *Model) handleFilterKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { case "ctrl+c": return m, tea.Quit default: - if len(msg.String()) == 1 { - m.filterText += msg.String() + if len(msg.Runes) == 1 { + m.filterText += string(msg.Runes) m.cursor = 0 m.tableOffset = 0 m.refreshLive()