Gegenbuch als Docker-Setup, lokales Buch auf eigener Maschine
Betreiber-Entscheidung: Das Gegenbuch laeuft auf einer eigenen Maschine fuer Prod und Staging; ein externes Git-Repository entfaellt, das Buch liegt lokal. Die Trennung, auf die es ankommt, ist damit gegeben - wer OpenCRM uebernimmt, kommt nicht ans Buch. Richtung bewusst so herum: Das Gegenbuch holt ueber HTTPS mit einem Token, das nur audit:read kann. OpenCRM kennt weder Adresse noch Schluessel des Gegenbuchs. Kein SSH-Zugang zum CRM noetig. tools/audit-notary/ enthaelt jetzt Dockerfile, entrypoint.sh, docker-compose.yml und .env.example. Zwei Dienste (prod, staging) mit getrennten Verzeichnissen und Schluesseln, gesteuert ueber COMPOSE_PROFILES - dasselbe Muster wie beim Caddy-Profil im Hauptstack. Der Signaturschluessel wird beim ersten Start auf der Gegenbuch-Maschine erzeugt. Lokaler Betrieb ist jetzt ein vollwertiger Modus statt eines Testschalters. Die Erfolgsmeldung benennt bei jedem Lauf, was abgedeckt ist und was nicht - statt der frueheren pauschalen Formulierung "kein Manipulationsschutz", die im Einsatz auf eigener Maschine schlicht falsch war. Verifiziert mit echtem Docker-Build gegen eine CRM-Attrappe: Genesis ohne Bestaetigung -> Code 4; mit Bestaetigung Normalbetrieb exit 0; Eintrag veraendert -> Alarm exit 2; Eintraege geloescht -> Alarm exit 2; Siegel verschwunden -> Alarm. Behoben beim Bauen: useradd -u 1000 || true verschluckte, dass UID 1000 im Node-Image vergeben ist - der Container startete gar nicht. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,6 +97,38 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung
|
|||||||
|
|
||||||
## ✅ Erledigt
|
## ✅ Erledigt
|
||||||
|
|
||||||
|
- [x] **🐳 Gegenbuch als Docker-Setup, lokales Buch auf eigener Maschine** (2026-08-22)
|
||||||
|
- Betreiber-Entscheidung: Das Gegenbuch laeuft auf einer **eigenen Maschine**
|
||||||
|
fuer Prod und Staging; ein externes Git-Repository entfaellt, das Buch
|
||||||
|
liegt lokal auf dieser Maschine. Die Trennung, auf die es ankommt, ist
|
||||||
|
damit gegeben – wer OpenCRM uebernimmt, kommt nicht ans Buch.
|
||||||
|
- Richtung bewusst so herum: Das Gegenbuch **holt** ueber HTTPS mit einem
|
||||||
|
Token, das nur `audit:read` kann. OpenCRM kennt weder Adresse noch
|
||||||
|
Schluessel des Gegenbuchs. Kein SSH-Zugang zum CRM noetig – das Token kann
|
||||||
|
ausschliesslich Pruefwerte lesen.
|
||||||
|
- Unterverzeichnis `tools/audit-notary/`: `Dockerfile`, `entrypoint.sh`,
|
||||||
|
`docker-compose.yml`, `.env.example`. Zwei Dienste (`prod`, `staging`) mit
|
||||||
|
getrennten Verzeichnissen und Schluesseln, gesteuert ueber
|
||||||
|
`COMPOSE_PROFILES` – dasselbe Muster wie beim Caddy-Profil im Hauptstack.
|
||||||
|
Der Signaturschluessel wird beim ersten Start auf der Gegenbuch-Maschine
|
||||||
|
erzeugt und verlaesst sie nie.
|
||||||
|
- **Lokaler Betrieb ist jetzt ein vollwertiger Modus**, kein Testschalter
|
||||||
|
mehr. Die Erfolgsmeldung benennt bei jedem Lauf, was abgedeckt ist
|
||||||
|
(„jemand veraendert Daten im CRM“) und was nicht („jemand uebernimmt diesen
|
||||||
|
Rechner hier“) – statt der frueheren pauschalen Formulierung „kein
|
||||||
|
Manipulationsschutz“, die im Einsatz auf eigener Maschine schlicht falsch
|
||||||
|
war.
|
||||||
|
- Jeder Durchlauf schreibt `status.txt` fuer die Ueberwachung; alles ausser
|
||||||
|
`exit=0` gehoert angesehen.
|
||||||
|
- Verifiziert mit echtem Docker-Build gegen eine CRM-Attrappe: Genesis ohne
|
||||||
|
Bestaetigung → Code 4; mit Bestaetigung → Buch angelegt, Normalbetrieb
|
||||||
|
exit 0; **Eintrag nachtraeglich veraendert → Alarm exit 2**; **Eintraege
|
||||||
|
geloescht (maxId geschrumpft) → Alarm exit 2**; Siegel verschwunden →
|
||||||
|
Alarm. Testartefakte und Image geloescht.
|
||||||
|
- Behoben beim Bauen: `useradd -u 1000 || true` verschluckte, dass UID 1000
|
||||||
|
im Node-Image bereits vergeben ist – der Container startete gar nicht.
|
||||||
|
Jetzt laeuft er als der vorhandene Benutzer `node`.
|
||||||
|
|
||||||
- [x] **🧮 Gegenbuch: Pruefmodus schreibt nicht mehr, Widerspruch aufgeloest (Pentest R181)** (2026-08-18)
|
- [x] **🧮 Gegenbuch: Pruefmodus schreibt nicht mehr, Widerspruch aufgeloest (Pentest R181)** (2026-08-18)
|
||||||
- **R181-01 (LOW→MED)** – Der Pruefmodus sagte zu, nichts zu veraendern und
|
- **R181-01 (LOW→MED)** – Der Pruefmodus sagte zu, nichts zu veraendern und
|
||||||
kein Schreibrecht zu brauchen – und pushte trotzdem: `ankerNachziehen()`
|
kein Schreibrecht zu brauchen – und pushte trotzdem: `ankerNachziehen()`
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# ============================================================
|
||||||
|
# Gegenbuch für OpenCRM
|
||||||
|
# ============================================================
|
||||||
|
# Diese Datei gehört auf den Gegenbuch-Rechner – NICHT auf den CRM-Server.
|
||||||
|
#
|
||||||
|
# Was hier passiert: Der Rechner holt regelmäßig einen kurzen Kontrollwert von
|
||||||
|
# OpenCRM ab und schreibt ihn in ein Buch, das nur hier liegt. Wird später im
|
||||||
|
# CRM etwas nachträglich verändert, widerspricht das dem Buch.
|
||||||
|
#
|
||||||
|
# Welche Bücher sollen laufen?
|
||||||
|
COMPOSE_PROFILES=prod,staging
|
||||||
|
|
||||||
|
# Nur Kosmetik – steht in den Einträgen des Buchs.
|
||||||
|
NOTAR_EMAIL=gegenbuch@example.de
|
||||||
|
|
||||||
|
# ---------------- Produktion ----------------
|
||||||
|
# Von welcher OpenCRM-Instanz wird geholt?
|
||||||
|
PROD_CRM_URL=https://crm.example.de
|
||||||
|
|
||||||
|
# Token eines Benutzers mit dem Recht audit:read – MEHR NICHT.
|
||||||
|
# Damit lassen sich ausschließlich Prüfwerte lesen: keine Kundendaten, keine
|
||||||
|
# Änderungen. Selbst wenn es abhandenkommt, ist damit nichts anzufangen.
|
||||||
|
PROD_CRM_TOKEN=
|
||||||
|
|
||||||
|
# Wie oft geprüft wird (Sekunden). 3600 = stündlich.
|
||||||
|
# Kürzer heißt: kleineres Zeitfenster, in dem eine Änderung unbemerkt bliebe.
|
||||||
|
PROD_INTERVAL=3600
|
||||||
|
|
||||||
|
# Beim ALLERERSTEN Start einmalig auf true setzen, danach wieder leeren.
|
||||||
|
# Grund: Die erste Eintragung legt fest, was als Ausgangszustand gilt – das
|
||||||
|
# soll nicht versehentlich passieren.
|
||||||
|
PROD_GENESIS_ACK=
|
||||||
|
|
||||||
|
# Normalerweise leer lassen. Nur nötig, wenn das Gedächtnis des Gegenbuchs
|
||||||
|
# verlorenging (z. B. Verzeichnis gelöscht) und du geklärt hast, warum.
|
||||||
|
PROD_ADOPT_ACK=
|
||||||
|
|
||||||
|
# Wo das Buch liegt. DIESES VERZEICHNIS GEHÖRT INS BACKUP.
|
||||||
|
PROD_DIR=./data/prod
|
||||||
|
|
||||||
|
# ---------------- Test / Staging ----------------
|
||||||
|
STAGING_CRM_URL=https://staging.example.de
|
||||||
|
STAGING_CRM_TOKEN=
|
||||||
|
STAGING_INTERVAL=3600
|
||||||
|
STAGING_GENESIS_ACK=
|
||||||
|
STAGING_ADOPT_ACK=
|
||||||
|
STAGING_DIR=./data/staging
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Gegenbuch – läuft auf einem EIGENEN Rechner, nicht dort, wo OpenCRM läuft.
|
||||||
|
#
|
||||||
|
# Der Container holt lesend einen Kontrollwert vom CRM (HTTPS + Token mit
|
||||||
|
# audit:read) und legt seine Einträge in einem Git-Repository auf DIESER
|
||||||
|
# Maschine ab. Er braucht keinen SSH-Zugang zum CRM, keine Datenbank, keine
|
||||||
|
# Shell dort. Umgekehrt kennt OpenCRM dieses Gegenbuch überhaupt nicht.
|
||||||
|
FROM node:20-slim
|
||||||
|
|
||||||
|
# git für das Buch, openssh-client für die Signaturen (ssh-keygen).
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
git openssh-client ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY notary.mjs /opt/notary/notary.mjs
|
||||||
|
COPY entrypoint.sh /opt/notary/entrypoint.sh
|
||||||
|
RUN chmod +x /opt/notary/entrypoint.sh
|
||||||
|
|
||||||
|
# Nicht als root laufen. Das Node-Image bringt bereits einen Benutzer mit
|
||||||
|
# UID 1000 mit ("node") – der passt zu Bind-Mounts unter ./data/.
|
||||||
|
USER node
|
||||||
|
WORKDIR /gegenbuch
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/notary/entrypoint.sh"]
|
||||||
@@ -18,7 +18,77 @@ der erste – es sieht nach doppeltem Boden aus und ist keiner. Das CRM braucht
|
|||||||
für dieses Verfahren **gar nichts** zu wissen: Es liefert nur einen lesbaren
|
für dieses Verfahren **gar nichts** zu wissen: Es liefert nur einen lesbaren
|
||||||
Kontrollwert, der keine Geheimnisse enthält.
|
Kontrollwert, der keine Geheimnisse enthält.
|
||||||
|
|
||||||
## Einrichten
|
## Einrichten mit Docker (empfohlen)
|
||||||
|
|
||||||
|
Auf dem **Gegenbuch-Rechner** – nicht auf dem CRM-Server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <dieses Repository> opencrm
|
||||||
|
cd opencrm/tools/audit-notary
|
||||||
|
cp .env.example .env
|
||||||
|
# .env ausfüllen: CRM-Adresse und Token eintragen
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Beim ersten Start einmalig `PROD_GENESIS_ACK=true` setzen (und danach wieder
|
||||||
|
leeren) – die erste Eintragung legt fest, was als Ausgangszustand gilt, und das
|
||||||
|
soll nicht versehentlich passieren.
|
||||||
|
|
||||||
|
**Zwei Bücher auf einer Maschine** sind vorgesehen: `prod` und `staging` sind
|
||||||
|
getrennte Dienste mit getrennten Verzeichnissen und getrennten Schlüsseln.
|
||||||
|
Welche laufen, steuert `COMPOSE_PROFILES` in der `.env`.
|
||||||
|
|
||||||
|
### Wer redet mit wem
|
||||||
|
|
||||||
|
```
|
||||||
|
Gegenbuch ──holt lesend──> OpenCRM (HTTPS, Token nur mit audit:read)
|
||||||
|
OpenCRM ─────────────────> (kennt das Gegenbuch nicht)
|
||||||
|
```
|
||||||
|
|
||||||
|
Das ist der eigentliche Schutz. Das Gegenbuch **holt** – es lässt sich nichts
|
||||||
|
schicken. OpenCRM kennt weder Adresse noch Schlüssel des Gegenbuchs. Wer
|
||||||
|
OpenCRM übernimmt, kommt hier nicht heran.
|
||||||
|
|
||||||
|
Das Token kann ausschließlich Prüfwerte lesen: keine Kundendaten, keine
|
||||||
|
Änderungen. Selbst wenn es abhandenkommt, ist damit nichts anzufangen.
|
||||||
|
|
||||||
|
Der Signaturschlüssel wird beim ersten Start **auf dem Gegenbuch-Rechner
|
||||||
|
erzeugt** und verlässt ihn nie.
|
||||||
|
|
||||||
|
### Was ins Backup gehört
|
||||||
|
|
||||||
|
Das Datenverzeichnis (`./data/prod` bzw. `./data/staging`). Darin liegen das
|
||||||
|
Buch, der Schlüssel und der Beobachtungsspeicher. Geht es verloren, beginnt die
|
||||||
|
Beobachtung von vorn – und der nächste Lauf sagt das ausdrücklich, statt „alles
|
||||||
|
gut" zu melden.
|
||||||
|
|
||||||
|
### Überwachung
|
||||||
|
|
||||||
|
Jeder Durchlauf schreibt seinen Stand nach `data/<instanz>/status.txt`:
|
||||||
|
|
||||||
|
```
|
||||||
|
2026-08-22T16:49:50+00:00 exit=0 in Ordnung
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alles außer `exit=0` gehört angesehen.** Wer eine Überwachung hat, greift
|
||||||
|
diese Datei ab; wer keine hat, schaut regelmäßig mit `docker compose logs`
|
||||||
|
hinein. Ein Alarm, den niemand liest, ist keiner.
|
||||||
|
|
||||||
|
### Was dieser Betrieb abdeckt – und was nicht
|
||||||
|
|
||||||
|
**Abgedeckt:** Jemand verändert oder löscht nachträglich Einträge im CRM –
|
||||||
|
auch mit direktem Datenbankzugriff. Das widerspricht dem Gegenbuch und fällt
|
||||||
|
beim nächsten Durchlauf auf.
|
||||||
|
|
||||||
|
**Nicht abgedeckt:** Jemand übernimmt den Gegenbuch-Rechner selbst. Dagegen
|
||||||
|
hülfe nur eine zusätzliche Ablage außerhalb (z. B. ein privates Git-Repository
|
||||||
|
auf einem dritten Server) – das ist vorbereitet, aber für die meisten
|
||||||
|
Installationen mehr Aufwand als Nutzen. Die Erfolgsmeldung benennt diese Grenze
|
||||||
|
bei jedem Lauf, damit sie nicht in Vergessenheit gerät.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Einrichten ohne Docker
|
||||||
|
|
||||||
Auf einem **anderen** Rechner als dem CRM-Server:
|
Auf einem **anderen** Rechner als dem CRM-Server:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# Gegenbuch für OpenCRM
|
||||||
|
# =====================
|
||||||
|
# Gehört auf einen EIGENEN Rechner – nicht dorthin, wo OpenCRM läuft.
|
||||||
|
#
|
||||||
|
# Richtung der Verbindung (das ist der eigentliche Schutz):
|
||||||
|
# Gegenbuch ──holt lesend──> OpenCRM (HTTPS, Token nur mit audit:read)
|
||||||
|
# OpenCRM ─────────────────> (kennt das Gegenbuch nicht)
|
||||||
|
#
|
||||||
|
# Wer OpenCRM übernimmt, kommt damit nicht an dieses Buch heran. Deshalb holt
|
||||||
|
# das Gegenbuch selbst, statt sich etwas schicken zu lassen.
|
||||||
|
#
|
||||||
|
# Start:
|
||||||
|
# cp .env.example .env # Werte eintragen
|
||||||
|
# docker compose up -d
|
||||||
|
#
|
||||||
|
# Zwei Bücher auf einer Maschine sind vorgesehen (Produktion und Test): zwei
|
||||||
|
# getrennte Dienste mit getrennten Verzeichnissen und getrennten Schlüsseln.
|
||||||
|
# Welche laufen, steuert COMPOSE_PROFILES in der .env.
|
||||||
|
|
||||||
|
services:
|
||||||
|
prod:
|
||||||
|
build: .
|
||||||
|
container_name: gegenbuch-prod
|
||||||
|
restart: unless-stopped
|
||||||
|
profiles: ["prod"]
|
||||||
|
environment:
|
||||||
|
INSTANZ: prod
|
||||||
|
CRM_URL: ${PROD_CRM_URL}
|
||||||
|
CRM_TOKEN: ${PROD_CRM_TOKEN}
|
||||||
|
NOTARY_INTERVAL: ${PROD_INTERVAL:-3600}
|
||||||
|
NOTAR_EMAIL: ${NOTAR_EMAIL:-gegenbuch@localhost}
|
||||||
|
# Nur beim allerersten Lauf einmalig auf true, danach wieder leeren:
|
||||||
|
NOTARY_GENESIS_ACK: ${PROD_GENESIS_ACK:-}
|
||||||
|
# Nur nach geklärtem Verlust des Beobachtungsspeichers, siehe README:
|
||||||
|
NOTARY_ADOPT_ACK: ${PROD_ADOPT_ACK:-}
|
||||||
|
volumes:
|
||||||
|
# Buch, Schlüssel, Beobachtungsspeicher und Statusdatei.
|
||||||
|
# Dieses Verzeichnis ist das Gegenbuch – es gehört ins Backup.
|
||||||
|
- ${PROD_DIR:-./data/prod}:/gegenbuch
|
||||||
|
|
||||||
|
staging:
|
||||||
|
build: .
|
||||||
|
container_name: gegenbuch-staging
|
||||||
|
restart: unless-stopped
|
||||||
|
profiles: ["staging"]
|
||||||
|
environment:
|
||||||
|
INSTANZ: staging
|
||||||
|
CRM_URL: ${STAGING_CRM_URL}
|
||||||
|
CRM_TOKEN: ${STAGING_CRM_TOKEN}
|
||||||
|
NOTARY_INTERVAL: ${STAGING_INTERVAL:-3600}
|
||||||
|
NOTAR_EMAIL: ${NOTAR_EMAIL:-gegenbuch@localhost}
|
||||||
|
NOTARY_GENESIS_ACK: ${STAGING_GENESIS_ACK:-}
|
||||||
|
NOTARY_ADOPT_ACK: ${STAGING_ADOPT_ACK:-}
|
||||||
|
volumes:
|
||||||
|
- ${STAGING_DIR:-./data/staging}:/gegenbuch
|
||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/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_TOKEN:?CRM_TOKEN fehlt – Token eines Benutzers mit audit:read}"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
node /opt/notary/notary.mjs
|
||||||
|
CODE=$?
|
||||||
|
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)"
|
||||||
|
printf '%s exit=%s %s\n' "$ZEIT" "$CODE" "$LAGE" > /gegenbuch/status.txt
|
||||||
|
sleep "$INTERVALL"
|
||||||
|
done
|
||||||
@@ -221,14 +221,22 @@ async function hole(pfad) {
|
|||||||
return j.data;
|
return j.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lokaler Betrieb ist ein vollwertiger Modus, wenn das Gegenbuch auf einem
|
||||||
|
// EIGENEN Rechner laeuft: Wer das CRM uebernimmt, kommt dann nicht an dieses
|
||||||
|
// Buch. Was fehlt, ist der Schutz gegen jemanden, der DIESEN Rechner
|
||||||
|
// uebernimmt – das gehoert benannt, aber es ist kein „kein Schutz“.
|
||||||
const OHNE_ANKER = () =>
|
const OHNE_ANKER = () =>
|
||||||
NUR_LOKAL ? ' – ACHTUNG: nur lokal, kein externer Anker, also kein Manipulationsschutz.' : '';
|
NUR_LOKAL
|
||||||
|
? '\n Betriebsart: lokal. Geschützt ist damit der Fall „jemand verändert Daten im ' +
|
||||||
|
'CRM“.\n NICHT geschützt ist der Fall „jemand übernimmt diesen Rechner hier“ – ' +
|
||||||
|
'dagegen hülfe\n nur eine zusätzliche Ablage außerhalb.'
|
||||||
|
: '';
|
||||||
|
|
||||||
// Ohne bekannte Mindesthoehe bleibt ein Rewind auf einen aelteren, echt
|
// Ohne bekannte Mindesthoehe bleibt ein Rewind auf einen aelteren, echt
|
||||||
// signierten Stand unerkennbar (R178-01). Das gehoert in die Erfolgsmeldung,
|
// signierten Stand unerkennbar (R178-01). Das gehoert in die Erfolgsmeldung,
|
||||||
// sonst liest sich „OK“ als mehr Gewissheit, als vorhanden ist.
|
// sonst liest sich „OK“ als mehr Gewissheit, als vorhanden ist.
|
||||||
const REWIND_VORBEHALT = () =>
|
const REWIND_VORBEHALT = () =>
|
||||||
REWIND_GESCHUETZT || ffBelegt
|
REWIND_GESCHUETZT || ffBelegt || NUR_LOKAL
|
||||||
? ''
|
? ''
|
||||||
: '\n Offen: Ein Zurückspulen der Reihe auf einen älteren, ebenfalls signierten Stand ' +
|
: '\n Offen: Ein Zurückspulen der Reihe auf einen älteren, ebenfalls signierten Stand ' +
|
||||||
'lässt sich hier nicht ausschließen.' +
|
'lässt sich hier nicht ausschließen.' +
|
||||||
@@ -251,6 +259,11 @@ const REWIND_VORBEHALT = () =>
|
|||||||
// bewusst NICHT mit dem Manipulationsalarm (2) verschmolzen.
|
// bewusst NICHT mit dem Manipulationsalarm (2) verschmolzen.
|
||||||
const abschliessendSicher = (anzahl) =>
|
const abschliessendSicher = (anzahl) =>
|
||||||
REWIND_GESCHUETZT ||
|
REWIND_GESCHUETZT ||
|
||||||
|
// Im lokalen Betrieb gibt es keinen Remote, den jemand zurueckspulen koennte.
|
||||||
|
// Der Vergleich gegen den eigenen Beobachtungsspeicher ist hier der
|
||||||
|
// vollstaendige Nachweis – die Grenze liegt bei der Integritaet dieses
|
||||||
|
// Rechners und ist als solche benannt, nicht ungeklaert.
|
||||||
|
(NUR_LOKAL && ffBelegt) ||
|
||||||
// BEWUSST NICHT `ankerBelegt` (Pentest R180-01): Die Anker-Refs zeigen nur
|
// BEWUSST NICHT `ankerBelegt` (Pentest R180-01): Die Anker-Refs zeigen nur
|
||||||
// den HOECHSTEN NOCH VORHANDENEN Stand – nicht den hoechsten je erreichten.
|
// den HOECHSTEN NOCH VORHANDENEN Stand – nicht den hoechsten je erreichten.
|
||||||
// Wer die obersten Refs loescht, senkt damit den Vergleichswert selbst; ein
|
// Wer die obersten Refs loescht, senkt damit den Vergleichswert selbst; ein
|
||||||
@@ -305,8 +318,9 @@ if (hatRemote) {
|
|||||||
process.exit(3);
|
process.exit(3);
|
||||||
}
|
}
|
||||||
} else if (process.env.NOTARY_ALLOW_LOCAL === 'true') {
|
} else if (process.env.NOTARY_ALLOW_LOCAL === 'true') {
|
||||||
// Der Schalter darf nicht zu einem glatten „OK“ fuehren: Leckt er je ins
|
// Ausdruecklich gewaehlter lokaler Betrieb (Gegenbuch auf eigenem Rechner,
|
||||||
// Produktivumfeld, gaebe es gruenes Licht auf nicht notarisiertem Stand.
|
// ohne zusaetzliche Ablage ausserhalb). Die Erfolgsmeldung benennt, was das
|
||||||
|
// abdeckt und was nicht – ein glattes „OK“ ohne Einordnung gibt es nicht.
|
||||||
NUR_LOKAL = true;
|
NUR_LOKAL = true;
|
||||||
} else {
|
} else {
|
||||||
console.error(
|
console.error(
|
||||||
|
|||||||
Reference in New Issue
Block a user