package stacks import ( "io" "log" "os" "path/filepath" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/config" ) // R-694 (v0.275.0) — a restore with no guest app.yaml (a load of kept data, a removed app, a rebuilt // guest) GENERATES the withheld admin login (D5: the unit never carries it), while the app's own login // comes back with its data. For six of the seven catalog apps with such a field the old password is the // one that works (measured from each entrypoint, `audits/version-travel-2026-09-26/D4/`); the page used // to show the new value as "the first password set at install". // // Through the PRODUCTION write (PersistUnitRedeployConfig), not the helper alone. // // COMPANION RED-PROOF (REPORT.md): make restoredLoginFields return nil — the nextcloud case then records // nothing and this fails at "restored_logins". func TestR694_ARestoreThatGeneratesTheLoginRecordsIt(t *testing.T) { for _, c := range []struct { name string app, env string guestHad bool wantNoted bool }{ {"nextcloud, guest app.yaml gone", "nextcloud", "NEXTCLOUD_ADMIN_PASSWORD", false, true}, {"nextcloud, guest kept the household's value", "nextcloud", "NEXTCLOUD_ADMIN_PASSWORD", true, false}, {"code-server applies the env at every start", "code-server", "PASSWORD", false, false}, } { t.Run(c.name, func(t *testing.T) { dir := t.TempDir() cfg := &config.Config{} cfg.Paths.StacksDir = filepath.Join(dir, "stacks") cfg.Stacks.ComposeCommand = "docker compose" app := filepath.Join(cfg.Paths.StacksDir, c.app) must(t, os.MkdirAll(app, 0o755)) must(t, os.WriteFile(filepath.Join(app, "docker-compose.yml"), []byte("services:\n web:\n image: x/y:1\n"), 0o644)) must(t, os.WriteFile(filepath.Join(app, ".felhom.yml"), []byte("display_name: X\ndeploy_fields:\n - env_var: "+c.env+"\n label: Admin\n type: password\n"), 0o644)) if c.guestHad { must(t, os.WriteFile(filepath.Join(app, "app.yaml"), []byte("deployed: true\nenv:\n "+c.env+": households-own\n"), 0o600)) } m, err := NewManager(cfg, log.New(io.Discard, "", 0)) must(t, err) must(t, m.ScanStacks()) must(t, m.PersistUnitRedeployConfig(c.app, map[string]string{c.env: "generated-at-restore"})) got := LoadAppConfig(app) noted := got != nil && len(got.RestoredLogins) == 1 && got.RestoredLogins[0] == c.env if noted != c.wantNoted { t.Fatalf("restored_logins = %v, want noted=%v", got.RestoredLogins, c.wantNoted) } }) } }