220 lines
8.8 KiB
PHP
220 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Providers;
|
|
|
|
use App\Support\Auth\Capabilities;
|
|
use InvalidArgumentException;
|
|
|
|
final class ProviderOperationRegistry
|
|
{
|
|
public const string BINDING_ACTIVE = 'active';
|
|
|
|
public const string BINDING_UNSUPPORTED = 'unsupported';
|
|
|
|
/**
|
|
* @return array<string, array{operation_type: string, module: string, label: string, required_capability: string}>
|
|
*/
|
|
public function definitions(): array
|
|
{
|
|
return [
|
|
'provider.connection.check' => [
|
|
'operation_type' => 'provider.connection.check',
|
|
'module' => 'health_check',
|
|
'label' => 'Provider connection check',
|
|
'required_capability' => Capabilities::PROVIDER_RUN,
|
|
],
|
|
'inventory_sync' => [
|
|
'operation_type' => 'inventory_sync',
|
|
'module' => 'inventory',
|
|
'label' => 'Inventory sync',
|
|
'required_capability' => Capabilities::PROVIDER_RUN,
|
|
],
|
|
'compliance.snapshot' => [
|
|
'operation_type' => 'compliance.snapshot',
|
|
'module' => 'compliance',
|
|
'label' => 'Compliance snapshot',
|
|
'required_capability' => Capabilities::PROVIDER_RUN,
|
|
],
|
|
'restore.execute' => [
|
|
'operation_type' => 'restore.execute',
|
|
'module' => 'restore',
|
|
'label' => 'Restore execution',
|
|
'required_capability' => Capabilities::TENANT_MANAGE,
|
|
],
|
|
'entra_group_sync' => [
|
|
'operation_type' => 'entra_group_sync',
|
|
'module' => 'directory_groups',
|
|
'label' => 'Directory groups sync',
|
|
'required_capability' => Capabilities::TENANT_SYNC,
|
|
],
|
|
'directory_role_definitions.sync' => [
|
|
'operation_type' => 'directory_role_definitions.sync',
|
|
'module' => 'directory_role_definitions',
|
|
'label' => 'Role definitions sync',
|
|
'required_capability' => Capabilities::TENANT_MANAGE,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array{operation_type: string, module: string, label: string, required_capability: string}>
|
|
*/
|
|
public function all(): array
|
|
{
|
|
return $this->definitions();
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array<string, array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}>>
|
|
*/
|
|
public function providerBindings(): array
|
|
{
|
|
return [
|
|
'provider.connection.check' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'provider.connection.check',
|
|
handlerNotes: 'Uses the current Microsoft Graph provider connection health-check workflow.',
|
|
exceptionNotes: 'Current-release provider binding remains Microsoft-only until a real second provider case exists.',
|
|
),
|
|
],
|
|
'inventory_sync' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'inventory_sync',
|
|
handlerNotes: 'Uses the current Microsoft Intune inventory sync workflow.',
|
|
exceptionNotes: 'Inventory collection is currently Microsoft Intune-specific provider behavior.',
|
|
),
|
|
],
|
|
'compliance.snapshot' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'compliance.snapshot',
|
|
handlerNotes: 'Uses the current Microsoft compliance snapshot workflow.',
|
|
exceptionNotes: 'Compliance snapshot runtime remains bounded to the Microsoft provider.',
|
|
),
|
|
],
|
|
'restore.execute' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'restore.execute',
|
|
handlerNotes: 'Uses the current Microsoft restore execution workflow.',
|
|
exceptionNotes: 'Restore execution remains Microsoft-only and must preserve dry-run and audit safeguards.',
|
|
),
|
|
],
|
|
'entra_group_sync' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'entra_group_sync',
|
|
handlerNotes: 'Uses the current Microsoft Entra group synchronization workflow.',
|
|
exceptionNotes: 'The operation type keeps current Entra vocabulary until the identity-neutrality follow-up.',
|
|
),
|
|
],
|
|
'directory_role_definitions.sync' => [
|
|
'microsoft' => $this->activeMicrosoftBinding(
|
|
operationType: 'directory_role_definitions.sync',
|
|
handlerNotes: 'Uses the current Microsoft directory role definition synchronization workflow.',
|
|
exceptionNotes: 'Directory role definitions are Microsoft-owned provider semantics.',
|
|
),
|
|
],
|
|
];
|
|
}
|
|
|
|
public function isAllowed(string $operationType): bool
|
|
{
|
|
return array_key_exists(trim($operationType), $this->definitions());
|
|
}
|
|
|
|
/**
|
|
* @return array{operation_type: string, module: string, label: string, required_capability: string}
|
|
*/
|
|
public function get(string $operationType): array
|
|
{
|
|
$operationType = trim($operationType);
|
|
|
|
$definition = $this->definitions()[$operationType] ?? null;
|
|
|
|
if (! is_array($definition)) {
|
|
throw new InvalidArgumentException("Unknown provider operation type: {$operationType}");
|
|
}
|
|
|
|
return $definition;
|
|
}
|
|
|
|
/**
|
|
* @return array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}|null
|
|
*/
|
|
public function bindingFor(string $operationType, string $provider): ?array
|
|
{
|
|
$operationType = trim($operationType);
|
|
$provider = trim($provider);
|
|
|
|
if ($operationType === '' || $provider === '') {
|
|
return null;
|
|
}
|
|
|
|
$bindings = $this->providerBindings()[$operationType] ?? [];
|
|
|
|
return $bindings[$provider] ?? null;
|
|
}
|
|
|
|
/**
|
|
* @return array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}|null
|
|
*/
|
|
public function activeBindingFor(string $operationType): ?array
|
|
{
|
|
$operationType = trim($operationType);
|
|
$bindings = $this->providerBindings()[$operationType] ?? [];
|
|
|
|
foreach ($bindings as $binding) {
|
|
if (($binding['binding_status'] ?? null) === self::BINDING_ACTIVE) {
|
|
return $binding;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return array{
|
|
* definition: array{operation_type: string, module: string, label: string, required_capability: string},
|
|
* binding: array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}
|
|
* }
|
|
*/
|
|
public function boundaryOperation(string $operationType, ?string $provider = null): array
|
|
{
|
|
$definition = $this->get($operationType);
|
|
$binding = is_string($provider) && trim($provider) !== ''
|
|
? $this->bindingFor($operationType, $provider)
|
|
: $this->activeBindingFor($operationType);
|
|
|
|
return [
|
|
'definition' => $definition,
|
|
'binding' => $binding ?? $this->unsupportedBinding($operationType, $provider ?? 'unknown'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}
|
|
*/
|
|
public function unsupportedBinding(string $operationType, string $provider): array
|
|
{
|
|
return [
|
|
'operation_type' => trim($operationType),
|
|
'provider' => trim($provider) !== '' ? trim($provider) : 'unknown',
|
|
'binding_status' => self::BINDING_UNSUPPORTED,
|
|
'handler_notes' => 'No explicit provider binding exists for this operation/provider combination.',
|
|
'exception_notes' => 'Unsupported combinations must block explicitly instead of inheriting Microsoft behavior.',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array{operation_type: string, provider: string, binding_status: string, handler_notes: string, exception_notes: string}
|
|
*/
|
|
private function activeMicrosoftBinding(string $operationType, string $handlerNotes, string $exceptionNotes): array
|
|
{
|
|
return [
|
|
'operation_type' => $operationType,
|
|
'provider' => 'microsoft',
|
|
'binding_status' => self::BINDING_ACTIVE,
|
|
'handler_notes' => $handlerNotes,
|
|
'exception_notes' => $exceptionNotes,
|
|
];
|
|
}
|
|
}
|