Commit Graph

5 Commits (daeea1db0e88bacac72a52debe13627f36a9dd3e)

Author SHA1 Message Date
nexxo 24eb7b3d80 Fix-Welle: Schlussreview-Befunde 1-6 zur Release-Decke
Sechs Befunde aus dem Schlussreview, in einer Welle behoben:

- BEFUND 1 (Important): eine leere Auswahl im Festnageln-Feld liess
  pinRelease() ueber `$this->ceilingChoice ?: null` in setCeiling(null)
  laufen — die Gegenhandlung (Decke abnehmen) — und meldete dabei die
  Erfolgsmeldung des Festnagelns. ConfirmPinRelease::confirm() schickt die
  Version jetzt als Event-Nutzlast (wie ConfirmSaveSecret den Schluessel),
  und pinRelease(string $version) weist eine leere Version ausdruecklich
  ab, mit einer eigenen Meldung (release_pin_empty).
- BEFUND 2 (Minor, durch 1 miterledigt): Modal und Seite lasen bisher zwei
  getrennte Eigenschaften ($version vs. $ceilingChoice). Der Fix oben
  beseitigt die Trennung.
- BEFUND 3 (Important, Text only): der Kommentar bei release_tag_exists()
  in deploy/lib/release.sh und der Fehlerbehandlungs-Abschnitt der Spec
  behaupteten, ceiling_missing schuetze gegen einen vom Release-Prozess
  geloeschten Tag. Tut es nicht: `git fetch --tags --force` (ohne
  --prune-tags, bewusst) entfernt keine lokal bereits geholten Tags, die
  drueben verschwunden sind. Beide Stellen beschreiben jetzt, wogegen die
  Pruefung tatsaechlich schuetzt (ein nie geholter oder nie existierender
  Tag) und wogegen nicht. Kein --prune-tags hinzugefuegt.
- BEFUND 4 (Minor): ConfirmPinRelease hatte keinen Test. Zwei neue Tests
  nach dem Vorbild von ConfirmSaveSecret in IntegrationsPageTest.
- BEFUND 5 (Minor): ceilingChoice wurde nie aus dem gesetzten Zustand
  vorbelegt. UpdateChannel::ceiling() ist jetzt public, Settings::mount()
  belegt das Feld damit vor.
- BEFUND 6 (Minor): eine von Hand geleerte Deckendatei liest die Konsole
  als "keine Decke" (ceiling() -> null), der Agent meldet dafuer aber
  ceiling_error. Der "Decke abnehmen"-Knopf stand nur hinter
  @if($update['ceiling']) und verschwand damit genau in dem Zustand, aus
  dem er zurueckfuehren muesste. Bedingung erweitert auf
  ($update['ceiling'] || $update['ceiling_error']).

Jeder Befund traegt einen eigenen Test in ReleaseCeilingConsoleTest.php.
Volle Suite: 2973 passed (10389 assertions).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 16:25:48 +02:00
nexxo 073e147ff8 Festnageln aus der Konsole
Task 5: Bedienoberfläche zum Festnageln einer Release-Version, in der
bestehenden Update-Handlungsleiste statt einer zweiten daneben.
Bestätigt im Modal (R23), Auswahlfeld selbst ohne Modal (R20).
2026-08-04 15:53:36 +02:00
nexxo d90137c521 Beleg: das Wartungsfenster achtet die Decke ohne eigene Regel 2026-08-04 15:39:02 +02:00
nexxo c93510ffe4 Fix-Runde 1: writeAtomic prueft Rueckgabewerte, ceiling() faengt Throwable
Zwei Important-Befunde aus dem Code-Review zu Task 3:

- writeAtomic() ignorierte den Rueckgabewert von File::put()/File::move()
  und meldete setCeiling() als "true", selbst wenn ein I/O-Fehler (volle
  Platte, Rechteproblem) nichts geschrieben oder eine .tmp liegen gelassen
  hatte. Beide Rueckgabewerte werden jetzt geprueft, eine liegen gebliebene
  .tmp wird im Fehlerfall aufgeraeumt, und der Fehlschlag wird bis zu
  setCeiling() durchgereicht (Rueckgabe false).

- ceiling() konnte state() doch werfen lassen: zwischen File::exists() und
  File::get() liegt ein Zeitfenster, und File::get() wirft eine
  FileNotFoundException, wenn die Datei dazwischen verschwindet. readJson()
  und lastLog() kapseln genau dieses Muster schon in try/catch(Throwable);
  ceiling() zieht jetzt nach.

Beide Befunde tragen einen eigenen Test: ein Verzeichnis an der Ceiling-
Datei-Stelle (exists() wahr, get() wirft) fuer den zweiten, eine echte
Rechteverweigerung (chmod 0500 als nicht-root Testbenutzer) fuer den
ersten -- kein Facade-Mock noetig.
2026-08-04 15:30:10 +02:00
nexxo 367198459c Der Kanal schreibt die Decke atomar und reicht sie durch 2026-08-04 15:13:43 +02:00