fix: P2+P3 bug fixes, hardening, and cleanup (18 files)
Bug fixes: - Add applyEnvOverrides to LoadFromBytes (M05) - Set state=failed on compose-up failure in selfupdate (M16) - Clamp usableMB to min 0 in memory check (M22) - Remove "manual" schedule from triggerAllCrossBackups (M23) - Add mmcblk device handling for partition paths (M21) - Fix stripPartition for mmcblk devices (L25) - Fix TruncateStr for UTF-8 and negative maxLen (L05/L06) - Fix AllDone to return false for empty restore plans (L14) - Fix PushOnce to return actual errors (L39) - Restore pending events on save failure in DrainPendingEvents (M03) - Add duplicate check in AddStoragePath (M04) - Call CleanupTempMounts after drive scan (H13) - Log SetStep save errors (M25) Hardening: - Guard scheduler Start() against double-start (M14) - Acquire mutex in scheduler Stop() before reading cancel (L24) - Cap log lines parameter to 10000 (L31) - Require POST for logout (L32) - Use sync.Once for Server.Close() (L49) - Panic on crypto/rand.Read failure in setup CSRF (L40) - Validate Bearer token against Hub API key in CSRF (H16 fix) - Replace custom hasPrefix with strings.HasPrefix (L13) - Replace simpleHash with crc32.ChecksumIEEE (L48) Cleanup: - Remove dead imageName function (L02) - Remove dead detectHostIPViaRoute function (L03) - Rename shadowed copy variable to cp (L07) - Copy DefaultEnabledEvents in GetNotificationPrefs early return (L09) - Update BUGHUNT.md with comprehensive audit results Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -264,8 +264,10 @@ func (s *Settings) GetNotificationPrefs() *NotificationPrefs {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
if s.Notifications == nil {
|
||||
events := make([]string, len(DefaultEnabledEvents))
|
||||
copy(events, DefaultEnabledEvents)
|
||||
return &NotificationPrefs{
|
||||
EnabledEvents: DefaultEnabledEvents,
|
||||
EnabledEvents: events,
|
||||
CooldownHours: 6,
|
||||
}
|
||||
}
|
||||
@@ -291,14 +293,14 @@ func (s *Settings) SetNotificationPrefs(prefs *NotificationPrefs) error {
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
copy := *prefs
|
||||
cp := *prefs
|
||||
if len(prefs.EnabledEvents) > 0 {
|
||||
copy.EnabledEvents = make([]string, len(prefs.EnabledEvents))
|
||||
cp.EnabledEvents = make([]string, len(prefs.EnabledEvents))
|
||||
for i, e := range prefs.EnabledEvents {
|
||||
copy.EnabledEvents[i] = e
|
||||
cp.EnabledEvents[i] = e
|
||||
}
|
||||
}
|
||||
s.Notifications = ©
|
||||
s.Notifications = &cp
|
||||
return s.save()
|
||||
}
|
||||
|
||||
@@ -422,6 +424,11 @@ func (s *Settings) GetSchedulableStoragePaths() []StoragePath {
|
||||
func (s *Settings) AddStoragePath(sp StoragePath) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
for _, existing := range s.StoragePaths {
|
||||
if existing.Path == sp.Path {
|
||||
return fmt.Errorf("storage path %q already registered", sp.Path)
|
||||
}
|
||||
}
|
||||
if sp.IsDefault {
|
||||
for i := range s.StoragePaths {
|
||||
s.StoragePaths[i].IsDefault = false
|
||||
@@ -808,7 +815,9 @@ func (s *Settings) DrainPendingEvents() []PendingEvent {
|
||||
copy(events, s.PendingEvents)
|
||||
s.PendingEvents = nil
|
||||
if err := s.save(); err != nil {
|
||||
s.log.Printf("[ERROR] Failed to save after draining pending events: %v", err)
|
||||
s.log.Printf("[ERROR] Failed to save after draining pending events: %v — restoring events", err)
|
||||
s.PendingEvents = events
|
||||
return nil
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user