fix: P0+P1 critical bug fixes across controller (24 files)
Concurrency fixes: - Deep-copy stacks in GetStack/GetStacks to prevent shared state mutation (C04) - Add per-state mutex to watchdog pathProbeState (C05) - Guard MetricsCollector.Start() with sync.Once against double-start (C06) - Hold diskJobMu across entire raw mount operation (C07) - Add mutex to SetEncryptionKey (C08), MigrateEncryption write lock (H03) - Use sync.Once for sync.Stop() channel close (H08) - Set syncing=true before releasing lock in TriggerSync (H09) - Deep-copy lastDBDump/lastBackup in GetFullStatus (H11) - Add WaitGroup for stderr goroutine in MigrateDrive (H19) - Add mutex to SetBackupRunningCheck (M18) Security fixes: - Validate Bearer token against Hub API key in CSRF middleware (H16) - Validate backup paths start with expected prefix in RemoveStack (M12) - Guard uuid[:8] slice with length check (H20) - Parse fstab fields exactly for mount target matching (H21) Bug fixes: - Use decrypted env vars for compose deploy (C01) - Log decrypt failures in DecryptMap instead of swallowing (C02) - Move Deployed=false inside lock in runComposeDeploy (C03) - Fix activeDrives() to skip disconnected drives (H02) - Fix Snapshot() stderr extraction from exec.ExitError (H01) - Check unlockCmd.Run() error in restic (H01) - Buffer template rendering via bytes.Buffer (H07) - Thread context.Context through cloudflare client (H10) - Fix leaf-name collision detection in cross-drive backup (H15) - Add nil check for crossDriveRunner (H17) - Use strings.TrimSpace instead of slice on command output (H18) - Make SaveAppConfig atomic with write-to-tmp+rename (H04) - Pass encKey on deploy failure SaveAppConfig (H05) - Fix IPv6 address format in TCP health probe Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,11 @@ func MountRaw(devicePath string) (string, error) {
|
||||
// Choose a directory name: prefer label, fall back to UUID prefix
|
||||
dirName := label
|
||||
if dirName == "" && uuid != "" {
|
||||
dirName = uuid[:8] // use first 8 chars of UUID
|
||||
if len(uuid) > 8 {
|
||||
dirName = uuid[:8]
|
||||
} else {
|
||||
dirName = uuid
|
||||
}
|
||||
}
|
||||
if dirName == "" {
|
||||
dirName = filepath.Base(devicePath) // "sdb1"
|
||||
@@ -441,12 +445,12 @@ func removeBindFstabEntry(fstabPath, targetMountPath string) error {
|
||||
// Remove both the comment line and the bind mount line
|
||||
if strings.Contains(line, "Bind mount (auto-generated by felhom-controller)") {
|
||||
// Check if the next line is the actual bind entry for this target
|
||||
if i+1 < len(lines) && strings.Contains(lines[i+1], targetMountPath) {
|
||||
if i+1 < len(lines) && fstabMatchesTarget(lines[i+1], targetMountPath) {
|
||||
i++ // skip the bind line too
|
||||
continue
|
||||
}
|
||||
}
|
||||
if strings.Contains(line, targetMountPath) && strings.Contains(line, "bind") {
|
||||
if fstabMatchesTarget(line, targetMountPath) && strings.Contains(line, "bind") {
|
||||
continue
|
||||
}
|
||||
kept = append(kept, line)
|
||||
@@ -454,3 +458,16 @@ func removeBindFstabEntry(fstabPath, targetMountPath string) error {
|
||||
|
||||
return safeWriteFile(fstabPath, []byte(strings.Join(kept, "\n")), 0644)
|
||||
}
|
||||
|
||||
// fstabMatchesTarget parses an fstab line and checks if the mount target (field 2) matches exactly.
|
||||
func fstabMatchesTarget(line, target string) bool {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
return false
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
return false
|
||||
}
|
||||
return fields[1] == target
|
||||
}
|
||||
|
||||
@@ -312,7 +312,10 @@ func (dm *DriveMigrator) MigrateDrive(ctx context.Context, req DriveMigrateReque
|
||||
}()
|
||||
|
||||
var stderrBuf strings.Builder
|
||||
var stderrWg sync.WaitGroup
|
||||
stderrWg.Add(1)
|
||||
go func() {
|
||||
defer stderrWg.Done()
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := stderr.Read(buf)
|
||||
@@ -326,10 +329,12 @@ func (dm *DriveMigrator) MigrateDrive(ctx context.Context, req DriveMigrateReque
|
||||
}()
|
||||
|
||||
if err := rsyncCmd.Wait(); err != nil {
|
||||
stderrWg.Wait()
|
||||
send("rolling_back", "rsync sikertelen, visszagörgetés...", 0)
|
||||
tx.rollback()
|
||||
return fail("Adatmásolás sikertelen", fmt.Errorf("rsync failed: %w — %s", err, stderrBuf.String()))
|
||||
}
|
||||
stderrWg.Wait()
|
||||
|
||||
// --- Step 3: Verify copy ---
|
||||
send("verifying", "Másolat ellenőrzése...", 62)
|
||||
|
||||
Reference in New Issue
Block a user