diff --git a/AGENTS.md b/AGENTS.md index 34b43e087..f9f8ca563 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -148,6 +148,11 @@ ### Authorization - Custom gates: `createAnyResource`, `canAccessTerminal` - Role hierarchy: `Role::MEMBER` (1) < `Role::ADMIN` (2) < `Role::OWNER` (3) with `lt()`/`gt()` comparison methods - Multi-tenancy via Teams — team auto-initializes notification settings on creation +- Authorize every server-side read and mutation where access can vary by user, role, team, or resource. Use policies, gates, or `$this->authorize(...)`; never rely on hidden Blade/Livewire controls such as `@can` for security. +- Scope queries to the current team before returning records. Treat route and model identifiers as untrusted, and prevent users from reading or changing resources owned by another team. +- Apply authorization consistently across Livewire actions, API and web controllers, actions, downloads, exports, search, event listeners, and any other path that exposes or changes protected data. +- Default to denying access when a policy or ownership relationship is missing or ambiguous. Members must not gain access to administrative, credential, security, billing, or instance-wide data merely because they belong to the team. +- Add authorization regression tests for protected changes. Cover permitted access, member restrictions where applicable, and cross-team access; verify unauthorized reads and writes return `403` or otherwise reveal no protected data. ### Event Broadcasting - Soketi WebSocket server for real-time updates (ports 6001-6002 in dev)