diff --git a/controller/internal/backup/offbox.go b/controller/internal/backup/offbox.go index 0f97969..989fc5c 100644 --- a/controller/internal/backup/offbox.go +++ b/controller/internal/backup/offbox.go @@ -441,6 +441,12 @@ func (m *Manager) RunOffboxBackup(ctx context.Context) error { o.LastError = "" o.SnapshotCount = snapshots var warns []string + // Zero-toggle honesty (take-two obs.): a configured target with NOTHING selected reports + // its emptiness instead of a bare success — the customer thinks offsite runs, but nothing + // is covered until at least one app is toggled. + if len(apps) == 0 { + warns = append(warns, "Sikeres — nincs mentésre jelölt alkalmazás") + } if len(missing) > 0 { warns = append(warns, fmt.Sprintf("Figyelmeztetés: %d alkalmazásnak nincs elérhető mentése, ezek kimaradtak: %s", len(missing), strings.Join(missing, ", "))) diff --git a/controller/internal/backup/offbox_test.go b/controller/internal/backup/offbox_test.go index 1a38576..3debafa 100644 --- a/controller/internal/backup/offbox_test.go +++ b/controller/internal/backup/offbox_test.go @@ -194,6 +194,43 @@ func TestOffbox_RunFailsFastAndAlerts(t *testing.T) { } } +// Zero-toggle honesty (take-two obs., v0.123.0): a run with a configured+escrowed target but ZERO +// toggled apps must stay status=ok yet report "Sikeres — nincs mentésre jelölt alkalmazás" instead +// of a bare success. Red-proof: drop the len(apps)==0 warns branch → the LastWarning assertion fails. +func TestOffbox_ZeroToggledRunReportsEmptiness(t *testing.T) { + m, sett := newOffboxManager(t) + m.SetOffboxRunner(func(_ context.Context, _ []string, args ...string) ([]byte, error) { + if contains(args, "cat") && contains(args, "config") { + return []byte(`{"version":2}`), nil // repo exists + } + return []byte(`[]`), nil + }) + // No SetAppOffbox call — zero apps toggled. + if err := m.RunOffboxBackup(context.Background()); err != nil { + t.Fatalf("zero-toggled run must not error: %v", err) + } + st := sett.GetOffboxTarget() + if st.LastStatus != "ok" { + t.Fatalf("zero-toggled run status = %q, want ok (emptiness is honesty, not failure)", st.LastStatus) + } + if !strings.Contains(st.LastWarning, "Sikeres — nincs mentésre jelölt alkalmazás") { + t.Fatalf("zero-toggled run must report its emptiness, LastWarning = %q", st.LastWarning) + } + + // Companion negative: with one toggled app captured, the emptiness copy must NOT appear. + nsRoot := m.AppNamespaceRoot("rallly") + if err := os.MkdirAll(filepath.Join(RecoveryUnitPath(nsRoot, "rallly"), "db-dumps"), 0o755); err != nil { + t.Fatal(err) + } + _ = sett.SetAppOffbox("rallly", true) + if err := m.RunOffboxBackup(context.Background()); err != nil { + t.Fatalf("toggled run must not error: %v", err) + } + if st := sett.GetOffboxTarget(); strings.Contains(st.LastWarning, "nincs mentésre jelölt") { + t.Fatalf("a covered run must not carry the emptiness copy, LastWarning = %q", st.LastWarning) + } +} + // TestOffbox_RepoIdempotent: when the repo exists (cat config succeeds), ensure must NOT init. func TestOffbox_RepoIdempotent(t *testing.T) { m, sett := newOffboxManager(t) diff --git a/controller/internal/web/handlers.go b/controller/internal/web/handlers.go index 5eb57db..f6604e2 100644 --- a/controller/internal/web/handlers.go +++ b/controller/internal/web/handlers.go @@ -671,7 +671,17 @@ func (s *Server) backupsHandler(w http.ResponseWriter, r *http.Request) { offboxTgt := s.settings.GetOffboxTarget() data["Offbox"] = offboxTgt data["OffboxConfigured"] = s.backupMgr.OffboxConfigured() - data["OffboxApps"] = s.buildOffboxApps() + offboxApps := s.buildOffboxApps() + data["OffboxApps"] = offboxApps + // Zero-toggle hint (take-two obs.): configured + escrowed but no app selected — nothing is + // actually covered by the offsite leg until the customer toggles at least one. + offboxToggled := 0 + for _, a := range offboxApps { + if a.Enabled { + offboxToggled++ + } + } + data["OffboxToggledCount"] = offboxToggled // SLICE 4 soft-quota usage bar (rendered only when a quota is set — shared model). data["OffboxQuotaPct"] = backup.OffboxQuotaPercent(offboxTgt) } else { diff --git a/controller/internal/web/templates/backups.html b/controller/internal/web/templates/backups.html index d606bca..71a2225 100644 --- a/controller/internal/web/templates/backups.html +++ b/controller/internal/web/templates/backups.html @@ -169,6 +169,9 @@

Mely alkalmazások mentődnek a távoli tárolóra?

+ {{if and .OffboxApps (eq .Offbox.EscrowState "escrowed") (eq .OffboxToggledCount 0)}} +

Nincs távoli mentésre jelölt alkalmazás — jelölj ki legalább egyet.

+ {{end}} {{if .OffboxApps}}
{{range .OffboxApps}}