diff --git a/docs/todo.md b/docs/todo.md index 0cd12dd0..50a6f87c 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -97,6 +97,19 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung ## ✅ Erledigt +- [x] **📄 `status.txt` nennt jetzt den Grund, nicht nur das Etikett** (2026-08-26) + - In der Statusdatei des Gegenbuchs stand für **jeden** Exit-2 derselbe Satz: + „BEFUND – Widerspruch zwischen CRM und Gegenbuch". Ein echter Widerspruch + sah damit genauso aus wie eine quittierpflichtige Erstsiegelung. + - Aufgefallen im Betrieb: Der Betreiber las „BEFUND" auf Staging und konnte + nicht entscheiden, ob er handeln muss – obwohl die Kette dort `valid:true` + meldet und der Alarm nur den erwarteten Siegelwechsel betraf. Wer nur die + Statusdatei liest (und dafür ist sie da – „damit eine Überwachung sie + abgreifen kann, ohne Logs zu durchsuchen"), bekam ein Etikett ohne Inhalt. + - Der Lauf wird jetzt mitgeschnitten; die erste `ALARM:`-Zeile landet als + `Grund:` in `status.txt`. Ohne Alarm die erste Ausgabezeile. + - Datei: `tools/audit-notary/entrypoint.sh` + - [x] **⚖️ Aufsicht und Eingriff getrennt: neuer Haken „Audit-Betrieb"** (2026-08-26) - Die DSGVO-Rolle trug `audit:*` **komplett**, also auch `audit:admin`. Ein DSGVO-Beauftragter konnte damit `seal-backlog`, `rehash` und `cleanup` – diff --git a/tools/audit-notary/entrypoint.sh b/tools/audit-notary/entrypoint.sh index 6f53c0d7..b973a25f 100755 --- a/tools/audit-notary/entrypoint.sh +++ b/tools/audit-notary/entrypoint.sh @@ -70,8 +70,16 @@ fi # Logs zu durchsuchen. while true; do ZEIT=$(date -Iseconds) - node /opt/notary/notary.mjs + # Ausgabe mitschneiden, um den GRUND in die Statusdatei zu bekommen. + # + # Vorher stand dort nur das Etikett ("BEFUND"), und das ist fuer jeden + # Exit-2 dasselbe - ein echter Widerspruch sieht darin aus wie eine + # quittierpflichtige Erstsiegelung. Wer nur die Statusdatei liest, kann + # nicht entscheiden, ob er handeln muss. Genau die Sorte Signal, gegen die + # dieses Werkzeug gebaut ist. + node /opt/notary/notary.mjs > /tmp/lauf.log 2>&1 CODE=$? + cat /tmp/lauf.log case $CODE in 0) LAGE="in Ordnung" ;; 1) LAGE="Betriebsfehler (Konfiguration, CRM nicht erreichbar, Commit)" ;; @@ -82,6 +90,15 @@ while true; do *) LAGE="unbekannter Code" ;; esac echo "[$INSTANZ] $ZEIT exit=$CODE ($LAGE)" - printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE" > /gegenbuch/status.txt + # Erste erklaerende Zeile mitnehmen: bei Alarm die ALARM-Zeile, sonst die + # erste Ausgabezeile ueberhaupt. + GRUND=$(grep -m1 '^ALARM: ' /tmp/lauf.log | sed 's/^ALARM: //') + if [ -z "$GRUND" ]; then + GRUND=$(grep -m1 -v '^[[:space:]]*$' /tmp/lauf.log) + fi + { + printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE" + [ -n "$GRUND" ] && printf 'Grund: %s\n' "$GRUND" + } > /gegenbuch/status.txt sleep "$INTERVALL" done