Files
duffyduckandClaude Opus 5 e76b4ace88 status.txt zeigt die Zusammenfassung, nicht die erste beliebige Zeile
Die Grund-Zeile nahm bei fehlendem Alarm schlicht die erste Ausgabezeile.
Beim ersten Prod-Lauf nach dem Versiegeln stand dort deshalb die
einmalige Notiz "Grundlage fuer die Rehash-Ueberwachung wird gesetzt"
statt des Ergebnisses "OK: Checkpoint N erstellt" - eine Randnotiz
verdeckte die Zusammenfassung.

Jetzt: bei Alarm die ALARM-Zeile, sonst die OK-Zeile, und erst wenn
beides fehlt die erste Zeile ueberhaupt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:25:45 +02:00

108 lines
4.7 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Gegenbuch-Schleife: einrichten, dann in festem Takt beglaubigen.
set -uo pipefail
: "${INSTANZ:?INSTANZ fehlt (z. B. prod oder staging)}"
: "${CRM_URL:?CRM_URL fehlt von welcher OpenCRM-Instanz soll geholt werden?}"
: "${CRM_EMAIL:?CRM_EMAIL fehlt Dienstkonto im CRM mit dem Recht audit:read}"
: "${CRM_PASSWORD:?CRM_PASSWORD fehlt Passwort dieses Dienstkontos}"
INTERVALL="${NOTARY_INTERVAL:-3600}"
BUCH=/gegenbuch/buch
SCHLUESSEL=/gegenbuch/schluessel
export NOTARY_STATE_FILE=/gegenbuch/beobachtungen.jsonl
export NOTARY_ALLOW_LOCAL=true # Buch liegt auf dieser Maschine
export NOTARY_PUSH=false # es gibt kein Ziel zum Pushen
# --- Rechte geraderuecken, dann Privilegien abgeben ------------------------
# Laeuft der Container als root, gehoert das Bind-Mount-Verzeichnis vermutlich
# ebenfalls root (typisch, wenn das Projekt als root geklont wurde). Wir setzen
# es auf den Arbeitsbenutzer um und starten uns selbst als dieser neu.
BENUTZER_UID="${PUID:-1000}"
BENUTZER_GID="${PGID:-1000}"
if [ "$(id -u)" = "0" ]; then
if ! chown -R "$BENUTZER_UID:$BENUTZER_GID" /gegenbuch 2>/dev/null; then
echo "[$INSTANZ] HINWEIS: Rechte auf /gegenbuch liessen sich nicht setzen." >&2
echo "[$INSTANZ] Falls es gleich an fehlenden Schreibrechten scheitert, auf dem Host:" >&2
echo "[$INSTANZ] chown -R $BENUTZER_UID:$BENUTZER_GID <datenverzeichnis>" >&2
fi
exec setpriv --reuid="$BENUTZER_UID" --regid="$BENUTZER_GID" --init-groups \
--inh-caps=-all "$0" "$@"
fi
echo "[$INSTANZ] Gegenbuch startet Quelle: $CRM_URL, Takt: ${INTERVALL}s"
# --- Signaturschlüssel: einmalig auf DIESER Maschine erzeugen ---------------
# Er verlässt den Rechner nie. OpenCRM kennt ihn nicht.
mkdir -p "$SCHLUESSEL"
if [ ! -f "$SCHLUESSEL/id_ed25519" ]; then
echo "[$INSTANZ] Erzeuge Signaturschlüssel..."
ssh-keygen -t ed25519 -f "$SCHLUESSEL/id_ed25519" -N "" -C "gegenbuch-$INSTANZ" -q
fi
chmod 600 "$SCHLUESSEL/id_ed25519"
if [ ! -f "$SCHLUESSEL/allowed_signers" ]; then
echo "gegenbuch-$INSTANZ namespaces=\"git\" $(cat "$SCHLUESSEL/id_ed25519.pub")" \
> "$SCHLUESSEL/allowed_signers"
fi
# --- Buch anlegen, falls noch nicht vorhanden ------------------------------
if [ ! -d "$BUCH/.git" ]; then
echo "[$INSTANZ] Lege Gegenbuch an..."
mkdir -p "$BUCH"
git -C "$BUCH" init -q -b main
fi
cd "$BUCH" || exit 1
git config user.email "${NOTAR_EMAIL:-gegenbuch@localhost}"
git config user.name "Gegenbuch $INSTANZ"
git config gpg.format ssh
git config user.signingkey "$SCHLUESSEL/id_ed25519.pub"
git config gpg.ssh.allowedSignersFile "$SCHLUESSEL/allowed_signers"
# Ein erster Commit, damit es eine Historie gibt, an die angehängt werden kann.
if ! git rev-parse HEAD >/dev/null 2>&1; then
git commit -q -S --allow-empty -m "Gegenbuch $INSTANZ angelegt"
fi
# --- Schleife ---------------------------------------------------------------
# Jeder Rückgabecode außer 0 gehört angesehen. Der letzte Stand steht
# zusätzlich in status.txt, damit eine Überwachung ihn abgreifen kann, ohne
# Logs zu durchsuchen.
while true; do
ZEIT=$(date -Iseconds)
# 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)" ;;
2) LAGE="BEFUND Widerspruch zwischen CRM und Gegenbuch" ;;
3) LAGE="nicht abschliessend feststellbar (u. a. erster Lauf)" ;;
4) LAGE="Gedaechtnis fehlt Bestaetigung noetig, siehe README" ;;
5) LAGE="Anker unvollstaendig" ;;
*) LAGE="unbekannter Code" ;;
esac
echo "[$INSTANZ] $ZEIT exit=$CODE ($LAGE)"
# Die aussagekraeftigste Zeile mitnehmen, nicht einfach die erste.
#
# Bei Alarm ist das die ALARM-Zeile. Sonst die Zusammenfassung ("OK: …") -
# denn ein Lauf kann davor beilaeufige Hinweise ausgeben (etwa das einmalige
# Setzen einer Ueberwachungs-Grundlage), und die verdeckten sonst das
# Ergebnis. Erst wenn beides fehlt, die erste Zeile ueberhaupt.
GRUND=$(grep -m1 '^ALARM: ' /tmp/lauf.log | sed 's/^ALARM: //')
[ -z "$GRUND" ] && GRUND=$(grep -m1 '^OK: ' /tmp/lauf.log)
[ -z "$GRUND" ] && GRUND=$(grep -m1 -v '^[[:space:]]*$' /tmp/lauf.log)
{
printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE"
[ -n "$GRUND" ] && printf 'Grund: %s\n' "$GRUND"
} > /gegenbuch/status.txt
sleep "$INTERVALL"
done