Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
use OpenNIT\Controllers\Admin\SettingsController;
use OpenNIT\Core\Application;
/**
* Regressionstest für den Modul-Reset-Bug: Das Speichern einer beliebigen
* Settings-Seite (z. B. /admin/contracts/settings) lud die Konfiguration über
* loadConfig(), dessen Defaults ALLE Module auf false setzten. Bei Instanzen
* ohne modules-Block in der runtime.php wurde dieser All-false-Zustand beim
* Speichern persistiert und legte die gesamte Instanz lahm.
*
* Erwartung seit dem Fix: loadConfig() nimmt als Modul-Default den EFFEKTIVEN
* Zustand aus der laufenden App-Konfiguration – Laden + Speichern ohne
* Modul-Änderung ist damit für die Module ein No-Op.
*/
return static function (): void {
// Hinweis: Der Test läuft ohne config/runtime.php (im Repo nicht vorhanden),
// exakt das Szenario der betroffenen Bestandsinstanzen.
$runtimeFile = dirname(__DIR__) . '/config/runtime.php';
if (file_exists($runtimeFile)) {
echo " (übersprungen: config/runtime.php vorhanden – Szenario nicht reproduzierbar)\n";
return;
}
// App mit effektiver Konfiguration simulieren (wie von public/index.php gebaut).
$effectiveModules = [
'contracts' => true,
'vault' => true,
'tickets' => true,
'cve' => true, // fehlte in der alten hartkodierten Default-Liste komplett
'ai_chat' => false,
];
$appRef = new ReflectionClass(Application::class);
$app = $appRef->newInstanceWithoutConstructor();
setPrivate($app, 'config', ['modules' => $effectiveModules]);
$ctrlRef = new ReflectionClass(SettingsController::class);
/** @var SettingsController $ctrl */
$ctrl = $ctrlRef->newInstanceWithoutConstructor();
// $app liegt auf BaseController (parent) – Reflection dorthin.
$appProp = new ReflectionProperty(\OpenNIT\Controllers\BaseController::class, 'app');
$appProp->setAccessible(true);
$appProp->setValue($ctrl, $app);
$config = callPrivate($ctrl, 'loadConfig');
test('loadConfig übernimmt den effektiven Modul-Zustand (kein All-false-Default)', function () use ($config, $effectiveModules) {
assertSame($effectiveModules, $config['modules'],
'modules muss dem effektiven Zustand entsprechen – sonst schaltet jedes Settings-Speichern Module ab');
});
test('loadConfig: aktives Modul bleibt aktiv (contracts)', function () use ($config) {
assertTrue((bool)$config['modules']['contracts']);
});
test('loadConfig: Module außerhalb der alten Default-Liste gehen nicht verloren (cve)', function () use ($config) {
assertTrue(array_key_exists('cve', $config['modules']));
assertTrue((bool)$config['modules']['cve']);
});
};