TenantAtlas/app/Console/Commands/GraphContractCheck.php
2025-12-14 20:23:18 +01:00

69 lines
2.0 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Services\Graph\GraphClientInterface;
use Illuminate\Console\Command;
class GraphContractCheck extends Command
{
protected $signature = 'graph:contract:check {--tenant=}';
protected $description = 'Validate Graph contract registry against live endpoints (lightweight probes)';
public function handle(GraphClientInterface $graph): int
{
$contracts = config('graph_contracts.types', []);
if (empty($contracts)) {
$this->warn('No graph contracts configured.');
return self::SUCCESS;
}
$tenant = $this->option('tenant');
$failures = 0;
foreach ($contracts as $type => $contract) {
$resource = $contract['resource'] ?? null;
$select = $contract['allowed_select'] ?? [];
$expand = $contract['allowed_expand'] ?? [];
if (! $resource) {
$this->error("[$type] missing resource path");
$failures++;
continue;
}
$query = array_filter([
'$top' => 1,
'$select' => $select,
'$expand' => $expand,
]);
$response = $graph->request('GET', $resource, [
'query' => $query,
'tenant' => $tenant,
]);
if ($response->failed()) {
$code = $response->meta['error_code'] ?? $response->status;
$message = $response->meta['error_message'] ?? ($response->errors[0]['message'] ?? $response->errors[0] ?? 'unknown');
$this->error("[$type] drift or capability issue ({$code}): {$message}");
$failures++;
continue;
}
if (! empty($response->warnings)) {
$this->warn("[$type] completed with warnings: ".implode('; ', $response->warnings));
} else {
$this->info("[$type] OK");
}
}
return $failures > 0 ? self::FAILURE : self::SUCCESS;
}
}