SITE_ORIGIN alone decides whether the site is www or not: CanonicalHostSubscriber sends the other spelling there with 301, cms:site:origin writes the setting, the system screen shows it. The roles now match the role help (editor: drafts, publisher: live content, admin: design, settings, users, system). The installer no longer reopens on an unreachable database, the session cookie follows ADMIN_PATH, percent-encoded credentials no longer break the container, consent only accepts same-site decisions, JSON-LD is HTML-safe, own CSS stays in its block, plus the editor, updater, download and public-output findings from the full review (ADR 099, ADR 100). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
75 lines
3.1 KiB
PHP
75 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Tests;
|
|
|
|
use App\Command\SiteOriginCommand;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
|
use Symfony\Component\Dotenv\Dotenv;
|
|
|
|
final class SiteOriginCommandTest extends TestCase
|
|
{
|
|
private string $root;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->root = sys_get_temp_dir().'/kant-origin-'.bin2hex(random_bytes(6));
|
|
mkdir($this->root);
|
|
file_put_contents($this->root.'/.env', "APP_ENV=\"prod\"\nSITE_ORIGIN=\"https://alt.example\"\nAPP_SECRET=\"bleibt\"\n");
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
foreach (glob($this->root.'/.env*') ?: [] as $file) {
|
|
unlink($file);
|
|
}
|
|
rmdir($this->root);
|
|
}
|
|
|
|
/** @return iterable<string, array{string, ?string}> */
|
|
public static function addresses(): iterable
|
|
{
|
|
yield 'mit www' => ['https://www.meine-firma.de', 'https://www.meine-firma.de'];
|
|
yield 'ohne www' => ['https://meine-firma.de', 'https://meine-firma.de'];
|
|
yield 'Schraegstrich und Grossschreibung werden bereinigt' => [' HTTPS://WWW.Meine-Firma.DE/ ', 'https://www.meine-firma.de'];
|
|
yield 'ein Port bleibt' => ['http://127.0.0.1:8080', 'http://127.0.0.1:8080'];
|
|
yield 'ohne Schema' => ['meine-firma.de', null];
|
|
yield 'mit Pfad' => ['https://meine-firma.de/start', null];
|
|
yield 'mit Abfrage' => ['https://meine-firma.de/?x=1', null];
|
|
yield 'mit Zugangsdaten' => ['https://user:pass@meine-firma.de', null];
|
|
yield 'falsches Schema' => ['ftp://meine-firma.de', null];
|
|
}
|
|
|
|
#[DataProvider('addresses')]
|
|
public function testOnlySchemeAndHostAreAccepted(string $input, ?string $expected): void
|
|
{
|
|
if (null === $expected) {
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
}
|
|
self::assertSame($expected, SiteOriginCommand::normalize($input));
|
|
}
|
|
|
|
public function testTheCommandShowsAndWritesTheAddress(): void
|
|
{
|
|
$tester = new CommandTester(new SiteOriginCommand($this->root, 'https://alt.example'));
|
|
self::assertSame(0, $tester->execute([]));
|
|
self::assertStringContainsString('https://alt.example', $tester->getDisplay());
|
|
self::assertSame('https://alt.example', $this->values()['SITE_ORIGIN'], 'Anzeigen schreibt nichts.');
|
|
|
|
self::assertSame(0, $tester->execute(['adresse' => 'https://www.neu.example/']));
|
|
self::assertStringContainsString('ohne www leitet dorthin um', $tester->getDisplay());
|
|
self::assertSame('https://www.neu.example', $this->values()['SITE_ORIGIN']);
|
|
self::assertSame('bleibt', $this->values()['APP_SECRET'], 'Die uebrigen Einstellungen bleiben erhalten.');
|
|
|
|
self::assertSame(1, $tester->execute(['adresse' => 'neu.example']));
|
|
self::assertStringContainsString('beginnt mit https://', $tester->getDisplay());
|
|
self::assertSame('https://www.neu.example', $this->values()['SITE_ORIGIN'], 'Eine abgelehnte Adresse aendert nichts.');
|
|
}
|
|
|
|
private function values(): array
|
|
{
|
|
return (new Dotenv())->parse((string) file_get_contents($this->root.'/.env'));
|
|
}
|
|
}
|