TenantAtlas/apps/platform/app/Policies/OperationRunPolicy.php
Ahmed Darrazi 2a856d2693
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m44s
feat: implement operations UI operator actions regression gate
2026-06-08 03:19:34 +02:00

158 lines
4.9 KiB
PHP

<?php
namespace App\Policies;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Services\Auth\ManagedEnvironmentAccessScopeResolver;
use App\Support\Operations\OperationRunCapabilityResolver;
use App\Support\Operations\Reconciliation\OperationRunReconciliationRegistry;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
class OperationRunPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId();
if ($workspaceId === null) {
return false;
}
return WorkspaceMembership::query()
->where('workspace_id', (int) $workspaceId)
->where('user_id', (int) $user->getKey())
->exists();
}
public function view(User $user, OperationRun $run): Response|bool
{
$workspaceId = (int) ($run->workspace_id ?? 0);
if ($workspaceId <= 0) {
return Response::denyAsNotFound();
}
$isMember = WorkspaceMembership::query()
->where('workspace_id', $workspaceId)
->where('user_id', (int) $user->getKey())
->exists();
if (! $isMember) {
return Response::denyAsNotFound();
}
$tenantId = (int) ($run->managed_environment_id ?? 0);
if ($tenantId > 0) {
$tenant = ManagedEnvironment::query()->withTrashed()->whereKey($tenantId)->first();
if (! $tenant instanceof ManagedEnvironment || (int) $tenant->workspace_id !== $workspaceId) {
return Response::denyAsNotFound();
}
$hasTenantEntitlement = app(ManagedEnvironmentAccessScopeResolver::class)->canAccess($user, $tenant);
if (! $hasTenantEntitlement) {
return Response::denyAsNotFound();
}
}
$requiredCapability = app(OperationRunCapabilityResolver::class)
->requiredCapabilityForRun($run);
if (! is_string($requiredCapability) || $requiredCapability === '') {
return true;
}
if (str_starts_with($requiredCapability, 'workspace')) {
$workspace = Workspace::query()->whereKey($workspaceId)->first();
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows($requiredCapability, $workspace)) {
return Response::deny();
}
return true;
}
if ($tenantId > 0) {
$tenant = ManagedEnvironment::query()->withTrashed()->whereKey($tenantId)->first();
if (! $tenant instanceof ManagedEnvironment) {
return Response::denyAsNotFound();
}
if (! Gate::forUser($user)->allows($requiredCapability, $tenant)) {
return Response::deny();
}
}
return true;
}
public function reconcile(User $user, OperationRun $run): Response|bool
{
$view = $this->view($user, $run);
if ($view instanceof Response && $view->denied()) {
return $view;
}
if ($view === false) {
return Response::denyAsNotFound();
}
if (app(OperationRunReconciliationRegistry::class)->forType($run->canonicalOperationType()) === null) {
return Response::deny('Operation type does not support reconciliation.');
}
$requiredCapability = app(OperationRunCapabilityResolver::class)
->requiredExecutionCapabilityForType((string) $run->type);
if (! is_string($requiredCapability) || $requiredCapability === '') {
return Response::deny('Operation type has no reconcile capability.');
}
$workspaceId = (int) ($run->workspace_id ?? 0);
$tenantId = (int) ($run->managed_environment_id ?? 0);
if (str_starts_with($requiredCapability, 'workspace')) {
$workspace = Workspace::query()->whereKey($workspaceId)->first();
if (! $workspace instanceof Workspace) {
return Response::denyAsNotFound();
}
return Gate::forUser($user)->allows($requiredCapability, $workspace)
? Response::allow()
: Response::deny();
}
if ($tenantId <= 0) {
return Response::denyAsNotFound();
}
$tenant = ManagedEnvironment::query()->withTrashed()->whereKey($tenantId)->first();
if (! $tenant instanceof ManagedEnvironment || (int) $tenant->workspace_id !== $workspaceId) {
return Response::denyAsNotFound();
}
return Gate::forUser($user)->allows($requiredCapability, $tenant)
? Response::allow()
: Response::deny();
}
}