Files
railwaysystem/docs/iot/ROUND5V7_RUNTIME_ISOLATION.md
T

123 lines
10 KiB
Markdown
Raw 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.
# Round 5V-7 — 旧客户端路径阻断与受管QA签署
日期:2026-10-15(Asia/Shanghai)。输入提交:`65c567152e4f57bd25af03da52cc7078ea264984`。
分支:`fix/iot-safety-hardening`。本轮只改归档工程的本地QA工具、工具测试、CI验证发现范围及文档。
没有修改原工程、实验工程、旧进程配置、数据库账号权限、路由、Tailscale或共享服务。
没有迁移、恢复、纠正sync_time、创建授权、发Mock业务控制命令或真实设备控制。
登录会正常产生自身认证审计;它不是零数据库写入,但没有授权/命令变更。
## 1. 结论与边界
| 标识 | 结论 | 实际范围 |
| --- | --- | --- |
| SOFTWARE_FUNCTIONAL_QA_PASSED | YES | 保留11项真实Kingbase、86项选定回归、12项工具、Chrome15路由及住宿Mock闭环的历史通过;未重跑完整矩阵 |
| SOFTWARE_FINAL_SIGNOFF | PASS_MANAGED_QA_SCOPE | 本轮受管隧道、旧端点拒绝守卫、新后端最小读冒烟、数据稳定观察和故障退出通过 |
| REAL_HARDWARE_VERIFIED | NO | 真实门锁/MQTT/人脸/DMS均未放行,未做现场硬件验收 |
此签署是当前受管QA运行/退出工作流的可交付候选,不是生产上线、永久数据库访问控制或硬件签署。
脱离工具手工重开14321、修改旧进程配置或共享同一账号,仍可能恢复旧访问;这些不在通过范围。
不得把手工SSH隧道或未绑定租约的应用启动替代本流程。
## 2. 旧进程和原访问路径的只读复核
- 旧Java PID51901,出生时间`2026-10-13 15:35:08`,cwd=`boot4-iot-fusion-test`;
实际JAR位于该工程的`RuoYi-Vue-master/ruoyi-admin/target/ruoyi-admin.jar`,不是归档工作树。
- 从进程环境只输出非秘密字段:DB_HOST=127.0.0.1、DB_PORT=14321、QA_DB_USER=fusion_qa_app。
实际运行JAR内application-druid.yml固定数据库`railwaysystem_fusion_qa_20261013`,默认Host/Port与环境一致。
- 另一Java PID53305,出生时间`2026-10-12 12:46:15`,属于另一工程;其JAR数据源模板是localhost:54321/iotlocks,
不是上述旧端点。本轮两个Java进程均未停止或修改。
- 开始时14321没有监听者,不存在可归属/可关闭的现有该端口隧道。其他既有SSH进程未发现14321转发参数,未操作它们。
- 旧任务`initialDelay=30000ms / fixedDelay=60000ms`,允许补偿时会按失败/待发状态扫描;失败分支可写sync_time。
实际调度间隔还包含数据库连接等待/失败处理,不能把60秒当作每分钟一定完成一次。
- 原归档`qa.py`不自动建14321隧道,但允许任意同名QA URL,且只检查新应用监听端口,未防止旧客户端借用新转发。
已证明的两条旧记录来源仍见[Round 5V-6](ROUND5V6_FINAL_SIGNOFF.md),不是正常Mock回执。
## 3. 实际采用的最小隔离
新增`scripts/qa/qa_isolation.py`,正常前台运行,认证只走既有合法SSH入口、Agent/密钥或交互提示。
它不接受或保存SSH密码,不改SSH/Tailscale/系统代理配置,不依赖停止旧进程或修改账号。
| 客户端/审计 | 本轮端点 | 隔离行为 |
| --- | --- | --- |
| 旧PID51901及其他14321客户端 | 127.0.0.1:14321 | 本任务守卫独占,连接立即关闭;没有数据库协议响应、没有任何上游 |
| 新归档后端PID35238 | 127.0.0.1:14327 | 仅归本任务SSH PID34187所有的loopback转发,经wzbmatebook到目标127.0.0.1:4321 |
| 独立只读指纹核验 | 经诊断SSH执行容器本地ksql | 只读事务/ROLLBACK,不通过14321,不恢复备份、不执行DDL |
守卫owner PID34164;同一租约绑定Redis35236、后端35238、前端35269。
其PID/出生时间/cwd/命令、监听IP与归属、固定QA库、心跳及新端点Java客户端依赖都被核验。
未发现其他Java客户端依赖14327;实际TCP连接只见新后端与自建SSH,旧PID51901未连接它。
14321已有未知监听者、新端点冲突、PID重用、心跳过期或所有权不匹配均安全拒绝,不清理未知资源。
不是只换端口:旧14321被拒绝守卫占住,实际bind测试得到占用错误,实际连接不返回数据库响应;
新启动器同时拒绝14321 URL、没有活动租约的start以及与租约不匹配的数据源。
前端也必须绑定同租约后端及对应端口,不能用旧8096后端冒充本版本。
看门狗持续检查;临时隧道失效时仅清理同租约应用,先关自己的SSH,最后释放拒绝守卫。
退出后的账本保留审计,不自动重用旧账本或信号未知PID。
### SSH继承配置的额外发现和修复
现有SSH目标和跳板配置均含与QA无关的RemoteForward17897。
首次受管试运行因该继承转发冲突失败,未启动应用;对应STOPPED账本保留。
本轮诊断会话也意外继承同一转发;单独cancel不足,因为后续mux命令客户端可能再次继承并申请转发。
已按确切归属退出本轮诊断ControlMaster,再以ClearAllForwardings和禁用ControlMaster的单次只读SSH复核:17897监听数为0。
没有修改持久SSH配置或取消其他会话的转发。
最终工具用独立目标配置和显式ProxyCommand复用既有跳板,跳板清除继承转发/本地命令;
目标只设置批准的HostName/User/22端口及唯一-L,StrictHostKeyChecking=yes,不复用ControlMaster,不发布远程端口。
此后正式运行没有继承无关转发。不要将失败的首次尝试隐去或算作成功启动。
## 4. 实际验证及数据证据
证据根:受保护且Git忽略的`.qa-runtime/round5v7/`;所有业务行仅在数据库内计算排序完整行指纹,未导出人员资料。
浏览器截图位于`output/playwright/round5v7-*-headers.png`,数据行和头像遮罩。
- 新工具的29项定向本机测试通过(原12项工具测试及17项隔离测试),不连接真实服务或数据库。
覆盖无租约拒绝、禁止旧URL、PID/监听者/心跳/来源端点拒绝、非本租约进程不被停止、真实本机拒绝socket等。
其中28项在启动前通过,补充前端错误端口防护后最终29项通过;不假称重跑86项后端测试。
- 正式受管租约创建于2026-10-15 01:52:49;应用在01:53:12启动。
实测Java21.0.2 / Boot4.1.0,fusion_qa_app,数据源仅目标QA库,独立Redis16389,前端18088/后端18096均loopback。
强制CLI保持MQTT enabled=false/mock=true、real-device-write-enabled=false、空白名单、自动补偿关闭、
Face HTTP/OpenAPI/QA危险入口/DMS/Quartz关闭;实际日志出现MOCK-MQTT,未见08001/SQL错误。
- 实际Chrome155最小冒烟:管理员登录/getInfo/getRouters成功;Student查询与Auth查询均HTTP200/业务200,JS错误0。
Auth页实际组件和45条总数正确,不是登录页/404;没有点击授权、撤权、入住或回执操作。
- 隔离前、运行中、退出前后共四次真实Kingbase只读采样。前后窗口1432秒(约23分52秒),
是名义60秒补偿周期的多倍;两表完整数据指纹均不变:
lock_auth45条:`af7e6a797bebef91a7d5570697265b5e`;lock_command83条:`271d15e2d0721015d3b020433c549c7c`。
包含所有字段,而不只是排除sync_time后的指纹。两表REAL行数均0。
- 两条脱敏旧记录sync_time分别保持`2026-10-14 16:51:29`与`16:51:30`,仍LEGACY/QUARANTINED/version0,
sync_status3、status0,没有纠正性UPDATE;其余原始记录也包含在完整指纹中。
- 正式守卫累计拒绝507次连接(含一次明确的本机负向验证,不把全部次数硬归给单个PID)。
旧日志完整追加窗口读取约1.1MB,发现2个补偿失败事件、0个成功updateSyncStatus UPDATE;未复制原日志正文。
这证明旧任务仍可能运行,但在受管窗口内无法通过旧端点获得QA连接,不是把任务静默禁用。
### 自建SSH异常退出演练
验证租约与PID身份后,仅向本轮自建SSH PID34187发送SIGTERM。
看门狗检测到监听者丢失,自动停止同租约前端/后端/Redis,随后关闭自己的资源;
终态STOPPED、cleanup_ok=true,故障检测按预期非零退出,退出证据保留。
14321、14327、18096、18088、16389均不再监听,旧两个Java的PID/出生时间不变。
退出后源QA只剩本次ksql只读会话,无fusion_qa_app残留连接,完整指纹仍一致。
随后实际`qa.py start`在无租约时拒绝,未连接数据库或再启动进程。
没有测试SIGKILL、主机断电或恶意绕过,也不把本测试写成这些保证。
## 5. 归档状态和剩余风险
共享Kingbase/GitLab容器ID、2026-10-06启动时间、restart0/OOM=false均未变;GitLab healthy。
临时恢复容器仍停止,本轮未启动或修改它。没有共享部署或真实硬件操作。
本轮只读远端仍为`feat/boot4-iot-fusion@373921447fa4727c20aed7b28c5d1519fe26fa78`,修复分支远端不存在。
该融合基线是修复分支祖先;本地保留此前七笔提交,本轮再追加工具/文档提交,不改写历史。
GitLab使用默认CI文件,项目Hook=0、非项目Hook=0、相关活跃Integration=0。
CI仍仅显式web+RUN_FUSION_VALIDATION=true可运行,只有验证无部署;新增隔离测试已纳入工具测试发现范围。
没有Push、MR、Merge或触发Runner;不把静态配置审核写成已执行远程CI。
本轮对已有七笔提交和新增暂存范围合计142个blob/路径版本完成扫描,未检出已知本机凭据值、
私钥正文、Token形态高风险项或新增备份/日志/照片/二进制文件;通用赋值命中已区分环境变量、占位符、
合成测试及禁用账号哨兵,不将扫描写成对继承历史的绝对无秘密保证。
原始备份、0600凭据、运行账本/日志/截图未被跟踪,扫描摘要保存在受保护忽略目录。
继承的测试密钥素材、历史凭据轮换、既有账号过宽授权、Vue2依赖及长期Kingbase许可仍保留风险,未自动处置。
在**必须使用受管入口**的前提下,当前软件候选不再因旧端点隔离而挂起;本轮最后仅需用户决定GitLab归档。
可另行批准后推送`fix/iot-safety-hardening`的精确本地HEAD,不Force Push、不覆盖融合基线,再经MR评审合入。
这不放行部署/生产/真实硬件;若要永久关闭旧服务、改旧配置、撤销账号权限或允许手工转发,仍须对应批准。
对恶意同用户进程/管理员主动绕过不提供系统级隔离保证;如运行场景要求该等级,应维持该场景PENDING并另行设计权限隔离。