gongxiangp2/scripts/material-preview-release-gate.test.mjs
WuYongJie a890660853 fix(materials): audit historical previews and gate production releases
Preserve known legacy failures by reviewed identity, probe material delivery before and after releases, and retain originals and downloads.
2026-10-23 19:47:58 +08:00

237 lines
16 KiB
JavaScript

import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { createRequire } from 'node:module'
import test from 'node:test'
import { bundleReleaseGate, buildPlan, canonicalDeliverySource, compareChecks, CRITICAL_MATERIAL_IDS, DELIVERY_FILES, KNOWN_LEGACY_MEMBERS_SHA256, normalizeDeliveryConfig, POLICY, runProbes, runReleaseStage, validateAccepted } from './material-preview-release-gate.mjs'
import { LEGACY_DOMAINS } from './check-legacy-storage-boundaries.mjs'
const sharp = createRequire(import.meta.url)('sharp')
const PNG = await sharp({ create: { width: 3, height: 2, channels: 3, background: '#4d5e6f' } }).png().toBuffer()
const hash = value => createHash('sha256').update(value).digest('hex')
const digest = value => hash(JSON.stringify(value))
const current = id => `https://s3.jiansun.vip/gongxiangpan/${id}.png`
const independent = id => `https://${LEGACY_DOMAINS[0]}/jsxiangche/${id}.png`
const compatible = id => `https://${LEGACY_DOMAINS[1]}/gongxiangpan/${id}.png`
const FRP = '<html><p>The server is powered by <a href="https://github.com/fatedier/frp">frp</a>.</p><p>Faithfully yours, frp.</p></html>'
const row = (materialId, registeredSource = current(materialId)) => ({ materialId, registeredSource, sourceSha256: hash(registeredSource) })
const code = Object.fromEntries(DELIVERY_FILES.map(file => [file, 'c'.repeat(64)]))
const config = { S3_ENDPOINT: 'http://192.168.58.20:9000', S3_BUCKET: 'gongxiangpan', S3_FILE_PATH: '由壹点AI/',
S3_PUBLIC_DOMAIN: 'https://s3.jiansun.vip/gongxiangpan', S3_REGION: 'us-east-1', SERVER_IP: '192.168.58.20', MINIO_API_PORT: '9000', APP_PUBLIC_URL: 'https://sc.jiansun.vip' }
const initial = () => [...CRITICAL_MATERIAL_IDS.map((id, i) => row(id, i ? current(id) : compatible(id))), row('legacy', independent('legacy')), row('untested-current'),
{ materialId: 'private-source', sourceSha256: hash('uploads/materials/private'), uncheckable: { classification: 'source_rejected', code: 'invalid_url' } }]
function database(rows) {
const events = []
const normalized = rows.map(r => ({ id: r.materialId, previewUrl: r.registeredSource || 'uploads/materials/private', materialType: '材质' })).sort((a, b) => a.id.localeCompare(b.id, 'en'))
return { events, prisma: { async $transaction(fn, options) {
events.push(options)
return fn({ async $executeRawUnsafe(sql) { events.push(sql) }, material: {
async count(query) { events.push(query); return normalized.length }, async findMany(query) {
events.push(query)
const start = query.cursor ? normalized.findIndex(r => r.id === query.cursor.id) + 1 : 0
return normalized.slice(start, start + query.take)
},
} })
} } }
}
const fixtureFetch = async url => {
const parsed = new URL(url)
if (parsed.hostname === LEGACY_DOMAINS[0]) return new Response(FRP, { status: 404, headers: { 'Content-Type': 'text/html' } })
if (parsed.hostname === LEGACY_DOMAINS[1]) throw new Error('old same-bucket route unavailable')
return new Response(PNG, { status: 200, headers: { 'Content-Type': 'image/png' } })
}
async function stage(stageName, rows, { accepted, capture, candidate, probeFetch = fixtureFetch, actualCode = code, targetCode = code, ...input } = {}) {
const db = database(rows)
const report = await runReleaseStage({ version: 1, stage: stageName, commit: 'b'.repeat(40), accepted, capture, candidate,
targetDeliveryConfig: config, ...input }, {
prismaClient: db.prisma, readDeliveryCode: async () => actualCode, targetDeliveryCode: targetCode,
environment: config, probe: plan => runProbes(plan, { fetchImpl: probeFetch }),
// Synthetic offline fixture proofs; the production stdin runner cannot supply
// these dependency injections and uses the fixed incident/original SHA values.
legacyFailureProof: { bytes: Buffer.byteLength(FRP), bodySha256: hash(FRP) },
compatibilityProof: { materialId: CRITICAL_MATERIAL_IDS[0], bodySha256: hash(PNG), width: 3, height: 2 },
legacyMembers: [row('legacy', independent('legacy'))],
})
assert.equal(db.events[1], 'SET TRANSACTION READ ONLY')
assert.deepEqual(db.events[0], { isolationLevel: 'RepeatableRead', timeout: 60_000, maxWait: 5000 })
return report
}
test('bootstrap records all metadata, exact 12 materials and all independent legacy rows without inventing health for omitted sources', async () => {
const report = await stage('bootstrap', initial())
assert.equal(report.passed, true)
assert.equal(report.allSelectedHealthy, false)
assert.equal(report.bootstrapRequiresExplicitShaReview, true)
assert.equal(report.inventory.length, 15)
assert.equal(report.plan.selected.length, 13)
assert.equal(report.checks.length, 14)
assert.equal(report.knownFailures.length, 2)
assert.equal(report.plan.unverified.length, 2)
assert.equal(report.plan.unverified.find(r => r.materialId === 'private-source').reason, 'unsupported_or_missing_registered_source')
assert.equal(report.budget.retries, 0)
validateAccepted(report)
assert.equal(report.checks.find(r => r.materialId === CRITICAL_MATERIAL_IDS[0] && r.role === 'registered').result.ok, false)
assert.equal(report.checks.find(r => r.materialId === CRITICAL_MATERIAL_IDS[0] && r.role === 'canonical').result.bodySha256, hash(PNG))
})
test('fixed same plan is checked before and after candidate with no metadata or content writes', async () => {
const accepted = await stage('bootstrap', initial())
const rows = [...initial(), row('new-current')]
const capture = await stage('capture', rows, { accepted })
const candidate = await stage('candidate', rows, { accepted, capture })
const post = await stage('post', rows, { accepted, capture, candidate })
assert.equal(capture.plan.selected.some(r => r.materialId === 'new-current' && r.reasons.includes('new_or_changed_source')), true)
assert.equal(post.passed, true)
assert.equal(post.planSha256, capture.planSha256)
assert.equal(candidate.planSha256, capture.planSha256)
assert.equal(post.inventorySha256, capture.inventorySha256)
validateAccepted(post)
})
test('missing or forged first baseline stops capture before image GET', async () => {
let calls = 0
await assert.rejects(stage('capture', initial(), { probeFetch: async () => { calls++; return fixtureFetch(current('x')) } }), /reviewed_baseline_required/)
const accepted = await stage('bootstrap', initial())
accepted.inventory.pop()
await assert.rejects(stage('capture', initial(), { accepted }), /baseline_digest_mismatch/)
assert.equal(calls, 0)
})
test('new failure or changed failure type blocks candidate; existing FRP incident remains explicit', async () => {
const accepted = await stage('bootstrap', initial()), capture = await stage('capture', initial(), { accepted })
const bad = await stage('candidate', initial(), { accepted, capture, probeFetch: async url => url === current(CRITICAL_MATERIAL_IDS[1])
? new Response('<html>failed</html>', { status: 200, headers: { 'Content-Type': 'text/html' } }) : fixtureFetch(url) })
assert.equal(bad.passed, false)
assert.ok(bad.problems.some(r => r.code === 'new_or_changed_failure'))
assert.ok(bad.knownFailures.some(r => r.materialId === 'legacy' && r.code === 'frp_default_404'))
const legacyChange = await stage('candidate', initial(), { accepted, capture, probeFetch: async url => url === independent('legacy')
? new Response('<Error><Code>NoSuchKey</Code></Error>', { status: 404, headers: { 'Content-Type': 'application/xml' } }) : fixtureFetch(url) })
assert.equal(legacyChange.passed, false)
})
test('a newly registered legacy failure cannot join the known baseline automatically', async () => {
const accepted = await stage('bootstrap', initial())
const capture = await stage('capture', [...initial(), row('new-legacy', independent('new-legacy'))], { accepted })
assert.equal(capture.passed, false)
assert.ok(capture.problems.some(r => r.materialId === 'new-legacy' && r.code === 'new_or_changed_failure'))
})
test('bootstrap only permits the exact documented FRP body and original canonical compatibility proof', async () => {
const wrongLegacy = await stage('bootstrap', initial(), { probeFetch: async url => url === independent('legacy')
? new Response(FRP + 'changed', { status: 404, headers: { 'Content-Type': 'text/html' } }) : fixtureFetch(url) })
assert.equal(wrongLegacy.passed, false)
const wrongCanonical = await stage('bootstrap', initial(), { probeFetch: async url => {
if (url !== current(CRITICAL_MATERIAL_IDS[0])) return fixtureFetch(url)
const different = await sharp({ create: { width: 3, height: 2, channels: 3, background: '#112233' } }).png().toBuffer()
return new Response(different, { headers: { 'Content-Type': 'image/png' } })
} })
assert.equal(wrongCanonical.passed, false)
})
test('bootstrap rejects an extra historical row, a replacement ID at equal count, and a changed historical source', async () => {
for (const rows of [
[...initial(), row('unreviewed-old', independent('unreviewed-old'))],
initial().map(r => r.materialId === 'legacy' ? row('replacement-old', independent('legacy')) : r),
initial().map(r => r.materialId === 'legacy' ? row('legacy', independent('different-source')) : r),
]) {
const bootstrap = await stage('bootstrap', rows)
assert.equal(bootstrap.passed, false)
assert.ok(bootstrap.problems.some(r => r.code === 'new_or_changed_failure'))
}
})
test('healthy same URL with different bytes requires review rather than silently rebaselining', async () => {
const accepted = await stage('bootstrap', initial()), capture = await stage('capture', initial(), { accepted })
const variant = await sharp({ create: { width: 3, height: 2, channels: 3, background: '#ffffff' } }).png().toBuffer()
const candidate = await stage('candidate', initial(), { accepted, capture, probeFetch: async url => url === current(CRITICAL_MATERIAL_IDS[1])
? new Response(variant, { headers: { 'Content-Type': 'image/png' } }) : fixtureFetch(url) })
assert.equal(candidate.passed, false)
assert.ok(candidate.problems.some(r => r.code === 'unchanged_url_content_changed'))
})
test('inventory drift, missing coverage, missing candidate, and detector failure all fail closed', async () => {
const accepted = await stage('bootstrap', initial()), capture = await stage('capture', initial(), { accepted })
await assert.rejects(stage('candidate', [...initial(), row('concurrent-upload')], { accepted, capture }), /inventory_or_capture_drift/)
await assert.rejects(stage('post', initial(), { accepted, capture }), /candidate_receipt_required/)
const broken = structuredClone(capture); broken.checks.pop(); broken.checksSha256 = digest(broken.checks)
await assert.rejects(stage('candidate', initial(), { accepted, capture: broken }), /probe_coverage_incomplete/)
const faulty = structuredClone(capture.checks)
faulty[0].result.ok = false; faulty[0].result.classification = 'decoder_unavailable'; faulty[0].result.code = 'image_decoder_unavailable'
assert.equal(compareChecks(capture.plan, faulty, capture).passed, false)
})
test('new unsupported source, absent key material and changes beyond budget cannot be dropped', async () => {
const accepted = await stage('bootstrap', initial())
await assert.rejects(stage('capture', [...initial(), { materialId: 'unsupported-new', sourceSha256: hash('x'), uncheckable: { code: 'invalid_url' } }], { accepted }), /new_or_changed_uncheckable_preview/)
assert.throws(() => buildPlan(initial().slice(1), accepted, { publicDomain: 'https://s3.jiansun.vip/gongxiangpan' }), /critical_material_coverage_missing/)
assert.throws(() => buildPlan([...initial(), ...Array.from({ length: POLICY.probes }, (_, i) => row(`new-${i}`))], accepted,
{ publicDomain: 'https://s3.jiansun.vip/gongxiangpan' }), /probe_budget_requires_independent_full_acceptance/)
})
test('delivery source or storage code changes expand scope and cannot skip large inventory', async () => {
const accepted = await stage('bootstrap', initial())
const changed = { ...code, [DELIVERY_FILES[0]]: 'd'.repeat(64) }
const capture = await stage('capture', initial(), { accepted, targetCode: changed })
assert.equal(capture.plan.expandedScope, true)
assert.ok(capture.plan.selected.some(r => r.materialId === 'untested-current'))
await assert.rejects(stage('candidate', initial(), { accepted, capture, targetCode: changed }), /candidate_delivery_identity_mismatch/)
const many = [...initial(), ...Array.from({ length: POLICY.probes }, (_, i) => row(`unchanged-${i}`))]
const largeBase = await stage('bootstrap', many)
await assert.rejects(stage('capture', many, { accepted: largeBase, targetCode: changed }), /probe_budget_requires_independent_full_acceptance/)
const outOfBand = await stage('capture', initial(), { accepted, actualCode: changed, targetCode: changed })
assert.equal(outOfBand.plan.expandedScope, true, 'a change since the accepted code baseline cannot disappear when target already equals current')
})
test('nonsecret delivery configuration changes expand scope and inconsistent candidate settings stop before GET', async () => {
const accepted = await stage('bootstrap', initial())
for (const [key, value] of [['S3_ENDPOINT', 'http://192.168.58.21:9000'], ['S3_BUCKET', 'other-bucket'], ['S3_FILE_PATH', 'other/'],
['SERVER_IP', '192.168.58.21'], ['MINIO_API_PORT', '9001'], ['S3_REGION', 'other-region']]) {
const targetDeliveryConfig = { ...config, [key]: value }
const capture = await stage('capture', initial(), { accepted, targetDeliveryConfig })
assert.equal(capture.plan.expandedScope, true, key)
await assert.rejects(stage('candidate', initial(), { accepted, capture, targetDeliveryConfig }), /candidate_delivery_identity_mismatch/)
}
await assert.rejects(stage('capture', initial(), { accepted, targetDeliveryConfig: undefined }), /complete_delivery_configuration_required/)
assert.throws(() => normalizeDeliveryConfig({ ...config, S3_ENDPOINT: 'http://user:secret@192.168.58.20:9000' }), /credential_or_query_in_delivery_configuration/)
assert.throws(() => normalizeDeliveryConfig({ ...config, S3_ACCESS_KEY_ID: 'must-not-be-logged' }), /complete_delivery_configuration_required/)
})
test('versioned historical membership proof exactly matches the independently reviewed 472 IDs and normalized source digests', async () => {
const { readFile } = await import('node:fs/promises')
const policy = JSON.parse(await readFile(new URL('./fixtures/material-preview-known-legacy-20261023.json', import.meta.url), 'utf8'))
assert.equal(policy.members.length, 472)
assert.equal(digest(policy.members), KNOWN_LEGACY_MEMBERS_SHA256)
assert.deepEqual(Object.keys(policy.members[0]).sort(), ['materialId', 'sourceSha256'])
assert.equal(JSON.stringify(policy).includes('https://'), false)
})
test('canonical mapping preserves bucket and key and never rewrites independent old storage', () => {
assert.equal(canonicalDeliverySource(independent('original'), 'https://s3.jiansun.vip/gongxiangpan'), independent('original'))
assert.equal(canonicalDeliverySource(compatible('%E4%B8%AD%E6%96%87'), 'https://s3.jiansun.vip/gongxiangpan'), current('%E4%B8%AD%E6%96%87'))
assert.throws(() => canonicalDeliverySource(compatible('x'), 'https://elsewhere.invalid/gongxiangpan'), /untrusted_public_bucket_configuration/)
})
test('read-only probe queue is bounded to four requests and one attempt with a fixed wall budget', async () => {
const accepted = await stage('bootstrap', initial()), plan = buildPlan(initial(), accepted, { publicDomain: 'https://s3.jiansun.vip/gongxiangpan' })
let active = 0, peak = 0, calls = 0
await runProbes(plan, { fetchImpl: async (url, options) => {
calls++; peak = Math.max(peak, ++active)
assert.equal(options.method, 'GET'); assert.equal(options.redirect, 'manual'); assert.equal(options.cache, 'no-store')
await new Promise(resolve => setTimeout(resolve, 2)); active--
return fixtureFetch(url)
} })
assert.equal(calls, plan.probes.length); assert.equal(peak, POLICY.concurrency)
let time = 0
await assert.rejects(runProbes(plan, { now: () => (time += POLICY.wallMs), fetchImpl: () => { throw Error('must not fetch') } }), /release_probe_wall_budget/)
})
test('exact-checkout bundle loads without an old image containing new scripts', async () => {
const bundle = await bundleReleaseGate(undefined, { runtimeBase: new URL('../package.json', import.meta.url).href })
assert.ok(bundle.length < 524288)
const gate = await import(bundle)
assert.equal(typeof gate.runReleaseStage, 'function')
assert.deepEqual(gate.POLICY, POLICY)
})