From b7508fe40123b3471590f248dea710203be7405f Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Sun, 20 Sep 2026 17:33:07 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20#209:=20analyse-nextcloud.sh=20pr=C3=BCft?= =?UTF-8?q?,=20ob=20das=20Importskript=20vorhanden=20und=20ladbar=20ist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- Changes.md | 5 +++ docs/konfiguration.md | 2 +- scripts/analyse-nextcloud.sh | 49 ++++++++++++++++++++++++- tests/75_AnalyseNextcloudSkriptTest.php | 14 ++++++- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Changes.md b/Changes.md index c1bd8ca..e067190 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,11 @@ --- +## 2026-09-20 – Analyse prüft das Importskript (#209) + +- **`scripts/analyse-nextcloud.sh`:** neuer Abschnitt 6 prüft, ob `scripts/container/nextcloud-import.php` im Container existiert und syntaktisch ladbar ist (`php -l`, ohne Ausführung), und nennt den Pfad, den der Host-Cronjob verwenden muss. Fehlt das Skript, endet die Analyse mit Exit 1 – auch bei erfolgreicher Verbindung. Ein `--dry-run`-Schalter für den Import wurde nicht ergänzt. +- **`tests/75_AnalyseNextcloudSkriptTest.php`:** prüft die Existenzabfrage und dass das Importskript nie ausgeführt wird. + ## 2026-09-20 – Überwachung des Nextcloud-Imports (#208) - **`migrations/096_nextcloud_watchdog.sql`** (neu): `company_settings.nextcloud_last_run` (Zeitstempel des letzten Laufs) und `nextcloud_alarm_stunden` (Schwelle, Default 24, 0 = aus). diff --git a/docs/konfiguration.md b/docs/konfiguration.md index 9710ce4..e0b50d0 100644 --- a/docs/konfiguration.md +++ b/docs/konfiguration.md @@ -96,7 +96,7 @@ sudo usermod -aG docker $USER ### Verbindung analysieren -Meldet der Import „PROPFIND fehlgeschlagen" oder findet er keine Dateien, grenzt `scripts/analyse-nextcloud.sh` die Ursache ein. Das Skript wird auf dem Host aufgerufen (nicht im Container) und arbeitet rein lesend – es importiert, verschiebt und löscht nichts. Das Passwort wird nie im Klartext ausgegeben. +Meldet der Import „PROPFIND fehlgeschlagen" oder findet er keine Dateien, grenzt `scripts/analyse-nextcloud.sh` die Ursache ein. Das Skript wird auf dem Host aufgerufen (nicht im Container) und arbeitet rein lesend – es importiert, verschiebt und löscht nichts. Das Passwort wird nie im Klartext ausgegeben. Zum Schluss prüft die Analyse, ob `scripts/container/nextcloud-import.php` im Container vorhanden und ladbar ist (ohne es auszuführen), und nennt den Pfad, den der Host-Cronjob verwenden muss. ```bash ./scripts/analyse-nextcloud.sh # Konfiguration, DNS, Verbindungsversuch diff --git a/scripts/analyse-nextcloud.sh b/scripts/analyse-nextcloud.sh index 49acc5d..6a1b154 100755 --- a/scripts/analyse-nextcloud.sh +++ b/scripts/analyse-nextcloud.sh @@ -7,13 +7,16 @@ # Schlägt der fehl, grenzt das Script die Ursache über Gegenproben ein: # ohne IP-Pinning, nur IPv4, nur IPv6. # +# Zuletzt wird geprüft, ob das Importskript im Container existiert und ladbar +# ist (der Cronjob muss denselben Pfad verwenden). +# # Rein lesend – es werden keine Belege importiert, verschoben oder gelöscht. # Das Passwort wird nie im Klartext ausgegeben. # # Usage: # ./analyse-nextcloud.sh [--verbose] # -# Exit-Code: 0 = Verbindung steht, 1 = Konfigurations- oder Verbindungsfehler +# Exit-Code: 0 = Verbindung steht und Importskript vorhanden, 1 = Konfigurations- oder Verbindungsfehler # ════════════════════════════════════════════════════════════════════════════ set -euo pipefail @@ -145,6 +148,42 @@ function isOk(array $r): bool return $r['errno'] === 0 && $r['code'] >= 200 && $r['code'] < 300; } +/** + * Prüft, ob der Importlauf selbst startbar ist. Die Analyse läuft über die + * Standardeingabe und braucht das Importskript nicht – ein verschobenes oder + * fehlendes Skript bliebe sonst unbemerkt, obwohl der Cronjob ins Leere läuft. + * Das Skript wird nur auf Syntax geprüft (php -l), nicht ausgeführt. + */ +$checkImportScript = static function () use ($section, $green, $red, $bold): bool { + $section('6. Importskript (Cronjob-Ziel)'); + + $rel = 'scripts/container/nextcloud-import.php'; + $path = '/var/www/html/' . $rel; + + if (!is_file($path)) { + echo ' ' . $red('✗') . ' ' . $rel . ' fehlt im Container.' . PHP_EOL; + echo ' Der Cronjob findet das Skript nicht und der Import läuft nie.' . PHP_EOL; + echo ' Auch prüfen, ob der Bind-Mount ./scripts:/var/www/html/scripts den Image-Inhalt verdeckt.' . PHP_EOL; + return false; + } + + echo ' ' . $green('✓') . ' ' . $rel . ' vorhanden' . PHP_EOL; + + $output = []; + exec(escapeshellarg(PHP_BINARY) . ' -l ' . escapeshellarg($path) . ' 2>&1', $output, $code); + if ($code !== 0) { + echo ' ' . $red('✗') . ' Das Skript ist nicht ladbar: ' . implode(' ', $output) . PHP_EOL; + return false; + } + echo ' ' . $green('✓') . ' Syntax gültig' . PHP_EOL; + + echo PHP_EOL . ' ' . $bold('Hinweis:') . ' Der Host-Cronjob muss genau diesen Pfad verwenden:' . PHP_EOL; + echo ' docker compose exec -T web php ' . $rel . PHP_EOL; + echo ' Mit `crontab -l` auf dem Host abgleichen.' . PHP_EOL; + + return true; +}; + // ── 1. Konfiguration ──────────────────────────────────────────────────────── $section('1. Konfiguration (Einstellungen → Nextcloud-Belegimport)'); @@ -272,6 +311,7 @@ if (!isOk($result)) { echo ' Netzwerkverbindung, Firewall und TLS-Zertifikat der Nextcloud prüfen.' . PHP_EOL; } + $checkImportScript(); exit(1); } @@ -328,6 +368,13 @@ if ($done !== null) { } } +$importOk = $checkImportScript(); + +if (!$importOk) { + echo PHP_EOL . ' ' . $red('Die Verbindung steht, aber der Importlauf ist nicht startbar.') . PHP_EOL . PHP_EOL; + exit(1); +} + echo PHP_EOL . ' ' . $green('Die Verbindung zur Nextcloud funktioniert.') . PHP_EOL . PHP_EOL; exit(0); PHPEOF diff --git a/tests/75_AnalyseNextcloudSkriptTest.php b/tests/75_AnalyseNextcloudSkriptTest.php index 6a96331..2a11b63 100644 --- a/tests/75_AnalyseNextcloudSkriptTest.php +++ b/tests/75_AnalyseNextcloudSkriptTest.php @@ -37,9 +37,21 @@ class AnalyseNextcloudSkriptTest extends TestCase // Verweise auf NextcloudImportService im Kommentar sind erwünscht (die cURL-Optionen // müssen dort synchron gehalten werden) – ausgeführt werden darf der Import nicht. $this->assert( - !str_contains($content, 'nextcloud-import.php') && !str_contains($content, 'new NextcloudImportService'), + !str_contains($content, 'new NextcloudImportService'), 'Skript startet keinen Importlauf' ); + // Das Importskript wird nie ausgeführt – nur per Syntaxprüfung (php -l) angefasst. + $this->assert( + !preg_match('/\b(passthru|shell_exec|system|proc_open|include|require)\b[^;\n]*nextcloud-import/', $content) + && str_contains($content, "' -l '"), + 'Skript führt das Importskript nicht aus, sondern prüft nur die Syntax' + ); + + // Die Analyse muss die Existenz des Importskripts im Container prüfen. + $this->assert( + str_contains($content, 'scripts/container/nextcloud-import.php') && str_contains($content, 'is_file($path)'), + 'Skript prüft, ob scripts/container/nextcloud-import.php im Container existiert' + ); // Das Passwort dient ausschließlich als cURL-Zugangsdatum. In Ausgaben darf // es nur als Länge (strlen) auftauchen, nie im Klartext.