fix: mitigate npm dependency advisories
This commit is contained in:
Generated
+54
-47
@@ -15,6 +15,7 @@
|
|||||||
"@nestjs/swagger": "^11.2.3",
|
"@nestjs/swagger": "^11.2.3",
|
||||||
"@prisma/adapter-pg": "^7.9.0",
|
"@prisma/adapter-pg": "^7.9.0",
|
||||||
"@prisma/client": "^7.9.0",
|
"@prisma/client": "^7.9.0",
|
||||||
|
"brace-expansion": "file:vendor/brace-expansion-compat",
|
||||||
"bullmq": "^5.79.2",
|
"bullmq": "^5.79.2",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
@@ -2918,14 +2919,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/archiver-utils/node_modules/brace-expansion": {
|
"node_modules/archiver-utils/node_modules/brace-expansion": {
|
||||||
"version": "1.1.16",
|
"resolved": "node_modules/archiver-utils/node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
"link": true
|
||||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/archiver-utils/node_modules/glob": {
|
"node_modules/archiver-utils/node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
@@ -2960,6 +2955,7 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/archiver-utils/node_modules/minimatch/vendor/brace-expansion-compat": {},
|
||||||
"node_modules/archiver-utils/node_modules/readable-stream": {
|
"node_modules/archiver-utils/node_modules/readable-stream": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
@@ -3128,10 +3124,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "18 || 20 || >=22"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/base64-js": {
|
"node_modules/base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
@@ -3259,12 +3258,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "2.1.2",
|
"resolved": "vendor/brace-expansion-compat",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz",
|
"link": true
|
||||||
"integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==",
|
},
|
||||||
|
"node_modules/brace-expansion-safe": {
|
||||||
|
"name": "brace-expansion",
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0"
|
"balanced-match": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browser-or-node": {
|
"node_modules/browser-or-node": {
|
||||||
@@ -3811,12 +3818,6 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/concat-stream": {
|
"node_modules/concat-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||||
@@ -6645,6 +6646,13 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/minimatch/node_modules/brace-expansion": {
|
||||||
|
"resolved": "node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/minimatch/vendor/brace-expansion-compat": {
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.8",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
@@ -7676,6 +7684,10 @@
|
|||||||
"minimatch": "^5.1.0"
|
"minimatch": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readdir-glob/node_modules/brace-expansion": {
|
||||||
|
"resolved": "node_modules/readdir-glob/node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/readdir-glob/node_modules/minimatch": {
|
"node_modules/readdir-glob/node_modules/minimatch": {
|
||||||
"version": "5.1.9",
|
"version": "5.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||||
@@ -7688,6 +7700,7 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readdir-glob/node_modules/minimatch/vendor/brace-expansion-compat": {},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
|
||||||
@@ -7816,14 +7829,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rimraf/node_modules/brace-expansion": {
|
"node_modules/rimraf/node_modules/brace-expansion": {
|
||||||
"version": "1.1.16",
|
"resolved": "node_modules/rimraf/node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
"link": true
|
||||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/rimraf/node_modules/glob": {
|
"node_modules/rimraf/node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
@@ -7858,6 +7865,7 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rimraf/node_modules/minimatch/vendor/brace-expansion-compat": {},
|
||||||
"node_modules/robust-predicates": {
|
"node_modules/robust-predicates": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz",
|
||||||
@@ -8568,15 +8576,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/test-exclude/node_modules/brace-expansion": {
|
"node_modules/test-exclude/node_modules/brace-expansion": {
|
||||||
"version": "1.1.16",
|
"resolved": "node_modules/test-exclude/node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
"link": true
|
||||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/test-exclude/node_modules/glob": {
|
"node_modules/test-exclude/node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
@@ -8613,6 +8614,9 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/test-exclude/node_modules/minimatch/vendor/brace-expansion-compat": {
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/through2": {
|
"node_modules/through2": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
|
||||||
@@ -9480,14 +9484,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zip-stream/node_modules/brace-expansion": {
|
"node_modules/zip-stream/node_modules/brace-expansion": {
|
||||||
"version": "1.1.16",
|
"resolved": "node_modules/zip-stream/node_modules/minimatch/vendor/brace-expansion-compat",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
"link": true
|
||||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/zip-stream/node_modules/glob": {
|
"node_modules/zip-stream/node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
@@ -9521,6 +9519,15 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zip-stream/node_modules/minimatch/vendor/brace-expansion-compat": {},
|
||||||
|
"vendor/brace-expansion-compat": {
|
||||||
|
"name": "brace-expansion",
|
||||||
|
"version": "5.0.8-compat.1",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion-safe": "npm:brace-expansion@5.0.8"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"bullmq": "^5.79.2",
|
"bullmq": "^5.79.2",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
|
"brace-expansion": "file:vendor/brace-expansion-compat",
|
||||||
"exceljs": "^4.4.0",
|
"exceljs": "^4.4.0",
|
||||||
"ioredis": "^5.11.1",
|
"ioredis": "^5.11.1",
|
||||||
"minio": "^8.0.7",
|
"minio": "^8.0.7",
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
"brace-expansion": "$brace-expansion",
|
||||||
"exceljs": {
|
"exceljs": {
|
||||||
"uuid": "11.1.1"
|
"uuid": "11.1.1"
|
||||||
},
|
},
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
# brace-expansion compatibility adapter
|
||||||
|
|
||||||
|
Older `minimatch` releases call `require('brace-expansion')` as a function,
|
||||||
|
while the security-fixed 5.x package exposes a named `expand` function.
|
||||||
|
This adapter preserves the legacy callable CommonJS API and delegates all
|
||||||
|
expansion work to the bounded `brace-expansion@5.0.8` implementation.
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const boundedBraceExpansion = require('brace-expansion-safe');
|
||||||
|
|
||||||
|
function expand(pattern, options) {
|
||||||
|
return boundedBraceExpansion.expand(pattern, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(expand, boundedBraceExpansion);
|
||||||
|
|
||||||
|
module.exports = expand;
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "brace-expansion",
|
||||||
|
"version": "5.0.8-compat.1",
|
||||||
|
"private": true,
|
||||||
|
"description": "CommonJS compatibility adapter for the bounded brace-expansion 5.0.8 implementation",
|
||||||
|
"main": "index.cjs",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"brace-expansion-safe": "npm:brace-expansion@5.0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1677,6 +1677,14 @@
|
|||||||
1. 运营端“系统日志”必须将人员操作审计与协议通讯日志分成两个独立页签。通讯日志至少支持协议、交互方向、事件类型、结果、关键字和时间范围过滤,并展示平台消息号、上游消息号或HTTP请求号、脱敏对象、结果码、耗时和安全详情。
|
1. 运营端“系统日志”必须将人员操作审计与协议通讯日志分成两个独立页签。通讯日志至少支持协议、交互方向、事件类型、结果、关键字和时间范围过滤,并展示平台消息号、上游消息号或HTTP请求号、脱敏对象、结果码、耗时和安全详情。
|
||||||
2. CMPP应覆盖客户登录/Submit、供应商SubmitResp、状态报告Deliver、上行Deliver及平台下游投递;HTTP应覆盖客户发送请求和平台回执/上行Webhook。数据库中一条记录必须对应一个真实业务报文,不得把同一报文的“入口收到”和“处理成功”拆成两条记录;处理结果、结果码和耗时写在该报文同一条记录中,失败、重试等后续真实交互另行记录。
|
2. CMPP应覆盖客户登录/Submit、供应商SubmitResp、状态报告Deliver、上行Deliver及平台下游投递;HTTP应覆盖客户发送请求和平台回执/上行Webhook。数据库中一条记录必须对应一个真实业务报文,不得把同一报文的“入口收到”和“处理成功”拆成两条记录;处理结果、结果码和耗时写在该报文同一条记录中,失败、重试等后续真实交互另行记录。
|
||||||
3. Gateway收到状态报告或上行后,必须对解包/解码失败及转发NestJS失败输出结构化安全日志;NestJS入口把业务处理结果合并回同一报文记录,以便区分“上游未发”“Gateway未收到”“Gateway转发失败”和“API落库失败”。一条正常短短信的供应商侧完整成功闭环应依次展示四个真实报文:平台→通道 `CMPP_SUBMIT`、通道→平台 `CMPP_SUBMIT_RESP`、通道→平台 `CMPP_DELIVER`、平台→通道 `CMPP_DELIVER_RESP`;箭头只表达报文实际传输方向。
|
3. Gateway收到状态报告或上行后,必须对解包/解码失败及转发NestJS失败输出结构化安全日志;NestJS入口把业务处理结果合并回同一报文记录,以便区分“上游未发”“Gateway未收到”“Gateway转发失败”和“API落库失败”。一条正常短短信的供应商侧完整成功闭环应依次展示四个真实报文:平台→通道 `CMPP_SUBMIT`、通道→平台 `CMPP_SUBMIT_RESP`、通道→平台 `CMPP_DELIVER`、平台→通道 `CMPP_DELIVER_RESP`;箭头只表达报文实际传输方向。
|
||||||
|
|
||||||
|
## 2026-07-26 依赖安全治理补充
|
||||||
|
|
||||||
|
- 依赖安全整改不得直接执行 `npm audit fix --force`;必须逐条核对公告的真实利用条件、当前代码调用路径、目标版本兼容性和生产依赖/构建工具边界,并通过干净安装、全量测试和生产构建。
|
||||||
|
- 前端不得引入 React Router 实验性 RSC 服务端 API;在官方发布兼容修复版前,必须由自动门禁扫描源码并固定已验证的客户端 SPA 版本。仅因审计建议降级到包含已知 XSS、RCE 或 DoS 公告的旧版本属于禁止操作。
|
||||||
|
- PostCSS 必须固定到 `8.5.18` 或更高修复版本。平台不得接受用户 CSS 后交由构建链处理;如未来新增此能力,必须显式禁用不可信 previous source map 自动加载并重新开展威胁建模。
|
||||||
|
- ExcelJS 的旧版 `minimatch` 调用接口与安全修复版 `brace-expansion` 5.x 不兼容时,允许使用受测试的本地 CommonJS 兼容适配层;适配层只能转发到官方有长度上限的实现,必须同时验证旧版 minimatch 花括号匹配、Excel 读写和干净 `npm ci`。
|
||||||
|
- Prisma CLI 只用于生成、迁移和构建,不属于 API 请求运行路径。其无上游修复版本的中危工具链公告需记录接受条件并持续跟踪,不得为审计数字清零而把 Prisma 7 数据访问栈盲目降级到 6.x。
|
||||||
4. 通讯日志不得保存短信正文、密码、密钥、Token、签名鉴权值或完整HTTP请求体;手机号只保存脱敏值。CMPP心跳不得逐包写入数据库,连接健康仍使用连接状态和聚合指标。
|
4. 通讯日志不得保存短信正文、密码、密钥、Token、签名鉴权值或完整HTTP请求体;手机号只保存脱敏值。CMPP心跳不得逐包写入数据库,连接健康仍使用连接状态和聚合指标。
|
||||||
5. 通讯日志写入不能阻塞短信主链路,默认批量异步写入,缓冲区应有上限和溢出告警;热数据默认保留30天,保留期允许通过环境变量配置。
|
5. 通讯日志写入不能阻塞短信主链路,默认批量异步写入,缓冲区应有上限和溢出告警;热数据默认保留30天,保留期允许通过环境变量配置。
|
||||||
6. 通讯日志方向固定使用“企业应用 → 平台、平台 → 供应商通道、供应商通道 → 平台、平台 → 企业应用”。供应商长短信每个真实 `SUBMIT` 和 `SUBMIT_RESP` 分片各记一条,企业应用每个真实 `SUBMIT_RESP` 也必须记录;内部 `submit-result` 聚合回调不是协议报文,不得重复生成通讯日志。
|
6. 通讯日志方向固定使用“企业应用 → 平台、平台 → 供应商通道、供应商通道 → 平台、平台 → 企业应用”。供应商长短信每个真实 `SUBMIT` 和 `SUBMIT_RESP` 分片各记一条,企业应用每个真实 `SUBMIT_RESP` 也必须记录;内部 `submit-result` 聚合回调不是协议报文,不得重复生成通讯日志。
|
||||||
|
|||||||
@@ -2451,3 +2451,12 @@ git diff --check
|
|||||||
- 新增 migration `20260725160000_add_reliable_receipt_delivery_tracking`,仅新增下游逐次投递表、上游回执收件箱及索引/外键,不改写既有短信、提交、回执或投递历史。回滚必须先停止新版本 API/Gateway,再删除两张新表;回滚会丢失新版本产生的逐次投递和待匹配收件箱证据。
|
- 新增 migration `20260725160000_add_reliable_receipt_delivery_tracking`,仅新增下游逐次投递表、上游回执收件箱及索引/外键,不改写既有短信、提交、回执或投递历史。回滚必须先停止新版本 API/Gateway,再删除两张新表;回滚会丢失新版本产生的逐次投递和待匹配收件箱证据。
|
||||||
- 发布前门禁通过:Prisma format/generate/validate,API 定向 3 suites / 119 tests,API 全量 26 suites / 325 tests,API TypeScript build,前端 TypeScript/Vite生产构建及 Gateway `go test ./...`。API 全量仅保留既有 Redis 不可用容错告警和 `--forceExit` 异步句柄提示;前端保留既有约 1.94 MB 单 chunk 警告。`git diff --check`通过。
|
- 发布前门禁通过:Prisma format/generate/validate,API 定向 3 suites / 119 tests,API 全量 26 suites / 325 tests,API TypeScript build,前端 TypeScript/Vite生产构建及 Gateway `go test ./...`。API 全量仅保留既有 Redis 不可用容错告警和 `--forceExit` 异步句柄提示;前端保留既有约 1.94 MB 单 chunk 警告。`git diff --check`通过。
|
||||||
- 本节当前为发布前记录;提交、推送、数据库/源码/环境备份、migration、服务重启和预发布只读验收结果在发布完成后追加。未经额外授权不发送真实短信,不改写历史业务记录。
|
- 本节当前为发布前记录;提交、推送、数据库/源码/环境备份、migration、服务重启和预发布只读验收结果在发布完成后追加。未经额外授权不发送真实短信,不改写历史业务记录。
|
||||||
|
|
||||||
|
## 2026-07-26 npm 依赖安全整改(发布前)
|
||||||
|
|
||||||
|
- 根项目将 PostCSS 从 `8.5.15` 固定到已修复的 `8.5.23`,对应任意 `.map` 文件路径穿越公告已从审计中消失;平台没有接收用户 CSS 并交给 PostCSS 的运行时路径。
|
||||||
|
- React Router 保持并精确固定当前最新版 `7.18.1`。实测按审计建议降到 `7.11.0` 会重新引入多条 XSS、开放重定向、反序列化和 DoS 公告,因此未采用。当前唯一剩余 high 为实验性 RSC 模式 CSRF,项目实际使用 `HashRouter` 客户端 SPA;新增 `security:verify` 门禁递归扫描前端源码,禁止引入 RSC 服务端 API。
|
||||||
|
- API 将 ExcelJS 间接使用的 `brace-expansion` 替换为官方长度受限的 `5.0.8`,同时增加本地 CommonJS 兼容适配层,使旧版 minimatch 的函数调用方式继续有效。直接覆盖 5.0.8 曾被兼容性测试明确拦截(`expand is not a function`),未把审计清零冒充功能可用。
|
||||||
|
- 独立 Linux 临时目录从锁文件执行两次全新 `npm ci --ignore-scripts` 成功:根项目 59 个包、API 726 个包;旧版 minimatch 三条真实依赖链花括号匹配和长度上限均通过。整改后根项目审计只剩同一条不适用 RSC 公告的 2 个依赖节点,API high 从 26 降为 0,仅剩 Prisma CLI→Valibot 的 3 个 moderate;该工具链不处理 API 请求且上游暂无修复版本,不降级 Prisma 7。
|
||||||
|
- 功能门禁通过:报备 Excel 专项 1 suite / 7 tests,API 全量 26 suites / 325 tests,API TypeScript build,前端 TypeScript/Vite生产构建,Gateway `go test ./...`、`go vet ./...`,以及依赖安全门禁。标准部署脚本也会在干净安装后、Prisma migration 前强制执行该门禁,失败即停止发布。前端保留既有约 1.94 MB 单 chunk 提示;API 测试保留既有 Redis 容错告警和 `--forceExit` 异步句柄提示。
|
||||||
|
- Windows 本地完整 `npm ci` 因另一进程占用两个原生 `.node` 文件而无法清理旧目录,未结束未知会话进程;随后非破坏性 `npm install` 修复本地依赖。锁文件可重建性以隔离 Linux 干净安装结果为准。提交、推送和预发布部署结果待发布后补记。
|
||||||
|
|||||||
Generated
+8
-8
@@ -16,7 +16,7 @@
|
|||||||
"lucide-react": "^1.18.0",
|
"lucide-react": "^1.18.0",
|
||||||
"react": "^19.2.7",
|
"react": "^19.2.7",
|
||||||
"react-dom": "^19.2.7",
|
"react-dom": "^19.2.7",
|
||||||
"react-router-dom": "^7.18.1",
|
"react-router-dom": "7.18.1",
|
||||||
"vite": "^8.0.16",
|
"vite": "^8.0.16",
|
||||||
"zustand": "^5.0.14"
|
"zustand": "^5.0.14"
|
||||||
},
|
},
|
||||||
@@ -1062,9 +1062,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.12",
|
"version": "3.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1119,9 +1119,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.15",
|
"version": "8.5.23",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
|
||||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
"integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -1138,7 +1138,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.12",
|
"nanoid": "^3.3.16",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
|
|||||||
+5
-1
@@ -11,6 +11,7 @@
|
|||||||
"start:local": "powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-local.ps1",
|
"start:local": "powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-local.ps1",
|
||||||
"start:local:minio": "powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-local.ps1 -OnlyMinio",
|
"start:local:minio": "powershell -NoProfile -ExecutionPolicy Bypass -File tools/start-local.ps1 -OnlyMinio",
|
||||||
"prisma:generate": "npm --prefix api run prisma:generate",
|
"prisma:generate": "npm --prefix api run prisma:generate",
|
||||||
|
"security:verify": "node tools/security/verify-dependency-mitigations.mjs",
|
||||||
"spike:contracts": "node tools/spike/validate-gateway-queue-contract.mjs",
|
"spike:contracts": "node tools/spike/validate-gateway-queue-contract.mjs",
|
||||||
"spike:gateway": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"$env:Path='C:\\Program Files\\Go\\bin;'+$env:Path; Push-Location gateway; go test ./...; Pop-Location\"",
|
"spike:gateway": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"$env:Path='C:\\Program Files\\Go\\bin;'+$env:Path; Push-Location gateway; go test ./...; Pop-Location\"",
|
||||||
"spike:bullmq": "node api/src/spike/bullmq-link-spike.mjs",
|
"spike:bullmq": "node api/src/spike/bullmq-link-spike.mjs",
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
"lucide-react": "^1.18.0",
|
"lucide-react": "^1.18.0",
|
||||||
"react": "^19.2.7",
|
"react": "^19.2.7",
|
||||||
"react-dom": "^19.2.7",
|
"react-dom": "^19.2.7",
|
||||||
"react-router-dom": "^7.18.1",
|
"react-router-dom": "7.18.1",
|
||||||
"vite": "^8.0.16",
|
"vite": "^8.0.16",
|
||||||
"zustand": "^5.0.14"
|
"zustand": "^5.0.14"
|
||||||
},
|
},
|
||||||
@@ -43,5 +44,8 @@
|
|||||||
"@types/react": "^19.2.17",
|
"@types/react": "^19.2.17",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^6.0.3"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"postcss": "8.5.23"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ echo "[deploy] Installing dependencies"
|
|||||||
npm ci --include=dev
|
npm ci --include=dev
|
||||||
npm --prefix api ci --include=dev
|
npm --prefix api ci --include=dev
|
||||||
|
|
||||||
|
echo "[deploy] Verifying dependency security mitigations"
|
||||||
|
npm run security:verify
|
||||||
|
|
||||||
echo "[deploy] Generating Prisma client and applying migrations"
|
echo "[deploy] Generating Prisma client and applying migrations"
|
||||||
npm --prefix api run prisma:generate
|
npm --prefix api run prisma:generate
|
||||||
npm --prefix api run prisma:migrate:deploy
|
npm --prefix api run prisma:migrate:deploy
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
import { extname, join, resolve } from 'node:path';
|
||||||
|
|
||||||
|
const workspaceRoot = resolve(import.meta.dirname, '..', '..');
|
||||||
|
const rootLock = JSON.parse(readFileSync(join(workspaceRoot, 'package-lock.json'), 'utf8'));
|
||||||
|
const apiLock = JSON.parse(readFileSync(join(workspaceRoot, 'api', 'package-lock.json'), 'utf8'));
|
||||||
|
|
||||||
|
assertVersionAtLeast(rootLock.packages['node_modules/postcss']?.version, [8, 5, 18], 'postcss');
|
||||||
|
assertEqual(rootLock.packages['node_modules/react-router']?.version, '7.18.1', 'react-router');
|
||||||
|
assertEqual(apiLock.packages['node_modules/brace-expansion-safe']?.version, '5.0.8', 'brace-expansion-safe');
|
||||||
|
assertEqual(
|
||||||
|
apiLock.packages['node_modules/brace-expansion']?.resolved,
|
||||||
|
'vendor/brace-expansion-compat',
|
||||||
|
'brace-expansion compatibility adapter',
|
||||||
|
);
|
||||||
|
|
||||||
|
const forbiddenRscPatterns = [
|
||||||
|
/\bunstable_RSC\w*/u,
|
||||||
|
/\bRSCRouterConfig\b/u,
|
||||||
|
/\bRSCStaticRouter\b/u,
|
||||||
|
/\bcreateCallServer\b/u,
|
||||||
|
/react-router\/dom\/server/u,
|
||||||
|
];
|
||||||
|
for (const filePath of sourceFiles(join(workspaceRoot, 'src'))) {
|
||||||
|
const source = readFileSync(filePath, 'utf8');
|
||||||
|
for (const pattern of forbiddenRscPatterns) {
|
||||||
|
if (pattern.test(source)) {
|
||||||
|
throw new Error(`React Router RSC mitigation violated by ${filePath}: ${pattern}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiRequire = createRequire(join(workspaceRoot, 'api', 'package.json'));
|
||||||
|
const expand = apiRequire('brace-expansion');
|
||||||
|
if (typeof expand !== 'function' || expand.EXPANSION_MAX_LENGTH !== 4_000_000) {
|
||||||
|
throw new Error('brace-expansion compatibility adapter is not using the bounded 5.0.8 implementation');
|
||||||
|
}
|
||||||
|
assertEqual(expand('{a,b}{1,2}').join(','), 'a1,a2,b1,b2', 'brace-expansion legacy API');
|
||||||
|
|
||||||
|
for (const relativePath of [
|
||||||
|
'node_modules/archiver-utils/node_modules/minimatch',
|
||||||
|
'node_modules/readdir-glob/node_modules/minimatch',
|
||||||
|
'node_modules/rimraf/node_modules/minimatch',
|
||||||
|
]) {
|
||||||
|
const loaded = apiRequire(join(workspaceRoot, 'api', relativePath));
|
||||||
|
const match = typeof loaded === 'function' ? loaded : loaded.minimatch;
|
||||||
|
if (typeof match !== 'function' || !match('file-a.xlsx', 'file-{a,b}.xlsx')) {
|
||||||
|
throw new Error(`Legacy minimatch compatibility failed for ${relativePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Dependency mitigations verified: PostCSS patched, React Router RSC unused, brace expansion bounded and compatible.');
|
||||||
|
|
||||||
|
function sourceFiles(directory) {
|
||||||
|
return readdirSync(directory).flatMap((name) => {
|
||||||
|
const path = join(directory, name);
|
||||||
|
if (statSync(path).isDirectory()) return sourceFiles(path);
|
||||||
|
return ['.js', '.jsx', '.ts', '.tsx'].includes(extname(path)) ? [path] : [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertVersionAtLeast(actual, minimum, label) {
|
||||||
|
if (!actual) throw new Error(`${label} is missing from package-lock.json`);
|
||||||
|
const parts = actual.split('.').map((part) => Number(part.replace(/\D.*$/u, '')));
|
||||||
|
if (minimum.some((value, index) => parts[index] < value && minimum.slice(0, index).every((item, i) => parts[i] === item))) {
|
||||||
|
throw new Error(`${label} ${actual} is older than ${minimum.join('.')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertEqual(actual, expected, label) {
|
||||||
|
if (actual !== expected) throw new Error(`${label}: expected ${expected}, received ${actual ?? 'missing'}`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user