P2-082: Webhook Signature Verification - Add require_signature field, verifySignatureWithDetails() - Support grace period during secret rotation - Log signature failures for audit P2-083: Webhook Delivery Logging - WebhookDeliveryLogger service for centralised logging - Track duration, response code, signature verification - Add getDeliveryStats() and getRecentSignatureFailures() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
18 KiB
18 KiB
TODO - core-content
Production quality improvements for the Content Module.
Legend:
- P1: Critical/Security - Must fix immediately
- P2: High priority - Fix soon
- P3: Medium priority - Important improvements
- P4: Low priority - Nice to have
- P5: Nice-to-have - When time permits
- P6+: Future/Backlog - Long-term improvements
P1 - Critical/Security
SEC-001: Add CSRF protection to webhook endpoints
- Status: Open
- Description: The webhook endpoint at
POST /api/content/webhooks/{endpoint}accepts external requests but only validates via HMAC signature. If signature verification is skipped (when no secret is configured), the endpoint is vulnerable. - File:
Controllers/Api/ContentWebhookController.php:205-210 - Fix: Require signature verification always OR add explicit opt-in flag to disable it, with warning logs.
- Acceptance: Webhooks without secrets must be explicitly enabled per-endpoint.
SEC-002: Sanitise HTML content before rendering
- Status: Fixed
- Description:
ContentItem::getSanitisedContent()falls back tostrip_tags()if HTMLPurifier is unavailable. This fallback is insufficient for XSS protection. - File:
Models/ContentItem.php:333-351 - Fix: Always require HTMLPurifier or a robust sanitiser. Add package dependency check in boot.
- Acceptance: Content rendering always goes through proper XSS sanitisation.
- Resolution: Created
Services/HtmlSanitiser.phpusing HTMLPurifier as a required dependency. Added HTMLPurifier to composer.json require. Added boot-time validation that throws RuntimeException if dependency missing. Removed insecure strip_tags() fallback. Added comprehensive XSS prevention tests intests/Unit/HtmlSanitiserTest.php.
SEC-003: Validate workspace access in MCP handlers
- Status: Open
- Description: MCP handlers check entitlements but workspace resolution via
orWhere('id', $slug)could expose content across workspaces if numeric IDs are guessed. - File:
Mcp/Handlers/ContentCreateHandler.php:212-220,ContentSearchHandler.php:129-137 - Fix: Add explicit workspace ownership/membership check before returning data.
- Acceptance: Users can only access content from workspaces they own or are members of.
SEC-004: Rate limit preview URL generation
- Status: Open
- Description: Preview token generation has no rate limiting. An attacker could enumerate valid content IDs by watching response times.
- File:
Controllers/ContentPreviewController.php:26-49 - Fix: Add rate limiting to preview generation endpoint.
- Acceptance: Preview generation limited to 30/minute per user.
SEC-005: Validate content_type enum in webhook payloads
- Status: Open
- Description: Webhook processing accepts arbitrary
content_typestrings from external sources without validation. - File:
Jobs/ProcessContentWebhook.php:288-289 - Fix: Validate against
ContentTypeenum before assigning to model. - Acceptance: Invalid content types rejected with clear error message.
P2 - High Priority
DX-001: Add missing type hints to scope methods
- Status: Open
- Description: Scope methods like
scopeForWorkspace,scopePublishedetc. use$querywithoutBuildertype hint. - Files:
Models/ContentItem.php:147-198,Models/ContentBrief.php:181-215 - Fix: Add
\Illuminate\Database\Eloquent\Buildertype hints. - Acceptance: All scope methods have proper return types.
DX-002: Document search service API response format
- Status: Open
- Description:
ContentSearchService::formatForApi()returns a specific structure but it's not documented. - File:
Services/ContentSearchService.php:467-493 - Fix: Add PHPDoc with return type schema or create a Resource class.
- Acceptance: API response format documented with example JSON.
TEST-001: Add integration tests for AI generation pipeline
- Status: Open
- Description:
AIGatewayServicehas no tests. The two-stage Gemini+Claude pipeline is critical but untested. - File:
Services/AIGatewayService.php - Fix: Add tests with mocked API responses for
generateDraft,refineDraft,generateAndRefine. - Acceptance: 80%+ coverage on AIGatewayService with edge case tests.
TEST-002: Add tests for webhook signature verification
- Status: Fixed
- Description:
ContentWebhookEndpoint::verifySignature()handles multiple formats but isn't fully tested. - File:
Models/ContentWebhookEndpoint.php:204-237 - Fix: Add unit tests for each signature format and grace period behaviour.
- Acceptance: Tests cover: sha256= prefix, grace period rotation, empty signature handling.
- Resolution: (2026-01-29) See P2-082 fix. Added comprehensive feature tests in
tests/Feature/WebhookSignatureVerificationTest.phpcovering all signature formats, grace period rotation, and various failure scenarios.
PERF-001: Add database index for content search
- Status: Open
- Description: LIKE-based search on
content_htmlhas no fulltext index, causing table scans. - File:
Services/ContentSearchService.php:142-162,Migrations/0001_01_01_000001_create_content_tables.php - Fix: Add MySQL fulltext index on title, excerpt, content_markdown columns OR document Meilisearch as required for production.
- Acceptance: Search queries under 100ms for 10k+ content items.
PERF-002: Optimise revision pruning for large datasets
- Status: Open
- Description:
ContentRevision::pruneAll()loads all content_item_ids into memory before iterating. - File:
Models/ContentRevision.php:595-609 - Fix: Use
chunk()or cursor to process in batches. - Acceptance: Pruning handles 100k+ content items without memory issues.
BUG-001: Fix content_briefs migration schema mismatch
- Status: Open
- Description: Migration defines
content_briefswith different columns than model fillable (e.g.,user_idvs model relationships). - File:
Migrations/0001_01_01_000001_create_content_tables.php:215-238,Models/ContentBrief.php:49-75 - Fix: Align migration with actual model usage or add a migration to fix schema.
- Acceptance: All ContentBrief columns are used and documented.
BUG-002: Fix ai_usage migration column naming
- Status: Open
- Description: Migration creates
featurecolumn but model usespurpose. Creates confusion. - File:
Migrations/0001_01_01_000001_create_content_tables.php:246,Models/AIUsage.php:46 - Fix: Add migration to rename column OR update model to use
feature. - Acceptance: Column name matches model fillable property.
P3 - Medium Priority
CODE-001: Extract webhook processing logic into service
- Status: Open
- Description:
ProcessContentWebhookjob contains 500+ lines of business logic that should be in a service. - File:
Jobs/ProcessContentWebhook.php - Fix: Create
ContentWebhookProcessingServicewith methods for each event type. - Acceptance: Job is under 100 lines, delegates to service.
CODE-002: Create ContentBriefResource for API responses
- Status: Open
- Description: Controllers manually format brief responses. A Resource class would ensure consistency.
- File:
Controllers/Api/ContentBriefController.phpreferencesContentBriefResourcewhich may not exist. - Fix: Create or verify
Resources/ContentBriefResource.phpexists with proper formatting. - Acceptance: All brief API responses use the Resource class.
CODE-003: Consolidate workspace resolution logic
- Status: Open
- Description: Three different
resolveWorkspace()methods exist with similar but not identical logic. - Files:
Controllers/Api/ContentSearchController.php,Mcp/Handlers/*,Services/ContentRender.php - Fix: Create trait or shared helper in core-tenant.
- Acceptance: Single source of truth for workspace resolution.
TEST-003: Add tests for revision diff algorithm
- Status: Open
- Description:
ContentRevision::getDiff()and LCS algorithm are complex but only lightly tested. - File:
Models/ContentRevision.php:233-509 - Fix: Add unit tests for edge cases: empty content, identical content, very long content.
- Acceptance: Diff algorithm has 90%+ coverage with edge cases documented.
TEST-004: Add webhook retry service tests
- Status: Open
- Description:
WebhookRetryServicehas retry logic with exponential backoff but no tests. - File:
Services/WebhookRetryService.php - Fix: Add tests for retry scheduling, backoff intervals, exhaustion handling.
- Acceptance: Full coverage of retry state transitions.
FEAT-001: Add content scheduling command
- Status: Open
- Description:
PublishScheduledContentcommand is registered but implementation needs verification. - File:
Console/Commands/PublishScheduledContent.php - Fix: Verify command works, add scheduler entry documentation.
- Acceptance: Scheduled content publishes automatically at the correct time.
FEAT-002: Add media upload validation
- Status: Open
- Description:
ContentMediaControllerstore method should validate file types, sizes, dimensions. - File:
Controllers/Api/ContentMediaController.php - Fix: Add comprehensive validation rules for media uploads.
- Acceptance: Reject files over size limit, invalid types, malformed images.
FEAT-003: Add bulk operations for content items
- Status: Open
- Description: No bulk delete, bulk status change, or bulk category assignment endpoints.
- Files: API routes, new controller methods needed
- Fix: Add bulk endpoints with proper authorisation and rate limiting.
- Acceptance: Can bulk-update up to 50 items per request.
P4 - Low Priority
DX-003: Add IDE helper annotations to models
- Status: Open
- Description: Models lack
@propertyannotations for dynamic attributes likestatus_color. - Files: All models in
Models/ - Fix: Add comprehensive
@propertyPHPDoc blocks for all magic attributes. - Acceptance: IDE autocomplete works for all model properties.
DX-004: Document configuration options
- Status: Open
- Description:
config.phphas comments but no comprehensive documentation of all options and their effects. - File:
config.php - Fix: Add CLAUDE.md section or dedicated config docs explaining each option.
- Acceptance: Every config option documented with type, default, and example.
CODE-004: Remove deprecated WordPress-specific code paths
- Status: Open
- Description: Multiple methods have WordPress-specific handling that may be unused.
- Files:
Models/ContentItem.php(wp_id, wp_guid), various scopes - Fix: Audit usage, add deprecation notices if still needed, or remove.
- Acceptance: Clear documentation of what is deprecated vs maintained.
CODE-005: Standardise error response format
- Status: Open
- Description: Error responses vary:
['error' => ...],['message' => ...], different status codes. - Files: All controllers in
Controllers/Api/ - Fix: Use consistent error format:
{error: string, code: string, message: string}. - Acceptance: All error responses follow documented schema.
PERF-003: Add eager loading hints to API responses
- Status: Open
- Description: Some API responses trigger N+1 queries for related data.
- Files:
Controllers/Api/ContentBriefController.php:31-77 - Fix: Add
->with(['workspace', 'contentItem'])where appropriate. - Acceptance: No N+1 queries in API responses (verified with debugbar).
TEST-005: Add factory states for all content statuses
- Status: Open
- Description: Factory states exist but may not cover all status/type combinations.
- Files:
Database/Factories/*.php(if they exist, or in test setup) - Fix: Ensure factories have states for: draft, publish, future, private, pending, trash.
- Acceptance: Tests can easily create content in any status.
P5 - Nice to Have
FEAT-004: Add content versioning comparison UI support
- Status: Open
- Description:
ContentRevision::getDiff()returns data but no documented UI integration. - File:
Models/ContentRevision.php - Fix: Document how to integrate diff data with frontend diff viewer.
- Acceptance: Example Livewire component or documentation for diff display.
FEAT-005: Add webhook event deduplication
- Status: Open
- Description: Same webhook could be received multiple times (network retry). No dedup.
- File:
Jobs/ProcessContentWebhook.php - Fix: Add deduplication based on payload hash + timestamp window.
- Acceptance: Duplicate webhooks within 5 minutes are skipped.
FEAT-006: Add content analytics tracking
- Status: Open
- Description: No tracking of content views, engagement, or performance metrics.
- Files: New feature needed
- Fix: Integrate with core-analytics or add simple view tracking.
- Acceptance: Can see view counts and basic metrics per content item.
CODE-006: Add event dispatching for content lifecycle
- Status: Open
- Description: Content creation/update/publish doesn't dispatch domain events for other modules.
- Files:
Models/ContentItem.php,Observers/ContentItemObserver.php - Fix: Dispatch events like
ContentPublished,ContentUpdatedetc. - Acceptance: Other modules can listen for content events.
DOCS-001: Add API documentation
- Status: Open
- Description: API endpoints lack OpenAPI/Swagger documentation.
- Files:
routes/api.php - Fix: Add Scribe or OpenAPI annotations for all endpoints.
- Acceptance: OpenAPI spec can be generated and used in API clients.
P6 - Future/Backlog
FEAT-007: Add content workflow/approval system
- Status: Backlog
- Description: No formal review/approval workflow for content before publishing.
- Fix: Add ContentWorkflow model with states and transitions.
FEAT-008: Add content localisation/translation support
- Status: Backlog
- Description: No i18n support for multilingual content.
- Fix: Add locale field and translation linking to ContentItem.
FEAT-009: Add content A/B testing
- Status: Backlog
- Description: No ability to test content variations.
- Fix: Add ContentVariant model for headline/content testing.
PERF-004: Add content caching layer
- Status: Backlog
- Description: CDN purge exists but no server-side caching strategy documented.
- Fix: Document caching strategy, add Redis caching for hot content.
CODE-007: Extract prompts to database-driven system
- Status: Backlog
- Description: AI prompts are hardcoded in
AIGatewayService. Prompts table exists but unused for this. - File:
Services/AIGatewayService.php:226-525 - Fix: Load prompts from database, allow admin editing.
Completed
P2-082: Webhook Signature Verification (2026-01-29)
- Description: Signature verification was present but not comprehensively tested or centrally logged.
- Resolution:
- Created
Services/WebhookDeliveryLogger.phpservice for centralised signature verification logging - Updated
Controllers/Api/ContentWebhookController.phpto use the new service - Added comprehensive feature tests in
tests/Feature/WebhookSignatureVerificationTest.php:- Tests for all signature header formats (X-Signature, X-Hub-Signature-256, X-WP-Webhook-Signature)
- Tests for grace period during secret rotation
- Tests for require_signature configuration
- Tests for signature failure audit logging
- Tests for timing-safe comparison verification
- Failed signature attempts are logged without storing potentially malicious payloads
- Security audit trail for all signature verification outcomes
- Created
P2-083: Webhook Delivery Logging (2026-01-29)
- Description: Webhook delivery lacked comprehensive logging for debugging and audit purposes.
- Resolution:
- Created
Services/WebhookDeliveryLogger.phpservice with:logSuccess()- logs successful deliveries with duration metricslogFailure()- logs failed deliveries with error detailslogSignatureFailure()- creates audit entries for signature failureslogSignatureNotRequired()- warns when verification is bypassedcreateDeliveryLog()- creates delivery log entries with full request detailsgetDeliveryStats()- retrieves delivery statistics for dashboardsgetRecentSignatureFailures()- retrieves recent failures for security monitoring
- Added comprehensive unit tests in
tests/Unit/WebhookDeliveryLoggerTest.php - Migration
2026_01_29_000001_add_signature_verification_fields.phpadds:signature_verified- boolean tracking verification successsignature_failure_reason- stores failure reason for auditprocessing_duration_ms- tracks processing timerequest_headers- stores safe headers for debuggingresponse_codeandresponse_body- tracks response details
- Created
SEC-002: HTML sanitisation fallback vulnerability (2026-01-29)
- Created
Services/HtmlSanitiser.phpusing HTMLPurifier - Added
ezyang/htmlpurifieras required dependency in composer.json - Updated
ContentItem::getSanitisedContent()to use the new service - Added boot-time validation to throw exception if HTMLPurifier is missing
- Removed insecure
strip_tags()fallback that allowed XSS via event handlers - Added 30+ unit tests covering XSS attack vectors and safe HTML preservation
Notes
Dependencies
- Requires
core-phpfor events and base infrastructure - Requires
core-tenantfor workspace and user models - Requires
ezyang/htmlpurifierfor XSS sanitisation (security-critical) - Optional:
core-agenticfor AI services (GeminiService, ClaudeService) - Optional:
core-mcpfor MCP tool registration
Testing
Run tests with: composer test from package root.
Run single test: ./vendor/bin/pest --filter=ContentSearchServiceTest
Last Audit
- Date: 2026-01-29
- By: Claude Code (core-content audit)
- Files Reviewed: ~70 PHP files