Validation: sail artisan test --filter=Spec433|Spec432|Spec431 --compact; pint --dirty --test; git diff --check Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #500
85 lines
3.3 KiB
PHP
85 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\TenantConfiguration;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\ProviderConnection;
|
|
use App\Support\Providers\ProviderReasonCodes;
|
|
|
|
final class ExchangePowerShellInvocationReadinessEvaluator
|
|
{
|
|
public function __construct(
|
|
private readonly ExchangePowerShellCredentialReferenceResolver $credentials,
|
|
private readonly ExchangePowerShellPermissionEvidenceEvaluator $permissions,
|
|
) {}
|
|
|
|
public function evaluate(ManagedEnvironment $environment, ProviderConnection $connection): ExchangePowerShellGateResult
|
|
{
|
|
if (! $this->scopeMatches($environment, $connection)) {
|
|
return ExchangePowerShellGateResult::blocked(
|
|
reasonCode: ProviderReasonCodes::TenantTargetMismatch,
|
|
failureCode: 'readiness_blocked_scope_mismatch',
|
|
message: 'Exchange PowerShell invocation readiness requires a matching workspace, environment, and provider connection.',
|
|
context: [
|
|
'readiness_state' => 'blocked',
|
|
'readiness_blocker' => 'scope',
|
|
'scope_state' => 'mismatch',
|
|
],
|
|
);
|
|
}
|
|
|
|
$credentialGate = $this->credentials->resolve($connection);
|
|
|
|
if (! $credentialGate->allowed) {
|
|
return $this->blockedFromGate($credentialGate, 'credential');
|
|
}
|
|
|
|
$permissionGate = $this->permissions->evaluate($environment, $connection);
|
|
|
|
if (! $permissionGate->allowed) {
|
|
return $this->blockedFromGate($permissionGate, 'permission');
|
|
}
|
|
|
|
return ExchangePowerShellGateResult::allowed([
|
|
'readiness_state' => 'ready_for_live_invocation',
|
|
'credential_state' => $credentialGate->context['credential_state'] ?? 'ready',
|
|
'permission_evidence_state' => $permissionGate->context['permission_evidence_state'] ?? 'verified',
|
|
'permission_currentness_days' => $permissionGate->context['permission_currentness_days'] ?? null,
|
|
]);
|
|
}
|
|
|
|
private function scopeMatches(ManagedEnvironment $environment, ProviderConnection $connection): bool
|
|
{
|
|
return (int) $connection->workspace_id === (int) $environment->workspace_id
|
|
&& (int) $connection->managed_environment_id === (int) $environment->getKey();
|
|
}
|
|
|
|
private function blockedFromGate(ExchangePowerShellGateResult $gate, string $blocker): ExchangePowerShellGateResult
|
|
{
|
|
return ExchangePowerShellGateResult::blocked(
|
|
reasonCode: $gate->reasonCode ?? ProviderReasonCodes::ProviderBindingUnsupported,
|
|
failureCode: $gate->failureCode ?? 'readiness_blocked',
|
|
message: $gate->message ?? 'Exchange PowerShell invocation readiness was blocked.',
|
|
context: [
|
|
'readiness_state' => 'blocked',
|
|
'readiness_blocker' => $blocker,
|
|
...$this->safeContext($gate->context),
|
|
],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $context
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function safeContext(array $context): array
|
|
{
|
|
return array_filter(
|
|
$context,
|
|
static fn (mixed $value): bool => is_scalar($value) || $value === null,
|
|
);
|
|
}
|
|
}
|