fix(legacy): keep static shell available during migration
This commit is contained in:
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
- 新版地址:`http://127.0.0.1:8877`
|
- 新版地址:`http://127.0.0.1:8877`
|
||||||
- 新版数据库:`next/data/local-preflight/xiaobai-normalized-v7.db`
|
- 新版数据库:`next/data/local-preflight/xiaobai-normalized-v7.db`
|
||||||
- 旧版`8765`未启动、未占用、未修改。
|
- 旧版`8765`未启动、未占用;旧版源码仅修复静态首页被API权限注册表误拦截的既有回归,
|
||||||
|
未增加产品功能。
|
||||||
- 本轮未连接NAS,未执行Docker构建或容器切换。
|
- 本轮未连接NAS,未执行Docker构建或容器切换。
|
||||||
|
|
||||||
## 迁移校验
|
## 迁移校验
|
||||||
@@ -53,6 +54,14 @@
|
|||||||
- Vite生产构建:通过
|
- Vite生产构建:通过
|
||||||
- Playwright:26项通过;在隔离测试数据库中重跑,包含注册、权限、16工作区、日夜、390px、长页路由复位和4K结构断言。
|
- Playwright:26项通过;在隔离测试数据库中重跑,包含注册、权限、16工作区、日夜、390px、长页路由复位和4K结构断言。
|
||||||
|
|
||||||
|
## 旧版并行可运行性
|
||||||
|
|
||||||
|
- 使用独立空数据目录和临时端口`8890`启动旧版,未读取或写入真实旧库,也未占用正式端口`8765`。
|
||||||
|
- `/api/health`返回`200 application/json`,静态首页`/`返回`200 text/html`。
|
||||||
|
- 发现并修复旧版既有回归:API权限注册表曾错误处理静态路径,使首页返回404;现仅`/api/*`
|
||||||
|
进入权限注册表,静态资源仍由原静态服务处理。
|
||||||
|
- 旧版全量基线为231项测试和32项subtest全部通过;静态首页绕过API注册表有直接回归测试。
|
||||||
|
|
||||||
## 未关闭项
|
## 未关闭项
|
||||||
|
|
||||||
- 4K信息密度和审美仍需用户人工确认。
|
- 4K信息密度和审美仍需用户人工确认。
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
## 已确认完成的基础
|
## 已确认完成的基础
|
||||||
|
|
||||||
- 新旧运行时完全分离,新版不导入旧版 `server.py`、`database.py`、`app.js` 或旧样式覆盖层。
|
- 新旧运行时完全分离,新版不导入旧版 `server.py`、`database.py`、`app.js` 或旧样式覆盖层。
|
||||||
|
- 旧版已在独立数据目录和临时端口完成首页、健康检查及231项测试与32项subtest验收;迁移期仍可运行。
|
||||||
- 账户、会话、管理员与会员双维度权限、私有数据隔离、系统凭据加密和模型密钥不回显已有服务端测试。
|
- 账户、会话、管理员与会员双维度权限、私有数据隔离、系统凭据加密和模型密钥不回显已有服务端测试。
|
||||||
- 行情供应商通过唯一 `DataGateway` 和来源策略进入业务层;公开展示源不能进入正式计算。
|
- 行情供应商通过唯一 `DataGateway` 和来源策略进入业务层;公开展示源不能进入正式计算。
|
||||||
- 情绪、竞价、观势、观气、观心、选股和复盘的核心确定性计算已有固定样本测试。
|
- 情绪、竞价、观势、观气、观心、选股和复盘的核心确定性计算已有固定样本测试。
|
||||||
|
|||||||
@@ -4779,10 +4779,11 @@ class RequestHandler(BaseHTTPRequestHandler):
|
|||||||
if parsed.path == "/api/auth/me":
|
if parsed.path == "/api/auth/me":
|
||||||
self.auth_me()
|
self.auth_me()
|
||||||
return
|
return
|
||||||
if parsed.path.startswith("/api/") and not self.require_auth():
|
if parsed.path.startswith("/api/"):
|
||||||
return
|
if not self.require_auth():
|
||||||
if not self.require_access("GET", parsed.path):
|
return
|
||||||
return
|
if not self.require_access("GET", parsed.path):
|
||||||
|
return
|
||||||
if parsed.path == "/api/admin/settings":
|
if parsed.path == "/api/admin/settings":
|
||||||
self.send_json(
|
self.send_json(
|
||||||
{"ok": True, **SERVICE.system_status(), "users": SERVICE.admin_users()}
|
{"ok": True, **SERVICE.system_status(), "users": SERVICE.admin_users()}
|
||||||
|
|||||||
@@ -281,6 +281,22 @@ class PublicKnowledgePermissionTests(unittest.TestCase):
|
|||||||
self.handler("/api/heaven/sector-phases/%E6%B2%B9%E6%B0%94", "send_json")
|
self.handler("/api/heaven/sector-phases/%E6%B2%B9%E6%B0%94", "send_json")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_static_shell_bypasses_the_api_access_registry(self):
|
||||||
|
handler = RequestHandler.__new__(RequestHandler)
|
||||||
|
handler.path = "/"
|
||||||
|
handler.require_auth = lambda: (_ for _ in ()).throw(
|
||||||
|
AssertionError("static request required authentication")
|
||||||
|
)
|
||||||
|
handler.require_access = lambda *_: (_ for _ in ()).throw(
|
||||||
|
AssertionError("static request entered the API registry")
|
||||||
|
)
|
||||||
|
served: list[str] = []
|
||||||
|
handler.serve_static = served.append
|
||||||
|
|
||||||
|
RequestHandler.do_GET(handler)
|
||||||
|
|
||||||
|
self.assertEqual(served, ["/"])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user