From 266eea723c4fdb20f4ad436fd81df27ed470cc7b Mon Sep 17 00:00:00 2001 From: xuans Date: Fri, 2 Oct 2026 09:18:55 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4SSH=E5=AF=86=E9=92=A5?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E5=B9=B6=E6=94=B6=E7=B4=A7=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除未注册的密钥 CLI、HTTP 处理和前端残留样式,保留 HTTPS 证书私钥路径与历史数据库兼容迁移;更新生产验收记录并记录后端、前端测试和构建结果。 --- backend/internal/cli/ssh_key.go | 29 ---- backend/internal/httpapi/ssh_key.go | 15 -- doc/Linux生产流程测试记录.md | 13 ++ doc/Scert整改任务执行清单.md | 13 ++ doc/Scert整改合并优化清单.md | 13 ++ frontend/src/views/Dashboard/Dashboard.css | 152 ------------------- frontend/src/views/Dashboard/SSHKeyModal.css | 131 ---------------- frontend/src/views/Dashboard/SSHKeyModal.vue | 3 - 8 files changed, 39 insertions(+), 330 deletions(-) delete mode 100644 backend/internal/cli/ssh_key.go delete mode 100644 backend/internal/httpapi/ssh_key.go delete mode 100644 frontend/src/views/Dashboard/SSHKeyModal.css delete mode 100644 frontend/src/views/Dashboard/SSHKeyModal.vue diff --git a/backend/internal/cli/ssh_key.go b/backend/internal/cli/ssh_key.go deleted file mode 100644 index b3bedb5..0000000 --- a/backend/internal/cli/ssh_key.go +++ /dev/null @@ -1,29 +0,0 @@ -package cli - -import ( - "errors" - - "github.com/spf13/cobra" -) - -func newSSHKeyCommand() *cobra.Command { - return &cobra.Command{ - Use: "ssh-key", - Short: "SSH 密钥登录功能已停用", - RunE: func(cmd *cobra.Command, args []string) error { - return errors.New("SSH 密钥登录功能已永久停用,仅支持 SSH 密码认证") - }, - } -} - -func newSSHKeyListCommand() *cobra.Command { - return newSSHKeyCommand() -} - -func newSSHKeyAddCommand() *cobra.Command { - return newSSHKeyCommand() -} - -func newSSHKeyDeleteCommand() *cobra.Command { - return newSSHKeyCommand() -} diff --git a/backend/internal/httpapi/ssh_key.go b/backend/internal/httpapi/ssh_key.go deleted file mode 100644 index 2fda3d3..0000000 --- a/backend/internal/httpapi/ssh_key.go +++ /dev/null @@ -1,15 +0,0 @@ -package httpapi - -import "github.com/gin-gonic/gin" - -func (s *Server) listSSHKeys(c *gin.Context) { - c.Status(404) -} - -func (s *Server) createSSHKey(c *gin.Context) { - c.Status(404) -} - -func (s *Server) deleteSSHKey(c *gin.Context) { - c.Status(404) -} diff --git a/doc/Linux生产流程测试记录.md b/doc/Linux生产流程测试记录.md index dcb5a5a..595a474 100644 --- a/doc/Linux生产流程测试记录.md +++ b/doc/Linux生产流程测试记录.md @@ -1809,3 +1809,16 @@ SQLite 新测试程序 SHA-256:4c81656fae63a2eebad999d58e6a79e63e6f441810e02ce - [~] P0-10、三数据库清库后的 Web 流程、Smail 系统账户发信、验证码密码重置和最终清库首次验收仍未完成。 总体生产部署验收仍未放行,当前状态保持 **P0-03:完成,等待复审**。 + +## 2026年10月2日 SSH 登录密钥入口移除复核 + +本轮按安全要求收紧产品边界:SSH 登录只允许密码认证,不提供私钥、公钥、密钥生成、授权文件写入或密钥登录管理能力。HTTPS 证书部署所需的证书私钥路径仍保留,二者用途不同。 + +- [x] 删除未注册的 SSH 密钥 CLI 入口文件,正式 CLI 不再包含密钥管理命令。 +- [x] 删除未注册的 SSH 密钥 HTTP 处理文件,生产路由继续不注册相关接口,`/api/v1/ssh-keys` 保持 404。 +- [x] 删除未引用的前端密钥弹窗文件和遗留样式,生产页面不提供密钥管理入口、命令或授权文件提示。 +- [x] 保留服务器主机指纹校验、SSH 密码字段和 HTTPS 证书私钥路径;没有把证书私钥误当作 SSH 登录凭据。 +- [x] 后端 `go test ./...` 全部通过;前端 241 项测试全部通过;Vite 生产构建通过;`git diff --check` 通过。 +- [~] 需要将最新候选包按正式安装流程部署到双机,并复核页面和 API 后再进入最终生产验收。 + +本轮不删除历史数据库迁移文件和禁用兼容测试;它们只用于既有数据库升级和安全回归,不会启用 SSH 密钥能力。总体生产验收仍未通过,既有证书 SAN、启动早期 502、Smail 系统账户发信和三数据库完整 Web 流程仍是门禁项。 diff --git a/doc/Scert整改任务执行清单.md b/doc/Scert整改任务执行清单.md index adb2006..f4c655c 100644 --- a/doc/Scert整改任务执行清单.md +++ b/doc/Scert整改任务执行清单.md @@ -1927,3 +1927,16 @@ P0-05 从 `[!]` 调整为 `[~]`,并未标记完成;P0-04 剩余门禁和全 - [ ] SQLite、MySQL、PostgreSQL 清库后的完整 Web 首次流程。 - [!] Smail 系统通知账户、真实发信、验证码、超级管理员重置密码和改密后重新登录闭环。 - [!] 第一台 `odacm.cn` 证书 SAN 不匹配及启动早期短暂 502 的生产结论。 + +## 2026年10月2日 SSH 登录密钥入口移除复核 + +本轮按安全要求收紧产品边界:SSH 登录只允许密码认证,不提供私钥、公钥、密钥生成、授权文件写入或密钥登录管理能力。HTTPS 证书部署所需的证书私钥路径仍保留,二者用途不同。 + +- [x] 删除未注册的 SSH 密钥 CLI 入口文件,正式 CLI 不再包含密钥管理命令。 +- [x] 删除未注册的 SSH 密钥 HTTP 处理文件,生产路由继续不注册相关接口,`/api/v1/ssh-keys` 保持 404。 +- [x] 删除未引用的前端密钥弹窗文件和遗留样式,生产页面不提供密钥管理入口、命令或授权文件提示。 +- [x] 保留服务器主机指纹校验、SSH 密码字段和 HTTPS 证书私钥路径;没有把证书私钥误当作 SSH 登录凭据。 +- [x] 后端 `go test ./...` 全部通过;前端 241 项测试全部通过;Vite 生产构建通过;`git diff --check` 通过。 +- [~] 需要将最新候选包按正式安装流程部署到双机,并复核页面和 API 后再进入最终生产验收。 + +本轮不删除历史数据库迁移文件和禁用兼容测试;它们只用于既有数据库升级和安全回归,不会启用 SSH 密钥能力。总体生产验收仍未通过,既有证书 SAN、启动早期 502、Smail 系统账户发信和三数据库完整 Web 流程仍是门禁项。 diff --git a/doc/Scert整改合并优化清单.md b/doc/Scert整改合并优化清单.md index c6adf5d..4e37fd3 100644 --- a/doc/Scert整改合并优化清单.md +++ b/doc/Scert整改合并优化清单.md @@ -2563,3 +2563,16 @@ P0-11 生产验收门禁 - [~] 启动早期 502 仍需按生产门禁继续评估:第二台本次安装后约第 2 秒探测出现 502,等待后恢复为严格 HTTPS 200;未开放 8443,也未绕过 Nginx。 当前总体状态仍为 **P0-03:完成,等待复审**,不能据此宣布生产整体验收通过。P0-10 负向恢复、三数据库清库后的完整 Web 流程、Smail 系统账户发信及密码重置闭环仍未完成。 + +## 2026年10月2日 SSH 登录密钥入口移除复核 + +本轮按安全要求收紧产品边界:SSH 登录只允许密码认证,不提供私钥、公钥、密钥生成、授权文件写入或密钥登录管理能力。HTTPS 证书部署所需的证书私钥路径仍保留,二者用途不同。 + +- [x] 删除未注册的 SSH 密钥 CLI 入口文件,正式 CLI 不再包含密钥管理命令。 +- [x] 删除未注册的 SSH 密钥 HTTP 处理文件,生产路由继续不注册相关接口,`/api/v1/ssh-keys` 保持 404。 +- [x] 删除未引用的前端密钥弹窗文件和遗留样式,生产页面不提供密钥管理入口、命令或授权文件提示。 +- [x] 保留服务器主机指纹校验、SSH 密码字段和 HTTPS 证书私钥路径;没有把证书私钥误当作 SSH 登录凭据。 +- [x] 后端 `go test ./...` 全部通过;前端 241 项测试全部通过;Vite 生产构建通过;`git diff --check` 通过。 +- [~] 需要将最新候选包按正式安装流程部署到双机,并复核页面和 API 后再进入最终生产验收。 + +本轮不删除历史数据库迁移文件和禁用兼容测试;它们只用于既有数据库升级和安全回归,不会启用 SSH 密钥能力。总体生产验收仍未通过,既有证书 SAN、启动早期 502、Smail 系统账户发信和三数据库完整 Web 流程仍是门禁项。 diff --git a/frontend/src/views/Dashboard/Dashboard.css b/frontend/src/views/Dashboard/Dashboard.css index b6205ec..a93976e 100644 --- a/frontend/src/views/Dashboard/Dashboard.css +++ b/frontend/src/views/Dashboard/Dashboard.css @@ -434,162 +434,10 @@ code { color: #63748c !important; } -.ssh-server-list { - display: grid; - gap: 14px; -} - -.ssh-server-card { - display: grid; - gap: 14px; - padding: 18px; - border: 1px solid #dfe7f1; - border-radius: 16px; - background: linear-gradient(135deg, #ffffff, #f8fbff); -} - -.ssh-server-card-heading, -.ssh-orphaned-heading, -.ssh-server-command { - display: flex; - align-items: center; - justify-content: space-between; - gap: 16px; -} - -.ssh-server-meta { - display: flex; - flex-wrap: wrap; - gap: 8px 18px; - color: #718198; - font-size: 12px; -} - -.ssh-server-domain-bindings { - display: grid; - gap: 8px; - padding: 12px; - border: 1px solid #e4ebf4; - border-radius: 12px; - background: #fff; -} - -.ssh-server-domain-list { - display: flex; - flex-wrap: wrap; - gap: 6px; -} - -.ssh-server-details { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 12px; -} - -.ssh-server-detail { - display: grid; - gap: 5px; - min-width: 0; - padding: 12px; - border: 1px solid #e4ebf4; - border-radius: 12px; - background: #fff; - color: #718198; - font-size: 12px; - line-height: 1.5; -} - -.ssh-server-detail strong { - color: #30435f; - font-size: 13px; -} - -.detail-label { - color: #8a98ab; - font-size: 11px; - letter-spacing: 0.04em; -} - -.ssh-server-detail code, -.ssh-server-command code { - overflow-wrap: anywhere; - color: #345f94; - font-family: ui-monospace, SFMono-Regular, Consolas, monospace; - font-size: 12px; -} - .inline-error { margin: 0; } -.ssh-server-command { - padding: 10px 12px; - border: 1px solid #d8e5f4; - border-radius: 12px; - background: #f3f8ff; -} - -.ssh-server-command > div { - display: grid; - gap: 5px; - min-width: 0; -} - -.ssh-orphaned-keys { - display: grid; - gap: 10px; - margin-top: 18px; - padding-top: 16px; - border-top: 1px solid #e7edf5; -} - -.ssh-orphaned-heading > div { - display: grid; - gap: 3px; -} - -.ssh-orphaned-list { - display: flex; - flex-wrap: wrap; - gap: 8px; -} - -.ssh-orphaned-item { - display: inline-flex !important; - align-items: center; - gap: 8px; - padding: 7px 10px; - border: 1px solid #e1e8f1; - border-radius: 9px; - background: #fbfcfe; - color: #6f7f94; - font-size: 12px; -} - -@media (max-width: 900px) { - -.ssh-server-details { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } -} - -@media (max-width: 640px) { - .ssh-server-card-heading, - .ssh-orphaned-heading, - .ssh-server-command { - align-items: stretch; - flex-direction: column; - } - - -.ssh-server-details { - grid-template-columns: minmax(0, 1fr); - } - - .ssh-server-command .inline-button { - align-self: flex-start; - } -} .modal-backdrop { position: fixed; inset: 0; diff --git a/frontend/src/views/Dashboard/SSHKeyModal.css b/frontend/src/views/Dashboard/SSHKeyModal.css deleted file mode 100644 index eea6c33..0000000 --- a/frontend/src/views/Dashboard/SSHKeyModal.css +++ /dev/null @@ -1,131 +0,0 @@ -.modal-backdrop.ssh-key-backdrop { - padding: 16px; -} - -.ssh-key-modal { - box-sizing: border-box; - width: min(100%, 1180px); - max-height: calc(100dvh - 32px); - overflow: auto; - padding: 18px 24px; -} - -.ssh-key-modal .modal-heading { - margin-bottom: 10px; - padding-bottom: 10px; -} - -.ssh-key-modal form { - grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); - gap: 18px; -} - -.ssh-key-modal .ssh-key-guide, -.ssh-key-modal .ssh-key-form-fields { - min-width: 0; - padding: 12px; -} - -.ssh-key-modal .ssh-key-guide-heading { - margin-bottom: 8px; -} - -.ssh-key-modal .ssh-key-guide-heading > div:first-child, -.ssh-key-modal .ssh-key-steps article > div, -.ssh-key-modal .field > span, -.ssh-key-modal .field-label-row > span { - display: flex; - align-items: center; - gap: 6px; -} - -.ssh-key-modal .ssh-key-steps { - gap: 6px; -} - -.ssh-key-modal .ssh-key-steps article { - gap: 5px; - padding: 7px 5px; -} - -.ssh-key-modal .ssh-key-steps strong { - font-size: 12px; -} - -.ssh-key-modal .ssh-key-platforms { - margin: 8px 0; - padding: 3px; -} - -.ssh-key-modal .platform-tab { - padding: 6px 8px; -} - -.ssh-key-modal .ssh-key-path-line, -.ssh-key-modal .ssh-key-path-summary { - gap: 5px; - padding: 6px 8px; - margin: 6px 0; -} - -.ssh-key-modal .ssh-key-path-summary { - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.ssh-key-modal .ssh-key-path-summary > div:last-child { - grid-column: auto; -} - -.ssh-key-modal .ssh-command-card { - margin-top: 6px; - padding: 7px 8px; -} - -.ssh-key-modal .ssh-command-heading { - margin-bottom: 4px; -} - -.ssh-key-modal .ssh-command-card > code { - font-size: 11px; - line-height: 1.4; -} - -.ssh-key-modal .field { - margin-bottom: 10px; - gap: 5px; -} - -.ssh-key-modal .field input, -.ssh-key-modal .field textarea { - min-height: 36px; - padding: 8px 10px; -} - -.ssh-key-modal .ssh-key-form-fields .field textarea { - min-height: 130px; -} - -.ssh-key-modal .ssh-key-form-fields .modal-actions { - margin-top: 10px; - padding-top: 10px; -} - -@media (max-width: 900px) { - .ssh-key-modal form { - grid-template-columns: minmax(0, 1fr); - } - - .ssh-key-modal .ssh-key-form-fields { - grid-column: 1; - } -} - -@media (max-width: 640px) { - .ssh-key-modal { - padding: 16px; - } - - .ssh-key-modal .ssh-key-path-summary { - grid-template-columns: minmax(0, 1fr); - } -} diff --git a/frontend/src/views/Dashboard/SSHKeyModal.vue b/frontend/src/views/Dashboard/SSHKeyModal.vue deleted file mode 100644 index 61bfc75..0000000 --- a/frontend/src/views/Dashboard/SSHKeyModal.vue +++ /dev/null @@ -1,3 +0,0 @@ -