From c69e45a57133c6db735c168085d308e641bdb58b Mon Sep 17 00:00:00 2001 From: Nexus Agent Date: Thu, 11 Jun 2026 17:49:43 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9C=8D=E5=8A=A1=E5=99=A8=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E5=8E=86=E5=8F=B2=E9=83=A8=E7=BD=B2=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E4=B8=8E=E9=97=A8=E6=8E=A7=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- deploy/gate_log.jsonl | 90 +++++++++++++++++++ .../2026-06-11-servers-search-history.md | 46 ++++++++++ 2 files changed, 136 insertions(+) create mode 100644 docs/audit/2026-06-11-servers-search-history.md diff --git a/deploy/gate_log.jsonl b/deploy/gate_log.jsonl index f98275cd..761e9cbf 100644 --- a/deploy/gate_log.jsonl +++ b/deploy/gate_log.jsonl @@ -1567,3 +1567,93 @@ {"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} {"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} {"ts":"2026-06-10T20:57:52+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md 32lines"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T20:58:56+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md 32lines"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T20:59:12+08:00","date":"2026-06-10","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md 36lines"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T21:18:32+08:00","date":"2026-06-10","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-guacd-handshake-fix.md 30lines"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T21:28:00+08:00","date":"2026-06-10","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-feature-removal.md 48lines"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-hosts-standalone.md"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T23:21:27+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-feature-removal.md 48lines"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-feature-removal.md"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"review","result":"BLOCK","detail":"audit missing changed files"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T23:23:19+08:00","date":"2026-06-10","gate":"summary","result":"BLOCK","detail":"6/7"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"changelog","result":"PASS","detail":"2026-06-10-rdp-feature-removal.md 48lines"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"audit","result":"PASS","detail":"2026-06-10-rdp-feature-removal.md"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-10T23:23:34+08:00","date":"2026-06-10","gate":"summary","result":"PASS","detail":"7/7"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"changelog","result":"PASS","detail":"2026-06-11-servers-search-history.md 44lines"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"audit","result":"BLOCK","detail":"file not found"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"test","result":"BLOCK","detail":"tests failed"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"review","result":"BLOCK","detail":"no audit file"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-11T17:47:02+08:00","date":"2026-06-11","gate":"summary","result":"BLOCK","detail":"4/7"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"changelog","result":"PASS","detail":"2026-06-11-servers-search-history.md 44lines"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"audit","result":"PASS","detail":"2026-06-11-servers-search-history.md"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"test","result":"PASS","detail":"all passed"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"lint","result":"PASS","detail":"0 violations"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"import","result":"PASS","detail":"ok"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"security","result":"PASS","detail":"0 HIGH"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"review","result":"PASS","detail":"audit covers changes"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"shell_eol","result":"PASS","detail":"all tracked sh LF"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"text_eol","result":"PASS","detail":"git index LF"} +{"ts":"2026-06-11T17:47:40+08:00","date":"2026-06-11","gate":"summary","result":"PASS","detail":"7/7"} diff --git a/docs/audit/2026-06-11-servers-search-history.md b/docs/audit/2026-06-11-servers-search-history.md new file mode 100644 index 00000000..8c1c84e9 --- /dev/null +++ b/docs/audit/2026-06-11-servers-search-history.md @@ -0,0 +1,46 @@ +# 审计 — 服务器搜索历史 MySQL 持久化 + +## 范围(文件清单) + +| 文件 | 变更 | +|------|------| +| `server/domain/models/__init__.py` | 新增 `AdminUiPreference` | +| `server/infrastructure/database/admin_ui_preference_repo.py` | 读写偏好 JSON | +| `server/infrastructure/database/migrations.py` | 建表 `admin_ui_preferences` | +| `server/utils/server_search_history.py` | 去重/上限 12 条 | +| `server/api/servers.py` | `GET/PUT /api/servers/search-history` | +| `server/api/schemas.py` | `ServerSearchHistoryUpdate` | +| `frontend/src/composables/useServerSearchHistory.ts` | API + localStorage 一次性迁移 | +| `frontend/src/pages/ServersPage.vue` | combobox 搜索历史 | +| `tests/test_server_search_history.py` | 单元 + API 往返 | + +## Step 3 规则扫描 + +| H | 规则 | 结论 | +|---|------|------| +| H1 | 路由在 `/{id}` 之前注册 | PASS — `search-history` 静态路径优先 | +| H2 | 仅当前管理员可读写 | PASS — `get_current_admin` + `admin_id` | +| H3 | 无静默吞错 | PASS — API 异常向上抛出 | +| H4 | 无跨层直连 SQL | PASS — 经 `admin_ui_preference_repo` | +| H5 | 输入校验 | PASS — Pydantic + 归一化 strip/上限 | + +## Closure + +| H | 判定 | 依据 | +|---|------|------| +| H1 | PASS | `servers.py` 路由顺序 | +| H2 | PASS | repo 按 `admin_id` + `context` | +| H3 | PASS | 无 bare except | +| H4 | PASS | 分层合规 | +| H5 | PASS | `server_search_history.py` | + +## DoD + +- [x] `pytest tests/test_server_search_history.py` 4 passed +- [x] `npm run type-check` 通过 +- [x] changelog `2026-06-11-servers-search-history.md` +- [x] migration 启动时建表 + +## 验证 + +Servers 页搜索 → 刷新 → 历史仍在;换浏览器同账号 → GET 返回相同 `history`/`last`。