gongxiangp2/scripts/check-legacy-storage-boundaries.test.mjs
chenpei 7326e273e1 fix: harden media upload and release safety
Protect upload cleanup and atomic completion paths, add durable media worker leases and brand asset validation, and introduce verified migration/bootstrap/deployment gates.
2026-08-12 18:04:08 +08:00

186 lines
7.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import assert from 'node:assert/strict'
import { promises as fs } from 'node:fs'
import path from 'node:path'
import test from 'node:test'
import {
scanLegacyStorageBoundaries,
TEMP_ROOT,
} from './check-legacy-storage-boundaries.mjs'
async function withFixture(files, callback) {
const root = await fs.mkdtemp(path.join(TEMP_ROOT, 'legacy-storage-boundary-'))
try {
for (const [relativePath, content] of Object.entries(files)) {
const absolutePath = path.join(root, relativePath)
await fs.mkdir(path.dirname(absolutePath), { recursive: true })
await fs.writeFile(absolutePath, content, 'utf8')
}
await callback(root)
} finally {
await fs.rm(root, { recursive: true, force: true })
}
}
test('拦截新 migration、Dockerfile 和 PowerShell 中的旧域名', async () => {
await withFixture({
'prisma/migrations/20260812_bad/migration.sql': "ALTER TABLE x SET DEFAULT 'https://s3.1080p.hk/x'",
Dockerfile: 'ENV STORAGE=https://s3.yydd.ai',
'scripts/deploy.ps1': "$target = 'https://s3.1080p.hk'",
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.deepEqual(
violations.map(item => item.relativePath).sort(),
['Dockerfile', 'prisma/migrations/20260812_bad/migration.sql', 'scripts/deploy.ps1'],
)
})
})
test('旧域名匹配不区分大小写,并覆盖常见前端与容器文件', async () => {
await withFixture({
'Dockerfile.production': 'ENV STORAGE=https://S3.1080P.HK',
'Containerfile.worker': 'ENV STORAGE=https://S3.YYDD.AI',
'components/legacy.jsx': "const host='https://S3.1080P.HK'",
'styles/legacy.scss': 'body{background:url(https://S3.YYDD.AI/a.png)}',
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.deepEqual(
violations.map(item => item.relativePath).sort(),
[
'Containerfile.worker',
'Dockerfile.production',
'components/legacy.jsx',
'styles/legacy.scss',
],
)
})
})
test('只跳过仓库根 uploads 数据,不得漏扫源码中的 uploads 路由', async () => {
await withFixture({
'uploads/runtime-data.json': '{"legacy":"https://s3.1080p.hk/data"}',
'app/api/uploads/[...path]/route.ts': "const target='https://s3.1080p.hk/source'",
'app/uploads/[...path]/route.ts': "const target='https://s3.yydd.ai/source'",
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.deepEqual(
violations.map(item => item.relativePath).sort(),
['app/api/uploads/[...path]/route.ts', 'app/uploads/[...path]/route.ts'],
)
})
})
test('allowlist 文件缺标记或精确计数变化时也会失败', async () => {
await withFixture({
'lib/network-detection.ts': "// LEGACY_READ_ONLY\nconst hosts=['s3.1080p.hk']",
'lib/url-rewrite.ts': "const target='s3.1080p.hk'",
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.equal(violations.length, 2)
})
})
test('精确只读兼容和唯一历史 migration 可以通过', async () => {
await withFixture({
'lib/network-detection.ts': "// LEGACY_READ_ONLY\nconst hosts=['s3.1080p.hk','s3.yydd.ai']",
'prisma/migrations/20251026015433_add_material_type/migration.sql': "DEFAULT 'https://s3.1080p.hk/logo.png'",
}, async root => {
assert.deepEqual(await scanLegacyStorageBoundaries(root), [])
})
})
test('品牌 migration 精确清洗旧品牌值并中和三个 Logo 默认值', async () => {
const migrationPath = path.join(
process.cwd(),
'prisma/migrations/20260811_update_brand_logo_defaults/migration.sql',
)
const content = await fs.readFile(migrationPath, 'utf8')
assert.equal((content.match(/s3\\\.1080p\\\.hk/gi) || []).length, 2)
assert.match(content, /LEGACY_DATA_REMEDIATION/)
assert.match(content, /UPDATE "system_settings"\s+SET "headerLogoUrl" = '\/brand\/header-logo\.png'/)
assert.match(content, /UPDATE "system_settings"\s+SET "loginLogoUrl" = '\/brand\/login-logo\.png'/)
assert.doesNotMatch(content, /DEFAULT[^;\n]*s3\.1080p\.hk/i)
assert.match(content, /"headerLogoUrl"[\s\S]*DEFAULT '\/brand\/header-logo\.png'/)
assert.match(content, /"loginLogoUrl"[\s\S]*DEFAULT '\/brand\/login-logo\.png'/)
assert.match(content, /ALTER COLUMN "logoUrl" SET DEFAULT '\/brand\/header-logo\.png'/)
await withFixture({
'prisma/migrations/20260811_update_brand_logo_defaults/migration.sql': content,
}, async root => {
assert.deepEqual(await scanLegacyStorageBoundaries(root), [])
})
})
test('品牌数据修复标记不能放行默认值回写或任意新 migration', async () => {
const shapedButUnsafe = `-- LEGACY_DATA_REMEDIATION
UPDATE "system_settings"
SET "headerLogoUrl" = '/brand/header-logo.png'
WHERE "headerLogoUrl" ~* '^https?://s3\\.1080p\\.hk(?:/|$)';
UPDATE "system_settings"
SET "loginLogoUrl" = '/brand/login-logo.png'
WHERE "loginLogoUrl" ~* '^https?://s3\\.1080p\\.hk(?:/|$)';
ALTER TABLE "system_settings" ALTER COLUMN "logoUrl" SET DEFAULT 'https://s3.1080p.hk/logo.png';`
await withFixture({
'prisma/migrations/20260811_update_brand_logo_defaults/migration.sql': shapedButUnsafe,
'prisma/migrations/20260812_bad/migration.sql': shapedButUnsafe,
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.deepEqual(
violations.map(item => item.relativePath).sort(),
[
'prisma/migrations/20260811_update_brand_logo_defaults/migration.sql',
'prisma/migrations/20260812_bad/migration.sql',
],
)
})
})
test('默认 Compose 拒绝相对 uploads,并要求容器路径和禁止自动建目录', async () => {
await withFixture({
'docker-compose.yml': `services:
app:
environment:
- UPLOAD_DIR=./uploads
volumes:
- ./uploads:/app/uploads
`,
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.equal(violations.length, 1)
assert.equal(violations[0].relativePath, 'docker-compose.yml')
assert.match(violations[0].reasons.join('\n'), /relative uploads bind/)
assert.match(violations[0].reasons.join('\n'), /UPLOAD_DIR=\/app\/uploads/)
assert.match(violations[0].reasons.join('\n'), /GONGXIANGP2_UPLOADS_MOUNT/)
assert.match(violations[0].reasons.join('\n'), /automatic host-path creation/)
})
})
test('默认 Compose 只接受显式宿主机挂载变量与固定容器路径', async () => {
await withFixture({
'docker-compose.yml': `services:
app:
environment:
UPLOAD_DIR: /app/uploads
volumes:
- type: bind
source: \${GONGXIANGP2_UPLOADS_MOUNT:?required}
target: /app/uploads
bind:
create_host_path: false
`,
}, async root => {
assert.deepEqual(await scanLegacyStorageBoundaries(root), [])
})
})
test('相对 uploads 只允许出现在名称明确的非生产 Compose', async () => {
await withFixture({
'docker-compose.dev.yml': `services:\n app:\n volumes:\n - ./uploads:/app/uploads\n`,
'docker-compose.production.yml': `services:\n app:\n volumes:\n - \${GONGXIANGP2_UPLOADS_MOUNT:-./uploads}:/app/uploads\n`,
'docker-compose.shadow.yml': `services:\n app:\n volumes:\n - ./uploads-shadow:/app/uploads\n`,
}, async root => {
const violations = await scanLegacyStorageBoundaries(root)
assert.deepEqual(violations.map(item => item.relativePath), ['docker-compose.production.yml'])
})
})