flnxi-Wu/__tests__/production-build-hardening.test.ts

57 lines
2.5 KiB
TypeScript

import fs from 'fs'
import path from 'path'
describe('production build hardening', () => {
const root = process.cwd()
const dockerfile = fs.readFileSync(path.join(root, 'Dockerfile'), 'utf8')
const dockerignore = fs.readFileSync(path.join(root, '.dockerignore'), 'utf8')
const buildScript = fs.readFileSync(path.join(root, 'scripts/build-obfuscated.js'), 'utf8')
it('Docker 生产镜像必须走混淆构建', () => {
expect(dockerfile).toContain('npm run build:prod')
expect(dockerfile).not.toMatch(/\bnpm run build\s*$/m)
})
it('Docker 构建上下文必须包含混淆脚本和配置', () => {
expect(dockerignore).toContain('scripts/*')
expect(dockerignore).toContain('!scripts/build-obfuscated.js')
expect(dockerignore).toContain('!scripts/obfuscate-config.js')
expect(dockerignore).toContain('!scripts/docker-entrypoint.sh')
})
it('生产运行镜像只复制 Prisma 运行迁移所需文件', () => {
expect(dockerfile).toContain('RUN rm -rf ./prisma')
expect(dockerfile).toContain('/app/prisma/schema.prisma ./prisma/schema.prisma')
expect(dockerfile).toContain('/app/prisma/migrations ./prisma/migrations')
expect(dockerfile).not.toContain('/app/prisma ./prisma')
expect(dockerfile).not.toMatch(/COPY\s+--from=builder[\s\S]*\/app\/prisma\s+\.\/prisma/)
})
it('生产运行镜像不能额外复制未混淆源码目录', () => {
expect(dockerfile).not.toMatch(/COPY\s+--from=builder[^\n]*\/app\/lib\s+\.\/lib/)
expect(dockerfile).not.toMatch(/COPY\s+--from=builder[^\n]*\/app\/app\s+\.\/app/)
})
it('混淆依赖缺失时不能静默跳过', () => {
expect(buildScript).toContain('生产混淆不能跳过')
expect(buildScript).toContain('process.exit(1)')
expect(buildScript).not.toContain('跳过混淆步骤')
})
it('混淆目标缺失或混淆失败时不能继续出包', () => {
expect(buildScript).toContain('failedFiles')
expect(buildScript).toContain('没有找到需要混淆的目标文件')
expect(buildScript).toContain('混淆失败的目标文件')
})
it('混淆配置保持保守,避免破坏 Next.js 服务端产物', () => {
const { obfuscatorOptions } = require('../scripts/obfuscate-config')
expect(obfuscatorOptions.compact).toBe(true)
expect(obfuscatorOptions.stringArray).toBe(true)
expect(obfuscatorOptions.controlFlowFlattening).toBe(false)
expect(obfuscatorOptions.deadCodeInjection).toBe(false)
expect(obfuscatorOptions.renameGlobals).toBe(false)
})
})