TenantAtlas/app/Support/Auth/Capabilities.php
ahmido a989ef1a23 feat: workspace context enforcement (specs 070–072) (#85)
Implements specs 070–072 (workspace foundation, workspace-scoped tenant selection, managed-tenants workspace enforcement).

Highlights
- Adds Workspace + WorkspaceMembership models/migrations + middleware to persist/enforce current workspace context.
- Scopes tenant selection to the current workspace.
- Makes legacy `/admin/managed-tenants*` routes redirect into workspace-scoped URLs.
- Enforces tenant routes under `/admin/t/{tenant}` to 404 when workspace context is missing or mismatched.
- Fixes Filament page Blade wrappers so header actions render on choose-workspace / choose-tenant / no-access pages.

Verification
- Pint: `vendor/bin/sail bin pint --dirty`
- Tests: `vendor/bin/sail artisan test --compact tests/Feature/Guards/NoAdHocFilamentAuthPatternsTest.php tests/Feature/Workspaces tests/Feature/Filament/ChooseTenantIsWorkspaceScopedTest.php tests/Feature/Filament/ChooseTenantRequiresWorkspaceTest.php tests/Feature/Filament/TenantSwitcherUrlResolvesTenantTest.php tests/Feature/ManagedTenants tests/Feature/AdminNewRedirectTest.php`

Notes
- Filament v5 / Livewire v4 compatible.
- Panel provider registration stays in `bootstrap/providers.php` (Laravel 11+ rule).
- No new heavy frontend assets added.

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #85
2026-02-02 10:07:41 +00:00

91 lines
2.4 KiB
PHP

<?php
namespace App\Support\Auth;
/**
* Canonical Capability Registry
*
* This is the single source of truth for all capability strings in the system.
* All role-to-capability mappings must reference only these constants.
*/
class Capabilities
{
/**
* @var array<string>|null
*/
private static ?array $all = null;
// Workspaces
public const WORKSPACE_VIEW = 'workspace.view';
public const WORKSPACE_MANAGE = 'workspace.manage';
public const WORKSPACE_ARCHIVE = 'workspace.archive';
// Workspace memberships
public const WORKSPACE_MEMBERSHIP_VIEW = 'workspace_membership.view';
public const WORKSPACE_MEMBERSHIP_MANAGE = 'workspace_membership.manage';
// Tenants
public const TENANT_VIEW = 'tenant.view';
public const TENANT_MANAGE = 'tenant.manage';
public const TENANT_DELETE = 'tenant.delete';
public const TENANT_SYNC = 'tenant.sync';
// Inventory
public const TENANT_INVENTORY_SYNC_RUN = 'tenant_inventory_sync.run';
// Findings
public const TENANT_FINDINGS_ACKNOWLEDGE = 'tenant_findings.acknowledge';
// Tenant memberships
public const TENANT_MEMBERSHIP_VIEW = 'tenant_membership.view';
public const TENANT_MEMBERSHIP_MANAGE = 'tenant_membership.manage';
// Optional mappings (no Graph resolution in v1)
public const TENANT_ROLE_MAPPING_VIEW = 'tenant_role_mapping.view';
public const TENANT_ROLE_MAPPING_MANAGE = 'tenant_role_mapping.manage';
// Backup schedules
public const TENANT_BACKUP_SCHEDULES_MANAGE = 'tenant_backup_schedules.manage';
public const TENANT_BACKUP_SCHEDULES_RUN = 'tenant_backup_schedules.run';
// Providers (existing gate names used throughout the app)
public const PROVIDER_VIEW = 'provider.view';
public const PROVIDER_MANAGE = 'provider.manage';
public const PROVIDER_RUN = 'provider.run';
// Audit
public const AUDIT_VIEW = 'audit.view';
/**
* Get all capability constants
*
* @return array<string>
*/
public static function all(): array
{
if (self::$all !== null) {
return self::$all;
}
$reflection = new \ReflectionClass(self::class);
return self::$all = array_values($reflection->getConstants());
}
public static function isKnown(string $capability): bool
{
return in_array($capability, self::all(), true);
}
}