From e28288f6911da002dce39e0e5208609a40bc0e30 Mon Sep 17 00:00:00 2001 From: hectorzhao Date: Wed, 22 Jul 2026 18:51:02 +0800 Subject: [PATCH] fix: repair SQL_ASCII signature encoding --- .../migration.sql | 19 +++++++++++++++++++ .../first-version-development-requirements.md | 1 + docs/system-functional-test-cases.md | 3 +++ docs/testing-progress.md | 7 +++++++ 4 files changed, 30 insertions(+) create mode 100644 api/prisma/migrations/20260722190000_repair_sql_ascii_signature_utf8/migration.sql diff --git a/api/prisma/migrations/20260722190000_repair_sql_ascii_signature_utf8/migration.sql b/api/prisma/migrations/20260722190000_repair_sql_ascii_signature_utf8/migration.sql new file mode 100644 index 0000000..5bee4c4 --- /dev/null +++ b/api/prisma/migrations/20260722190000_repair_sql_ascii_signature_utf8/migration.sql @@ -0,0 +1,19 @@ +-- The previous bracket-normalization migration ran against a legacy SQL_ASCII +-- database. PostgreSQL treated the UTF-8 bracket regexp as individual bytes and +-- removed the trailing 0x91 byte from the final Chinese character in two known +-- signatures. Restore only the rows whose primary key and corrupt byte sequence +-- both match the pre-migration backup, so later user edits cannot be overwritten. +UPDATE "SmsSignature" +SET name = convert_from( + decode('e38090e888aae5a4a9e4bfa1e681afe4bfa1e8afbae7bd91e38091', 'hex'), + 'SQL_ASCII' +) +WHERE id IN ( + 'cmrj2ci1r00544pnkt64wza4e', + 'cmrobgqp7002nwenke5wh09fr' +) +AND encode(convert_to(name, 'SQL_ASCII'), 'hex') = + 'e38090e888aae5a4a9e4bfa1e681afe4bfa1e8afbae7bde38091'; + +-- Rollback guidance: do not restore the invalid byte sequence. If rollback is +-- required, keep the repaired UTF-8 values and only roll back application code. diff --git a/docs/first-version-development-requirements.md b/docs/first-version-development-requirements.md index 81c3026..b1a7feb 100644 --- a/docs/first-version-development-requirements.md +++ b/docs/first-version-development-requirements.md @@ -1638,4 +1638,5 @@ - 客户端/HTTP整批超限时不创建任务、短信记录或账务冻结,HTTP返回429及`DAILY_SEND_LIMIT_EXCEEDED`。CMPP合法Submit整包超限时返回唯一一个非0 `SUBMIT_RESP`(日限额映射`result=8`),每个目的号码仍保留`rejected/DAILY_LIMIT`审计主记录;不冻结、不扣费、不占用额度,也不再生成或投递异步`DELIVER`回执。 - 日额度在任务正式受理时按北京时间占用;待审核和定时任务占用受理日额度,后续审核拒绝、取消或发送失败均不返还。发送校验固定遵循身份/应用权限、请求结构和全部号码基础格式、签名/模板/引流、禁发时段及风控、路由通道、余额原子校验与冻结、日额度原子占用、任务落库入队的业务优先级。余额早期读取只能用于提示,最终资格判断与冻结必须紧邻任务受理执行。 - 号码基础校验只判断空值、字符、长度、数量上限、重复及多号码完整性;号段识别用于运营商和地区快照及路由提示,未知号段不得据此拒绝,必须继续按全国或三网兼容通道处理。 +- 预发布历史数据库仍为`SQL_ASCII`时,数据迁移不得使用可能把多字节UTF-8字符拆成单字节处理的正则字符类。中文签名修复必须同时校验主键和原始字节序列,并从迁移前备份恢复完整UTF-8;长期生产数据库必须规划迁移到`UTF8`编码。 - 首次开通HTTP接口时,后端默认开启单条发送、状态查询、回执回调、上行查询、上行回调和客户端自助密钥六项能力,回执/上行投递默认为HTTP Webhook。参数复制必须包含应用名称、AppID、六项能力、基础地址、文档、QPS、白名单和真实投递方式。 diff --git a/docs/system-functional-test-cases.md b/docs/system-functional-test-cases.md index d421df2..11e1c0e 100644 --- a/docs/system-functional-test-cases.md +++ b/docs/system-functional-test-cases.md @@ -3719,5 +3719,8 @@ npm run verify:phase8 | TC-SEND-DAILY-006 | 待审核/定时任务受理后再拒绝或取消 | 受理日额度已占用且不返还;失败、取消和最终送达统计不得反向修改日用量 | | TC-SEND-ORDER-001 | 请求同时存在号码格式、模板和余额错误 | 按固定业务顺序先返回号码基础错误;修复号码后返回签名/模板错误,只有业务资格通过后才执行最终余额原子校验/冻结 | | TC-SEND-ORDER-002 | 号段库无法识别但号码基础格式合法 | 不以未知号段拒绝;记录未知运营商快照并继续匹配全国或三网兼容通道,正常产生提交、消费和回执数据 | +| TC-SIGN-UTF8-001 | SQL_ASCII数据库执行历史签名黑括号规范化后出现截断UTF-8 | 字节检查准确识别非法行;补偿migration仅修复主键与损坏hex同时匹配的记录,恢复为迁移前备份中的`【航天信息信诺网】` | +| TC-SIGN-UTF8-002 | 修复后查询企业签名及关联报备数据 | `SmsSignature`全部49条可按UTF-8读取;企业签名、企业模板、报备任务、报备记录和待报备资料接口不再因PostgreSQL 22021返回500 | +| TC-SIGN-UTF8-003 | 目标签名在补偿migration前已被人工修改 | 原始hex不匹配时不得覆盖;重复执行修复SQL结果不变且不产生非法字节 | | TC-HTTP-PARAM-002 | 首次开通HTTP后查看并复制参数 | 六项能力默认开启,回执/上行为HTTP Webhook;复制文本含AppID和“客户端自助密钥”,与真实API/DB一致 | | TC-HTTP-PARAM-003 | 升级前已开通HTTP且Webhook能力开启,投递模式仍为cmpp | migration将对应回执/上行模式回填为http,参数复制不再显示CMPP长连接 | diff --git a/docs/testing-progress.md b/docs/testing-progress.md index d4d0310..db99621 100644 --- a/docs/testing-progress.md +++ b/docs/testing-progress.md @@ -2231,3 +2231,10 @@ git diff --check - 发布后`cmpp-gateway`、`cmpp-api`、Nginx、PostgreSQL、Redis和MinIO均active,`12026/17890/8090/3000/9000/6379/5432`监听;API/Gateway health、Redis PONG、PostgreSQL readiness和60条migration状态通过。`gateway.submit.commands`为`pending=0、lag=0`,7个通道TPS权威配置存在,部署后API/Gateway error journal均无记录。 - 2条active上游通道均恢复`connected/currentConnections=1`。另1条disabled通道的状态行仍显示`connected/1`,但`updatedAt=2026-07-09 03:24:26.242`且本次启动无对应重连日志,确认为历史状态残留而非当前连接;5条deleted测试通道均为failed/0连接。本轮未修改或清理该历史数据。 - 外部首页、运营登录页、客户端登录页和API health均返回HTTP 200,公网CMPP `8.160.169.106:17890` TCP连接成功。生产源码确认API下发`result=8`且Gateway读取业务结果码;未通过真实短信制造超限条件,未发送、重投、充值、审核或修改生产业务数据。 + +## 2026-07-22 SQL_ASCII签名UTF-8损坏修复(待发布) + +- 预发布企业签名、报备任务/记录、待报备资料及部分模板读取接口返回500。Nginx与API stderr确认`SmsSignature.findMany()`等查询触发PostgreSQL `22021 invalid byte sequence for encoding UTF8: 0xe7 0xbd 0xe3`,不是前端或权限问题。 +- 生产数据库编码为`SQL_ASCII`。`20260722173000_normalize_sms_signature_brackets`中的中文正则字符类按字节工作,把名称末尾“网”的UTF-8最后字节`0x91`误当成黑括号字节删除。49条签名中准确识别2条非法UTF-8;迁移前备份证明二者原值均为`【航天信息信诺网】`。 +- 新增补偿migration,仅当两个已确认ID及损坏hex同时匹配时恢复备份中的正确UTF-8,不覆盖之后的人工编辑;明确禁止回滚到非法字节,并补充SQL_ASCII与关联接口回归用例。 +- 本地真实SQL_ASCII临时库从零应用61条migration后插入生产同款损坏hex,补偿SQL首次执行恢复两条正确UTF-8、第二次执行保持不变,随后删除临时库;本地共享库也已应用第61条migration。API全量24 suites / 290项、API build、前端build、Gateway `go test ./...`、Prisma generate/validate/status和`git diff --check`均通过。