/** Real upstream acceptance, restricted to the named local QA database. No production configuration writes. */ import assert from 'node:assert/strict' import { randomUUID } from 'node:crypto' import { mkdir, readFile, writeFile } from 'node:fs/promises' import { PrismaClient } from '@prisma/client' import type { AiModelAdminState } from '../lib/ai-model-types' const db = new URL(process.env.DATABASE_URL || '') assert.equal(db.hostname, '127.0.0.1'); assert.equal(db.port, '55441'); assert.equal(db.pathname, '/ai_model_test') const output = 'D:/AI Code/gongxiangp2/output/ai-image-adapter-20261015', base = 'http://127.0.0.1:3125' const targets = ['gpt-image-2', 'gpt-image-2-vip', 'gpt-image-2.5', 'gpt-image-2.5-flare', 'gpt-image-2.5-sunburst'] const prisma = new PrismaClient({ log: [] }) async function save(name: string, data: unknown) { await mkdir(output, { recursive: true }); await writeFile(`${output}/${name}.json`, JSON.stringify(data, null, 2)) } async function main() { const jar = new Map() function store(r: Response) { for (const entry of r.headers.getSetCookie()) { const raw = entry.split(';')[0], at = raw.indexOf('='); jar.set(raw.slice(0, at), raw.slice(at + 1)) } } const cookie = () => Array.from(jar).map(([key, value]) => `${key}=${value}`).join('; ') const csrf = await fetch(base + '/api/auth/csrf'); store(csrf) const signed = await fetch(base + '/api/auth/callback/credentials', { method: 'POST', redirect: 'manual', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Cookie: cookie() }, body: new URLSearchParams({ csrfToken: (await csrf.json()).csrfToken, email: 'ai-admin-1@example.invalid', password: 'AiAdminLocalTest-20261012', callbackUrl: base + '/admin', json: 'true' }) }); store(signed); assert.equal(signed.status, 200) async function request(path = '', method = 'GET', body?: unknown) { const r = await fetch(base + '/api/admin/ai-models' + path, { method, headers: { Cookie: cookie(), 'Content-Type': 'application/json' }, ...(body ? { body: JSON.stringify(body) } : {}), signal: AbortSignal.timeout(195000) }) const text = await r.text(); assert.ok(!process.env.DETAIL_GENERATOR_API_KEY || !text.includes(process.env.DETAIL_GENERATOR_API_KEY), 'Credential leaked') const data = JSON.parse(text); assert.equal(r.status, 200, JSON.stringify({ status: r.status, code: data.code, error: data.error })); return data as AiModelAdminState } let state = await request(), provider = state.providers.find(p => p.credentialSource === 'environment')! assert.ok(provider) const phase = process.argv[2] || 'inspect' if (phase === 'check') { const flags = (s: AiModelAdminState) => s.providers.map(p => ({ id: p.id, models: p.models.map(m => ({ key: m.key, enabled: m.enabled, stages: m.stages })) })) const beforeFlags = flags(state), beforeDefaults = state.defaults const count = async () => (await prisma.$queryRawUnsafe>('SELECT COUNT(*)::int AS count FROM ai_model_verifications'))[0].count const beforeCount = await count() async function reject(path: string, body: unknown, status: number, token = cookie()) { const r = await fetch(base + '/api/admin/ai-models' + path, { method: 'POST', headers: { Cookie: token, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }) const data = await r.json(); assert.equal(r.status, status, JSON.stringify({ status: r.status, code: data.code })); return data } for (const modelId of ['nano-banana-2-2k-cl', 'nano-banana-2-4k-cl']) { const m = provider.models.find(m => m.id === modelId)! assert.ok(m); assert.equal(m.capabilities.reason, '仅支持文生图,不能接收产品参考图') const result = await reject(`/providers/${provider.id}/models/${m.key}/verify`, { stage: 'image', revision: provider.revision, idempotencyKey: randomUUID() }, 400) assert.equal(result.code, 'model_capability_unsupported') } for (const modelId of targets) { const receipt = JSON.parse(await readFile(`${output}/test-${modelId}.json`, 'utf8')) await request(`/providers/${provider.id}/models/${receipt.modelKey}/verify`, 'POST', { stage: 'image', revision: provider.revision, idempotencyKey: receipt.idempotencyKey }) } assert.equal(await count(), beforeCount, 'Rejected or replayed submissions must not create any new model execution') const configuration = (s: AiModelAdminState, key: string, enabled: boolean, stages: Array<'image'>) => ({ revision: s.revision, defaults: s.defaults, providers: s.providers.map(p => ({ id: p.id, revision: p.revision, models: p.models.map(m => ({ key: m.key, enabled: m.key === key ? enabled : m.enabled, stages: m.key === key ? stages : m.stages })) })) }) for (const modelId of targets.filter(id => id.includes('2.5'))) { const m = provider.models.find(m => m.id === modelId)! assert.equal(m.verification.image.status, 'failed'); assert.equal(m.enabled, false) const r = await fetch(base + '/api/admin/ai-models/configuration', { method: 'PUT', headers: { Cookie: cookie(), 'Content-Type': 'application/json' }, body: JSON.stringify(configuration(state, m.key, true, ['image'])) }) assert.equal(r.status, 400); assert.equal((await r.json()).code, 'model_verification_required') } const passed = provider.models.find(m => m.id === 'gpt-image-2-vip')! assert.equal(passed.verification.image.status, 'passed'); assert.equal(passed.enabled, false); assert.deepEqual(passed.stages, []) state = await request('/configuration', 'PUT', configuration(state, passed.key, true, ['image'])) assert.ok(state.providers.find(p => p.id === provider.id)!.models.find(m => m.key === passed.key)!.enabled) state = await request('/configuration', 'PUT', configuration(state, passed.key, false, [])) assert.deepEqual(flags(state), beforeFlags); assert.deepEqual(state.defaults, beforeDefaults) const anonymous = await fetch(base + '/api/admin/ai-models'); assert.equal(anonymous.status, 401) const otherJar = new Map() const absorb = (r: Response) => { for (const item of r.headers.getSetCookie()) { const raw = item.split(';')[0], at = raw.indexOf('='); otherJar.set(raw.slice(0, at), raw.slice(at + 1)) } } const otherCookie = () => Array.from(otherJar).map(([key, value]) => `${key}=${value}`).join('; ') const otherCsrf = await fetch(base + '/api/auth/csrf'); absorb(otherCsrf) const otherSigned = await fetch(base + '/api/auth/callback/credentials', { method: 'POST', redirect: 'manual', headers: { Cookie: otherCookie(), 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ csrfToken: (await otherCsrf.json()).csrfToken, email: 'ai-admin-2@example.invalid', password: 'AiAdminLocalTest-20261012', callbackUrl: base + '/admin', json: 'true' }) }); absorb(otherSigned); assert.equal(otherSigned.status, 200) provider = state.providers.find(p => p.id === provider.id)! await reject(`/providers/${provider.id}/models/${passed.key}/verify`, { stage: 'image', revision: provider.revision, idempotencyKey: randomUUID() }, 403, otherCookie()) assert.equal(await count(), beforeCount) await save('native-check', { textOnlyRejectedBeforeCall: true, idempotentReplays: targets.length, rejectedEnable: 3, passedEnableSaveAndRestore: true, unrelatedSettingsPreserved: true, anonymous: 401, ordinaryAdmin: 403, verificationCountUnchanged: true, productionTouched: false }) console.log('Native API acceptance passed: reference-image eligibility, replay safety, enable gating, settings restoration and authorization.'); return } if (phase === 'reconcile') { const modelId = process.argv[3]; assert.ok(targets.includes(modelId)) const receipt = JSON.parse(await readFile(`${output}/test-${modelId}.json`, 'utf8')) assert.equal(receipt.status, 'unknown') const script = await readFile(`${output}/upstream-trace-request.sh`, 'utf8') assert.ok(script.includes(`client:${receipt.idempotencyKey}`)) const log = await readFile(`${output}/upstream-trace-request.sh.log`, 'utf8') const proof = JSON.parse(log.split(/\r?\n/).find(line => line.startsWith('{'))!) assert.equal(proof.status, 'failed_final'); assert.equal(proof.httpStatus, 502); assert.equal(proof.errorCode, 'service_rejected') assert.match(proof.requestId, /^[a-f0-9-]{36}$/) state = await request(`/providers/${provider.id}/verifications/${receipt.verification.id}/reconcile`, 'POST', { outcome: 'failed', reference: proof.requestId, note: `已按本次请求编号只读核查上游记录,最终状态 failed_final,HTTP 502,service_rejected,请求已结束。`, confirmed: true }) const verification = state.providers.find(p => p.id === provider.id)!.models.find(m => m.key === receipt.modelKey)!.verification.image assert.equal(verification.status, 'failed'); assert.ok(verification.reconciled) await save(`reconciled-${modelId}`, { proof, verification, productionTouched: false }); console.log(JSON.stringify({ modelId, proof, verification })); return } if (phase === 'sync') { const models = provider.models.filter(m => targets.includes(m.id)); assert.equal(models.length, targets.length) const preserved = provider.models.filter(m => !targets.includes(m.id)).map(m => ({ key: m.key, enabled: m.enabled, stages: m.stages, verification: m.verification })) state = await request(`/providers/${provider.id}/sync`, 'POST', { revision: provider.revision, modelKeys: models.map(m => m.key) }) provider = state.providers.find(p => p.id === provider.id)! assert.deepEqual(provider.models.filter(m => !targets.includes(m.id)).map(m => ({ key: m.key, enabled: m.enabled, stages: m.stages, verification: m.verification })), preserved) const result = provider.models.filter(m => targets.includes(m.id)).map(m => ({ id: m.id, capabilities: m.capabilities, verification: m.verification.image.status })) assert.ok(result.every(m => m.capabilities.allowedStages.includes('image'))) await save('sync', { productionTouched: false, unrelatedModelsPreserved: true, models: result }); console.log(JSON.stringify(result)); return } if (phase === 'test') { const modelId = process.argv[3]; assert.ok(targets.includes(modelId)) try { await readFile(`${output}/test-${modelId}.json`); throw new Error('This model already has a test receipt; inspect it instead of repeating a paid call') } catch (error: any) { if (error.code !== 'ENOENT') throw error } const model = provider.models.find(m => m.id === modelId)!; assert.ok(model.capabilities.allowedStages.includes('image')) const actor = await prisma.user.findUniqueOrThrow({ where: { email: 'ai-admin-1@example.invalid' } }); assert.ok(actor.isSuperAdmin) const idempotencyKey = randomUUID(), startedAt = new Date().toISOString() await save(`test-${modelId}`, { modelId, modelKey: model.key, providerId: provider.id, idempotencyKey, startedAt, status: 'submitting' }) state = await request(`/providers/${provider.id}/models/${model.key}/verify`, 'POST', { stage: 'image', revision: provider.revision, idempotencyKey }) const fresh = state.providers.find(p => p.id === provider.id)!.models.find(m => m.key === model.key)! const rows = await prisma.$queryRawUnsafe('SELECT id,stage,status,request_id,task_id,evidence,message FROM ai_model_verifications WHERE model_key=$1 AND actor_id=$2 AND idempotency_key=$3', model.key, actor.id, idempotencyKey) assert.equal(rows.length, 1) await save(`test-${modelId}`, { modelId, modelKey: model.key, providerId: provider.id, idempotencyKey, startedAt, status: rows[0].status, verification: fresh.verification.image, record: rows[0], productionTouched: false }) console.log(JSON.stringify({ modelId, status: rows[0].status, verification: fresh.verification.image, evidence: rows[0].evidence })) assert.equal(rows[0].status, 'passed', 'Real reference-image test must pass before release'); return } console.log(JSON.stringify(provider.models.filter(m => targets.includes(m.id) || m.id.endsWith('-cl')).map(m => ({ id: m.id, enabled: m.enabled, reason: m.capabilities.reason, stages: m.capabilities.allowedStages, verification: m.verification.image })))) } main().catch(error => { console.error(error instanceof Error ? error.message : 'Image acceptance failed'); process.exitCode = 1 }).finally(() => prisma.$disconnect())