feat: add scoped read-only audio preview and isolated Dify transport

This commit is contained in:
2026-10-09 16:10:59 +08:00
parent 27772bec61
commit 4d0af7f3f4
36 changed files with 1517 additions and 68 deletions
@@ -9,6 +9,8 @@ $access = file_get_contents($root . '/app/common/service/followupaudio/FollowupA
$middleware = file_get_contents($root . '/app/adminapi/http/middleware/AuthMiddleware.php');
$stream = file_get_contents($root . '/app/common/service/followupaudio/FollowupAudioStream.php');
$console = file_get_contents($root . '/config/console.php');
$apply = file_get_contents($root . '/app/common/service/followupaudio/FollowupAudioApply.php');
$gate = file_get_contents($root . '/app/common/service/followupaudio/FollowupAudioGate.php');
$checks = 0;
function expectEndpoint(bool $condition, string $message): void
{
@@ -26,8 +28,13 @@ expectEndpoint(str_contains($controller, 'array_diff(array_keys($params), $allow
expectEndpoint(str_contains($controller, 'count($items) > 500'), 'bounded review items');
expectEndpoint(str_contains($controller, "'code' => 'FOLLOWUP_AUDIO_STALE_REVIEW'"), 'typed stale review response');
expectEndpoint(substr_count($controller, 'Logic::requireEnabled(true)') >= 3, 'upload capability gate');
expectEndpoint(str_contains($logic, "Store::verified(\$p['model_key'])"), 'per-model audio capability gate');
expectEndpoint(str_contains($logic, "'models' => ProviderConfig::publicModels()"), 'only fingerprint-verified server model labels advertised');
expectEndpoint(str_contains($logic, "Store::ready(\$p['model_key'])"), 'per-model mode-aware readiness gate');
expectEndpoint(str_contains($logic, "'models' => \$enabled ? ProviderConfig::readyModels() : []"), 'only scoped fingerprint-ready server labels advertised');
expectEndpoint(str_contains($logic, '$verified = Store::verified()') && str_contains($logic, "'audio_verified' => \$verified"), 'full accuracy verification remains separate');
expectEndpoint(str_contains($logic, "'preview_only' => \$preview") && str_contains($logic, "'can_review' => \$enabled && \$ready"), 'explicit preview and review capabilities');
expectEndpoint(strpos($apply, 'FollowupAudioGate::assertMayApply();') < strpos($apply, '$connection = Db::connect()'), 'preview hard denial before any apply DB access');
expectEndpoint(strpos($apply, 'FollowupAudioGate::assertMayApply($task);') < strpos($apply, "if (\$task['status'] === 'applied')"), 'persistent preview origin denied before idempotent applied path');
expectEndpoint(str_contains($gate, 'FOLLOWUP_AUDIO_PREVIEW_ONLY') && str_contains($gate, 'FOLLOWUP_AUDIO_PREVIEW_SCOPE_DENIED'), 'stable fail-closed preview errors');
expectEndpoint(!str_contains($logic, 'Dify 音频能力') && !str_contains($logic, 'api_key') && !str_contains($logic, 'base_url'),
'provider-neutral public capabilities never expose credentials or addresses');
expectEndpoint(str_contains($logic, "(int) \$upload['diagnosis_id'] !== \$p['diagnosis_id']"), 'upload/diagnosis binding');