- Add encrypted cast to UserTwoFactorAuth secret and recovery_codes - Hash invitation tokens on creation using Hash::make() - Update token verification to use Hash::check() - Add migration commands for existing data: - security:encrypt-2fa-secrets - security:hash-invitation-tokens - Add tests for encryption and hashing Fixes SEC-003, SEC-004 from security audit. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
542 lines
15 KiB
Markdown
542 lines
15 KiB
Markdown
# core-tenant TODO
|
|
|
|
Comprehensive task list for improving the multi-tenancy package. Items are prioritised by impact and urgency.
|
|
|
|
## Legend
|
|
|
|
- **P1** - Critical/Security (must fix immediately)
|
|
- **P2** - High (affects production quality)
|
|
- **P3** - Medium (should address soon)
|
|
- **P4** - Low (quality of life improvements)
|
|
- **P5** - Nice-to-have (future enhancements)
|
|
- **P6** - Backlog (ideas for later consideration)
|
|
|
|
---
|
|
|
|
## P1 - Critical / Security
|
|
|
|
### SEC-001: Add rate limiting to EntitlementApiController
|
|
**Status:** Open
|
|
**File:** `Controllers/EntitlementApiController.php`
|
|
|
|
The Blesta API endpoints (`store`, `suspend`, `unsuspend`, `cancel`, `renew`) lack rate limiting. A compromised API key could be used to mass-provision or cancel packages.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add rate limiting middleware to all Blesta API routes
|
|
- Configure sensible limits (e.g., 60 requests/minute per IP)
|
|
- Log rate limit violations for security monitoring
|
|
|
|
---
|
|
|
|
### SEC-002: Validate API authentication on EntitlementApiController routes
|
|
**Status:** Open
|
|
**File:** `Routes/api.php`, `Controllers/EntitlementApiController.php`
|
|
|
|
The Blesta API controller routes are not visible in `api.php` - they may be registered elsewhere or missing authentication. Verify all Blesta API endpoints require proper API key authentication.
|
|
|
|
**Acceptance Criteria:**
|
|
- Confirm all entitlement API routes require authentication
|
|
- Add API key validation middleware if missing
|
|
- Document required scopes for each endpoint
|
|
|
|
---
|
|
|
|
### SEC-003: Encrypt 2FA secrets at rest
|
|
**Status:** Open
|
|
**File:** `Concerns/TwoFactorAuthenticatable.php`, `Migrations/0001_01_01_000000_create_tenant_tables.php`
|
|
|
|
The `user_two_factor_auth.secret` column stores TOTP secrets. While marked as `text`, these should be encrypted at rest using Laravel's `encrypted:string` cast.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add `'secret_key' => 'encrypted'` cast to UserTwoFactorAuth model
|
|
- Create migration to encrypt existing secrets
|
|
- Verify decryption works correctly in TotpService
|
|
|
|
---
|
|
|
|
### SEC-004: Audit workspace invitation token security
|
|
**Status:** Open
|
|
**File:** `Models/WorkspaceInvitation.php`
|
|
|
|
Invitation tokens are 64-character random strings, which is good. However:
|
|
- Tokens should be hashed when stored (store hash, compare with hash_equals)
|
|
- Add brute-force protection for invitation acceptance endpoint
|
|
- Consider shorter expiry for high-privilege roles (owner/admin)
|
|
|
|
**Acceptance Criteria:**
|
|
- Store hashed tokens instead of plaintext
|
|
- Add rate limiting to invitation acceptance
|
|
- Add configurable expiry per role type
|
|
|
|
---
|
|
|
|
### SEC-005: Add CSRF protection to webhook test endpoint
|
|
**Status:** Open
|
|
**File:** `Controllers/Api/EntitlementWebhookController.php`
|
|
|
|
The `test` endpoint triggers an outbound HTTP request. Ensure it cannot be abused as a server-side request forgery (SSRF) vector.
|
|
|
|
**Acceptance Criteria:**
|
|
- Validate webhook URL against allowlist or blocklist
|
|
- Prevent requests to internal IP ranges (127.0.0.0/8, 10.0.0.0/8, etc.)
|
|
- Add timeout and response size limits
|
|
|
|
---
|
|
|
|
### SEC-006: Validate workspace_id in RequireWorkspaceContext middleware
|
|
**Status:** Open
|
|
**File:** `Middleware/RequireWorkspaceContext.php`
|
|
|
|
The middleware accepts workspace_id from multiple sources (header, query, input) without validating the authenticated user's access in all code paths.
|
|
|
|
**Acceptance Criteria:**
|
|
- Always validate user has access to the resolved workspace
|
|
- Make `validate` parameter the default behaviour
|
|
- Log workspace access attempts for security monitoring
|
|
|
|
---
|
|
|
|
## P2 - High Priority
|
|
|
|
### DX-001: Add strict_types declaration to all PHP files
|
|
**Status:** Open
|
|
**Files:** Multiple files missing declaration
|
|
|
|
Several files are missing `declare(strict_types=1);`:
|
|
- `Models/Workspace.php`
|
|
- `Models/User.php`
|
|
- `Services/EntitlementService.php`
|
|
|
|
**Acceptance Criteria:**
|
|
- Add strict_types to all PHP files
|
|
- Run tests to verify no type coercion issues
|
|
|
|
---
|
|
|
|
### DX-002: Document EntitlementService public API
|
|
**Status:** Open
|
|
**File:** `Services/EntitlementService.php`
|
|
|
|
The EntitlementService is the core API for entitlement checks but lacks comprehensive PHPDoc. External consumers need clear documentation.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add complete PHPDoc to all public methods
|
|
- Document exception conditions
|
|
- Add @throws annotations where applicable
|
|
- Create usage examples in documentation
|
|
|
|
---
|
|
|
|
### TEST-001: Add tests for namespace-level entitlements
|
|
**Status:** Open
|
|
**File:** `tests/Feature/EntitlementServiceTest.php`
|
|
|
|
The test file covers workspace-level entitlements but not namespace-level (`canForNamespace`, `recordNamespaceUsage`, etc.).
|
|
|
|
**Acceptance Criteria:**
|
|
- Test `canForNamespace()` with various ownership scenarios
|
|
- Test entitlement cascade (namespace -> workspace -> user tier)
|
|
- Test `provisionNamespacePackage()` and `provisionNamespaceBoost()`
|
|
- Test namespace cache invalidation
|
|
|
|
---
|
|
|
|
### TEST-002: Add integration tests for EntitlementApiController
|
|
**Status:** Open
|
|
**File:** `tests/Feature/EntitlementApiTest.php`
|
|
|
|
Need HTTP-level integration tests for the API endpoints, including authentication, validation, and error cases.
|
|
|
|
**Acceptance Criteria:**
|
|
- Test all CRUD operations via HTTP
|
|
- Test validation error responses
|
|
- Test authentication failures
|
|
- Test rate limiting (once implemented)
|
|
|
|
---
|
|
|
|
### PERF-001: Optimise EntitlementService cache invalidation
|
|
**Status:** Open
|
|
**File:** `Services/EntitlementService.php`
|
|
|
|
The `invalidateCache()` method iterates all features and clears each key individually. This is O(n) where n = feature count.
|
|
|
|
**Acceptance Criteria:**
|
|
- Use cache tags when available (Redis)
|
|
- Implement version-based cache busting
|
|
- Benchmark before/after with 100+ features
|
|
|
|
---
|
|
|
|
### PERF-002: Add database indexes for common queries
|
|
**Status:** Open
|
|
**File:** `Migrations/0001_01_01_000000_create_tenant_tables.php`
|
|
|
|
Missing indexes identified:
|
|
- `users.tier` (for tier-based queries)
|
|
- `namespaces.slug` (currently only unique in combination)
|
|
- `entitlement_usage_records.user_id`
|
|
|
|
**Acceptance Criteria:**
|
|
- Create migration adding missing indexes
|
|
- Verify query plan improvements with EXPLAIN
|
|
|
|
---
|
|
|
|
### CODE-001: Extract WorkspaceScope to separate file
|
|
**Status:** Open
|
|
**File:** `Scopes/WorkspaceScope.php`
|
|
|
|
The WorkspaceScope class exists but is referenced in BelongsToWorkspace trait without actually being applied as a global scope. Clarify the architecture.
|
|
|
|
**Acceptance Criteria:**
|
|
- Document when WorkspaceScope vs BelongsToWorkspace should be used
|
|
- Consider applying WorkspaceScope as a proper global scope
|
|
- Update CLAUDE.md with guidance
|
|
|
|
---
|
|
|
|
### CODE-002: Consolidate User model relationships
|
|
**Status:** Open
|
|
**File:** `Models/User.php`
|
|
|
|
The User model has many undefined relationships (Page, Project, Domain, Pixel, etc.) that reference classes not in this package. These should either be:
|
|
1. Moved to the consuming application
|
|
2. Made conditional on class existence
|
|
|
|
**Acceptance Criteria:**
|
|
- Audit all relationships for undefined classes
|
|
- Add `class_exists()` guards or move to app layer
|
|
- Document which relationships are package-native vs app-specific
|
|
|
|
---
|
|
|
|
### CODE-003: Remove hardcoded domain in EntitlementApiController
|
|
**Status:** Open
|
|
**File:** `Controllers/EntitlementApiController.php`, Line 80
|
|
|
|
The workspace creation uses hardcoded domain `'hub.host.uk.com'`. This should be configurable.
|
|
|
|
**Acceptance Criteria:**
|
|
- Move to config value
|
|
- Add sensible default
|
|
- Document in CLAUDE.md
|
|
|
|
---
|
|
|
|
## P3 - Medium Priority
|
|
|
|
### DX-003: Add return type hints to all Workspace relationships
|
|
**Status:** Open
|
|
**File:** `Models/Workspace.php`
|
|
|
|
Many relationship methods have correct docblocks but inconsistent return types. Standardise for IDE support.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add explicit return types to all relationship methods
|
|
- Verify PHPStan/Larastan passes at level 6+
|
|
|
|
---
|
|
|
|
### DX-004: Create EntitlementException subtypes
|
|
**Status:** Open
|
|
**File:** `Exceptions/EntitlementException.php`
|
|
|
|
Currently there's a single EntitlementException. Consider subtypes:
|
|
- `LimitExceededException`
|
|
- `PackageNotFoundException`
|
|
- `FeatureNotFoundException`
|
|
|
|
**Acceptance Criteria:**
|
|
- Create exception hierarchy
|
|
- Update EntitlementService to throw specific exceptions
|
|
- Update documentation with exception types
|
|
|
|
---
|
|
|
|
### TEST-003: Add tests for WorkspaceTeamService
|
|
**Status:** Open
|
|
**File:** `Services/WorkspaceTeamService.php`
|
|
|
|
No dedicated test file for WorkspaceTeamService. The service handles team CRUD, permissions, and member management.
|
|
|
|
**Acceptance Criteria:**
|
|
- Test team creation/update/deletion
|
|
- Test permission checks (hasPermission, hasAnyPermission, hasAllPermissions)
|
|
- Test member assignment to teams
|
|
- Test default team seeding
|
|
- Test member migration from roles to teams
|
|
|
|
---
|
|
|
|
### TEST-004: Add tests for EntitlementWebhookService
|
|
**Status:** Open
|
|
**File:** `Services/EntitlementWebhookService.php`
|
|
|
|
Need tests for webhook dispatch, signature verification, and circuit breaker functionality.
|
|
|
|
**Acceptance Criteria:**
|
|
- Test webhook registration
|
|
- Test event dispatch (sync and async)
|
|
- Test signature signing and verification
|
|
- Test circuit breaker trigger and reset
|
|
- Test delivery retry logic
|
|
|
|
---
|
|
|
|
### TEST-005: Add edge case tests for TotpService
|
|
**Status:** Open
|
|
**File:** `Services/TotpService.php`
|
|
|
|
Current tests may not cover:
|
|
- Clock drift (WINDOW parameter)
|
|
- Invalid base32 input
|
|
- Empty/null code handling
|
|
|
|
**Acceptance Criteria:**
|
|
- Test verification with clock drift
|
|
- Test malformed secret handling
|
|
- Test edge cases in base32 encode/decode
|
|
|
|
---
|
|
|
|
### PERF-003: Lazy-load Workspace relationships
|
|
**Status:** Open
|
|
**File:** `Models/Workspace.php`
|
|
|
|
The Workspace model has 30+ relationships. Many are to external packages (Core\Mod\Social, etc.). Consider:
|
|
- Marking heavy relationships as lazy
|
|
- Using `withCount` instead of loading full relations for counts
|
|
|
|
**Acceptance Criteria:**
|
|
- Audit which relationships are commonly N+1 issues
|
|
- Add `$with` property sparingly
|
|
- Document recommended eager loading patterns
|
|
|
|
---
|
|
|
|
### CODE-004: Standardise error responses across API controllers
|
|
**Status:** Open
|
|
**Files:** `Controllers/EntitlementApiController.php`, `Controllers/Api/EntitlementWebhookController.php`
|
|
|
|
Error response formats vary. Standardise to consistent structure:
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": "Error message",
|
|
"code": "ERROR_CODE"
|
|
}
|
|
```
|
|
|
|
**Acceptance Criteria:**
|
|
- Create API response trait or service
|
|
- Apply to all API controllers
|
|
- Document response format
|
|
|
|
---
|
|
|
|
### CODE-005: Add validation for webhook URL in registration
|
|
**Status:** Open
|
|
**File:** `Services/EntitlementWebhookService.php`
|
|
|
|
The `register()` method doesn't validate the webhook URL format or accessibility.
|
|
|
|
**Acceptance Criteria:**
|
|
- Validate URL format (must be https in production)
|
|
- Optionally verify URL is reachable
|
|
- Block internal IP ranges
|
|
|
|
---
|
|
|
|
### FEAT-001: Add soft deletes to WorkspaceInvitation
|
|
**Status:** Open
|
|
**File:** `Models/WorkspaceInvitation.php`
|
|
|
|
Invitations are currently hard-deleted. Soft deletes would preserve audit trail.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add SoftDeletes trait
|
|
- Update delete operations
|
|
- Add migration for deleted_at column
|
|
|
|
---
|
|
|
|
### FEAT-002: Add invitation resend functionality
|
|
**Status:** Open
|
|
**File:** `Models/WorkspaceInvitation.php`
|
|
|
|
Users may miss invitation emails. Add ability to resend with updated expiry.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add `resend()` method to WorkspaceInvitation
|
|
- Extend expiry on resend
|
|
- Track resend count/timestamps
|
|
- Rate limit resends
|
|
|
|
---
|
|
|
|
## P4 - Low Priority
|
|
|
|
### DX-005: Add IDE helper annotations
|
|
**Status:** Open
|
|
|
|
Add `@mixin` and `@method` annotations for better IDE autocomplete with Eloquent.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add annotations to all models
|
|
- Document pattern for future models
|
|
|
|
---
|
|
|
|
### DX-006: Create artisan command for provisioning packages
|
|
**Status:** Open
|
|
|
|
Manual package provisioning via tinker is error-prone. Add CLI command.
|
|
|
|
**Acceptance Criteria:**
|
|
- `php artisan tenant:provision-package {workspace} {package}`
|
|
- Add interactive mode
|
|
- Support dry-run option
|
|
|
|
---
|
|
|
|
### TEST-006: Add mutation testing
|
|
**Status:** Open
|
|
|
|
Run infection/mutation testing to verify test quality.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add infection to dev dependencies
|
|
- Configure for core services
|
|
- Achieve >80% mutation score on critical code
|
|
|
|
---
|
|
|
|
### CODE-006: Extract constants from WorkspaceMember
|
|
**Status:** Open
|
|
**File:** `Models/WorkspaceMember.php`
|
|
|
|
Role constants should be in an enum for type safety.
|
|
|
|
**Acceptance Criteria:**
|
|
- Create WorkspaceMemberRole enum
|
|
- Update model to use enum
|
|
- Update all role comparisons
|
|
|
|
---
|
|
|
|
### CODE-007: Add configurable invitation expiry
|
|
**Status:** Open
|
|
**File:** `Models/Workspace.php`, Line 654
|
|
|
|
The `invite()` method has hardcoded 7-day expiry. Make configurable.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add config key `tenant.invitation_expiry_days`
|
|
- Document configuration option
|
|
|
|
---
|
|
|
|
### FEAT-003: Add workspace transfer ownership
|
|
**Status:** Open
|
|
|
|
Allow workspace owners to transfer ownership to another member.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add `transferOwnership()` method to WorkspaceManager
|
|
- Require confirmation from new owner
|
|
- Log ownership transfer in audit log
|
|
|
|
---
|
|
|
|
### FEAT-004: Add bulk invitation support
|
|
**Status:** Open
|
|
|
|
Allow inviting multiple users at once (CSV upload or multi-email input).
|
|
|
|
**Acceptance Criteria:**
|
|
- Add `inviteMany()` method
|
|
- Support CSV email import
|
|
- Handle duplicates gracefully
|
|
|
|
---
|
|
|
|
## P5 - Nice to Have
|
|
|
|
### DX-007: Add OpenAPI/Swagger documentation
|
|
**Status:** Open
|
|
|
|
Generate API documentation from route definitions.
|
|
|
|
**Acceptance Criteria:**
|
|
- Add scramble or l5-swagger
|
|
- Document all API endpoints
|
|
- Include authentication requirements
|
|
|
|
---
|
|
|
|
### FEAT-005: Add workspace activity log
|
|
**Status:** Open
|
|
|
|
Track all significant workspace actions for audit purposes.
|
|
|
|
**Acceptance Criteria:**
|
|
- Log member additions/removals
|
|
- Log permission changes
|
|
- Log package/boost changes
|
|
- Provide query interface
|
|
|
|
---
|
|
|
|
### FEAT-006: Add usage forecasting
|
|
**Status:** Open
|
|
|
|
Predict when a workspace will hit limits based on usage trends.
|
|
|
|
**Acceptance Criteria:**
|
|
- Track daily usage aggregates
|
|
- Implement simple linear projection
|
|
- Show "estimated days until limit" in dashboard
|
|
|
|
---
|
|
|
|
### FEAT-007: Add webhook event filtering
|
|
**Status:** Open
|
|
|
|
Allow webhooks to filter events by additional criteria (e.g., specific features only).
|
|
|
|
**Acceptance Criteria:**
|
|
- Add filter configuration to webhook
|
|
- Support feature code patterns
|
|
- Support threshold filtering for limit events
|
|
|
|
---
|
|
|
|
## P6 - Backlog / Ideas
|
|
|
|
### IDEA-001: GraphQL API for entitlements
|
|
Consider adding GraphQL endpoint for more flexible entitlement queries.
|
|
|
|
### IDEA-002: Real-time usage updates
|
|
WebSocket support for live usage updates in dashboard.
|
|
|
|
### IDEA-003: Entitlement simulation mode
|
|
Allow testing "what if I upgrade" scenarios without actual changes.
|
|
|
|
### IDEA-004: Multi-region support
|
|
Support for workspace data residency requirements.
|
|
|
|
### IDEA-005: Workspace templates
|
|
Pre-configured workspace setups for different use cases.
|
|
|
|
---
|
|
|
|
## Completed
|
|
|
|
_Move items here when done with completion date._
|
|
|
|
<!-- Example:
|
|
### SEC-001: Add rate limiting to API
|
|
**Status:** Done (2026-01-29)
|
|
**PR:** #123
|
|
-->
|