- Move URI config calls before maybeGetRawHTMLDefinition() which
finalizes the config and prevents further set() calls
- Use Mockery::mock()->shouldIgnoreMissing() for CdnPurgeService stub
to satisfy type hint in ContentItemObserver
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HTMLPurifier: set HTML.DefinitionID and HTML.DefinitionRev which
are required when using maybeGetRawHTMLDefinition().
CdnManager: bind a stub in tests when Plug\Cdn\CdnManager class
is not available (external dependency not in test environment).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create Database/Factories for ContentWebhookEndpoint, ContentWebhookLog,
ContentItem, ContentTaxonomy, ContentBrief
- Register HTML5 elements (section, article, figure, figcaption, mark)
with HTMLPurifier custom definitions
- Use RefreshDatabase trait in TestCase with SQLite in-memory DB
- Update Pest.php to use custom Tests\TestCase
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous getSanitisedContent() method fell back to strip_tags() when
HTMLPurifier was unavailable. This fallback was insecure as strip_tags()
does not sanitise attributes, allowing XSS via onclick, onerror, and
javascript: URLs.
Changes:
- Created Services/HtmlSanitiser.php using HTMLPurifier as the sole sanitiser
- Added ezyang/htmlpurifier as a required dependency in composer.json
- Added boot-time validation that throws RuntimeException if missing
- Removed insecure strip_tags() fallback from ContentItem model
- Added 30+ unit tests covering XSS attack vectors
Closes SEC-002 from TODO.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>