49 lines
1.8 KiB
PHP
49 lines
1.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
it('prevents ai governance surfaces from declaring direct outbound or vendor-specific provider runtime code', function (): void {
|
|
$root = app_path();
|
|
|
|
$files = collect(File::allFiles($root))
|
|
->map(fn (\SplFileInfo $file): string => str_replace($root.'/', '', $file->getPathname()))
|
|
->filter(fn (string $relativePath): bool => str_starts_with($relativePath, 'Support/Ai/')
|
|
|| $relativePath === 'Support/ProductKnowledge/ContextualHelpResolver.php'
|
|
|| $relativePath === 'Support/SupportDiagnostics/SupportDiagnosticBundleBuilder.php')
|
|
->values();
|
|
|
|
$patterns = [
|
|
'outbound_http' => '/\bHttp::/',
|
|
'guzzle_client' => '/\bnew\s+Client\b/',
|
|
'curl_runtime' => '/\bcurl_/i',
|
|
'openai_vendor' => '/\bOpenAI\b/i',
|
|
'anthropic_vendor' => '/\bAnthropic\b/i',
|
|
'gemini_vendor' => '/\bGemini\b/i',
|
|
'openrouter_vendor' => '/\bOpenRouter\b/i',
|
|
'chat_completions_runtime' => '/\bChatCompletion\b/i',
|
|
];
|
|
|
|
$hits = [];
|
|
|
|
foreach ($files as $relativePath) {
|
|
$contents = file_get_contents($root.'/'.$relativePath);
|
|
|
|
if (! is_string($contents) || $contents === '') {
|
|
continue;
|
|
}
|
|
|
|
$lines = preg_split('/\R/', $contents) ?: [];
|
|
|
|
foreach ($patterns as $label => $pattern) {
|
|
foreach ($lines as $index => $line) {
|
|
if (preg_match($pattern, $line) === 1) {
|
|
$hits[] = $relativePath.':'.($index + 1).' ['.$label.'] '.trim($line);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
expect($hits)->toBeEmpty("AI governance surfaces must stay vendor-neutral and must not perform outbound provider runtime calls directly:\n".implode("\n", $hits));
|
|
}); |