first commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
use app\common\service\DifyChatService;
|
||||
|
||||
$app = new think\App(dirname(__DIR__));
|
||||
$app->initialize();
|
||||
|
||||
function assertSecretSafe(array $result, string $secret, string $message): void
|
||||
{
|
||||
$serialized = json_encode($result, JSON_UNESCAPED_UNICODE) ?: '';
|
||||
if (str_contains($serialized, $secret)) {
|
||||
fwrite(STDERR, "FAIL: {$message}\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$qwenSecret = 'unit-test-qwen-sensitive-placeholder';
|
||||
$openAiSecret = 'unit-test-openai-sensitive-placeholder';
|
||||
$baseConfig = [
|
||||
'enable' => false,
|
||||
'base_url' => 'https://ai.example.test/v1',
|
||||
'timeout' => 90,
|
||||
'models' => [
|
||||
'qwen' => ['name' => 'qwen-test', 'label' => 'Qwen', 'api_key' => $qwenSecret],
|
||||
'openai' => ['name' => 'openai-test', 'label' => 'OpenAI', 'api_key' => $openAiSecret],
|
||||
],
|
||||
];
|
||||
|
||||
function assertAllSecretsSafe(array $result, array $secrets, string $message): void
|
||||
{
|
||||
foreach ($secrets as $secret) {
|
||||
assertSecretSafe($result, $secret, $message);
|
||||
}
|
||||
}
|
||||
|
||||
$secrets = [$qwenSecret, $openAiSecret];
|
||||
|
||||
$resolveProfile = (new ReflectionClass(DifyChatService::class))->getMethod('resolveProfileConfig');
|
||||
$resolvedQwen = $resolveProfile->invoke(null, $baseConfig, 'qwen');
|
||||
$resolvedOpenAi = $resolveProfile->invoke(null, $baseConfig, 'openai');
|
||||
if (
|
||||
!is_array($resolvedQwen)
|
||||
|| !is_array($resolvedOpenAi)
|
||||
|| ($resolvedQwen['api_key'] ?? null) !== $qwenSecret
|
||||
|| ($resolvedOpenAi['api_key'] ?? null) !== $openAiSecret
|
||||
) {
|
||||
fwrite(STDERR, "FAIL: each model key must resolve only its own server credential\n");
|
||||
exit(1);
|
||||
}
|
||||
if ($resolveProfile->invoke(null, $baseConfig, 'other') !== null) {
|
||||
fwrite(STDERR, "FAIL: non-whitelisted profile must not resolve server configuration\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
config($baseConfig, 'prescription_ai');
|
||||
$disabled = DifyChatService::chat('qwen', [], 'test', 'test-user');
|
||||
assertAllSecretsSafe($disabled, $secrets, 'disabled response must not expose credentials');
|
||||
|
||||
$enabledConfig = $baseConfig;
|
||||
$enabledConfig['enable'] = true;
|
||||
config($enabledConfig, 'prescription_ai');
|
||||
foreach (['other', 'QWEN', ' openai', 'gpt-5.6-sol'] as $invalidProfile) {
|
||||
$invalid = DifyChatService::chat($invalidProfile, [], 'test', 'test-user');
|
||||
if (($invalid['error_code'] ?? '') !== 'INVALID_PROFILE') {
|
||||
fwrite(STDERR, "FAIL: invalid profile must be rejected before upstream work\n");
|
||||
exit(1);
|
||||
}
|
||||
assertAllSecretsSafe($invalid, $secrets, 'invalid-profile response must not expose credentials');
|
||||
}
|
||||
|
||||
$invalidUrlConfig = $baseConfig;
|
||||
$invalidUrlConfig['enable'] = true;
|
||||
$invalidUrlConfig['base_url'] = 'file:///not-allowed';
|
||||
config($invalidUrlConfig, 'prescription_ai');
|
||||
$invalidUrl = DifyChatService::chat('qwen', [], 'test', 'test-user');
|
||||
assertAllSecretsSafe($invalidUrl, $secrets, 'invalid URL response must not expose credentials');
|
||||
|
||||
$headerInjectionConfig = $baseConfig;
|
||||
$headerInjectionConfig['enable'] = true;
|
||||
$headerInjectionConfig['models']['qwen']['api_key'] = $qwenSecret . "\r\nInjected: value";
|
||||
config($headerInjectionConfig, 'prescription_ai');
|
||||
$headerInjection = DifyChatService::chat('qwen', [], 'test', 'test-user');
|
||||
assertAllSecretsSafe($headerInjection, $secrets, 'invalid credential response must not expose credentials');
|
||||
|
||||
echo "Prescription AI secret safety: OK\n";
|
||||
Reference in New Issue
Block a user