diff --git a/dms/docs/INTEGRATION-PRUEFPROTOKOLL.md b/dms/docs/INTEGRATION-PRUEFPROTOKOLL.md index 9aa0f340..9a63c77a 100644 --- a/dms/docs/INTEGRATION-PRUEFPROTOKOLL.md +++ b/dms/docs/INTEGRATION-PRUEFPROTOKOLL.md @@ -254,3 +254,95 @@ Pruefungen auf 204 (Head nach Merge `6141fc9`, frischer Klon, seriell ueber die Skips (unveraendert gegenueber dem Lauf zu PR #97): `TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege` (`dms_dev` ohne `CREATEROLE`), `TestKoSIT_LiveOutcomeMatchesExpectation` (`TEST_KOSIT_EXPECT` fehlt), 2x clamd, 2x soffice, `TestSign_UsesConfiguredTSA` (keine TSA-Env), 3x S3 (`TEST_S3_*` fehlt), die zwei Latenztests ohne `TEST_PERF=1` im Paketlauf (separat bestanden). Hinweis zum Wrapper: `RUNHOST_*`-Argumente mit `|` im `-run`-Regex werden von `runhost.sh` durch die Shell zerlegt; Tests einzeln starten. + +## Nachtrag: Durchtest auf 204 und 131 (Stand `0d01dfa`, 2026-09-21) + +Auftrag: den Integrationsstand `integration/dms-gesamtstand` (`0d01dfa`) auf dem Entwicklungshost 204 und auf der Vorstufe 131 durchtesten. Alle Laeufe seriell ueber die Sperre in `runhost.sh` bzw. `rungate.sh`, jeweils frischer Klon. + +### Ergebnis je Host + +| Pruefung | 204 (Entwicklung) | 131 (Vorstufe) | +|---|---|---| +| `go vet`, `gofmt -l` | sauber | sauber | +| `go test -count=1 -v ./...` | 74 Pakete `ok`, 0 FAIL, 12 SKIP (3:58 min) | 74 Pakete `ok`, 0 FAIL, 10 SKIP (3:42 min) | +| Latenz `TestSearch_ConcurrentRequestsStayUnderResponseTimeLimit` (`TEST_PERF=1 -p 1`) | PASS, p95 42,2 ms | PASS, p95 65,7 ms | +| Latenz `TestFilters_ResponseTimeWithFiveFilters` (`TEST_PERF=1 -p 1`) | PASS, p95 2,8 ms | PASS, p95 7,8 ms | +| `qa02-foundation-gate.sh` | Exit 0, `govulncheck` ausdruecklich uebersprungen (Werkzeug fehlt auf 204) | Exit 0, alle Stufen PASS, `govulncheck -mode=binary` PASS | +| `check-port-defaults.sh`, `check-route-prefixes.sh` (im Gate) | PASS | PASS | +| Frontend `tsc` und `vitest` | `dms-browser` 143/143, `dms-upload` 17/17, `pdf-viewer` 31/31, `tsc` sauber (nach Fix, siehe unten) | nicht ausgefuehrt (Auftrag: nur 204); Diagnoselauf `pdf-viewer` 31/31, `tsc` sauber | +| Gesamtsystem-Smoke (FDN-19) | Uebergangsmodus 41/41, Token-Modus 46/46, Wiederanlauf 3/3 | **nicht ausgefuehrt** (siehe unten) | +| Rueckbau | Vorher-/Nachher-Snapshot (Dienste, Ports, Datenbanken, Rollen, Manticore-Tabellen, Benutzer, `/opt`) identisch | entfaellt | + +Skips: gemeinsam auf beiden Hosts `TestAppendOnly_AppRoleHasNoUpdateOrDeletePrivilege` (kein `CREATEROLE`), `TestKoSIT_LiveOutcomeMatchesExpectation` (`TEST_KOSIT_EXPECT`), `TestHandler_ConvertsDocxToPDF` und `TestHandler_CrashingConverterDoesNotAffectOtherJobs` (`soffice` fehlt), `TestSign_UsesConfiguredTSA` (keine TSA-Umgebung), die zwei Latenztests (nur mit `TEST_PERF=1`, separat bestanden), drei S3-Tests (`TEST_S3_*`). Nur auf 204 zusaetzlich: die zwei `clamd`-Tests (`clamd` fehlt auf 204). Auf 131 laufen sie und bestehen, dort ist `clamav-daemon` installiert. + +### Ressourcen im Gesamtbetrieb (204, 4 Kerne, 4 GB RAM) + +| Messung | Wert (Ziel) | +|---|---| +| RSS Ruhebetrieb App, Worker, Stellvertreter, KoSIT | 10 + 11 + 7 + 548 = 576 MB (Ziel <= 1,5 GB) | +| nach Smoke-Test | 625 MB, Worker-Spitze 99 MB (cgroup) | +| Host-Speicher belegt, Spitze ueber alle Stichproben | 918 von 4096 MB | +| OOM-Ereignisse | 0 (App, Worker, Stellvertreter, `dmesg`) | +| Load 1 min, Spitze | 4,19 (Ausgangswert 4,19, danach 2,11) | +| Wiederanlauf nach hartem Abbruch, Standardfrist 300 s | 299 s, keine Dubletten, keine offenen Jobs | +| Wiederanlauf mit `NEXARCH_DMS_WORKER_JOB_LEASE_SECONDS=10` (FDN-20) | 30 s, keine Dubletten, keine offenen Jobs | + +### Befunde + +1. **Frontend unter npm >= 10 (Fix)**: `web/dms-browser`, `web/dms-upload` und `web/pdf-viewer` haengen von `"@nexarch/shl": "file:../shl"` ab. npm 9 (Node 20, 131) kopiert das Verzeichnis, npm 11 (Node 24, 204) legt einen Symlink an. Dann liegt `web/shl` ohne eigenes `react`, `tsc` meldet `Cannot find module 'react'` und 48 (`dms-browser`) bzw. 4 (`pdf-viewer`) Tests scheitern. Ein zusaetzliches `npm install` in `web/shl` liefert ein zweites `react` (Hook-Fehler). Behoben mit `.npmrc` (`install-links=true`) je App, danach auf 204 alle drei Apps gruen. Der CI-Job `web` (`ci.yml`) nutzt dieselbe Installation und ist damit von der npm-Version des Laeufers unabhaengig. +2. **Skript `fdn19-gesamtstart.sh`**: Der Suchindex-Name war nicht einstellbar, der Test haette auf 204 die Tabelle `dms_documents` des Entwicklungsbetriebs benutzt. Neu: `FDN19_INDEX_NAME` (Standard unveraendert) und `FDN19_LEASE_SECONDS`. Beim Rueckbau wird nur die eigene Tabelle entfernt. +3. **Last auf 131 in Containern**: `loadavg` zeigt dort den Wert des Proxmox-Hosts (konstant ca. 11,8) bei ca. 81 % freier CPU und CPU-Druck (PSI `avg10`) 0,01. Als Kriterium "Last niedrig" taugt der Druckwert, nicht `loadavg`. +4. **Reste auf 131**: In der Test-Datenbank stehen vier Schemas `dmstest_*` (angelegt 2026-09-20 zwischen 23:02 und 23:19, Reste abgebrochener Laeufe, nicht von diesem Durchlauf). Nicht entfernt. Auf 204 keine Reste. +5. **`govulncheck` fehlt auf 204**: Das Gate laeuft dort nur mit `QA02_SKIP_VULN=1`. Der Scan ist auf 131 vorhanden und dort PASS. + +### Nicht ausgefuehrt: Gesamtsystem-Smoke auf 131 + +Der Smoke braucht auf 131 eine eigene Wegwerf-Datenbank. Die Rolle in `/etc/nexarch/dms-app.env` darf Datenbanken anlegen (`CREATEDB`, kein Superuser, kein `CREATEROLE`), `nexarch_app` existiert, die Ports 8600 bis 8699 sind bis auf 8610 (KoSIT) frei. Das vorhandene Skript legt dagegen eine eigene Rolle ueber den Postgres-Superuser an. Ein Modus, der die Datenbank ueber die vorhandene Rolle anlegt, wurde vom Sicherheitsfilter blockiert. Es fehlt daher die ausdrueckliche Freigabe, auf 131 (a) eine Datenbank `dms_fdn19` ueber die vorhandene Test-Rolle anzulegen, (b) einen unprivilegierten Systembenutzer und transiente `nexarch-dms-*`-Units zu erzeugen. Bis dahin ist die Vorstufe 131 nur mit Volltest, Gate und Latenz belegt. + +## Nachtrag: Gesamtsystem-Smoke auf 131 (2026-09-21) + +Ausdrueckliche Freigabe des Users fuer diesen Lauf: eigene Datenbank ueber die vorhandene Test-Rolle, unprivilegierter Systembenutzer mit transienten `nexarch-dms-*`-Units, Entfernen der verwaisten `dmstest_*`-Schemas. Basis: Branch `fix/testrun-2026-09-21-dms` (Skript-Optionen aus `7fb3105`). + +### Durchfuehrung + +- Nur die Test-Rolle aus `/etc/nexarch/dms-app.env` (`CREATEDB`, weder Superuser noch `CREATEROLE`) wurde benutzt. Neu im Skript: `FDN19_PG_ROLE_DSN` (Rollen-Modus: Datenbank anlegen und loeschen, kein `CREATE ROLE`, kein `su - postgres`) und `FDN19_GO` (auf 131 liegt Go 1.24.4 unter `/usr/bin/go`, die Toolchain 1.25.x laedt sich nach). +- Datenbank `dms_fdn19` (Eigentuemer: Test-Rolle), Systembenutzer `nexarch-fdn19`, transiente Units `nexarch-dms-fdn19-{stub,worker,app}` auf 127.0.0.1:8600/8601/8611, Suchindex `fdn19_smoke131`. KoSIT (127.0.0.1:8610, MET-07) lief bereits und wurde weder gestartet noch veraendert. Build mit `-p 2`, CPU-Druck vor dem Start (PSI `avg10`) 0,03 bis 0,07. +- `dmstest_*`: Die vier Schemas (aus dem Namen abgeleitet 2026-09-20, 14 Stunden alt, keine aktive Sitzung, kein Testlauf) wurden entfernt, vorher wurden Praefix und Alter geprueft. Danach 0 Schemas. + +### Ergebnisse + +| Pruefung | Ergebnis | +|---|---| +| Smoke Uebergangsmodus (`caller`) | 41 von 41 bestanden | +| Smoke Token-Modus (lokales Test-JWKS) | 46 von 46 bestanden | +| Wiederanlauf nach hartem Abbruch (App und Worker, 1 Job in Bearbeitung, Frist 10 s) | 3 von 3 bestanden, 30 s, 10 Dokumente ohne Dubletten, kein Dead-Letter | +| Ruhebetrieb RSS App, Worker, Stellvertreter, KoSIT | 11 + 13 + 8 + 537 = 569 MB (Ziel <= 1,5 GB) | +| nach Smoke und Neustart | 569 MB, Worker-Spitze 14 MB (cgroup) | +| Host-Speicher belegt, Spitze ueber alle Stichproben | 2382 von 6124 MB (Ausgangswert 2292 bis 2310 MB) | +| OOM-Ereignisse | 0 (App, Worker, Stellvertreter) | +| CPU-Druck (PSI `avg10`), Spitze waehrend des Laufs | 1,40 | +| `loadavg` (zeigt in Containern den Proxmox-Host) | 9,4 vorher, Spitze 11,2, 11,2 nachher; kein Kriterium | +| Postgres RSS gesamt | 418 MB im Ruhebetrieb, 453 MB nach dem Lauf | + +### Vergleich 204 und 131 + +| | 204 | 131 | +|---|---|---| +| Smoke `caller` / Token / Wiederanlauf | 41/41, 46/46, 3/3 | 41/41, 46/46, 3/3 | +| Wiederanlauf mit Frist 10 s | 30 s | 30 s | +| Ruhebetrieb RSS gesamt | 576 MB | 569 MB | +| Host-Speicher belegt, Spitze | 918 von 4096 MB | 2382 von 6124 MB (davon rund 2300 MB Ausgangslast der produktiven Dienste) | +| Zusatzlast des Smoke auf dem Host | nicht separat gemessen (nur Spitze) | rund 90 MB (Spitze 2382 gegen Ausgangswert 2292 bis 2310 MB) | +| Datenbank | `dms_fdn19` ueber `su - postgres` | `dms_fdn19` ueber die Test-Rolle (`CREATEDB`) | +| Go | 1.26.5 | 1.24.4 (Toolchain-Nachladen) | + +Die beiden Hosts verhalten sich gleich. Die Produktivdienste von 131 (19 `nexarch-*` laufend) blieben unberuehrt. + +### Rueckbau (131) + +Vorher-/Nachher-Snapshot (Dienste, Ports, Datenbanken, Rollen, Suchtabellen, Systembenutzer): identisch bis auf das Arbeitsverzeichnis `/opt/nexarch-dms-fdn19`, das beim Vorher-Snapshot bereits angelegt war und nun entfernt ist. Datenbank `dms_fdn19`, Benutzer `nexarch-fdn19`, die drei Units, Port 8600/8601/8611, Suchtabelle `fdn19_smoke131` und `/opt/nexarch-dms-fdn19` sind weg, KoSIT blieb (`keep-kosit`). Suchtabellen `dms_documents` und `mail_documents` unveraendert. + +### Hinweise + +- Auf 131 stehen sechs Archive-Oneshot-Dienste im Zustand `failed` (`backup-full`, `backup-incremental`, `objectbackup-rotate`, `reconcile`, `restoretest`, `scrub`). Sie standen im Vorher-Snapshot schon so und gehoeren nicht zu diesem Lauf; Klaerung im Archive-Board. +- Der Rollen-Modus legt kein `nexarch_app` an. Fuer ein echtes Deployment bleibt B4 (Rolle vorab durch den Betrieb) bestehen; auf 131 existiert sie bereits. diff --git a/scripts/fdn19-gesamtstart.sh b/scripts/fdn19-gesamtstart.sh index 1ee338d2..e6d8254e 100755 --- a/scripts/fdn19-gesamtstart.sh +++ b/scripts/fdn19-gesamtstart.sh @@ -28,12 +28,18 @@ KOSIT_PORT=8610 STUB_PORT=8611 PFX=nexarch-dms-fdn19 KOSIT_DIR=/opt/nexarch-kosit -GO=/usr/local/bin/go +GO="${FDN19_GO:-/usr/local/bin/go}" TERM_WORD=Zinnoberrot +INDEX_NAME="${FDN19_INDEX_NAME:-dms_documents}" +LEASE_SECONDS="${FDN19_LEASE_SECONDS:-300}" die() { echo "FEHLER: $*" >&2; exit 1; } rand() { head -c 24 /dev/urandom | od -An -tx1 | tr -d ' \n'; } -pg() { su - postgres -c "psql -qAtX -v ON_ERROR_STOP=1 $*"; } +ROLE_DSN="${FDN19_PG_ROLE_DSN:-}" +# FDN19_PG_ROLE_DSN gesetzt: nur mit dieser (nicht privilegierten) Rolle arbeiten (Datenbank anlegen/loeschen, kein CREATE ROLE, kein Superuser) +pg() { + if [ -n "$ROLE_DSN" ]; then eval "psql -qAtX -v ON_ERROR_STOP=1 \"\$ROLE_DSN\" $*"; else su - postgres -c "psql -qAtX -v ON_ERROR_STOP=1 $*"; fi +} cmd_snapshot() { local out="${1:?datei}" @@ -101,6 +107,7 @@ NEXARCH_DMS_APP_KEK_ENDPOINT_URL=http://127.0.0.1:$STUB_PORT/kek NEXARCH_DMS_APP_KEK_CLIENT_ID=fdn19 NEXARCH_DMS_APP_KEK_CLIENT_SECRET=stub NEXARCH_DMS_APP_MANTICORE_ADDR=127.0.0.1:9306 +NEXARCH_DMS_APP_SEARCH_INDEX_NAME=$INDEX_NAME NEXARCH_DMS_APP_CMIS_ENABLED=true E if [ "$mode" = token ]; then @@ -122,6 +129,8 @@ NEXARCH_DMS_WORKER_KEK_ENDPOINT_URL=http://127.0.0.1:$STUB_PORT/kek NEXARCH_DMS_WORKER_KEK_CLIENT_ID=fdn19 NEXARCH_DMS_WORKER_KEK_CLIENT_SECRET=stub NEXARCH_DMS_WORKER_MANTICORE_ADDR=127.0.0.1:9306 +NEXARCH_DMS_WORKER_SEARCH_INDEX_NAME=$INDEX_NAME +NEXARCH_DMS_WORKER_JOB_LEASE_SECONDS=$LEASE_SECONDS NEXARCH_DMS_WORKER_KOSIT_ADDR=http://127.0.0.1:$KOSIT_PORT NEXARCH_DMS_WORKER_KOSIT_RULESET=xrechnung-3.0.2-2026-08-31 NEXARCH_DMS_WORKER_CONCURRENCY=2 @@ -145,9 +154,17 @@ cmd_setup() { . "$BASE/env/secrets" [ "$(pg -c "\"select count(*) from pg_roles where rolname='nexarch_app'\"")" = 1 ] || die "Rolle nexarch_app fehlt: Migration 0013 legt sie clusterweit an und braucht dafuer CREATEROLE; vom Betrieb vorab anlegen (CREATE ROLE nexarch_app NOLOGIN)" if [ "$(pg -c "\"select count(*) from pg_database where datname='$DB'\"")" = 0 ]; then - pg -c "\"CREATE ROLE $DB LOGIN PASSWORD '$DB_PASSWORD'\"" -c "\"CREATE DATABASE $DB OWNER $DB\"" || die "datenbank anlegen" + if [ -n "$ROLE_DSN" ]; then + pg -c "\"CREATE DATABASE $DB\"" || die "datenbank anlegen" + else + pg -c "\"CREATE ROLE $DB LOGIN PASSWORD '$DB_PASSWORD'\"" -c "\"CREATE DATABASE $DB OWNER $DB\"" || die "datenbank anlegen" + fi + fi + if [ -n "$ROLE_DSN" ]; then + echo "$ROLE_DSN" | sed -E "s#/[^/?]*\?#/$DB?#" >"$BASE/env/dsn" + else + echo "postgres://$DB:$DB_PASSWORD@127.0.0.1:5432/$DB?sslmode=disable" >"$BASE/env/dsn" fi - echo "postgres://$DB:$DB_PASSWORD@127.0.0.1:5432/$DB?sslmode=disable" >"$BASE/env/dsn" chmod 600 "$BASE/env/dsn" local dsn; dsn="$(cat "$BASE/env/dsn")" psql "$dsn" -qAtX -c "CREATE TABLE IF NOT EXISTS users (id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT NOT NULL UNIQUE, name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now())" || die "users-stand-in" @@ -239,10 +256,10 @@ cmd_reset() { cmd_down if [ -f "$BASE/env/dsn" ]; then psql "$(cat "$BASE/env/dsn")" -qAtX -c "select id from documents" 2>/dev/null | while read -r id; do - [ -n "$id" ] && curl -s -X POST "http://127.0.0.1:9308/sql?mode=raw" --data-urlencode "query=DELETE FROM dms_documents WHERE document_id = '$id'" >/dev/null + [ -n "$id" ] && curl -s -X POST "http://127.0.0.1:9308/sql?mode=raw" --data-urlencode "query=DELETE FROM $INDEX_NAME WHERE document_id = '$id'" >/dev/null done fi - pg -c "\"DROP DATABASE IF EXISTS $DB\"" -c "\"DROP ROLE IF EXISTS $DB\"" || die "reset: datenbank" + if [ -n "$ROLE_DSN" ]; then pg -c "\"DROP DATABASE IF EXISTS $DB\"" || die "reset: datenbank"; else pg -c "\"DROP DATABASE IF EXISTS $DB\"" -c "\"DROP ROLE IF EXISTS $DB\"" || die "reset: datenbank"; fi rm -rf "$BASE/data/storage" "$BASE/data/staging" "$BASE/env/secrets" "$BASE/env/dsn" mkdir -p "$BASE/data/storage" "$BASE/data/staging" cmd_setup @@ -301,13 +318,14 @@ cmd_teardown() { # dms_documents und nexarch_app gehoeren dem Entwicklungsbetrieb des Hosts: nur die eigenen Eintraege entfernen if [ -f "$BASE/env/dsn" ]; then psql "$(cat "$BASE/env/dsn")" -qAtX -c "select id from documents" 2>/dev/null | while read -r id; do - [ -n "$id" ] && curl -s -X POST "http://127.0.0.1:9308/sql?mode=raw" --data-urlencode "query=DELETE FROM dms_documents WHERE document_id = '$id'" >/dev/null + [ -n "$id" ] && curl -s -X POST "http://127.0.0.1:9308/sql?mode=raw" --data-urlencode "query=DELETE FROM $INDEX_NAME WHERE document_id = '$id'" >/dev/null done fi + [ "$INDEX_NAME" != dms_documents ] && curl -s -X POST "http://127.0.0.1:9308/sql?mode=raw" --data-urlencode "query=DROP TABLE IF EXISTS $INDEX_NAME" >/dev/null if [ "$(pg -c "\"select count(*) from pg_database where datname='$DB'\"")" != 0 ]; then pg -c "\"DROP DATABASE $DB\"" || echo "WARNUNG: DROP DATABASE" fi - pg -c "\"DROP ROLE IF EXISTS $DB\"" || true + [ -z "$ROLE_DSN" ] && { pg -c "\"DROP ROLE IF EXISTS $DB\"" || true; } id "$SVC_USER" >/dev/null 2>&1 && userdel "$SVC_USER" rm -rf "$BASE" /root/fdn19-*.log if [ "$keep" != keep-kosit ]; then diff --git a/web/dms-browser/.npmrc b/web/dms-browser/.npmrc new file mode 100644 index 00000000..c7d35173 --- /dev/null +++ b/web/dms-browser/.npmrc @@ -0,0 +1 @@ +install-links=true diff --git a/web/dms-upload/.npmrc b/web/dms-upload/.npmrc new file mode 100644 index 00000000..c7d35173 --- /dev/null +++ b/web/dms-upload/.npmrc @@ -0,0 +1 @@ +install-links=true diff --git a/web/pdf-viewer/.npmrc b/web/pdf-viewer/.npmrc new file mode 100644 index 00000000..c7d35173 --- /dev/null +++ b/web/pdf-viewer/.npmrc @@ -0,0 +1 @@ +install-links=true