#!/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 " >&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