Schriften ins Repository, Anleitung fuer neue Websites, Schutzkopfzeilen
CMS quality / php (8.2) (push) Canceled after 0s
CMS quality / php (8.4) (push) Canceled after 0s
CMS quality / browser (push) Canceled after 0s
CMS quality / mysql (push) Canceled after 0s

Die Lato-Dateien liegen jetzt unter public/assets/fonts/ samt OFL-Text
und einer Lizenznotiz: auf einem frischen Server fehlt nichts, und es
wird nie versehentlich von Google geladen.

docs/NEUE-WEBSITE.md beschreibt, wie eine neue Kundenwebsite entsteht -
Reihenfolge, Dokumentformat, Bilder, SEO, Pruefungen - und nennt am
Ende die fuenf Fehler, die hier immer wieder passiert sind.

Permissions-Policy ergaenzt (Kamera, Mikrofon, Standort, Sensoren aus),
X-Powered-By entfernt: der Server nannte in jeder Antwort seine genaue
PHP-Fassung. Die Browserpruefung misst die Kopfzeilen jetzt.

Behoben: der Editor kannte Schema v17, der Validator v18 - die
Beitragsnavigation liess sich in keinem aktuellen Dokument einfuegen.
Ein Test bindet die Zahl des Editors an die des Validators.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5 committed 2026-09-13 15:28:31 +02:00
1 parent 7c6b2a9ec8
commit a2dfd0f796
20 files changed
+401 -3

No files matched your search

+23
View File
@@ -879,6 +879,29 @@ final class CmsTest extends TestCase
self::assertStringContainsString('Nächstes Projekt', $rand);
}
public function testEveryPublicAnswerCarriesItsProtectiveHeaders(): void
{
// Diese Kopfzeilen fehlen lautlos, wenn jemand eine Antwort an der Stelle vorbeibaut, die
// sie setzt. Ein Test ist billiger als die Entdeckung im Betrieb.
$this->pages->publish('page-1', $this->pages->saveDraft('page-1', DemoContent::starter('Startseite'), 0), 1);
foreach (['/', '/gibt-es-nicht'] as $adresse) {
$antwort = $this->request($adresse);
$csp = (string) $antwort->headers->get('Content-Security-Policy');
self::assertStringContainsString("default-src 'self'", $csp, $adresse);
self::assertStringContainsString("object-src 'none'", $csp, $adresse);
// Ein eingeschleustes <base> würde jeden Verweis der Seite umlenken.
self::assertStringContainsString("base-uri 'none'", $csp, $adresse);
self::assertStringContainsString("frame-ancestors 'none'", $csp, $adresse);
self::assertSame('nosniff', $antwort->headers->get('X-Content-Type-Options'), $adresse);
self::assertStringContainsString('camera=()', (string) $antwort->headers->get('Permissions-Policy'), $adresse);
}
// Und der Vordereingang verrät nicht, welche PHP-Fassung hier läuft.
$index = (string) file_get_contents(__DIR__.'/../public/index.php');
self::assertStringContainsString("header_remove('X-Powered-By')", $index);
self::assertStringContainsString('Header always unset X-Powered-By', (string) file_get_contents(__DIR__.'/../public/.htaccess'));
}
public function testABackgroundPictureShrinksForSmallScreensEvenWhenSetOnce(): void
{
// Gemessen auf der nachgebauten Startseite: das Telefon lud das Hintergrundbild mit 1920
+7
View File
@@ -1,5 +1,6 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { EditorHistory, createBlock, locate, insertBlock, duplicateBlock, moveBlock, upgradeDocument, effectiveDesign, setDesign, insertPreset, insertRow, blockPath, insertMedia, setEffect, isPluginBlock, blockLabel, blockIcon, canContain, isContainer, setStyle, effectiveStyle, hoverStyle, resetStyleDevice, clearStyle, copyStyle, SCHEMA_VERSION } from '../public/assets/editor-model.js';
import { readFile } from 'node:fs/promises';
import { designCss } from '../scripts/build-design.mjs';
@@ -64,6 +65,12 @@ test('v1 to v2 migration preserves all content and IDs, is idempotent and reject
assert.deepEqual(migrated, { ...original, schemaVersion: 2 });
assert.deepEqual(upgradeDocument(structuredClone(migrated)), migrated);
assert.throws(() => upgradeDocument({ ...original, schemaVersion: 999 }));
// Der Editor muss dieselbe Fassung kennen wie der Validator - sonst laesst sich in einem
// aktuellen Dokument nichts mehr einfuegen, ohne dass irgendwo eine Fehlermeldung erscheint.
// Genau das ist hier schon zweimal passiert, zuletzt bei v18.
const validator = readFileSync(new URL('../src/Content/DocumentValidator.php', import.meta.url), 'utf8');
const hoechste = Math.max(...[...validator.matchAll(/schemaVersion >= (\d+)/g)].map(treffer => Number(treffer[1])));
assert.equal(SCHEMA_VERSION, hoechste, `Der Editor kennt v${SCHEMA_VERSION}, der Validator kennt v${hoechste}.`);
assert.equal(original.schemaVersion, 1);
});