启用生产镜像服务端混淆构建
This commit is contained in:
parent
c7d93111c4
commit
b267b36486
@ -59,9 +59,11 @@ docs
|
||||
*.md
|
||||
!VERSION.txt
|
||||
|
||||
# 脚本(保留 docker-entrypoint.sh)
|
||||
scripts
|
||||
# 脚本(只保留生产构建和容器启动必需入口)
|
||||
scripts/*
|
||||
!scripts/docker-entrypoint.sh
|
||||
!scripts/build-obfuscated.js
|
||||
!scripts/obfuscate-config.js
|
||||
|
||||
# 临时文件
|
||||
uploads
|
||||
|
||||
@ -158,7 +158,7 @@ RUN if [ ! -d "node_modules/.prisma" ]; then \
|
||||
fi
|
||||
|
||||
# 构建 Next.js 应用(standalone 模式)
|
||||
# 商业交付镜像必须在构建阶段暴露失败,不能吞掉构建错误继续出包。
|
||||
# 商业交付镜像必须完成服务端混淆;混淆失败不能继续出包。
|
||||
RUN set -ex && \
|
||||
if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
|
||||
export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
|
||||
@ -172,7 +172,7 @@ RUN if [ ! -d "node_modules/.prisma" ]; then \
|
||||
else \
|
||||
unset PRISMA_SCHEMA_ENGINE_BINARY; \
|
||||
fi && \
|
||||
npm run build
|
||||
npm run build:prod
|
||||
|
||||
# 验证构建产物(允许 ESLint 警告,但不允许致命错误)
|
||||
RUN if [ ! -f ".next/standalone/server.js" ]; then \
|
||||
|
||||
37
__tests__/production-build-hardening.test.ts
Normal file
37
__tests__/production-build-hardening.test.ts
Normal file
@ -0,0 +1,37 @@
|
||||
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('混淆依赖缺失时不能静默跳过', () => {
|
||||
expect(buildScript).toContain('生产混淆不能跳过')
|
||||
expect(buildScript).toContain('process.exit(1)')
|
||||
expect(buildScript).not.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)
|
||||
})
|
||||
})
|
||||
@ -1238,6 +1238,8 @@ NAS 私有化系统可能在平板或窄屏浏览器里使用。模板编辑器
|
||||
- `docker-compose.source-test.yml` 的 MinIO 和 MinIO Client 默认值已改成固定版本,源码测试入口不再默认使用 `latest`。
|
||||
- `docs/deployment/部署说明.md` 已把 `APP_IMAGE` 必填、HTTP Registry 前置配置、版本化发布命令和完整 `APP_IMAGE` 回滚写成主线步骤。
|
||||
- `Dockerfile` 已取消 `npm run build` 失败后继续出镜像的逻辑;构建失败会直接阻断镜像产出。
|
||||
- `Dockerfile` 已改为生产镜像执行 `npm run build:prod`,构建后会对服务端 chunks 和许可证 API 产物做混淆;混淆失败会直接阻断镜像产出,避免“脚本存在但客户镜像未启用”的防拆空档。
|
||||
- `scripts/build-obfuscated.js`、`scripts/obfuscate-config.js`、`.dockerignore`:混淆依赖缺失不再静默跳过;Docker 构建上下文只放行生产构建和容器启动必需脚本,确保混淆配置能进入构建阶段。
|
||||
- `deploy-new-fixed.ps1`、`发布管理.ps1`、`license-server/deploy.ps1` 已加默认停止闸门;不追加明确确认参数时不会继续执行旧服务器、旧 Harbor、许可证部署或 Docker 清理逻辑。
|
||||
- `flnxi-agent/README.md` 已把 Node 版 Agent 定位改成历史实现说明,不再把 Docker 运行命令写成新客户推荐安装方式。
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ npm run verify:template-data
|
||||
- `build-material-image.ps1`
|
||||
构建主应用镜像。它属于历史/内部维护备用入口,保留旧的测试/正式分层规则,但仍带 Harbor / `latest` 旧口径;客户正式交付、升级、回滚优先用根目录的 `deploy-registry.ps1`,不要把它当成客户升级主线。若确需用它推送旧 Harbor,必须显式追加 `-AcknowledgeLegacyHarborPush`。
|
||||
- `build-obfuscated.js`
|
||||
生产构建后的混淆处理
|
||||
生产构建后的服务端混淆处理。客户交付镜像通过 `Dockerfile` 执行 `npm run build:prod` 时会自动调用;混淆依赖或配置缺失会直接失败,不能静默跳过。
|
||||
- `docker-entrypoint.sh`
|
||||
主应用容器启动入口
|
||||
- `generate-shared-test-env.ps1`
|
||||
|
||||
@ -20,9 +20,9 @@ let JavaScriptObfuscator;
|
||||
try {
|
||||
JavaScriptObfuscator = require('javascript-obfuscator');
|
||||
} catch {
|
||||
console.log('⚠️ javascript-obfuscator 未安装,跳过混淆步骤');
|
||||
console.log(' 如需启用混淆,请运行: npm install -D javascript-obfuscator');
|
||||
process.exit(0);
|
||||
console.error('❌ javascript-obfuscator 未安装,生产混淆不能跳过');
|
||||
console.error(' 请先运行: npm install');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const { obfuscatorOptions } = require('./obfuscate-config');
|
||||
|
||||
27
scripts/obfuscate-config.js
Normal file
27
scripts/obfuscate-config.js
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Production obfuscation options.
|
||||
*
|
||||
* Keep this conservative: the goal is to raise reverse-engineering cost for
|
||||
* server-side license and paid-feature code without making Next.js output
|
||||
* brittle or dramatically increasing bundle size.
|
||||
*/
|
||||
const obfuscatorOptions = {
|
||||
compact: true,
|
||||
controlFlowFlattening: false,
|
||||
deadCodeInjection: false,
|
||||
debugProtection: false,
|
||||
disableConsoleOutput: false,
|
||||
identifierNamesGenerator: 'hexadecimal',
|
||||
renameGlobals: false,
|
||||
rotateStringArray: true,
|
||||
selfDefending: false,
|
||||
simplify: true,
|
||||
splitStrings: false,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: ['base64'],
|
||||
stringArrayThreshold: 0.35,
|
||||
transformObjectKeys: false,
|
||||
unicodeEscapeSequence: false,
|
||||
}
|
||||
|
||||
module.exports = { obfuscatorOptions }
|
||||
Loading…
x
Reference in New Issue
Block a user