diff --git a/DEMO_RUNBOOK.md b/DEMO_RUNBOOK.md index 9d6b96d41..eb90253b8 100644 --- a/DEMO_RUNBOOK.md +++ b/DEMO_RUNBOOK.md @@ -5,8 +5,9 @@ ## 当前验收边界 -Round 5V 已核对目标 Kingbase 版本、低权限账号及迁移前表结构。005 尚未执行: -`MIGRATION_WAITING_APPROVAL`。不能将 H2/替身测试、构建成功或登录页显示称为 +Round 5V-2 用户已明确批准仅对目标QA库执行005增量迁移,但备份/隔离恢复前提 +尚未满足,当前状态为 `MIGRATION_AUTHORIZED_BLOCKED_RESTORE`,005未执行。 +不能将 H2/替身测试、构建成功或登录页显示称为 Kingbase 事务/浏览器业务闭环验收。真实硬件验收始终未进行。 迁移前置、失败回滚和核验清单见 [迁移计划](docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md)。 **不要执行 qa-bootstrap 全量初始化、清空测试数据、重建库、重置已有账号或序列。** @@ -65,7 +66,10 @@ python3 scripts/qa/qa.py verify-snapshot --snapshot-dir .qa-runtime/snapshot-REP 检查使用只读 repeatable-read 事务并 rollback,记录版本、schema、列、索引和计数; 不打印业务行。快照含两张受影响表的敏感内容,仅存 `.qa-runtime/`(目录0700, 数据0600);其 XML 解析和 SHA 验证不等同于原生全库备份或数据库恢复演练。 -本机未找到原生备份客户端,完整备份及回退演练由管理员按迁移计划准备。 +在本轮已检查范围中未找到匹配的原生备份客户端,本机Docker守护进程不可用, +也未发现或取得可用的独立恢复实例。仅有两表快照不能通过恢复门禁。 +需要提供已有且获准使用的恢复环境、匹配版本工具和受保护的QA库DDL管理配置; +不要创建数据库、猜测密码、提权或把业务账号当成迁移账号。 ## 3. 启停隔离 QA(迁移批准并完成后) @@ -114,6 +118,6 @@ stop只处理本脚本账本中且进程命令身份仍匹配的PID;不会清 `.gitlab-ci.yml` 已改为显式web+RUN_FUSION_VALIDATION=true才允许的验证流水线; Java21、私有JDBC预检及npm ci,**无部署job**。本轮未Push,也未触发/验证远程Runner。 -当前仍缺明确005迁移授权、原生备份/回退演练、真实Kingbase生命周期验证和 -依托新QA后端的完整Chrome验收。后端未获准迁移时,单独前端会明确返回502, +005授权已明确;当前仍缺可用的原生备份/隔离恢复条件、已配置的授权DDL管理账号、真实Kingbase生命周期验证和 +依托新QA后端的完整Chrome验收。迁移安全前提未满足时,单独前端会明确返回502, 不得用旧实验后端或伪造API响应冒充新版本验收。 diff --git a/docs/iot/ROUND5V2_ACCEPTANCE.md b/docs/iot/ROUND5V2_ACCEPTANCE.md new file mode 100644 index 000000000..c92c8ea41 --- /dev/null +++ b/docs/iot/ROUND5V2_ACCEPTANCE.md @@ -0,0 +1,93 @@ +# Round 5V-2 — authorization received, restore prerequisite blocked + +Date: 2026-10-14. Branch `fix/iot-safety-hardening`; starting commit +`5560a3ac0456b694609cdf9f21f7f59810950d76`. The user explicitly approved the +non-destructive migration on the named QA database, but not bypassing backup or +restore proof, database creation/deletion, privilege expansion or hardware control. + +## Fresh actual database evidence + +Read-only JDBC inspection connected only to +`192.168.139.218:4321/railwaysystem_fusion_qa_20261013`, using `fusion_qa_app`. +The server returned `KingbaseES V009R003C018`, database name exact, current schema +`public`, internal server endpoint `172.17.0.5:54321`. `transaction_read_only=on`, +repeatable-read transaction ended in rollback. No DDL/DML was issued. + +- Base tables: public54, iotlocks9. Counts: train_student47, train_enrollment57, + train_accommodation34, lock_auth10, lock_command15. No personal rows were printed. +- Round 5S lifecycle metadata is absent. Existing schema/index definitions remain + in their pre-migration state. Historical LEGACY defaults cannot be claimed applied. +- App role is not superuser/createdb/createrole; no CREATE on either application + schema, affected tables owned by kingbase. Existing DML grants were inspected, + not exercised. Extra TRUNCATE/TRIGGER/REFERENCES on public.sys_menu, + public.sys_notice_read, public.sys_role_menu remain unchanged pending admin review. +- An initial read-only table-inventory query through information_schema.tables + returned SQLSTATE42501. The probe now reuses the already-readable pg_tables + catalog view and completes successfully without extra grants. + +Evidence: `scripts/qa/QaDatabaseProbe.java` and private +`.qa-runtime/round5v2-preflight.log` (metadata/counts only). + +## Migration scope PASS; runtime DDL semantics BLOCKED + +Full 005 content was reviewed and independently allowlisted: 20 statements, +16 ADD COLUMNs and 4 CREATE INDEXes (2 unique), all limited to the two approved +`iotlocks` tables. No DROP/TRUNCATE/DELETE/UPDATE/GRANT or sequence reset. +SHA256: `90648b6ac67470f9a14f0795c4479dfb4811d4907e41a13ee5eeada16582b87f`. +The file was not changed. Additive scope is verified, but actual Kingbase DDL +transaction rollback, null-key uniqueness, repeated execution and lock behavior +have NOT been tested because the prerequisite restore gate is blocked. + +## Concrete backup/restore blockers + +1. No sys_dump/sys_restore/ksql/pg_dump/pg_restore on local PATH or in the scoped + common install/download locations checked. A PostgreSQL client was not installed + or substituted as evidence of Kingbase compatibility. +2. Docker CLI and Docker.app exist, but the configured desktop-linux daemon socket + does not exist; docker info fails. No usable local Kingbase restore instance + was discovered or supplied. No Docker startup, install, database creation, + network modification or engine initialization was performed. +3. Existing SSH alias wzbmatebook is reachable, but no vendor tools were found on + PATH or in the bounded /opt, /usr/local, /usr/lib, /home/wzb search; no matching + database/container process was reported. This is only a scoped resource check, + not a claim that no vendor installation exists anywhere. +4. Existing SSH authentication to database host 192.168.139.218 as configured user + wzb was denied. No password guessing, root fallback, new host-key acceptance, + remote installation or server changes were attempted. +5. Protected local QA configuration is 0600 and contains the usable app credential. + No explicit QA DDL-management connection or isolated restore connection was + found among its keys. Web-admin login keys are NOT treated as database-admin + credentials. The application role was not elevated or used to attempt DDL. + +BACKUP_CREATED = BLOCKED: no new native consistent backup. +ISOLATED_RESTORE_VERIFIED = BLOCKED: no actual isolated database restore. +Previous private XML snapshots remain protected but do not satisfy either result. +Therefore formal migration and all dependent phases stop, as explicitly required. + +## Work completed without migration + +- Frontend production build rerun successfully from this archive, using its own + declared dependencies/lockfile and Quill transpilation configuration. Evidence: + `.qa-runtime/round5v2-frontend-build.log`. No Antigravity temporary path was used. +- 11 QA-tool tests rerun successfully. The modified Java probe actually compiled + and ran on Java21 against Kingbase in read-only mode. No critical backend source + changed; prior 85 JUnit results are historical evidence, not a new Kingbase run. +- Runbook and migration plan now acknowledge authorization and identify restore + prerequisites, rather than incorrectly saying user approval is still missing. +- New Spring Boot/Redis/Chrome was not started; no old experiment backend or fake + API substituted. Full login/routes, original homepage/charts, nine IoT pages and + accommodation software E2E remain BLOCKED, not PASS. +- Safety defaults remain MQTT Mock, real writes false, whitelist empty, face HTTP + disabled, OpenAPI/QA control interfaces disabled. No real device operation occurred. + +## Required inputs to unblock this same workflow + +Provide a matching licensed Kingbase native tool location, an **already existing +and approved** independent restore instance/database with protected connection +configuration, and the existing authorized DDL-management connection for this QA +database. Do not send passwords in chat. No new database or expanded app privilege +is requested or inferred. Once those inputs exist, prove restore first, then follow +the migration plan and run actual Kingbase transactions, startup and Chrome E2E. + +SOFTWARE_QA_READY = BLOCKED. +READY_FOR_SUPERVISED_HARDWARE_TEST = BLOCKED. diff --git a/docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md b/docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md index e4ff6aa63..6894ae236 100644 --- a/docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md +++ b/docs/iot/ROUND5V_KINGBASE_MIGRATION_PLAN.md @@ -1,5 +1,17 @@ # Round 5V — isolated Kingbase migration and rollback gate +## Current Round 5V-2 decision + +The user explicitly authorized migration 005 **only** on +`railwaysystem_fusion_qa_20261013`, together with protected backup and isolated +restore rehearsal. Scope SHA256 remains +`90648b6ac67470f9a14f0795c4479dfb4811d4907e41a13ee5eeada16582b87f`. +Authorization is no longer missing. Status: `MIGRATION_AUTHORIZED_BLOCKED_RESTORE`. +No DDL or business data writes have been performed because native backup and +actual isolated restore cannot yet be proved. Existing two-table XML snapshots +are not an acceptable substitute. Do not create a database or elevate privileges +to overcome this gate. See [current evidence](ROUND5V2_ACCEPTANCE.md). + ## Scope and observed prestate 2026-10-14 read-only JDBC probe: database `railwaysystem_fusion_qa_20261013`, user @@ -51,7 +63,7 @@ the global/database/user search path or accidentally query system `sys_user` vie native backup utility or restore destination is assumed or provisioned here. Do not use a mismatched PostgreSQL client or restore into any shared database. -## Execution and failure rollback (not executed in this round without approval) +## Execution and failure rollback (authorized, blocked on backup/restore) With an approved migration account, enforce `current_database()` equals the exact target before any change. Begin a transaction, set a local lock timeout (5s), diff --git a/scripts/qa/QaDatabaseProbe.java b/scripts/qa/QaDatabaseProbe.java index c165ea6b7..6e8491bb7 100644 --- a/scripts/qa/QaDatabaseProbe.java +++ b/scripts/qa/QaDatabaseProbe.java @@ -40,8 +40,15 @@ public class QaDatabaseProbe { r.next(); if (!DATABASE.equals(r.getString(1))) throw new SecurityException("Database mismatch"); } query(c,"identity", "SELECT current_database(), current_user, current_schema(), version()"); + query(c,"server_endpoint", "SELECT inet_server_addr(),inet_server_port(),current_database(),current_user"); + query(c,"read_only_transaction", "SHOW transaction_read_only"); query(c,"search_path", "SHOW search_path"); query(c,"schemas", "SELECT schema_name FROM information_schema.schemata ORDER BY schema_name"); + // Kingbase information_schema.tables can require extra catalog privileges; + // reuse the readable pg_tables view rather than broadening the app role. + query(c,"table_inventory", "SELECT schemaname,count(*) FROM pg_tables WHERE schemaname IN ('public','iotlocks') GROUP BY schemaname ORDER BY schemaname"); + query(c,"training_counts", "SELECT 'train_student',count(*) FROM public.train_student UNION ALL SELECT 'train_enrollment',count(*) FROM public.train_enrollment UNION ALL SELECT 'train_accommodation',count(*) FROM public.train_accommodation"); + query(c,"round5s_prestate", "SELECT count(*) FROM information_schema.columns WHERE table_schema='iotlocks' AND table_name IN ('lock_auth','lock_command') AND column_name IN ('execution_mode','environment_id','intent_key','intent_version','execution_state','intent_action','intent_at','attempt_started_at')"); query(c,"columns", "SELECT table_schema,table_name,column_name,data_type,is_nullable,column_default " + "FROM information_schema.columns WHERE (table_schema='iotlocks' AND table_name IN ('lock_auth','lock_command')) ORDER BY table_name,ordinal_position"); query(c,"constraints", "SELECT table_schema,table_name,constraint_name,constraint_type FROM information_schema.table_constraints "