fix(security): harden TLS, timeouts, validation, logging, and token generation
- Default TLS verification on, opt-in UPKEEP_INSECURE_SKIP_VERIFY - Alert webhooks use 10s timeout client, close response bodies - URL input validates http/https scheme for HTTP monitors - Stdlib logs route to stderr instead of discard - Panic on crypto/rand failure in token generation - Cluster startup warnings for non-HTTPS and missing secret - Replace demo SMTP creds with obvious placeholders - Color-coded log entries and scroll hints in logs tab
This commit is contained in:
@@ -1,5 +1,54 @@
|
||||
package tui
|
||||
|
||||
func (m Model) viewLogsTab() string {
|
||||
return "\n" + m.logViewport.View()
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func colorizeLog(line string) string {
|
||||
lower := strings.ToLower(line)
|
||||
switch {
|
||||
case strings.Contains(lower, "confirmed down"),
|
||||
strings.Contains(lower, "is down"),
|
||||
strings.Contains(lower, "missed heartbeat"),
|
||||
strings.Contains(lower, "failed check"),
|
||||
strings.Contains(lower, "ssl warning"):
|
||||
return dangerStyle.Render(line)
|
||||
case strings.Contains(lower, "recovered"),
|
||||
strings.Contains(lower, "is up"),
|
||||
strings.Contains(lower, "recovery"):
|
||||
return specialStyle.Render(line)
|
||||
case strings.Contains(lower, "engine"),
|
||||
strings.Contains(lower, "cluster"):
|
||||
return titleStyle.Render(line)
|
||||
default:
|
||||
return line
|
||||
}
|
||||
}
|
||||
|
||||
func (m Model) viewLogsTab() string {
|
||||
content := m.logViewport.View()
|
||||
if strings.TrimSpace(content) == "" || content == "Waiting for logs..." {
|
||||
return "\n No log entries yet. Logs appear as monitors run checks."
|
||||
}
|
||||
|
||||
lines := strings.Split(content, "\n")
|
||||
var colored []string
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
colored = append(colored, line)
|
||||
continue
|
||||
}
|
||||
colored = append(colored, colorizeLog(line))
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, l := range lines {
|
||||
if strings.TrimSpace(l) != "" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
header := subtleStyle.Render(fmt.Sprintf(" %d entries [↑/↓] Scroll [PgUp/PgDn] Page", count))
|
||||
return "\n" + header + "\n\n" + strings.Join(colored, "\n")
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"go-upkeep/internal/models"
|
||||
"go-upkeep/internal/monitor"
|
||||
"go-upkeep/internal/store"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -317,7 +318,26 @@ func (m *Model) initSiteHuhForm() tea.Cmd {
|
||||
huh.NewInput().Title("URL").
|
||||
Placeholder("https://example.com").
|
||||
Description("Required for HTTP monitors").
|
||||
Value(&m.siteFormData.URL),
|
||||
Value(&m.siteFormData.URL).
|
||||
Validate(func(s string) error {
|
||||
if m.siteFormData.SiteType == "push" {
|
||||
return nil
|
||||
}
|
||||
if s == "" {
|
||||
return fmt.Errorf("URL is required for HTTP monitors")
|
||||
}
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid URL")
|
||||
}
|
||||
if u.Scheme != "http" && u.Scheme != "https" {
|
||||
return fmt.Errorf("URL must start with http:// or https://")
|
||||
}
|
||||
if u.Host == "" {
|
||||
return fmt.Errorf("URL must include a host")
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
huh.NewInput().Title("Check Interval (seconds)").
|
||||
Placeholder("60").
|
||||
Value(&m.siteFormData.Interval),
|
||||
|
||||
Reference in New Issue
Block a user