Files
railwaysystem/DEMO_RUNBOOK.md
T

223 lines
15 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.
# SYFJGYD 学员管理系统 — Java 21 / Spring Boot 4 隔离 QA 运行手册
本手册仅对应 `boot4-iot-fusion-archive` 的 `fix/iot-safety-hardening` 本地候选版本。
原 RailwaySystem 和历史实验工程只读;不执行 Push、Merge、共享部署或硬件操作。
## 当前验收边界
当前分项结论(2026-10-15,Round 5V-7),三项必须分开:
`SOFTWARE_FUNCTIONAL_QA_PASSED=YES`;Round 5V-6的`SOFTWARE_FINAL_SIGNOFF=PENDING_OPERATING_ISOLATION`已在
Round 5V-7完成受管QA运行/退出路径验证,现为`PASS_MANAGED_QA_SCOPE`;
`REAL_HARDWARE_VERIFIED=NO`。
Round 5V-5 已经通过 Tailscale 跳板恢复访问,并对新融合后端完成登录、培训页、IoT页和既有Mock状态冒烟。
此前的断网不是撤销已通过的功能验收。两条旧授权的同步时间现已定位到旧实验进程的补偿写入,
不是新融合后端的正常Mock回执,也不能再标成“原因未知”。
完整时间线和脱敏归因见[Round 5V-6](docs/iot/ROUND5V6_FINAL_SIGNOFF.md);
实际隔离、观察窗口、故障退出和签署范围见[Round 5V-7](docs/iot/ROUND5V7_RUNTIME_ISOLATION.md)。
Round 5V-4 已在获准的新建离线 Kingbase V9 容器中实际恢复原生备份,完成
005 的提交、重复执行、异常/断连/锁超时回滚及原备份恢复演练,然后才对
`railwaysystem_fusion_qa_20261013` 执行 16 列 / 4 索引增量迁移。
11 项真实 Kingbase Service/Mapper/事务测试(含独立测试 JVM 强制中断)已通过。
当前 QA 后端、15 个 Chrome 路由与合成学员入住/调宿/退宿的 Mock 双回执闭环已实际验收。
详见 [本轮软件验收记录](docs/iot/ROUND5V4_SOFTWARE_QA.md)。
Round 5V-4 收尾18:27实测服务器22/4321均超时,后端出现08001/EOF;当时状态为
`BLOCKED_NETWORK`,不是软件功能失败或迁移未执行。Round 5V-5 已恢复合法链路并完成最小冒烟,
且已停止该轮本机QA三进程和临时隧道。不要重做005、覆盖恢复或修改系统路由。
不能将 H2/替身测试、构建成功或登录页显示称为
Kingbase 事务/浏览器业务闭环验收。真实硬件验收始终未进行。
迁移前置、失败回滚和核验清单见 [迁移计划](docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md)。
**不要执行 qa-bootstrap 全量初始化、清空测试数据、重建库、重置已有账号或序列。**
## 1. 构建前提
- Java 21(本机验证 21.0.2)、Maven 3.9.x;全部模块统一 release 21。
- Node 22.23.2、npm 10.9.8(`build_ui/.nvmrc` / packageManager / lockfile)。
- Python 3.9+、本机 `redis-server`(新实例只监听 loopback 的独立端口)。
- 合法取得当前商业 JDBC 9.0.0;不向 Git 或公共 Maven 上传二进制。
从本工作树根目录执行(路径以实际 checkout 为准,不引用 RuoYi-Vue-master):
```bash
java -version
mvn -version
export KINGBASE_JDBC_JAR='/absolute/path/to/authorized/kingbase8-9.0.0.jar'
bash scripts/bootstrap/install-kingbase-jdbc.sh
bash scripts/bootstrap/check-kingbase-jdbc.sh
mvn -B -f RuoYi-Vue/pom.xml -pl ruoyi-admin -am '-Dtest=Round5s*,Round5vAccommodationAtomicityTest,RealIotSecurityGateTest,FaceExtractClientMockTest,CommandRespHandlerMockTest,DmsHttpClientTest,DmsTokenManagerTest,TrainIotLockAuthBridgeMockTest' -Dsurefire.failIfNoSpecifiedTests=false package
python3 -m unittest discover -s scripts/qa -p 'test_qa*.py' -v
mvn -B -f RuoYi-Vue/pom.xml -pl ruoyi-admin -am -Dtest=Round5v4MissingResourceTest -Dsurefire.failIfNoSpecifiedTests=false test
```
驱动私有坐标:`cn.com.kingbase:kingbase8:9.0.0`;SHA256:
`e439bd1c48ce654748c4f333b874a61465702ceb18f29ee017c3f9bc47738c23`。
安装脚本先校验供应商文件,再用固定版本 Maven install plugin 安装到本机私有仓库。
`ruoyi-admin/lib` 不再是构建依赖来源。CI 由管理员合规预置同一私有依赖,缺失即失败。
```bash
cd build_ui
node --version
npm --version
npm ci --ignore-scripts --no-audit --no-fund
npm run build:prod
cd ..
```
不得用实验工程/node_modules1/node_modules2、服务器 symlink 或临时依赖目录替代
lockfile 安装。Quill 2 的转译配置与实验工程一致。Vue 2/CLI 4 的废弃依赖及旧版
node-ipc engine/ESLint peer 警告仍存在:本轮不做整套前端框架迁移,不声称无漏洞。
## 2. 凭据和只读身份检查
将 `qa-bootstrap/round5v.env.example` 的键名交给管理员,在 Git 外受保护文件中
填写真实 QA 配置并设置 owner-only 权限 0600。不要把密码放命令行、截图或报告。
脚本也兼容本机已有 `~/.railwaysystem-qa.env` 中的 `FUSION_QA_APP_PASSWORD` 和
身份加密键,但**不会复用其中可能指向旧库的 QA_DB_URL**。
```bash
python3 scripts/qa/qa.py inspect --config /protected/round5v.env
python3 scripts/qa/qa.py snapshot --config /protected/round5v.env
python3 scripts/qa/qa.py verify-snapshot --snapshot-dir .qa-runtime/snapshot-REPLACE_WITH_ACTUAL_ID
```
固定目标:`railwaysystem_fusion_qa_20261013`;固定运行账号:`fusion_qa_app`。
检查使用只读 repeatable-read 事务并 rollback,记录版本、schema、列、索引和计数;
不打印业务行。快照含两张受影响表的敏感内容,仅存 `.qa-runtime/`(目录0700,
数据0600);其 XML 解析和 SHA 验证不等同于原生全库备份或数据库恢复演练。
服务器现有kingbase容器的 `/home/kingbase/install/kingbase/bin/` 已确认具备
V009R003C018原生工具;现有kingbase管理角色可经容器本地连接认证,不需要给
fusion_qa_app提权。已完成原生备份,服务器及本机副本均在非Git目录,目录0700、文件0600。
最新位置、SHA及独立恢复解阻方案见 [本轮记录](docs/iot/ROUND5V3_SERVER_BACKUP.md)。
`sys_restore --file=/dev/null`成功仅证明归档可完整读取,不能替代实际数据库恢复。
Round 5V-4 已另获明确授权,复用服务器现有 V9 镜像创建专用隔离恢复容器,
原生恢复及迁移/回滚均已实际验证;该授权不扩展到其他实例或数据库。
恢复证据及新建资源身份见本轮记录;不要把一次性演练脚本当作通用初始化脚本重跑,
不要复用共享库进行覆盖恢复。历史 Round 5V-3 文档保留为当时的真实阻塞记录。
## 3. 启停隔离 QA(目标库 005 已完成)
### 经跳板访问时的受管运行隔离(强制)
旧实验进程曾配置 `DB_HOST=127.0.0.1 / DB_PORT=14321`。端口没有监听者,**不代表没有旧客户端等着重连**。
Round 5V-5 在该端口建立隧道时,旧实验进程重新访问同一QA库,补偿任务写了两条旧授权的同步时间。
不要手工开放14321或用普通SSH转发替代下面的守卫;单纯更换端口不算隔离。
先只读核对现有Java进程、SSH监听者和非秘密数据源Host/Port。从本工作树根目录,终端A运行:
```bash
python3 scripts/qa/qa_isolation.py
# 默认选择临时空闲端口;需固定端口时可显式 --port 14327,但仍会检查客户端依赖。
```
工具首先持有14321的**拒绝连接专用socket**,不读写数据库协议、不连接任何上游;
已有未知监听者会导致安全失败,不停止它。新版SSH仅监听127.0.0.1的独占端口,
通过既有wzbmatebook链路访问目标4321;不继承SSH配置中的额外转发/本地命令,不复用共享ControlMaster。
身份认证只走既有合法密钥/Agent或交互密码提示,不将密码放参数、配置或日志。
必须看到`QA_ISOLATION_READY`后,才在终端B执行下面的启动命令。
Git外0600配置可不设置`FUSION_QA_DB_URL`,启动器会采用当前受管账本的确切URL;
如显式设置,必须与该账本的127.0.0.1端口和固定QA库完全匹配,否则拒绝。
只读inspect/snapshot在存在活动账本时也采用同一默认端点;无账本时允许其原有只读预检,但不允许应用start。
启动器核对守卫/SSH的PID、出生时间、cwd、命令、loopback监听归属及新端点Java客户端冲突。
看门狗持续核验并更新心跳;隧道退出或核验失败会清理**同一租约**的前端/后端/Redis,
再关自己的SSH,最后释放拒绝端口。账本/退出证据在`.qa-runtime/`,不进Git。
正常停止可先执行`qa.py stop`,再在终端A按Ctrl+C;只停止本任务所属资源,不按名字pkill。
旧实验进程不被停止、旧配置/账号不被修改;受管工作流以外的管理员手动重开14321仍可恢复旧链路,
这不是永久数据库权限撤销或系统级网络隔离。不得绕过受管入口进行QA写入演示。
若需要永久停用旧服务或调整账号,须另获对应批准。原始Kingbase全矩阵驱动仍锁定旧原地址,
不要拿当前隧道配置重跑它;本轮只做启动/登录/查询,不重做005或完整业务矩阵。
```bash
python3 scripts/qa/qa.py start --config /protected/round5v.env
python3 scripts/qa/qa.py frontend
```
默认端口:后端18096、前端18088、独立 Redis16389,仅监听127.0.0.1;端口占用即
失败,不杀旧进程、不改共享 Redis。启动器先确认目标数据库和16列/4索引存在,
缺迁移拒绝启动;列/索引的完整定义仍须按迁移计划人工核验。PID 输出不代表就绪。
安全值强制为 MQTT Mock=true / enabled=false / real-device-write-enabled=false /
whitelist空 / protocol-verified=false / retry-task-enabled=false;人脸 HTTP关闭;
OpenAPI、QA危险接口、Druid控制台和Quartz自动启动关闭;旧DMS关闭。
继承环境中的 Spring/IoT/DMS/JVM 注入覆盖被过滤,数据库 URL/账号由命令行固定。
启动器将构建包复制为 `.qa-runtime/ruoyi-admin-<SHA前缀>.jar` 并校验散列,防止 Maven
覆盖正在运行的嵌套 JAR。Druid URL 去除 JDBC 秒单位超时参数,池统一使用连接30秒/
网络60秒;实际 Kingbase/Druid 探针验证了 60000ms,不能把 URL 的 15 当成池毫秒值。
JWT和独立Redis密钥由安全随机数首次生成至 `.qa-runtime/runtime-secrets.env`,0600,
以进程环境注入,不写源码/命令行;数据库及身份密钥仅取受保护配置文件。
不得为演示去打开真实门禁或危险接口。
```bash
curl --noproxy '*' --fail http://127.0.0.1:18096/captchaImage
# 真实 Chrome 访问 http://127.0.0.1:18088 ,使用管理员单独提供的 QA 账号。
python3 scripts/qa/qa.py stop
```
stop只处理本脚本账本中且进程命令身份仍匹配的PID,等待其退出再移除账本;不会清端口、杀其他Chrome、
停止实验工程或修改系统网络。JWT、访问日志、快照、浏览器证据均不进入Git。
## 4. 可复现的真实 Kingbase / Chrome 软件验收
仅在已迁移、已批准合成写入的同名 QA 库执行:
```bash
python3 scripts/qa/run_kingbase_tests.py --approve-synthetic-qa-writes --config /protected/round5v.env
# 真实 Kingbase 11 项;不使用 H2,不启动任何真实 MQTT / 人脸客户端。
# 合成数据有 R5V4 标识并保留审计,不删除既有数据,不重置序列。
```
Chrome 验收使用 Playwright CLI 技能(本轮实际 Chrome 155.0.8059.40),打开独立
`round5v4` 会话后运行:
```bash
python3 scripts/qa/browser_login.py --config /protected/round5v.env
# 若 QA 自身启用验证码:从实际截图识别后,加 --use-current-page --captcha ACTUAL_ANSWER;
# 不关闭验证码。本轮现有配置的 captchaImage 返回 captchaEnabled=false,未改其开关。
playwright-cli -s=round5v4 run-code --filename=scripts/qa/browser_regression.js
python3 scripts/qa/browser_fixture.py seed --approve-synthetic-qa-writes --config /protected/round5v.env
```
登录配置额外需要受保护文件中的 QA_ADMIN_USERNAME / QA_ADMIN_PASSWORD。登录驱动仅
在独立 about:blank 页内存中读取配置,关闭该页后填写登录表单,不把配置上传至应用。
CLI 不具备本机工具时使用技能自带 wrapper;不要为此修改工程依赖或系统浏览器设置。
`seed` 仅首次执行,生成 `.qa-runtime/round5v4/browser-fixture.properties`;已存在则拒绝覆盖。
按该文件学号在动态菜单 `/equip/accommodation` 搜索,依次入住、调房至同标识 B 宿舍、退宿。
每次操作后,先观察 AWAITING_ACK,然后执行受控回执驱动,再到授权和指令页面核对:
```bash
python3 scripts/qa/browser_fixture.py state --approve-synthetic-qa-writes --config /protected/round5v.env
python3 scripts/qa/browser_fixture.py ack --approve-synthetic-qa-writes --config /protected/round5v.env
python3 scripts/qa/browser_fixture.py verify --approve-synthetic-qa-writes --config /protected/round5v.env
```
驱动使用真实 Mapper/Service,只接受该文件合成人员与两把合成门锁、MOCK 来源及
`round5v-local-mock` 环境的当前 AWAITING_ACK 指令,不开放任何 HTTP 回执端点。
授权页按人员编号过滤,指令页按 fixture.marker(分组编号)过滤,应有四条 CONFIRMED 指令。
住宿 V2 模型只持久化分配与最后变更时间,页面已按真实字段标注,不捏造独立入住/退宿时间戳。
1. 管理员真实登录、getInfo/getRouters、原品牌菜单和首页图表;培训核心查询。
2. IoT九页:group/gateway/device/face/auth/command/accesslog/mqttlog/config,
必须验证组件渲染及实际QA查询,不能把SPA fallback HTTP200当作无404证明。
3. 为本轮创建可追踪的合成业务样本,不复用/覆盖既有培训测试记录:报名、
住宿预分配、入住、调宿、退宿、授权意图与`iotlocks.lock_command`流水。
4. 用实际Kingbase Mapper/Service/事务管理器覆盖迁移计划中的崩溃、并发、晚到ACK、
提交/回滚场景;外部MQTT和人脸只能是可控替身。危险Mock HTTP端点保持关闭,
ACK由隔离的Service测试驱动,不通过开放生产式控制接口来换取通过。
5. 受控Mock ACK成功只能证明软件闭环,不能证明真实门锁已授权或撤权。
现有 H2 与替身测试仍不等于真实数据库证据;本轮新增
`Round5v4KingbaseIntegrationTest` 才是上述 Kingbase 事务和应用进程中断验证的执行入口。
## 5. CI与硬件边界
`.gitlab-ci.yml` 已改为显式web+RUN_FUSION_VALIDATION=true才允许的验证流水线;
Java21、私有JDBC预检及npm ci,**无部署job**。本轮未Push,也未触发/验证远程Runner。
本轮数据库、事务、启动和 Chrome 软件验收已经完成;仍未做真实门锁、人脸或网关验收。
硬件测试另需老师批准、确认协议中未验证的帧校验字段/回执及重传策略、单台白名单和人工核对流程。
商业驱动和恢复容器许可仅按现有合法 QA/试用环境验证,不代表生产部署许可。
应用账号既有的三张系统表过宽权限未扩大也未自动收回,应由管理员另行最小化。
任何安全前提不满足时,不得用旧实验后端或伪造 API 响应冒充新版本验收。