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>
Add phpunit.xml and tests/Pest.php for standalone test execution.
Apply Laravel Pint formatting fixes across all source files.
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>
- Core\Mod\Tenant -> Core\Tenant
- Mod\Agentic -> Core\Mod\Agentic
Part of namespace restructure to align with L1/L2 module conventions.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Aligns content module namespace with the standard module structure
convention (Core\Mod\{Name}) for consistency across the monorepo.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>