Files
LinkPort/docs/change-rationale.md
T

199 KiB
Raw Blame History

变更原因与设计记录

Kubernetes 本机高位和固定端口(2026-10-02)

原因:用户要求使用高位端口,并能在页面配置固定端口。结果:Kubeconfig 代理提供自动/固定两种模式,自动分配 49152–65535,绑定失败最多尝试 32 个端口;固定范围为 1024–65535,占用或绑定拒绝时明确报错,不自动改端口。仅监听 127.0.0.1。字段为 outbound.localPort,省略或 0 为自动,旧配置继续兼容,无迁移。目标数据库端口和网关对外端口不变。独立隧道无法共享同一固定端口,具体范围、持久连接及 SPDY 超时限制见 Kubernetes 配置。

实际验证:Go 1.27.1 全量测试中的 model、outbound、gateway 和所有协议包通过,新增 SPDY fixture 覆盖高位范围、固定端口通信、冲突拒绝及关闭后重新绑定。没有真实 Kubernetes 集群验证。go vet ./...、前端类型检查和生产构建通过,新嵌入程序 artifacts/ansi-insert/linkport.exe 构建通过,恢复 web/dist/.gitkeep。Playwright 使用新程序及隔离数据库/28181、28182 端口,代理上传与保存回读用例通过,覆盖固定端口 55032、编辑保留和 390px 无溢出;同文件资产重传用例在搜索框定位处超时,未进入端口配置。全量后端仍复现 API WebDAV 口令、cluster RSA fixture panic、desktop Windows 数据路径和 syncjob 明文秘密断言失败,不记为全套通过。前端保留 Node 22.10/Vite 推荐版本和 chunk 大小提示。未部署真实服务或修改真实目标数据。

默认 SQLite 数据目录改为用户目录(2026-10-01)

原因:工作区下的 data/linkport.sqlite 不适合作为桌面应用默认数据位置。

行为与范围:未设置 LINKPORT_DATA 时,默认使用当前用户主目录下 .linkport/linkport.sqlite(例如 C:\Users\zoe\.linkport\linkport.sqlite)。不再发现或使用工作区 data/linkport.sqlite。显式环境变量路径优先级不变。

移除 WebDAV 同步口令与加密(2026-10-01)

原因:WebDAV 同步口令和同步对象加密不再需要,简化跨设备同步配置。

行为与范围:WebDAV 同步配置及 backups/ 快照改为直接存储同步 JSON;删除设置、同步请求和界面中的同步口令输入与校验。独立配置导出/导入仍保持原有口令加密。旧本地设置和请求中的口令字段仅作兼容读取并被忽略,不会继续写入或用于加密。

兼容影响:已有加密 WebDAV 对象无法被新版本读取,升级前应清理或重新上传同步对象;WebDAV 传输认证密码仍按原方式保存。

实际验证:针对性 Go 包测试可编译;旧同步测试中关于加密内容和错误口令的断言按新行为失败。前端 vue-tsc 通过,Vite 构建受当前 Node 22.10.0 低于 Vite 要求的 22.12.0 影响,未完成。

账号备注与统一筛选变更(2026-09-29)

原因:账号显示名称并不是认证身份,且很多账号没有适合维护的名称。账号身份应继续由稳定 ID 和用户名承担,描述信息改为可选的账号备注;同时项目/环境筛选与各列表页自己的筛选条件此前分散在卡片、画板或审计区域,跨页面切换时难以发现和复用。

行为与范围:TargetAccount 的领域字段、JSON 响应、草稿、导入、映射、连接测试、集群/监控/过期提示和持久化统一使用可选 remark。备注先去除首尾空白,最多 100 个 UTF-8 字节,可以为空;显示时按备注、用户名、本地化“未填写备注”回退。旧请求、导入、备份、同步和历史数据中的 name 仍可读取,显式 remark(包括空字符串)优先;新响应和新写入不再输出 name。启动迁移按主键窄更新当前目标、目标历史和配置模板中的加密目标 JSON,使用旧密文 CAS 条件保证幂等,不改变 SQLite schema 或密钥用途。降级到不认识 remark 的旧版本前必须保留备份。

项目/环境筛选与目标、网关/概览、拖拽连线、代理管理、命令审计、连接事件筛选统一放入页面顶部区域;旧页面内重复筛选控件已移除,状态继续按浏览器范围保存,窄屏控件逐行排列。连线协议筛选覆盖 TCP、MySQL、MongoDB、SSH、SFTP、HTTP、HTTPS、SQL Server、Redis、RabbitMQ、PostgreSQL 共 11 种协议。筛选只改变当前视图,不改变绑定、布局或后端数据。

兼容与降级影响:旧账号字段只作为读取兼容层和迁移输入,不能再通过正常保存路径持久化;没有备注的账号仍可认证和映射。旧浏览器或旧程序可能只显示用户名,旧程序保存后可能丢失新备注,因此发布前应完成备份。其他资源的 name 字段不受影响。

实际验证:Go 1.25.0 下账号模型、API、当前/历史/模板迁移专项通过;go vet -p=1 ./... 通过;全量 go test ./... -count=1 -timeout=120s 的业务包通过,剩余失败为当前 Windows 沙箱的 ACL/SQLite 快照权限限制(6 个既有用例)。vue-tsc --noEmit -p web/tsconfig.json 通过,git diff --check 通过。npm.cmd --prefix web run build 在 Vite 启动 esbuild 时被环境以 spawn EPERM 阻止,未生成新 web/dist 或 executable,因此未用旧程序运行 LINKPORT_E2E_BINARY Playwright 验收;新增跨页面筛选用例已加入 web/tests/workspace-filters.spec.ts,待可创建子进程的环境执行。

恢复 Drone 默认源码克隆(2026-09-29)

原因与结果:Git 服务现已可由 Drone 直接获取源码,原先关闭默认克隆后再启动 Alpine、安装 Git、写入 .netrc、补取引用并核对提交的步骤已无必要。删除 clone.disable 和自定义 clone 步骤后,Drone 在用户步骤开始前使用默认克隆取得当前构建源码,流水线直接从前端构建开始,减少一次容器启动和 Alpine 软件源依赖。

范围与兼容:仅改变 CI 源码获取方式;前端构建、Go 1.25.0 六平台串行编译、包验证、IPFS 上传、代理变量和明文令牌均不变,无应用配置或数据迁移。仓库凭据、引用选择和提交检出改由 Drone 默认克隆实现负责,不再执行仓库脚本原有的 SHA-1/SHA-256 协商补取及提交一致性复核;需要当前 Drone/Git 服务组合支持目标仓库。

实际验证:使用 Go 1.25.0 和仓库固定的 go.yaml.in/yaml/v3 成功解析 .drone.yml,并断言不再存在 clone 配置且用户步骤仍依次为 frontend-build、build-binaries、package;自定义克隆指令检索无残留,git diff --check 通过。未触发远端 Drone,因此默认克隆仍需用新构建记录确认。

Redis 与 MongoDB 网关允许无客户端账号(2026-09-28)

原因与结果:Redis 与 MongoDB 上游都可关闭认证,但新建网关原先仍强制创建客户端账号和密码,无法直接提供无认证入口。现在这两类网关都可保存空的 gatewayAccounts,客户端无需执行本地认证即可连接;若配置任意网关账号,则恢复原有协议认证。上游账号是否需要认证仍由目标服务的账号列表独立决定。

范围与兼容:放开 Redis、MongoDB 网关的空账号列表、模型校验、创建草稿及对应协议认证分支;MySQL 等其他网关及已有带账号网关行为不变。沿用现有加密配置,无数据库迁移;旧版本不识别该无客户端认证配置,回退前需停服并核对备份。

实际验证:Go 1.25.0 模型、API 和 Redis 协议定向测试,以及前端 Redis 草稿逻辑测试通过;协议覆盖使用本机 RESP/net.Pipe fixture,不是 live-server Redis 验证。未修改真实 data,未部署或重启服务。

资产入口改为网络代理(2026-09-27)

原因:用户希望管理网络连通方式,Kubeconfig 应与 SSH、SOCKS5 一样独立保存,再关联目标服务和网关;文件分类和内联配置使同一用途出现不同操作路径。

结果:主入口改为「代理管理 → 新建代理」,顶部直接选择 Kubeconfig、SSH、SOCKS5 或 sing-box。文件不再出现在主列表;上传作为凭据配置步骤保留,旧文件仍可经搜索与引用编辑。目标先选择代理类型再引用记录;普通协议网关继承目标的代理,TCP 纯转发网关可直接引用四种代理。只选类型、丢失引用或混入其他模式配置会阻止保存,不会默默变为直连。

范围与兼容:前端管理/选择表单、model 的 TCP 引用契约、store 的运行时解析/引用校验/导入、API 的解析与间接依赖保护。新 tcpForward.mode="proxy" 只存 outboundId、host/port,Kubeconfig 资源和凭据属于代理;API 继续脱敏。旧空 mode/SOCKS5、目标或网关内联 K8s、原代理 ID、文件凭据及备份均保留,无数据库迁移和真实 data 操作。旧执行程序不认识新的 proxy mode,回退须核对备份兼容性。保留 SSH 确认会话绑定、运行中共享配置修改拦截和删除保护。

实际验证:新增 model/store/API 矩阵和本机 SOCKS5 字节转发 fixture 通过;Go 1.25.0 全量测试仅复现已知六项 Windows ACL/快照环境失败,全量 vet 通过。前端 15 个逻辑测试文件最终通过,包含新增代理逻辑 11 项;类型检查通过。构建受 Vite/esbuild spawn EPERM 阻止,未生成最新生产资源和 executable,浏览器用例仅更新并发现,未执行。新增文案按 multilingual-ui 沿用项目本地中文、英文、日文字典。功能说明见 网络代理管理,命令与限制见 测试记录。

新建资产类型直接选择(2026-09-27)

原因:新建文件资产时,类型隐藏在下拉框内,用户需要展开才能看到其他类型。

结果:资产类型移到创建表单顶部,以可换行的六个单选项直接展示,复用既有类型名称。默认 Kubeconfig、切换类型清除本次上传、保留名称/环境/备注及编辑时类型不可改的规则保持。按 multilingual-ui 检查后复用已有文案,没有新增翻译机制。

范围与兼容:仅文件资产创建/编辑页的类型控件与顺序;就地创建仍使用入口指定类型,列表筛选、API、存储格式及已存资产不变,无迁移。同步更新四个现有 Playwright 流程的类型选择及编辑禁用断言。

实际验证:npm.cmd --prefix web run build 的 Vue 类型检查通过,Vite/esbuild 仍被环境以 spawn EPERM 阻止。四个相关 Playwright 用例发现成功,但没有最新生产资源及 executable,未执行浏览器验收;git diff --check 通过。操作说明见 文件资产,详细记录见 测试记录。

全模块职责与设计模式重构(2026-09-27)

原因:核心三处重构后,启动、连接会话、集群探测、告警、同步以及前端编辑仍各自混合多个变化原因。按用户要求扩大到全模块,先核对每个模块的职责和依赖,再拆分实际存在的耦合点;已有单一职责的基础设施维持原结构。

结果:启动采用组合根与命令分派,11 个业务协议集中到工厂;模型将运行契约和账号规则归位。API 拆分身份适配、路由/锁管线与领域命令。网关将审计、认证、流量和异常释放集中到连接会话,实例统一停止与锁外等待。集群以协议策略驱动遍历模板。告警拆分规则与通知,通过消费者侧 Repository 访问存储;同步拆分调度/租约与传输,并通过 ObjectStore 适配 WebDAV。备份加密信封独立于数据库快照。前端增加连接草稿工厂与提交构建器、凭据会话、游标加载模板和画板浏览器适配器。

范围:覆盖 cmd、model、api、gateway、protocol、outbound、cluster、store、alerts、syncjob、backup、web;desktop、security、localcert、cryptotool、navicat、buildinfo、testutil、devcert、静态资源嵌入与 scripts 经审查保留清晰的现有边界。完整的实际拆分/保留清单和扩展入口见 全模块架构 与 模块说明。没有为了覆盖率改写协议报文、加密算法或增加通用框架。

兼容与迁移:本轮不改变用户可见行为、文案、HTTP 路由/载荷、配置和加密格式、数据库 schema。认证/CSRF 与错误优先级、操作锁范围、确认会话绑定、网关快照与停止顺序、集群限额与取消、告警重试、同步租约及冲突顺序保持。按 SQL 安全技能核对并保留既有 SQL/事务/锁,无迁移、部署或真实 data 操作。保留此前未提交的 Redis 零账号、页面交互、Kubeconfig、Sing-box、运行中编辑和 MySQL 策略等功能。

测试维护:全前端逻辑回归发现持久目标 SSR 用例仍要求“停止并重新启动网关”,与此前已实现的运行中保存后重试行为不符。仅更新该用例的恢复指引断言,产品文案和运行实现未改动。

实际验证:各拆分模块先执行包级检查,再运行 Go 1.25.0 全仓测试与 vet。全仓 vet 通过;全量测试仅复现原有 6 项 Windows ACL/SQLite 快照环境失败,其余通过。前端 14 个单进程逻辑测试文件最终均通过,包括新增 14 项草稿/凭据/分页测试;Vue 类型检查通过。Vite/esbuild 仍受 spawn EPERM 阻止,无新生产资源或包含它们的 executable,未执行 Playwright 浏览器验收。四个方向的交叉源码审查未发现本轮引入的具体缺陷,但不替代浏览器或 race 验证。详细命令与失败清单见 测试记录。协议、HTTP 和数据库验证均为本地 fixture/隔离数据,不是 live-server 验收。

核心模块按设计模式重构(2026-09-27)

原因:出口选择与 SOCKS5 握手耦合,server.go 混合公共请求控制与网关操作,App.vue 在读取、写入和会话清理中重复维护资源缓存。新增能力会跨越不相关职责,难以单独验证。

结果:出口采用函数策略与工厂,并用装饰器统一每次拨号的校验/超时;SOCKS5 握手独立成文件。网关动作采用私有命令表,把启停、测试和 SSH 指纹逻辑移到 gateway_actions.go,server.go 保留认证、CSRF、路由和原有锁。前端通过注入请求的 useResourceCatalog 门面管理四类列表和刷新代次,App.vue 负责页面/会话协调。先做保行为搬移并验证,再拆分职责;不引入新依赖或额外抽象框架。

范围与兼容:保持已有超时、KeepAlive、诊断、取消清理、失败不回退直连、网关错误/权限/会话绑定和前端保存优先于旧响应的语义。HTTP、配置、数据库、产品文案和原有未提交功能均保持兼容,无迁移,未操作真实数据目录。扩展规则见 核心设计模式。

实际验证:出口完整包与 API 聚焦回归通过;前端新增 10 项注入请求的异步行为测试及类型检查通过,全仓 Go vet 通过。全量 Go 测试仍仅有 6 项已记录的 Windows ACL/SQLite 快照环境失败,其余通过。生产构建在 Vite 启动 esbuild 时受到当前沙箱 spawn EPERM 限制,未生成新程序或执行浏览器验收。完整结果见 测试记录。协议和 SSH 会话绑定测试均使用本地 fixture,不代表真实服务器连通性验证。

sing-box 单 outbound 连接资产(2026-09-27)

原因:资产管理原有 direct、SOCKS5、SSH 和 Kubernetes 路径无法表达 VLESS、VMess、Trojan、Hysteria 2、TUIC、Shadowsocks 等 sing-box outbound。直接逐个实现协议会扩大长期维护面;本次官方资料核对未找到 Go library API 的跨版本稳定性承诺,嵌入 module 还会与本仓库固定 Go 1.25.0 发生现实工具链冲突(官方 v1.14.2 go.mod 要求 1.25.5)。连接用户自行运行的常驻代理会把端口、认证和生命周期交给部署者,因此选择由 linkport 管理外部 binary。

结果行为:连接资产新增 sing-box mode,接收最多 64 KiB 的单个 outbound JSON object,也支持粘贴或导入完整配置后自动提取远程 outbound。linkport 删除用户 tag、拒绝未能提取远程 outbound 的完整配置和宿主文件/进程/路由能力,生成只监听 127.0.0.1 且带随机认证的 SOCKS5 入站,并把最终路由固定到该 outbound。首次目标拨号执行 sing-box run -c,相同规范化配置与 binary 路径共享进程,最后一条连接关闭后清理。失败不回退直连。资产“检查配置”执行 10 秒上限的 sing-box check -c,只验证当前 binary 接受配置,不启动 run、不拨代理或目标;失败响应只含安全错误常量和耗时,不附加 diagnostics 或 sing_box_start 阶段。

安全与秘密:binary 通过 LINKPORT_SING_BOX 定位,未设置时从 PATH 查找,发布包不捆绑。整个 singBoxOutbound 视为秘密,加密持久化且不经 API 回显;历史差异和导入预览只显示 secretChanged,脱敏 bundle 清空正文。运行配置关闭日志,命令 stdout/stderr 丢弃,临时目录/文件请求 0700/0600 并在结束后删除。递归拒绝 *_path、detour、plugin/外部进程、自定义 resolver、network namespace、bind/routing mark 等能力,因为子进程继承 linkport OS 身份。

影响范围:普通目标可引用新的共享连接资产,路径和诊断增加 sing_box_start/connect/negotiation/authentication,随后沿用 target_connect 和目标协议阶段。当前只承载 TCP,不启用 mixed/TUN/UDP/系统代理;独立 TCP 网关仍只使用 SOCKS5 或 Kubernetes,不接受 sing-box 资产。运行时可能产生多个子进程,因此“单 EXE”不是“单 OS 进程”。

兼容与迁移:沿用加密 outbounds 记录,无 SQLite 表结构迁移,旧 direct/SOCKS5/SSH/K8s 数据不变。旧 linkport 不认识新 mode,回退前应停服并保留完整加密备份。linkport 不声明 sing-box 最低/最高版本;部署应固定 binary,并在升级后先检查配置再测试目标。2026-09-27 官方最新稳定版为 v1.14.2;sing-box 的 GPL v3-or-later 及附加名称条款归其上游,linkport 不重新分发该 binary。

实际验证:Go 1.25.0 聚焦 model/outbound/store/api 的 SingBox 测试、model/outbound 全包及全仓 go vet -p=1 ./... 通过;前端单进程 sing-box.test.mjs 10 项、connection-stages.test.mjs 6 项及 Vue 类型检查通过。覆盖大小/结构/危险字段、tag 规范化、受控 SOCKS5 配置、进程共享与重启、目标域名透传、API/bundle/历史差异脱敏和三语闭合错误映射。全仓 Go 测试除 6 个 Windows 文件权限/便携 SQLite 快照用例返回 Access is denied 外通过;生产前端构建受 esbuild spawn EPERM 阻塞,未生成新 executable 或执行 Playwright。当前机器未安装 sing-box,也未连接真实代理或目标;上述结果是 fixture 验证,不是 live-server 或远程协议验收。详细命令、沙箱限制和官方依据见 测试记录 与 sing-box 连接资产。

Kubernetes 端口候选与权限预检(2026-09-27)

原因:资源查询已经返回 Pod、Service、Deployment 和 StatefulSet 声明的 TCP 端口,但网关 Kubeconfig 纯端口转发仍要求重复手输,容易选错 Service 端口;同时读取资源成功不代表具备 pods/portforward 权限,错误通常要到启动时才暴露。

结果:Kubernetes 表单把发现到的端口作为候选,在不会覆盖已保存值或用户手工值的前提下自动建议单个/首个端口。Service 候选和手工值明确为 Service 端口,其他资源为容器端口,界面统一称为“资源端口”。网关 Kubeconfig 模式增加非阻断权限预检,后端使用 SelfSubjectAccessReview 分别检查目标资源 get、必要的 Pod list 和 create pods/portforward,严格区分允许、明确拒绝和无法判断。预检只返回白名单化元数据与稳定错误码,不返回凭据或 Kubernetes 原始错误。上传/内联 Kubeconfig 的共享校验会在保存、发现、预检和正式运行前拒绝可能读取服务端文件或执行本机命令的配置,资产保存错误也通过稳定 code 传到前端翻译。

范围与兼容:新增只读资产子接口及前端诊断控件,不改变网关保存、备份格式或数据库结构。上传/内联 Kubeconfig 新增自包含安全约束:拒绝 CA、客户端证书/密钥及 Token 的外部文件引用,并拒绝 exec/auth-provider 登录插件,避免以 linkport 身份读取主机/UNC 路径或执行命令;现有此类资产需先 flatten、改用内嵌凭据后重新上传。旧不安全资产仍可原样导出加密备份,但重命名、恢复、导入预览和包含它的合并导入都会重新校验并拒绝。显式本地 Kubeconfig 文件路径及其中的登录插件仍作为可信部署配置保持兼容;既有网关级持久隧道复用、断线重解析 Pod 和指数退避不变。预检结果不持久化、不阻止保存;授权允许也不证明对象存在、Pod Ready、端口匹配或 SPDY 成功,集群禁用权限审查时显示未知并继续允许实际测试。

实际验证:Go 1.25.0 下聚焦测试、internal/outbound 全包和全量 go vet 通过;受控 TLS fixture 覆盖允许、拒绝、无 authorizer 意见、评估错误、权限审查被拒绝及登录插件阻断,API fixture 覆盖认证、资产类型、查询校验、稳定响应和凭据不泄漏。前端类型检查及 7 项专项逻辑测试通过,相关 Playwright 场景可发现;Vite/esbuild 被当前沙箱的 spawn EPERM 阻止,没有生成新程序或执行浏览器回归。测试使用隔离资产与本机 fixture,不是对真实 Kubernetes RBAC、网络策略或 SPDY 成功链路的验收;全量 Go 中 6 个既有 Windows ACL/SQLite 快照用例仍失败。详细命令见 测试记录。

关闭连接测试时清理结果状态(2026-09-26)

原因:目标草稿测试会打开独立结果页,但编辑器底部同时保留“连接成功/连接失败”和“实测连接阶段”。用户关闭结果页后会立即看到这份重复结果,表现为关闭操作没有隐藏测试状态。

结果:连接测试结果页完成关闭后,统一清空全局结果数据和当前目标草稿测试的内联摘要、阶段诊断;标题返回按钮、底部“关闭”和 Esc 均经过同一关闭事件。编辑草稿、测试账号选择和未保存状态不重置,再次点击“测试连接”会生成全新的结果。

范围、兼容与迁移:仅调整前端测试结果的显示生命周期和对应浏览器回归,不改变连接测试请求、成功判定、诊断脱敏、目标配置或保存行为。已保存目标、网关及草稿测试共用的结果页在关闭时也会释放旧详情数据。没有 API、配置格式、SQLite 或数据迁移影响,也没有新增或变更用户可见文案。

实际验证:vue-tsc --noEmit -p web/tsconfig.json 通过,更新后的 workspace-features.spec.ts 可被 Playwright 正确发现,共 3 项;回归断言覆盖结果页消失、编辑器内联状态消失及“实测连接阶段”消失。npm.cmd --prefix web run build 的类型检查通过,但 Vite 启动 esbuild 时被当前 Windows 沙箱以 spawn EPERM 拒绝,因此无法生成新嵌入程序,也未把测试发现当作浏览器执行通过。Go 1.25.0 下,go vet -p=1 ./... 通过;完整 go test ./... -count=1 -timeout=120s 除 6 项既有 Windows ACL/SQLite 快照环境失败外其余包通过,故不宣称后端全量通过。Go 协议包使用仓库本地 fixture,并非真实服务器验收;未连接真实目标服务,未修改真实 data。

运行中编辑目标与网关配置(2026-09-26)

原因:目标服务和网关服务的编辑入口在有关联网关运行时被禁用,API 也要求先停止。修改目标地址、凭据、监听或访问策略因此必须中断所有现有客户端;旧的“先启动 listener、再保存 enabled”和“先停止、再保存 disabled”顺序还会在持久化失败时短暂发布未提交状态或停止已经工作的服务。

结果:目标和网关自身可在运行中保存。每条已接受连接持有接受时的不可变配置快照;保存成功后只有新连接使用新配置。目标更新先解析所有引用网关,在一次目标持久化成功后批量发布运行快照;网关监听地址变化先预绑定候选 listener,再保存和切换,旧 listener 停止接受新连接但不关闭其已有连接。启动在生命周期锁内重新加载、预绑定并保存 enabled 后才发布;停止先保存最新运行快照的 disabled 状态,保存失败则继续运行。绑定、校验或持久化任一步失败都会关闭候选 listener,并保持数据库、运行快照和原 listener 不变。

并发与安全:运行实例采用 compare-and-swap;较新的网关编辑、目标批量更新、启动或停止先完成时,陈旧请求返回 409,要求刷新重试。停止状态只比较生命周期 enabled 变化,使停止后排队的旧 PUT 不能重新覆盖,同时允许在全部网关停止后进行历史恢复、导入或 WebDAV 替换。存储为内联出口生成的 OutboundID 只是引用间接层,CAS 清除顶层和目标映射中的该 ID 后比较实际已解析出口,避免相同路由误报冲突。协议类型仍不可修改;共享文件资产/连接资产的运行中引用保护和删除保护、WebDAV 全量替换停服要求均不放宽。

SSH/SFTP 候选地址变化会清除旧 pin,并在保存前只探测公开主机密钥,不发送目标认证凭据。首次保存返回 409、stage: target_host_confirmation 和 SHA256 指纹;用户核对后前端带临时 hostFingerprint 重试一次,服务端重新探测且一致才保存实际 host key。取消确认保留编辑草稿且不报保存失败。该临时字段不进入模型、历史或 API 回读。

兼容与迁移:沿用现有目标、网关和监听 API;新增的结构化 409 只出现在需要 SSH/SFTP 候选身份确认时。没有 SQLite schema 或数据迁移,旧记录无需重写。普通目标或网关配置编辑仍不迁移目标、不替换凭据,也不主动断开;显式「切换目标」操作从 2026-09-28 起会在保存成功后主动断开该网关的现有连接,详见后文记录。

实际验证:Go 1.25.0 下,运行配置/生命周期/SSH 定向回归对 internal/gateway、internal/api 通过;go test -p=1 ./internal/gateway ./internal/api -skip '^TestDatabaseSnapshotSessionAndPreview$' -count=1 -timeout=120s 通过,go vet ./... 通过。规定的全量 go test ./... -count=1 -timeout=120s 未全绿:复现 6 项既有 Windows ACL/便携 SQLite 快照环境失败,另有未修改的 internal/protocol/pgproxy/TestPreparedRejectsDifferentIdentity/account 间歇 fixture 失败;该子项随后单次复跑通过,20 轮复跑仍间歇失败。本功能涉及的 gateway 全包通过,API 除既有快照项外通过。

前端 vue-tsc --noEmit 通过;Playwright 成功发现 running-edit.spec.ts、target-editor-test.spec.ts、workspace-features.spec.ts 共 19 项,覆盖运行中编辑入口、监听端口切换、SSH 确认取消/重试及关闭测试结果清理。npm.cmd --prefix web run build 在类型检查后因当前 Windows 沙箱禁止 Node 启动 esbuild 而报 spawn EPERM,没有新前端产物或新嵌入程序,因此未运行 Playwright,也未使用旧程序代替。后端覆盖使用隔离 SQLite、本机 TCP/SSH fixture;浏览器运行编辑场景使用占位上游,不是真实数据库服务。未停止本地服务,未读取、迁移或修改真实 data、审计、TLS 和主密钥材料。

网关 TCP 独立端口映射支持 Kubeconfig(2026-09-26)

最终复验:使用 Go 1.25.0 实际执行新增模型、存储、API、既有 TCP 边界测试,均通过;go vet -p=1 ./... 通过。全量 go test ./... -count=1 -timeout=120s 仅复现 6 个既有 Windows ACL/SQLite 快照环境失败,未出现本功能失败。前端逻辑测试 6/6、关联映射测试 5/5,Vue 类型检查通过;Vite/esbuild 仍被环境以 spawn EPERM 阻止,故未生成新程序或执行 Playwright,只在工作区临时目录成功发现 3 个相关场景。测试使用隔离 SQLite、临时端口和 Kubernetes fixture,未连接真实集群或修改真实 data。

原因:纯端口转发原来只接受 SOCKS5 代理、目的主机和端口。需要访问 Kubernetes 内固定资源时,用户必须额外创建目标服务或维护其他出口配置,与「网关服务直接做端口映射」的操作预期不一致;Kubeconfig 内容如果复制到网关记录,也会扩大敏感信息的持久化和回显范围。

结果:TCP 网关的纯端口转发新增 socks5 与 k8s 两种方式。K8s 方式直接选择 Kubeconfig 资产、Context、命名空间、Pod/Service/Deployment/StatefulSet 资源和容器端口,不关联目标服务或账号,也不要求 host/outboundId。保存时只持久化资产 ID 和资源元数据,Get/List、启动和测试时再从资产解析 Kubeconfig 正文并构造现有 Kubernetes port-forward 出口;API 脱敏、网关历史和网关备份条目均不包含正文。模式切换重建互斥字段,列表、连线画板、启动检查和连接测试显示 K8s 资源路径,不再生成空主机或 undefined 摘要。

范围、兼容与迁移:改动限于 TCP 独立转发模型、网关资产解析、存储/备份引用校验,以及网关编辑和状态展示。缺省/空 mode 保持旧 SOCKS5 语义;现有 SOCKS5 转发、TCP 目标关联、共享连接资产和其他协议不迁移。直接引用会进入资产删除保护、影响分析和运行中更新保护;停止后更新 Kubeconfig 时先用待写入正文校验所有直接引用网关,失败则事务回滚,避免后续列表或启动被无效 Context 破坏。完整加密备份在 assets 中保留正文,网关只保留引用;缺失或错误类型资产在预览/恢复阶段拒绝。无 SQLite schema 或数据迁移,但旧版本无法理解 K8s 独立映射,回退和多节点同步前需处理新配置。

实际验证:Go 1.25.0 下,模型、存储、API 和既有 Kubernetes 出口专项在工作区隔离临时目录中串行通过;覆盖运行时注入、字段互斥、旧 SOCKS5 兼容、API 脱敏、资产删除和运行保护、无效更新原子回滚、加密备份及恢复校验。模型全包通过;Store 全包仅 2 项既有 Windows 快照权限用例失败,API 全包仅既有 portable SQLite snapshot 用例失败,故不宣称三包全量均通过;go vet -p=1 对 model/store/api 通过。前端 tcp-kube-forward.test.mjs 6/6、关联账号映射测试 5/5、Vue 类型检查及差异格式检查通过,覆盖双向切换、精确 payload、旧无 mode 回读和摘要;Playwright 在工作区临时目录中发现新增文件的 2 项用例,但尚未用新构建程序执行。受限执行环境第一次拒绝系统临时目录,并发首次编译还出现 compile.exe: exit status 9;改用工作区 TEMP/GOTMPDIR/GOCACHE 与 -p=1 后上述专项通过,不能把前两次环境失败记为测试失败或通过。Kubernetes 拨号使用隔离 TLS API fixture,既有传输覆盖使用模拟 API/SPDY fixture;未连接真实集群,未验证现场 RBAC、网络策略或业务服务,也未修改真实 data。完整命令和后续全量结果见 测试记录。

所有独立弹层改为工作区子页面(2026-09-26)

原因与行为:居中弹框和遮罩在长表单、宽表格及手机页面中显示空间不足,嵌套确认也容易遮挡上下文。目标、网关、资产编辑器以及搜索、详情、预览、敏感信息、确认和输入流程现统一使用带返回按钮的工作区子页面;标题、正文滚动和底部操作区保持稳定,Esc 只关闭最上层页面,未保存更改仍需明确确认。确认请求在当前页关闭后再推进队列,重复点击或重复导航不会误操作后一请求;退出登录会取消待处理请求,保存和测试期间禁止关闭编辑页。表格列设置原浮动面板也改为子页面;选择器、操作菜单、工具提示和短暂通知保持控件原交互。详见 工作区子页面。

范围与兼容:只改变前端展示与导航容器,原 API、请求顺序、权限、校验、草稿、定时清密、资源标识、配置格式和数据存储不变,无迁移要求。沿用现有内存工作区模型,不新增 URL 路由;浏览器刷新行为不变。关闭页面仍恢复入口焦点,运行保护、引用保护和冲突处理继续生效。

实际验证:vue-tsc --noEmit、2 项页面确认队列测试、工作区页面源码禁止项测试和 git diff --check 通过;静态检查确认 web/src 已移除 el-dialog、el-drawer、el-popover 和 ElMessageBox 弹层实现。Playwright 成功发现 56 个文件、125 项用例。npm.cmd --prefix web run build 的类型阶段通过,Vite 因当前 Windows 沙箱禁止 esbuild 子进程而报 spawn EPERM,开发服务器也在相同阶段失败,因此没有新前端产物或本地预览 URL;未构建新嵌入程序或运行 Playwright,不使用测试发现或旧程序结果代替本轮验收。Go 1.25.0、工作区内缓存/临时目录及串行编译下,go vet ./... 通过;go test -p=1 ./... -count=1 -timeout=120s 的其余包通过,但仍有 6 项既有 Windows 文件权限或 SQLite 快照环境失败,分布于 cmd/linkport、internal/api、internal/desktop、internal/security 和 internal/store,全量测试不记为通过。测试只使用隔离临时目录,未停止本地服务或修改真实 data。

新建服务入口补充:目标列表和网关列表分别固定新建类别,不再在编辑器内提供“资源类别”下拉;“服务类型”是两类新建表单的第一个配置字段,编辑已有服务时继续锁定协议。这样先确定协议后再展示对应参数,也避免从明确入口进入后重复选择类别。只影响表单顺序与展示,不改变 API、保存结构或已有数据;对应浏览器回归已加入 target-editor-test.spec.ts,本轮仅完成用例发现,未在受 spawn EPERM 限制的环境中执行。

Redis 上游允许零账号(2026-09-26)

原因与行为:部分 Redis 服务没有启用 ACL/密码,过去目标至少一个账号和网关必须选择 targetAccountId 的统一约束会迫使用户创建虚假凭据。现在仅 Redis 允许保存空账号列表;草稿与已保存目标测试、集群识别、手动/周期健康检查、持续连接以及网关默认或账号级映射均可使用空账号 ID,并且不会向单节点、Cluster、Sentinel 或重定向节点发送上游 AUTH。Redis 网关仍先校验客户端网关账号和密码;客户端 HELLO AUTH 中的三项认证参数在转发到零账号上游前移除。

约束与兼容:Redis 一旦添加任意目标账号,所有测试、识别和映射立即恢复显式选择有效账号的规则;普通节点、Cluster/replication 及显式 Sentinel 账号认证失败时不降级。未选择 Sentinel 账号时,原有“自动尝试目标账号或无认证”兼容模式仍只针对 Sentinel 保留。只有 Sentinel 需要认证而数据节点不需要时,需创建一个 authMethod: "none" 的数据账号并另选 Sentinel 凭据账号。沿用现有加密目标 JSON、空 targetAccountId 和配置备份格式,无 SQLite 迁移;响应中的空 accounts 可能因 omitempty 被省略,前端按空列表处理。给已绑定的零账号 Redis 添加首个账号后,需为相关网关补选账号再启动。

实际验证:Go 1.25.0、工作区临时目录和串行编译下,model、cluster、gateway、redisproxy 全包及 Redis API 定向回归通过,go vet -p=1 ./... 通过。最终 go test -p=1 ./... -count=1 -timeout=120s 未全绿:功能相关包均通过,失败为 6 项既有 Windows 权限/SQLite 快照环境问题,分布于 cmd/linkport、internal/api、internal/desktop、internal/security 和 internal/store;首次未限制并发的全量运行还遇到编译子进程 Access denied,因此以 -p=1 结果为准。前端 vue-tsc --noEmit、Redis 纯逻辑 4 项、持续连接 6 项、账号映射 5 项通过;Playwright --list 在工作区 TEMP 下成功发现 target-auth 与 target-editor-test 两个文件的 22 项用例。Vite/esbuild 受当前沙箱 spawn EPERM 阻止,无法生成新的 dist 和嵌入式可执行程序,因此按必须使用新构建程序的规则未运行 E2E。协议覆盖使用本机 RESP/net.Pipe fixture,验证普通连接、Cluster、Sentinel、认证降级边界和 HELLO AUTH 重写,不是实际 Redis/Sentinel 服务器兼容验收;未修改真实 data。

MySQL 放行 character_set_results 会话设置(2026-09-26)

原因与行为:客户端连接初始化常见的 SET character_set_results = NULL 被安全读写和只读策略拦截。该设置只决定返回结果编码,不改变上游后续 SQL 的解析方式;现允许 NULL、DEFAULT 以及静态 utf8mb4、utf8、utf8mb3、ascii、latin1,拒绝其他字符集、用户变量、动态值和 SET GLOBAL。

范围与兼容:仅放宽结果字符集设置;sql_mode、character_set_client、character_set_connection、collation_connection、SET CHARACTER SET 和 WHERE 检查不变。无数据格式迁移,现有连接重新建立后生效。详见 MySQL 写入保护和账号模式。

实际验证:Go 1.25.0 下 go test ./internal/protocol/mysqlproxy ./internal/model -count=1 -timeout=120s 与 go vet ./internal/protocol/mysqlproxy 通过;新增 fixture 覆盖安全读写/只读策略、网关转发以及 SET GLOBAL、非白名单字符集拒绝。internal/api 仍有一项既有 SQLite 快照环境失败(cannot create a complete portable SQLite snapshot),与本次改动无关。

MySQL 三种账号模式与常用协议命令放行(2026-09-25)

原因与行为:COM_BINLOG_DUMP 被统一协议白名单拒绝,且复制事件不能按普通 SQL OK/结果集处理。新增复制注册、Binlog/GTID 持续转发、统计文本、进程列表、选项切换和常用管理命令;只读账号继续拒绝管理写操作。复制流保留事件与序号,EOF/错误后关闭专用连接,客户端断开或上下文取消时释放上游,注册审计不记录凭据。

按用户确认提供只读、安全读写(默认)和普通读写三个账号模式。旧 readwrite 继续要求 UPDATE/DELETE 外层 WHERE;显式 unrestricted 跳过 SQL 解析和解析兼容模式初始化,由上游控制权限。全局只读仍优先,普通读写仅限 MySQL。影响范围为 MySQL 协议、账号模式模型校验和账号编辑/展示,无数据库迁移;已有连接需要重新建立才能使用新策略。详见 账号模式与协议命令。

实际验证:Go 1.25.0 MySQL 和模型包测试、账号模式 API 保存回归、go vet ./... 通过。使用本机 TCP MySQL 协议 fixture 验证流式转发、序号回绕、模式与命令行为,不连接真实 MySQL。全量后端测试仍有 6 项既有文件权限/SQLite 快照测试失败(Access is denied、cannot create a complete portable SQLite snapshot),其余包通过;日志 .cache/sqlite-removal/mysql-modes-full-test.log。Vue 类型检查和 2 项模式展示逻辑测试通过,新增 Playwright 用例可发现;Vite/esbuild 的 spawn EPERM 阻止构建新二进制,未运行浏览器回归。

拖拽连线改为可移动服务画板并支持全屏(2026-09-25)

原因与行为:固定左右两列无法自由整理服务关系。改为可拖动节点、平移和缩放的画板,网关蓝色、目标绿色;按实际账号按钮位置绘制跟随节点的连线。卡片顶部移动布局,连接区继续负责绑定;提供适应、重置与全屏,支持退出按钮和 Esc,浏览器全屏不可用时铺满窗口。按项目、环境保存本地布局,全屏隐藏重复明细以扩大操作空间。

范围与兼容:仅修改连线视图、独立画板状态与计算模块,以及 App.vue 的范围参数;沿用原有账号绑定、测试和启停接口。布局只存资源 ID、坐标与视角,不存凭据,无数据库迁移。操作和限制见 服务连线画板。

实际验证:Vue TypeScript 检查通过,7 项内存 Node 测试通过,覆盖布局、缩放、存储隔离、首次测量/视口自适应和手势清理;新增浏览器回归并确认 Playwright 可发现测试。Vite 构建因环境的 esbuild spawn EPERM 失败,未能生成新二进制运行浏览器套件;未连接真实目标服务。

MySQL 严格拒绝无 WHERE 的更新和删除(2026-09-25)

原因与结果:用户要求严格限制不带 WHERE 的 UPDATE/DELETE。新增独立 AST 写入保护,在 MySQL 网关所有账号的普通 SQL 和二进制预处理准备阶段执行;批次预先整体检查,外层缺少 WHERE 即拒绝并审计,子查询条件、JOIN ON、LIMIT、字符串或注释不算外层条件。带条件的写入保留既有权限检查,只读账号继续禁止全部写入。

范围与兼容:只改 MySQL 协议模块和相关 fixture,不增加开关、数据库迁移或业务 SQL 改写。为使严格检查与上游词法一致,读写连接也在初始化/重置时固定 SQL 模式和安全字符集;文本动态 SQL、可执行注释、优化器提示、解析失败和修改解析环境的请求被拒绝。WHERE 1=1 仍允许,存储例程/触发器等服务器内部行为不在保证范围。完整边界及客户端适配见 MySQL 写入保护。

实际验证:Go 1.25.0、工作区内缓存/临时目录及 GOFLAGS=-p=2 下,go test ./internal/protocol/mysqlproxy -count=1 -timeout=120s 和 go vet ./... 通过;新增策略用例补充 SET LOCAL、系统变量引号、排序规则及可见过程定义后,标准定向测试再次通过。go test ./... -count=1 -timeout=120s 中 MySQL 及其他协议包通过,全量仍复现此前 6 个本机权限/快照失败,位于 cmd/linkport、internal/api、internal/desktop、internal/security、internal/store,未宣称全量通过。日志见 .cache/sqlite-removal/mysql-where-full-test.log 和 mysql-where-vet.log。git diff --check 通过。测试使用本机协议 fixture 和隔离临时库,没有连接外部真实 MySQL,也没有执行真实业务数据更新;本轮无前端改动,未运行前端构建/Playwright,未部署或重启服务。

目标账号使用下拉切换编辑(2026-09-25)

原因与结果:用户要求账号页在添加多个账号后可以下拉切换。目标账号编辑改为下拉选择当前账号,仅展示当前账号字段;添加后自动选中新账号,切换保留各账号未保存的输入,删除当前账号后选择剩余账号。保存和草稿测试触发的账号校验可自动选中对应账号并定位字段。

范围与兼容:涉及目标账号 Vue 组件、父级错误定位及已有账号浏览器测试。继续保存完整账号数组,保留账号 ID、密码沿用/清空、私钥资产、有效期和 32 个账号上限;底部连接测试仍可独立选择测试账号。无 API、后端或数据库迁移。使用说明见 连接配置页签。

实际验证:vue-tsc --noEmit、git diff --check 通过;使用工作区内临时目录后 Playwright --list 成功发现 123 项用例,包含新增目标账号回归。使用 Node 22.22.3 与 Vue 编译器加载实际组件 setup,验证账号切换、草稿保留、新增自动选中、跨账号错误定位、删除到空列表及重新新增,全部通过;这是组件状态验证,不是浏览器布局验证。独立子智能体复查未发现遗漏。最终 npm.cmd --prefix web run build 的类型检查通过,但 Vite 启动 esbuild 被环境 spawn EPERM 阻断,因此未生成新嵌入程序,未执行需要新程序的 Playwright 套件。未改动后端,本轮未重复运行 Go 检查,未使用真实目标数据。

连接方式仅保留独立页签(2026-09-25)

原因与结果:用户指出已有独立「连接方式」页签,无需在「连接信息」中重复展示。移除目标新建/编辑表单中连接信息区域的连接方式组件,保留独立页签内的直连、SSH/SOCKS5 连接资产和 Kubernetes 配置;删除高级页中将连接方式指向连接信息的过时提示。页签切换继续共用目标草稿,地址/TLS 联动、保存和测试沿用既有逻辑;目标内联 Kubernetes 字段的校验错误改为定位到「连接方式」,使用户仍可直接修正对应字段,独立连接资产编辑的错误定位不变。

范围与兼容:仅调整前端展示入口、相关浏览器用例与使用文档,无后端 API、配置格式或数据库迁移;已有连接资产引用和内联 Kubernetes 配置保持兼容。详见 连接配置页签。

实际验证:vue-tsc --noEmit 通过;Node 直接执行实际校验模块,确认资源、命名空间和缺失 Kubeconfig 三类目标校验均定位到 outbound,独立连接资产仍定位 target。相关既有浏览器用例已调整为独立页签操作,并覆盖无重复控件、切换保留草稿及错误定位。前端打包在 esbuild 启动时遇到 spawn EPERM,因此未生成新程序或执行浏览器套件;不把静态检查作为真实 Kubernetes/代理连接验证。无后端改动或真实数据操作。

恢复全部六平台打包并默认串行执行(2026-09-25)

原因与结果:用户要求结束临时 Linux 单平台验证,恢复所有平台,并将打包并发改为 1。编译脚本和发布脚本恢复 Linux、Windows、macOS 各自的 amd64/arm64,共六个目标。Drone 与脚本默认同时设置 BUILD_JOBS=1、GO_BUILD_PARALLELISM=1,默认 GOMAXPROCS 随之为 1,六个平台逐一构建,失败后不再启动后续平台。

范围与兼容:恢复六包清单校验、两个 ZIP 和四个 tar.gz、六个独立包 CID 和四文件索引,回执 files 从五项恢复为十项;单包或三包清单不能用于本次发布,需使用新的构建工作区,已有包不删除。直接上传和最终完整下载地址保留,无应用配置或数据库迁移。README、IPFS 发布 和 输出目录 已同步。

实际验证:Node 22.22.3 下 25 项脚本测试通过,覆盖默认六个平台不重叠执行、Go 编译并发为 1、首个平台失败后停止、显式并发覆盖、六个压缩包内容、七次 IPFS add 请求及最终下载 URL;YAML 配置和差异检查通过。编译使用替身 Go,上传使用本机 HTTP fixture,未运行真实六平台交叉编译或远端 Drone/IPFS 发布。

临时仅发布 Linux amd64(2026-09-25)

原因与结果:用户要求缩短打包等待,以快速验证 IPFS 上传与最终下载地址。编译脚本和发布脚本的目标列表同步收敛为 linux/amd64,当前只生成 linkport-<VERSION>-linux-amd64.tar.gz,不编译 Windows/macOS;前端构建、Linux 单文件验证、校验清单和直接上传流程继续执行。IPFS 请求由三包加索引共四次降为一包加索引共两次,成功日志仍包含下载总页和 Linux 包完整直链。

范围与兼容:仅影响 Drone 发布目标、清单校验和对应回归测试;应用运行行为及本地 Windows 打包入口不变,无数据迁移,旧包不删除。当前脚本拒绝旧多平台清单,需在新工作区构建;回执字段结构不变,files 由七项变为五项(一个包和四个索引文件)。恢复多平台时需同步修改两个目标列表和测试。README、发布说明 及 输出目录 已更新。

实际验证:Node 22.22.3 下编译脚本及发布脚本共 25 项测试通过,覆盖仅启动 Linux 编译、缺失二进制与构建失败、单包校验、两次 IPFS add 请求、完整 HTTP 下载地址、上传失败及日志不泄露令牌;差异检查通过。编译使用替身 Go、上传使用本机 HTTP fixture,未运行真实 Go 交叉编译或远端 Drone/IPFS 发布,不据此宣称实际上传问题已解决。

打包成功后直接上传 IPFS(2026-09-25)

原因与结果:实际 Drone 日志显示三个包生成成功后进入事件判断的跳过分支,因此没有执行上传,也没有最终 CID 或下载地址;日志未显示实际事件值,不能认定具体触发类型。移除 DRONE_BUILD_EVENT 条件,打包命令后直接执行 node scripts/ci-release.mjs upload,成功后沿用完整下载页和各平台直链汇总,失败仍使步骤失败。

范围与兼容:所有成功执行到打包末尾的事件均上传,包括手动构建、PR 和事件变量缺失的构建;替代此前仅 push/tag 上传的限制。不更改包格式、平台范围、代理或凭据,无应用数据迁移。说明见 IPFS 发布。

实际验证:YAML 解析确认上传紧跟打包且不含步骤事件过滤;Node 22.22.3 下发布脚本 10 项测试通过,覆盖三包及索引上传、完整下载 URL、校验失败、部分上传失败及令牌不出现在日志。测试使用本地 HTTP fixture,未触发真实 Drone/IPFS 发布。

简化 Drone 克隆配置(2026-09-25)

原因与结果:用户反馈 .drone.yml:19 附近配置过于复杂。删除单独的 Git 版本、对象格式和重复提交日志,将两项必填参数检查合并为 Shell 参数断言,将缺失提交补取改为一行短路命令。保留新版 Git 安装、私有仓库 netrc 认证、自动识别 SHA-1/SHA-256、构建 ref 补取及完整提交 ID 校验;其余打包和发布行为不变,无配置或数据迁移。说明见 IPFS 发布。

实际验证:YAML 解析、Shell 语法和差异检查通过;使用本机 Git 2.54.0、Git sh 和临时 SHA-1/SHA-256 仓库,六种克隆场景(两种格式各验证主分支、PR ref 和 SHA 补取)均严格检出预期提交;必填参数为空时失败。未运行真实 Drone 容器或远端私有仓库认证。

忽略本地临时测试输出(2026-09-25)

原因与结果:汇总提交时发现 .tmp-test/ 中的编译缓存和测试二进制尚未被忽略。增加仅针对仓库根目录的忽略规则,防止生成产物进入源码历史;保留所有现有文件,不改变应用行为,无迁移。目录说明同步到 本地输出目录。验证使用 git check-ignore 检查缓存和二进制路径,并执行差异检查。

补充临时构建目录忽略规则(2026-09-27)

原因与结果:当前测试和构建工具还会在根目录 .tmp/ 及 web/.tmp/ 写入缓存、浏览器结果和临时测试文件;这两类目录此前会出现在 Git 未跟踪状态中。补充仅针对这两个目录的忽略规则,保留现有文件,不改变应用行为,无迁移。目录说明同步到 本地输出目录。

实际验证:使用 git check-ignore 确认 .tmp/、web/.tmp/、.tmp-test/、bin/、artifacts/ 和 data/ 均被忽略,并执行差异检查。

打包日志直接显示 IPFS 下载地址(2026-09-25)

原因与结果:原 package 步骤只显示本地压缩包路径,最终下载链接位于独立 upload-ipfs 步骤,不便查找。将上传合并到 package 的最后一条命令;push/tag 成功上传三包及索引后,在同一打包日志末尾输出 https://ipfs.freeicu.top/ipfs/<CID>/ 下载总页及各包完整直链。其他事件明确提示跳过上传;上传失败使打包步骤失败,不输出最终成功汇总。

范围与兼容:只调整 Drone 步骤编排和日志位置,沿用原头部、代理、认证、三平台范围及上传脚本;PR 仍只打包,包结构和回执格式不变,无应用配置或数据库迁移。说明见 IPFS 发布。

实际验证:Node 22.22.3 下两组发布脚本测试共 25 项通过,包含完整下载地址及部分上传失败断言;YAML 解析、命令顺序和原头部检查通过。使用 Git sh 与替身上传命令验证 push/tag 执行、pull_request/promote/空事件跳过,并确认上传失败退出码传递。使用本机 HTTP fixture,未触发真实 Drone 或真实 IPFS 上传。

移除 SQLite 文件菜单及功能(2026-09-25)

原因与结果:用户明确要求移除整个“SQLite 文件”菜单及功能。删除侧边栏入口、页面标题与说明分支、专用 Vue 组件及状态模块、SQLite 文件浏览 API 路由与实现、internal/sqlitebrowser 及专用测试;同步调整全菜单浏览器测试和 UI 文档。

范围与兼容:原 POST /api/v1/tools/sqlite/inspect、POST /api/v1/tools/sqlite/query 在通过通用认证及 CSRF 校验后返回 404,调用方需停止使用。没有数据库迁移,也不删除真实 SQLite 文件;应用持久化、配置备份及停服恢复继续保留。功能状态见 SQLite 文件。

实际验证:Node 22.22.3 下 vue-tsc --noEmit 及 git diff --check 通过;Playwright test --list 成功发现剩余 122 项测试。独立子智能体只读复查未发现入口或实现残留。npm.cmd --prefix web run build 在 Vite 启动 esbuild 时被当前环境的 spawn EPERM 阻断,改用工作区内临时目录仍失败,因此未生成新嵌入程序,未运行需要新程序的 Playwright 浏览器套件。

Go 1.25.0 的 go test ./... -count=1 -timeout=120s 与 go vet ./... 首次被工作区外缓存/临时目录写权限阻断;将缓存和临时目录移到 .cache/sqlite-removal 后完成重试,仍遇到 vet.exe 启动拒绝。Go 测试有 6 项失败,分布于 cmd/linkport、internal/api、internal/desktop、internal/security 和 internal/store:5 项报告文件权限拒绝,API 备份测试返回无法生成完整快照;其余包测试通过,全量检查未通过。验证日志位于 .cache/sqlite-removal/go-test.log、.cache/sqlite-removal/go-vet.log。验证仅使用隔离临时数据和本机 fixture,不是外部真实协议服务器验证;未操作真实 data。

项目图标与启动标识(2026-09-24)

原因:用户要求设计项目图标并在启动时打印。新增蓝底白色 P 与青色连接点的 SVG,复用于 README、登录/侧栏和 favicon,随前端嵌入程序;正常服务启动打印纯 ASCII 对应标识,沿用现有版本日志。命令行查询、JSON、路径、证书和维护命令不打印图案,避免污染机器可读输出。只改变品牌展示及正常启动日志,无数据或配置迁移,不修改 EXE 原生资源图标。设计和使用边界见 docs/branding.md。

实际验证(2026-09-25):Node 22.22.3 生产构建、Go 1.25.0 go test ./... -count=1 -timeout=120s 和 go vet ./... 通过。新增命令边界测试验证正常启动打印一次、维护命令及 stdout 不含标识,原 JSON/路径测试仍通过。新嵌入程序 bin/dev-build/branding-20260925/linkport.exe 通过隔离启动/登录验证,全部 124 项 Playwright 通过;确认 SVG 正常加载及 favicon 引用,检查实际 ASCII 启动日志和桌面/登录截图,预览保存在 bin/previews/branding-20260925/。测试使用临时数据与本机 fixture,不是上游真实服务器验证。差异检查通过,未部署或修改真实 data。

功能重要性与语义颜色(2026-09-24)

原因:用户反馈界面只有白底黑字,功能重要性难以区分。统一主题主色为蓝色(深色采用亮蓝),浅色背景使用淡蓝灰;核心导航显示文字标记,配置/监控图标使用紫/青区分,统计卡增加语义色边框、浅底和数字,网关启动/停止用绿/橙区分,状态色块及异常面板突出成功/异常。保留文字和图标、焦点与禁用态,不以颜色替代状态说明。覆盖公共主题、导航、首页、网关统计/操作及连接编辑器选中页签,不改数据、权限、网络或操作确认,无迁移。主题偏好存储值不变。

实际验证:npm.cmd --prefix web run build 通过(本机 Node 22.10 提示 Vite 引擎版本及既有 chunk 大小警告);随后 Go 1.25.0 构建新嵌入程序 bin/dev-build/ui-colors-20260924/linkport.exe,以 LINKPORT_E2E_BINARY 指向它,在隔离数据库和 18381/18382 端口运行全部 Playwright:主题/响应式 5 项通过,其余 119 项通过。后半套因 Node 22.10 缺少 node:sqlite 改用已安装的 Node 22.22.3 执行;未修改系统默认版本。检查浅色桌面、深色手机真实截图,预览位于同目录的 light-desktop.png / dark-mobile.png;代表性主按钮和语义文字在 8% 色底上的配色计算最低对比度为浅色/海蓝 4.51:1、深色 4.99:1,不宣称已覆盖所有状态的无障碍审计。git diff --check 通过。浏览器后端/协议验证使用隔离本机服务或 fixture,未连接真实目标或修改真实 data;无后端业务改动,未重复运行全量 Go 单测。

完整下载地址集中输出(2026-09-24)

用户指出前一轮只核对已有代码而未产生修改。本次调整上传成功日志:先输出 IPFS URI,末尾集中输出下载总页及七个文件的完整 HTTP(S) URL,每个地址单独一行,使用当前 API 同源网关和实际返回 CID。仅改变日志排版,不改上传、包格式或流水线配置,无迁移要求。通过本机 HTTP fixture 验证八条独立地址及失败不输出成功汇总;未重新发布真实 IPFS 产物。

发布目标缩减为三个(2026-09-24)

按用户要求排除 windows/arm64、linux/arm64、darwin/amd64,仅构建和发布 linux/amd64、windows/amd64、darwin/arm64。同步编译循环、归档目标、清单/索引校验及回归测试;有限并行和下载直链不变,不修改流水线触发。每次发布生成三个包及两份本地清单,执行三个单包 add 和一次四文件索引 add,成功回执含七项文件。旧六平台产物/CID不删除;新校验不接受旧六平台清单,需使用新输出目录重新打包,消费者不应写死旧包数。无应用或数据库迁移。验证使用隔离 fake Go 与 HTTP fixture,不宣称三平台真实重新编译或上传已完成。

上传成功后打印各平台下载直链(2026-09-24)

原因:用户要求 IPFS 上传后在构建日志打印下载地址。保留已有下载总页和 IPFS URI,增加六包及四份索引/清单的同源网关 HTTP(S) 直链;包使用自身 CID 和 filename 参数。仅全部上传成功后打印,部分失败不显示最终下载直链。只调整发布脚本日志及测试/文档,不改流水线触发、上传协议、回执或包格式,无迁移要求。验证:本机 HTTP fixture 检查全部十条直链及 URI、失败不输出包直链、令牌不泄漏;未重新执行真实 IPFS 发布或探测网关。

六平台有限并行编译(2026-09-24)

原因:原脚本六个平台串行且每次 go build -p 1,用户反馈耗时。先统一下载模块,默认每批并行两个平台、每平台包编译并发为 2,默认 GOMAXPROCS=2;环境变量允许调节,内存不足可将 BUILD_JOBS/GO_BUILD_PARALLELISM 均退回 1。等待同批全部子任务并检查退出码,失败不生成发布元数据。仅调整编译步骤环境、脚本和打包阶段测试列表,保留用户验证可用的流水线头部、触发、归档格式和 IPFS 行为,无应用/数据库迁移。不添加宿主机挂载或跨构建缓存,不保证首次依赖下载加速;真实速度与峰值内存尚需 runner 实测。

实际验证:新增 15 项隔离 fake Go/shell 测试通过,覆盖六目标、并发重叠及上限、参数边界、模块下载次数、失败等待同批任务与 guard 清理;既有发布及路径 13 项测试通过,shell 语法及差异检查通过。测试不是实际编译性能基准。用户提供的 logs_zoe_linkport_17_1_3.log 仍为旧串行脚本输出,打印到六平台但无退出状态,不能据此确认最终发布成功。

打包恢复后的上传可见性(2026-09-24)

用户反馈当前可打包,保留现有 .drone.yml,不再调整头部、平台或触发条件。为避免逐包上传等待期间看不出进度,发布脚本在每次请求前打印包序号/总数及文件名,索引请求前打印四文件提示;全部成功后打印同源 /ipfs/<索引CID>/ 下载页。日志仅声明 add 已接受及请求 pin,不代表独立验证 pin 状态。回执格式、七请求上传、六平台包与失败退出行为不变,无数据迁移;API 同源网关需由部署提供,本次不自动探测下载页。

验证:发布脚本与路径测试覆盖进度输出、成功下载页、部分失败不输出最终下载页及令牌不出现在日志中;使用本机 HTTP fixture,未重新触发 Drone 或上传真实包。此前本地真实发布的六包完整 Range SHA256 和索引字节验证记录保存在 bin/releases/ci.gateway-check.json、bin/releases/ci.index-check.json;不将用户的可打包反馈视为整条 IPFS 发布已验证。令牌配置以当前用户要求的 YAML 明文为准,不需要 Drone Secret,仓库读者可见。

基于可触发配置替换发布步骤(2026-09-24)

原因:用户确认恢复原始配置后可正常触发。以该版本为基准,仅把原 plugins/docker 步骤替换为前端编译、六平台编译、归档验证及 IPFS 上传;头部、代理和 clone 不变,不添加 type、platform 或顶层 trigger。仅上传步骤限制 push/tag。按用户明确要求,IPFS_TOKEN 明文配置,无需 Secret;仓库及历史读者可获取令牌,需限制访问并在泄露时轮换。无应用或数据库迁移。验证发布脚本测试与配置前缀一致性、git diff --check;未运行远端 Drone,不能认定触发故障根因或宣称已恢复。

Drone 省略显式流水线类型(2026-09-24)

原因:用户反馈现有 Drone 环境添加 type: docker 后不执行打包,要求移除。仅删除 .drone.yml 的显式类型字段,保留平台、事件、六平台打包及 IPFS 上传步骤;不修改应用、产物格式或数据,无数据迁移。尚未取得服务端日志,不能认定通用根因或保证删除后恢复。实际验证:本地差异检查及 git diff --check;未触发远端 Drone,恢复情况需用新提交构建确认。

Drone 六平台小请求 IPFS 发布(2026-09-24)

原因:用户要求保留 Windows/Linux/macOS × amd64/arm64 六个平台独立包并发布到 IPFS,不构建或推送 Docker 镜像。最初八文件整批上传约 117MB 时连接中断,而单包约 18MB 请求成功,因此改用小请求作为规避策略,尚未证实 Cloudflare 具体大小上限。节点组合目录接口 object/new、files/stat、dag/put 返回 404,不依赖它们。仅使用 /api/v0/add:六包各自 wrap-with-directory=false、pin=true、CIDv1,严格校验每包 Name/CID;随后把安全转义下载页、含六包 CID/SHA256 的 JSON 索引、原 release.json 和 SHA256SUMS.txt 四个小文件包装为目录上传,同样请求 pin。每次显式使用 linkport-ci-release/1 User-Agent。

范围与兼容:修改发布脚本、专项测试及 IPFS 文档,不改应用运行时、数据库、六平台打包方式或本地单 EXE 入口。固定 API https://ipfs.freeicu.top、必需的 Drone ipfs_token Secret、现有 http://192.168.9.1:7893 代理保持不变,不要求 ipfs_api Secret;本次不改 .drone.yml。令牌通过 curl stdin 配置传递,不写仓库、不进 argv 或日志,保留 TLS 校验并禁用隐式 curl 配置。原六包和两份清单保持不变,生成索引只放受检临时目录。失败立即终止,不写最终成功回执;已成功请求 pin 的单包不自动撤销。已有回执时在上传前拒绝覆盖。

发布格式迁移:ci.ipfs.json 继续使用 { cid, files },但 cid 现在代表四文件索引目录,files 由八项变为十项。六包 URI 为各自 ipfs://<包CID>,四个索引/清单文件 URI 为 ipfs://<索引CID>/<文件名>,旧消费者必须停止将包文件名拼到索引 CID 后面。下载页使用 /ipfs/<包CID>?filename=<编码文件名> 和两份原清单的相对链接。索引文本内 CID 不是 DAG 链接,pin 索引目录不会递归 pin 六包;迁移与备份须同时保留全部包 CID 和索引 CID,各包依赖自己的 add pin=true 请求。公开纯函数 createIpfsIndex(manifest, archiveEntries) 返回 { index, html },供真实发布复用;输入六项 file/cid/sha256,输出 packages 补齐 os/arch/uri。

本次实际验证:node --test scripts/ci-release.test.mjs scripts/project-paths.test.mjs 共 13 项通过,覆盖七个请求、逐次 pin/CIDv1/wrap 参数、显式 User-Agent、完整六包索引和十项回执、安全转义/下载链接、纯函数不修改输入、校验失败零请求、部分包/索引失败无成功回执、令牌不进 argv/日志、原文件字节保留及回执防覆盖。使用本机 HTTP fixture,不是真实节点发布;git diff --check 通过。只读使用实际进度 JSON 验证纯函数可生成六包索引,无真实网络请求或 bin 写入;未重复运行应用 Go/前端/浏览器回归。

据主代理提供的实测记录,请求通过 http://192.168.9.1:7893 代理:/api/v0/add 不带认证返回 401,带认证空文件请求返回 400 file argument 'path' is required。/api/v0/version 使用应用 User-Agent 返回 200,而 Python-urllib 默认 User-Agent 被 Cloudflare 1010 拦截;此前的 403 不代表上传不可用。object/new、files/stat、dag/put 均返回 404,发布实现不依赖这些组合目录接口。

117MB 八文件整批上传连接中断,单个约 18MB 包上传返回 HTTP 200,因此改用小请求逐包发布;尚未确定 Cloudflare 的具体大小上限,也不认定中断原因已被证实。当前六个 archive 已逐个上传 HTTP 200,均请求 pin=true;/api/v0/pin/ls?arg=<本次CID> 返回 404,无法独立查询 pin 状态,不能声称已独立确认递归 pin。

该域名公共网关对六包的首 1024 字节 Range 请求均返回 206,内容与本地一致;完整下载曾中途 IncompleteRead,主代理正在分块校验,不能据此声称完整公网下载已验证。索引目录发布及最终真实 CID、完整下载校验结果由主代理补充。本次脚本测试使用本机 HTTP fixture;只读调用纯函数验证真实进度 JSON 可生成六包索引,不发起真实网络请求或修改 bin 产物。

前一阶段打包验证(保留既有记录,非本次重跑):node --test scripts/ci-release.test.mjs scripts/project-paths.test.mjs 共 10 项通过,包含六包归档/解压、元数据与校验、缺包/篡改/重复输出拒绝、multipart 八文件与 Bearer 认证、目录 CID、失败响应及保留原文件。上传测试使用本机 HTTP fixture,不是真实 IPFS。前端生产构建通过(本机 Node 22.10 有 Vite 版本提示及既有 chunk 警告,CI 固定 Node 22.19.0);Go 1.25.0 六平台真实交叉编译通过,并检查六个二进制 GOOS/GOARCH/CGO 元数据;实际生成六个压缩包及两份清单,校验全部通过。Windows amd64 在隔离数据库/端口完成版本、启动、内嵌网页及登录冒烟;其他平台未做本机运行验证,Linux amd64 冒烟已配置到 CI。YAML 事件/平台/Secret 断言、脚本语法、git diff --check 通过;未执行完整 Drone 或真实 IPFS 发布,未改应用代码,也未重复运行全量 Go/浏览器回归。

Drone 保留镜像构建、移除推送(2026-09-24)

原因:镜像构建已成功,但远端仓库拒绝推送,用户明确要求删除 Docker 推送。Docker 插件设置 dry_run: true,保留真实镜像构建而不执行 push;镜像名改为本地 linkport:latest,移除 registry、username、password 以及对 docker_username / docker_password Secret 的依赖。SHA-256 克隆、精确提交校验及全局/构建代理参数不变。仅影响 CI 发布行为,无应用运行时和数据迁移;此后成功构建不再发布镜像,也未新增镜像导出或持久化,临时 Docker 环境中的镜像不作为可下载产物交付。

实际验证:按 Docker 插件官方 dry_run 定义配置;YAML 解析、禁止推送/无发布凭据断言、原克隆命令与代理参数保持不变检查、git diff --check 通过。未运行新的完整 Drone/Docker 构建,不将静态检查视为真实 CI 验证。

Drone 外网统一走指定代理(2026-09-24)

原因:用户要求外网统一使用 192.168.9.1:7893,前一版仅为 clone 注入可选代理 Secret,未覆盖后续构建和发布。现将 HTTP/HTTPS 代理移至流水线全局环境,固定为 http://192.168.9.1:7893,大小写变量一致,直连名单仅保留 localhost/IPv4/IPv6 回环地址。Docker 插件继承代理环境,并使用 build_args_from_env 传入六个预定义代理构建参数,使软件源、Git、npm、Go 模块、基础镜像和推送请求使用代理;不向最终镜像写入代理 ENV。此为 HTTP/HTTPS 工具代理配置,不等同于网络层封锁直连。保留 SHA-256 自动识别、精确提交检出、TLS 校验及镜像发布凭据。无运行时数据迁移;旧代理 Secret 不再使用,更换 CI 网络需修改代理地址。宿主机 Docker daemon 拉取步骤镜像仍需额外配置,已提供 systemd 示例但未修改或重启宿主机。

实际验证:YAML 解析、所有步骤有效代理环境、六项 Docker 构建参数及原克隆命令/registry 配置保持不变检查通过,git diff --check 通过。本机使用 curl 显式指定该代理且清空绕过列表,访问 Alpine 3.22 main/x86_64 的 APKINDEX 返回 CONNECT 200 和 HTTP 200;这是本机到真实代理的验证,不代表远端 runner、嵌套构建网络或镜像发布已验证。未执行完整 Drone/Docker 构建。

Drone 克隆步骤可选代理(2026-09-24)

原因:克隆步骤现场安装 Git 时可能受到 Alpine 软件源网络访问限制。为 clone 容器增加来自 Drone Secret 的 http_proxy、https_proxy、no_proxy,同时映射对应大写环境变量,使 apk 和 Git 能使用同一组可选代理设置;不在命令中展开或打印代理地址,不在仓库写入凭据。只影响克隆步骤的出站连接,不改变对象格式协商、精确提交检出、TLS 校验或 Docker 发布配置;无运行时配置和数据迁移。未配置时流水线不指定代理。runner 拉镜像、Dockerfile 下载及推送不在此配置范围内。

实际验证:YAML 解析、六个环境变量的 Secret 映射及原有克隆命令/Docker 发布配置不变检查、git diff --check 通过。未连接真实代理、未运行 Alpine 容器或 Drone runner,不将静态检查视为网络代理验证。

Drone 自动识别 SHA-256 仓库与精确检出(2026-09-23)

原因:默认克隆方式及前一版协议 v0 兼容配置不满足自动识别 SHA-256 仓库的要求。保留 clone.disable: true 和 Docker 发布步骤,改用 Alpine 3.22 安装 Git/CA,通过 git clone --no-checkout 协商 SHA-1/SHA-256 格式,不预先初始化仓库。克隆后补取构建引用及缺失的指定提交,detached checkout 并严格核对 DRONE_COMMIT_SHA,支持分支继续前进时重建旧提交以及非普通分支引用。日志显示 Git 版本、对象格式与最终提交;认证文件仅写入克隆容器 HOME,保持 TLS 校验。仅影响 CI 克隆,新增 Alpine 软件源访问依赖,无运行时或数据迁移;此前强制协议 v0 的兼容方案由此替代。

实际验证:读取 YAML 中的真实克隆脚本,模拟 Drone 的美元符号转义后,在 Windows Git Bash / Git 2.54.0 中使用隔离本地 SHA-1、SHA-256 仓库各验证旧提交、tag、PR 引用、按 SHA 补取和缺失提交失败,共 10 项通过;成功用例均核对对象格式、detached HEAD 和完整提交 ID。使用虚拟凭据验证其未写入共享源码目录、未出现在命令输出中。YAML 解析及 git diff --check 通过。测试使用 file transport fixture,不代表 Alpine 容器、真实 Drone runner、Gitea HTTP 克隆或私有仓库认证验证通过;未运行无关后端/前端测试。

Drone 克隆阶段协议兼容(2026-09-23)

原因:实际构建在源码 git fetch 阶段报 fatal: expected flush after ref listing,不是打包命令没有运行,也不是未触发构建。保留当前 Docker 镜像发布配置,将自动克隆替换为显式 drone/git:1 步骤,通过 Git 环境配置使用协议 v0 和 HTTP/1.1,并允许两次重试,绕开可能的协议协商兼容问题;不认定已证实反向代理或 Gitea 故障。继续使用 Drone 的认证和提交引用,保持 TLS 校验,不引入额外凭据。影响范围仅 CI 克隆阶段,无运行时或数据迁移。实际验证:本机 Git v2 和 v0/HTTP/1.1 的远端引用读取均成功;这不代表 runner 网络或镜像中的克隆已验证,仍需真实 Drone 重跑确认。

Drone 产物可见性与 Gitea 包发布(2026-09-23)

补充:Gitea 上传步骤使用 Alpine 镜像且没有安装 Git,push 发布版本现直接读取 Drone 提供的 DRONE_COMMIT_SHA,缺失时明确失败,避免已完成打包却在发布阶段报 git: not found。仅影响 push 的包版本取值实现,版本仍为完整提交 SHA;无迁移。本地 YAML 解析与事件检查通过,真实 Drone runner 未验证。

原因:Drone 原先只在临时工作区创建归档,构建成功后无法直接下载,容易误判为“打包没有反应”。现在 package 步骤打印路径及归档 SHA256,push/tag 在配置 gitea_user 与 gitea_token 时上传到 Gitea Generic Packages,并打印下载地址;未配置则明确跳过。PR 仍只验证打包,tag IPFS 上传维持原行为。push 用提交 SHA、tag 用 VERSION 作为包版本;重复发布相同版本文件可能失败。仅影响 CI 和发布方式,不改变运行时行为或数据,无迁移。若无构建记录仍需检查 Drone 仓库启用、Gitea webhook 和 runner。本地验证:YAML 解析及事件/步骤静态检查、git diff --check;未运行真实 Drone/Gitea 上传。

Drone CI Linux 打包修复(2026-09-23)

原因:现有流水线仍引用旧 agentdb 模块和命令入口,不能编译本项目。改为固定 Go 1.25.0 和 Node 22.19.0,先测试并构建前端,再以受限编译并发生成内嵌页面的 linkport Linux amd64 无 CGO 单文件程序,使用既有 verify-package.mjs 在隔离临时数据库与端口上验证后归档并生成 SHA256;可选标签 IPFS 上传保留且 API 路径不重复拼接。仅影响 CI 构建与发布,无运行时配置或数据迁移。本地 YAML 解析及 Go 1.25.0 Linux amd64 交叉编译通过;Windows 宿主无法运行 Linux 验证程序,未在真实 Drone runner/IPFS 节点发布,也未连接真实目标服务。

SSH 连接测试拨号前诊断(2026-09-23)

补充:实际 SSH 主机密钥与已确认密钥不匹配时,类型化 ssh_host_identity 并显示库的固定原始错误 ssh: host key mismatch;本地缺失配置独立归类 ssh_host_key_unconfirmed。API 的 rawError 只对白名单中的该精确判定非空,其他上游原始错误继续隐藏,以免暴露凭据或服务端任意文本。前端测试弹窗显示此安全原始判定,复制脱敏诊断不包含它。验证使用 SSH 本地服务 fixture、网关错误白名单测试和前端组件测试;未连接真实目标。

原因:未确认的目标主机密钥在本地校验时失败,原错误没有类型化证据,连接测试显示未定位具体阶段。变更后仅对此可确定的配置错误返回 ssh_host_identity,并明确该阶段可能发生在 TCP 建连前;其余未知错误不推断为认证问题。SSH/SFTP 范围,无数据迁移,不改变主机密钥验证强度或业务连接。验证使用本地 fixture 与网关分类测试,不代表用户的真实目标已连接。

目标协议持续连接覆盖(2026-09-23)

原因:现有持久设置只支持四种数据库备用池和 SSH/K8s 隧道,其他已支持协议无法开启后台可达性保持。

结果与范围:全部目标协议允许开启。无法安全交接预认证会话且没有共享隧道时,网关每 15 秒使用既有协议测试进行独立后台探测,完成即关闭连接,状态为 probe,不计入复用次数。四种单节点数据库仍保留备用池,SSH/K8s 出口仍保留持续隧道;集群直连仅探测、不共享会话。探测模式不是长期占用目标连接,客户端仍独立建连。明确拒绝时暂停重试,网络失败退避重试;不改变既有客户端连接生命周期。

兼容与迁移:保留 connectionOptions.persistent 字段和默认关闭状态,无数据库迁移;新模式只影响主动开启的目标。周期性探测增加目标连接及认证开销,不修改生产数据。实际验证:模型与网关针对性 Go 测试通过(探测使用 fixture),前端组件 6/6 通过,go vet ./... 通过,vue-tsc --noEmit 通过。完整 Go 测试中数据库快照和 Windows 私有文件权限相关用例因当前沙箱拒绝访问失败;Vite 构建因 esbuild 子进程 spawn EPERM 中断,Playwright 尚未运行。不将 fixture 或组件测试视为真实目标在线验证。

目标后台持续连接与共享隧道(2026-09-22)

原因:用户要求无客户端时仍保持目标连接或 K8s 转发隧道,后续客户端可以复用;原来目标连接和隧道都随单个客户端建立、关闭。

结果与范围:目标高级设置增加 connectionOptions.persistent,默认关闭以保留既有行为。开启后,运行中的引用网关按绑定、目标账号、端点、认证库、数据库、凭据和访问权限范围预建资源。单节点 MySQL/MongoDB/PostgreSQL/Redis 维护一个已认证、尚未服务客户端的备用会话,每 15 秒检查;交接后立即补充,客户端使用过的会话不回收,避免事务、游标、数据库选择和订阅状态污染。客户端指定不同初始数据库时仍独立新建。网关连接测试始终使用临时资源,不借用或启动后台池。

SSH/K8s 出口维护独立于客户端的共享隧道,每个客户端获取独立流。SSH 流的超时通过独立 loopback 桥接实现,不设置共享 TCP 的会话级 deadline;保留半关闭和 EOF 数据排空。K8s 共用一个原生 port-forward,使用既有 SPDY 心跳,断线后重新按资源选 Pod,不保存 Pod IP。其他协议的直连/SOCKS5 不做不安全的通用已认证会话复用;集群只支持既有规则允许的共享隧道,不缓存主节点会话,也不放宽 K8s 固定资源限制。

生命周期与安全:仅在网关运行期间预热,网络或未知失败按 1–30 秒退避重建,不重放业务请求;明确的类型化认证/权限/身份拒绝暂停后台重试,避免持续错误密码登录。过期账号不建立或借出连接。停用开关/在线切换停止旧配置预热,已交接会话和已租用隧道流继续原生命周期;停服强制释放隧道并取消未完成建连。前台遇到尚未就绪的池仍用原配置建立临时连接,不降级直连。运行面板只展示资源标识、就绪状态和安全计数,不回显原始错误、密码或内部键。

集成回归同时修复 ConfigurableTable 仅保留 selection 导致 expand 结构列被过滤的问题:现在保留 selection/expand/index,运行详情及后台连接状态可从表格展开查看,不受普通数据列排序/显隐设置影响。共享隧道拨号遵守目标连接超时;在线切换前已接受但尚未取得隧道流的请求,只有在明确“尚未发起拨号即退役”时才按旧配置独立拨号,其他错误不重试业务数据。

兼容性与验证:新增目标 JSON 字段,无 SQLite 表迁移;旧配置默认按需连接,旧版本不能提供后台保持语义。现有生产数据未修改,未部署或提交。数据库保活仅使用协议 Ping/只读操作,无新增业务写入、显式事务或行锁。新界面沿用本仓库现有中文机制,不引入不存在的 Shopee i18n 系统。协议/隧道使用本机隔离 fixture 验证,并非真实 MongoDB、SSH 或 K8s 服务验收;实现、支持边界及最终检查见 docs/persistent-targets.md、docs/testing.md。

独立 TCP 网关经 SOCKS5 纯端口转发(2026-09-22)

原因:用户明确目标服务用于协议及账号密码处理,当前需求只是把本机端口经已有 SOCKS5 代理转发出去。强制建立目标服务或后台自动生成目标都会引入不必要的资源与账号语义,因此将纯端口转发直接归属网关。

结果:TCP 网关新增「纯端口转发」模式,通过 tcpForward: {host, port, outboundId} 保存目的地址和已有 SOCKS5 代理引用,不创建目标服务。支持分别配置 127.0.0.1:1081 → 已有 SOCKS5 → 192.168.11.16:8080 与 127.0.0.1:1082 → 已有 SOCKS5 → 192.168.11.16:8082。业务协议、账号密码与 TLS 原样透传,不进行协议转换、凭据替换或 TLS 终止;SOCKS5 认证仅复用代理自身凭据。批量创建仍只递增监听端口,不递增目的端口。

约束:独立模式仅适用于 type: "tcp",与目标引用和账号映射互斥,原有 TCP 目标关联模式保持不变。代理被引用时禁止删除或改类型;运行中的引用仍禁止编辑共享代理,但网关自身的监听和映射可在线保存,只影响新连接。停止相关网关后才可修改共享代理,停止不会解除删除/改类型的引用保护。tcpForward: null 清除独立模式,之后可按原流程绑定 TCP 目标。独立模式没有目标周期健康检查,仅提供手动连接测试和运行指标,不能把端口可达解释为业务认证或 TLS 验收。

范围与兼容:涉及网关模型、存储解析、代理引用保护、API、TCP 运行链路及网关 UI;不自动产生目标或业务账号,不修改真实目标数据。网关配置及备份/WebDAV 沿用现有 bundle 与代理引用校验,无 schema 迁移。旧版不支持 tcpForward 新字段,回退前需备份并核对配置兼容性,不能因旧版支持 TCP 就认为支持独立模式。操作与边界见 docs/tcp-port-mapping.md。

图视图补充:纯端口转发没有目标关联是合法状态,因此不显示“未关联目标”提示,禁止拖到目标绑定,但保留手动测试按钮,避免把独立模式误导为缺少目标配置。

实际验证:Go 1.25.0 全量 go test ./... -count=1 -timeout=120s、go vet ./... 通过;新增 API 边界测试命令 go test ./internal/api -run '^TestTCPIndependentBoundary' -count=1 -timeout=120s -v 通过(5 项测试、21 项子测试),涵盖无效代理/字段、账号冲突、部分更新、模式切换、引用重绑定、代理改类型及影响范围响应脱敏。TestIndependentTCPForwardTwoRoutes 经本地带密码 SOCKS5 fixture 转发两条映射到本地 TCP fixtures 并校验二进制字节,不是真实用户 192.168.11.16 网络验证。

构建与浏览器验证:首次 Node 22.10 构建成功但存在 Vite 版本警告;补充图视图后,使用机器已有 Node 22.22.3 重新执行 scripts/build.ps1 -SkipTests,完成 npm build 与 Go 1.25.0 编译,生成最终程序 artifacts/tcp-independent/linkport.exe,无 Node 版本警告,仅有 chunk 大小警告。最终重建前两项定向 Playwright 已通过。此前全量在 Node 22.10 下因 node:sqlite 不可用而在测试发现阶段失败;仅在当前 shell 通过 fnm use 22.22.3 切换已有版本后,一次运行在 59 项时因工具 200 秒时限中断,并非用例失败结论。最终使用 Node 22.22.3、LINKPORT_E2E_BINARY=artifacts/tcp-independent/linkport.exe,在隔离端口 19281/19282 延长时限完整重跑,121/121 通过(6.6 分钟),包含最终图视图修复;日志 artifacts/tcp-independent-playwright-final.log,详见 docs/testing.md。

连接诊断、资产影响与完整备份优化(2026-09-22)

原因:用户要求并行实现此前列出的七项优化,减少网络/凭据问题混淆、共享资产变更误操作、监听地址歧义和全库恢复风险,并收敛已有回归失败。

结果与范围:

  • 连接测试增加实际执行阶段、状态和耗时,成功/失败/跳过/未执行分开;按真实 TCP、TLS、SOCKS5、SSH、Kubernetes API/转发及协议回调记录,不从错误文本推断前置步骤已成功。驱动无法分开的阶段合并显示,未知认证结果不归咎密码。配置路径与实测阶段分开,详情只包含允许的阶段码,不泄漏服务端原始错误或凭据。
  • SSH 连接资产支持不发送密码的指纹探测、旧/新指纹核对、五分钟内显式确认并保存。确认绑定会话、端点、资产和原配置,严格身份变更缺确认返回 409;持久跳过保持醒目标记,另提供仅本次测试跳过且不保存信任的操作。已有不变严格配置无需重新探测。
  • 共享资产编辑器加载跨项目完整影响范围,列出直接/间接目标和运行中的网关;加载失败或仍有运行引用时禁止保存。独立查看影响入口不因编辑被禁用而消失。删除前展示影响,并仍由服务端引用检查防止并发误删;原有停服再改共享资产的限制保留。
  • 监听预检短暂 bind 并释放,明确不是端口预留。界面区分配置监听、实际绑定和客户端候选;通配地址不作为拨号地址,回环候选注明仅本机,支持复制。统计当前/累计接受连接、客户端边界收发字节及脱敏最近错误;保留 TCP 写半关闭行为。全网卡且无白名单持续警示。
  • 多账号连线、编辑与切换统一显示网关账号 → 目标账号 → 目标级 authSource;后端拒绝禁用源账号的独立切换,前端检查缺失/禁用/协议不兼容引用。此处不新增目标账号禁用字段,也不把 authSource 改为账号字段。长连线标签可通过完整关联列表查看。
  • 完整 SQLite 快照使用在线备份接口包含 WAL 已提交页,支持下载、完整性/密钥检查、资源数量及摘要预览。真正恢复采用服务独占锁保护的停服命令,私有暂存后再次确认 SHA256,先自动备份当前库,检查相同 schema/user_version,再使用 SQLite 内部原子备份恢复事务替换页面;不在线重命名/覆盖活动文件。该原子性由数据库备份 API 提供,不新增业务批量 UPDATE 或应用长事务。
  • 回归修复包括异步类别确认取消后恢复原生 radio 的选中状态;从共享 K8s 连接切换直连或其他资产时清除旧的已解析出口,避免误保存为内联 K8s。测试等待旧确认框退出动画、正确操作 Element Plus switch、验证 K8s 请求无需地址而服务端只派生资源名称,并断言安全的本地化诊断而非原始上游错误。小屏账号编辑回归将映射说明放到对应目标页,不放宽免滚动断言。
  • 全量检查同时定位 MySQL 集群发现的池化结果生命周期问题:保留到拓扑中的主机名/角色改为拥有独立字符串,避免关闭结果后被复用覆盖;进程内 fixture 独立构造字段/文本行,避免共享结果池沿用旧字段元数据。保留并加强主节点、角色和端口断言,增加确定性的缓冲区覆盖测试;不增加重试、放宽超时、改 SQL 或升级依赖,详见 internal/cluster/README.md。

兼容与迁移:沿用单 SQLite、现有账号和配置格式,无业务表迁移;诊断和指标为新增响应字段。严格 SSH 指纹创建/变更 API 增加显式确认要求,自动化需先探测;旧跳过开关仍默认 false。全库文件包含可解密凭据、管理员和 TLS,恢复会替换登录身份及同步状态,来源 schema 不一致时拒绝。数据库下载/预览只限管理会话和 CSRF,不允许 API token。未部署、未迁移真实数据、未修改生产目标。本仓库无指定 Shopee i18n 框架,沿用现有中文 UI;阶段标签使用闭集防止不可信错误进入界面。

验证与文档:实际命令及结果见 testing.md;功能细节见 connection-stages.md、ssh-connection-test.md、asset-impact.md、tcp-port-mapping.md、database-snapshots.md。所有协议验证为本机隔离 fixture,不声称真实 SSH/K8s/数据库服务实测。

脚本相对路径与便携工具链(2026-09-22)

原因:用户在其他工作副本启动时遇到 Go is required,并要求所有脚本跨机器使用、删除固定绝对路径。原脚本包含固定 Go 安装位置,若干 Node 验证入口与浏览器服务还依赖调用者当前目录。

结果:移除 Go 固定安装目录与用户目录扫描,Go/Node 默认优先使用项目 tools 目录,再从 PATH 获取;可选显式覆盖按项目根目录解析相对值,错误覆盖不降级。构建、打包和矩阵脚本共享工具查找,Node 子进程使用配套运行环境。验证脚本与浏览器测试服务统一按脚本位置定位项目,文件参数和 LINKPORT_E2E_BINARY 的相对值不再依赖调用目录;Shell 入口增加项目便携工具链优先级,工具目录不进入 Git/Docker 上下文。

范围与兼容:涉及开发/打包/验证脚本和测试启动器,不改变业务 API、Go 1.25.0 约束、数据库选择或发行版运行。工具只安装在未加入 PATH 的系统目录时,需要自行加入 PATH 或放入项目 tools;验证脚本的相对参数现在统一以项目根目录为基准。用户显式外部路径仍兼容。运行时规范化、临时目录清理范围检查、停止服务前构建保护与容器内挂载契约保留;不自动安装软件或修改系统 PATH。

验证:新增 Go/Node 隔离查找和 Node 脚本搬移测试,覆盖项目路径优先级、相对覆盖、空格目录和异地调用。实际构建及协议/浏览器验证边界见 测试记录,操作见 本地构建说明。不以本机验证推断另一台机器已具备完整工具链。

WebDAV 替代 S3 同步并提供独立备份(2026-09-22)

原因:用户要求将 S3 同步改为 WebDAV 同步备份,不再保留双入口造成配置歧义,同时需要不影响共享同步状态的归档能力。

结果:传输改为 WebDAV 基础目录、相对前缀和 Basic/匿名认证,MKCOL 创建子目录,强 ETag 与条件 PUT 保留双端冲突保护。保留手动/定时同步、删除传播和停止网关后应用远端的约束;新增独立加密快照上传,不读取或覆盖共享文件、不改变同步基线或解决冲突。管理页、状态、事件及会话保护 API 统一替换为 WebDAV;密码和口令不回传,拒绝跳转和服务商正文泄漏,改变地址或用户名不继承旧登录密码。

范围与兼容:涉及 backup/store/syncjob/api 和独立 Vue 组件/composable。新增独立加密设置、状态表;旧 S3 表、文件保留但停止使用,旧 API 返回 404,新自动任务默认关闭,需要重新配置。沿用设置与基线、配置替换与基线的短事务原子性,数据库操作限单例或已定位资源,不把网络请求放入事务。升级须停服并备份完整数据目录,本轮未部署或迁移真实数据。备份是配置快照,不含审计/个人登录等设备数据;无远端列表、自动轮转和在线恢复选择,下载后通过配置管理导入。手动备份会更新任务时间并顺延下次自动同步。

验证:Go HTTP fixture 覆盖认证、目录编码、条件写入、强 ETag、并发冲突、双端同步、独立可恢复快照以及重定向/错误脱敏;浏览器包含隔离程序连接本机 Node WebDAV fixture 的备份与同步链路。未测试真实外部 WebDAV 服务,实际完整结果见 测试记录,操作与迁移见 WebDAV 同步备份。

目标空密码与无认证连接(2026-09-22)

原因:用户指出部分服务无需密码即可登录。现有账号密码本已允许为空,但前后端统一要求目标用户名,Mongo 上游始终发起 SCRAM,HTTP 始终添加 Basic 头;编辑空密码还会按既有规则保留旧密码,导致无法明确表达无认证与主动清除密码。

结果:具名账号继续允许空密码,由目标服务器决定是否接受;编辑器提供“使用空密码(清除已保存密码)”,保存和草稿测试统一发送显式空值。MongoDB、Redis、HTTP(S) 的目标账号新增 authMethod: none,保留账号 ID 与网关映射,不发送上游用户名/密码,保存时清除原凭据及私钥/证书引用。Mongo 跳过上游 SASL,HTTP 去除客户端 Authorization 后仅在有目标用户名时设置 Basic;Redis 沿用既有无凭据时不发 AUTH 的实现。URL 导入带凭据时切回密码模式并撤销清空标记,避免已填密码被忽略。

安全与兼容:网关登录、权限、源地址限制和账号到期检查不放宽;上游认证失败不会自动降级。SSH/SFTP 仍可用私钥;其他具名协议不新增无认证选项。旧配置空密码保留语义不变,使用现有账号 JSON,无数据库迁移;旧版不支持 none 模式,回退前需重新配置。保留工作区已有 SSH 指纹跳过改动,不部署、不提交、不修改真实目标数据。

验证:模型/API 专项覆盖协议限制、空密码、显式清除、草稿不落库及不放宽网关认证;Mongo/HTTP 使用本机协议 fixture 验证不发送上游认证、仍拒绝错误网关密码及目标拒绝时返回失败,Redis 无认证覆盖沿用现有 fixture。浏览器使用新构建程序、隔离数据库及模拟远程结果,不代表真实服务验证。实际构建和回归结果见 测试记录。

SSH 转发允许显式跳过主机指纹(2026-09-22)

原因:用户要求 SSH 转发主机指纹可以跳过。新增 outbound.skipHostKeyVerify 布尔开关,默认 false,前端显示不安全提示;显式开启才放宽指纹必填和比对,不放宽密码认证。关闭开关恢复原有严格校验并保留原指纹。测试返回实际观察到的服务器指纹,不把跳过模式当成可信身份确认。

范围与兼容:统一 Outbound 配置、API 校验、SSH 连接测试和实际转发、连接资产编辑器;SSH/SFTP 目标自身的身份策略不变。配置通过现有 JSON 存储,无表迁移,未修改真实数据或部署程序。旧版本忽略新字段,回退前需补齐合法指纹。本仓库无 multilingual-ui 所指定的 Shopee i18n 框架,检查后沿用现有中文文案,不新增翻译框架。

验证:Go 1.25.0 全量测试、go vet、前端构建通过;新增本机 SSH fixture 覆盖空/错误指纹显式放行、转发回显、仍拒绝错误密码、关闭后严格拒绝,非真实远端服务器验证。新程序 Playwright 专项 3 项通过,见 testing.md。

合并 origin/main 943ea75(2026-09-22)

原因:将远端最新提交合入本地 main,同时保留已提交的 TCP 映射、MongoDB 非 admin 认证库和单 SQLite 存储等功能。

结果与范围:整合三平台回环本地模式、Windows 新库 ACL、Unix 数据库权限检查、单 EXE 打包及 bin 构建目录、范围输入与保存后缓存更新、请求路径诊断和响应式布局。补齐远端引用但未提交的 Unix 平台实现及请求诊断模块;诊断不保留请求体、凭据或 URL 查询参数。修正桌面验证脚本对已退出子进程的重复等待。

兼容与迁移:沿用 local_metadata 中的库内主密钥,不引入远端所述 local_key 格式,不恢复 LINKPORT_MASTER_KEY 或外部审计/TLS 文件。保留显式旧库迁移能力及旧 DPAPI 文件,不改动真实 data,不部署。Unix 本地模式会拒绝组或其他用户可访问的已有数据库。下方合入的历史记录仅描述当时分支状态;当前格式和实际脚本以 single-file-storage.md、platform-support.md、build-output.md 为准,不表示仓库存在六目标 package.mjs。

实际验证:见 docs/testing.md 的同日合并记录;测试失败如实保留,不把交叉编译或本机 fixture 当作异系统或生产服务实测。

TCP 端口映射与默认全网卡监听(2026-09-21)

原因:用户要求纯 TCP 端口映射,并明确默认监听 0.0.0.0;现有协议网关强制账号与协议认证,不适合透传。

结果:新增 tcp handler,使用现有目标、出口、监听生命周期和来源/连接数限制。TCP 目标与网关无需账号,普通及拖拽绑定不要求 targetAccountId;接口拒绝 TCP 账号配置、TLS 终止及只读策略,普通协议的账号约束不变。界面隐藏 TCP 的账号/TLS 终止设置,明确提示无网关认证和全网卡监听风险;连接测试与定时探测仅检查 TCP 可达。停止时断开两端;2026-09-28 起运行中显式切换目标也会断开现有连接,让客户端重连后使用新目标。SSH/K8s 包装透出底层写半关闭,避免隐藏已有能力。

范围与兼容:新增协议类型,无数据库迁移,不编辑真实配置或启动正式映射。默认开放监听网卡不等于绕过来源白名单;应用认证和 TLS 由客户端及目标负责。旧程序不识别 tcp 配置。未实现 UDP、应用命令审计、账号级映射或协议集群发现。本项目无 multilingual-ui 指定的 Shopee i18n 机制,沿用现有中文文案模式。

验证:新增隔离 TCP/API/网关测试及浏览器回归,具体命令与实际结果记录在 docs/testing.md;操作说明见 docs/tcp-port-mapping.md。TCP 字节回显测试使用本机 fixture,不声称已连接真实 K8s/SSH/SOCKS5 生产环境。

移除 MongoDB 网关 admin 认证库限制(2026-09-21)

原因:客户端使用业务库作为 authSource 时,网关在验证账号密码前因硬编码 admin 限制拒绝认证,导致 MongoSecurityException。

结果与范围:MongoDB 网关允许任意非空认证库,普通及 speculative SCRAM 路径均生效;同一认证会话绑定初始认证库,继续交换时切库仍拒绝。网关账号、密码和账号映射规则不变,目标认证库继续来自目标配置而非客户端参数,不放宽目标权限。admin 保持兼容,无存储迁移,不修改真实数据;本轮未部署或自动提交。

验证:Go 1.25.0 全量测试及 vet 通过,新增测试覆盖业务认证库、speculative 认证、错误密码、未知账号、空认证库及会话中切库。官方 Go 驱动在 admin/业务库和读写/只读四种组合下通过 TLS、认证与命令测试,上游为本地 fixture,不等同于 Java 驱动或真实 MongoDB 验证。前端构建和新二进制上的六项相关 Playwright 回归通过,详见 docs/testing.md。

拖拽账号映射的连接路径与测试(2026-09-21)

多账号显示补充:用户要求目标服务多账号在拖拽时直接可见,因此目标账号列表改为常驻展开,显示名称和用户名。连线固定落到对应账号行,选择源账号不再触发布局变化;仅同协议账号可接收关联。影响仅为连线图展示与交互,不迁移数据、不修改其他账号映射。最新 linkport-multi-account.exe 的五项专项回归通过,account-targets 截图复跑通过,已检查桌面与窄屏显示。未替换正在运行的服务。

原因:单个网关账号拖拽关联目标后,网关本身不一定有默认目标;原 UI 读取网关顶层字段生成路径,出现“直连 → 未配置地址/端口”,原测试 API 也只允许默认目标。用户明确要求网关账号对应目标账号。

结果:新增 GatewayConnectionTest 与 gatewayTest helper,网关测试先选择账号映射,按实际目标配置显示路径;多账号显式选择,不随机测试第一条映射。API 支持 gatewayAccountId,通过现有账号 Apply 规则解析目标凭据、TLS 和出口;不新增账号解析规则,不回退未知/禁用账号。新增测试领域逻辑位于 internal/api/gateway_connection.go,server.go 仅调用。拖拽图增加测试入口和 K8s 资源说明;目标只有一个账号也显示账号入口。单账号拖拽仍调用原有按账号保存接口,其他账号不受影响;当前界面已取消整卡批量绑定,仅保留旧 API 的兼容语义。

范围与兼容:只改变测试选路和界面路径,未修改真实账号、存储、既有路由和网关监听,无数据迁移。无 query 的旧测试 API 保持默认目标行为。列表和请求不新增密码/Kubeconfig 内容,诊断仍为固定阶段白名单。本项目没有 multilingual-ui 指定的 Shopee i18n 框架,沿用现有中文文案模式。

验证:前端构建、Go 1.25.0 全量测试与 vet 通过;API fixture 验证账号独立路由、SOCKS5 出口、无效账号拒绝及不改变映射。相关六项浏览器用例通过,补充多账号选择后的 gateway-connection-path 两项单独复跑通过。浏览器请求模拟目标失败,未连接真实 Kubernetes/MongoDB;全量 UI 结果见 docs/testing.md。

资产新建与目标服务统一弹框(2026-09-21)

原因:用户要求新建资产与新建目标服务采用相同弹框,原资产列表仍使用侧边抽屉,内联新建另用较小的弹框。

结果与范围:AssetsManager、OutboundManager 的新建/编辑,以及 AssetCreateDialog 的内联创建均复用 ConnectionEditorDialog。共享组件 tabs/tab 改为可选,缺省时不渲染导航;现有目标/网关继续传入原有页签,不改变行为。沿用已有中文文案,没有新增多语言接口或硬编码新提示。

兼容与保护:不修改资产载荷、后端接口、存储、项目/环境规则、校验与未保存守护;保留工作区插槽、内联 append-to-body、关闭清理和读取中禁用保存。无需迁移,无真实数据写入。新建和编辑使用同一组件路径,避免两种交互继续分叉。

实际验证:生产前端构建、Go 1.25.0 全量测试、vet 通过。新增两项浏览器用例通过,覆盖桌面/手机尺寸与目标弹框一致、底部按钮可见、关闭守护和草稿重置;既有资产备注保存及内联资产用例共三项通过。响应式测试更新“所有共享弹框均有连接页签”的旧假定后,两项重跑通过,仍验证各表单固定底部按钮和滚动布局。首轮新增用例捕获了打开/关闭动画尚未结束时的测量和重叠断言,改为等待状态稳定并关闭截图动画后通过,未通过修改产品守护逻辑来绕过测试。基于新构建 linkport-asset-dialog.exe 的全量浏览器结果见 docs/testing.md;未部署替换用户运行程序。

侧栏菜单与资源互斥切换(2026-09-21)

原因:用户反馈左侧菜单太小,希望菜单和资源能够相互切换。原菜单与树上下共存且菜单限制 48vh,入口行高仅 34px。

结果:新增 SidebarPanels 组件承载菜单/资源切换与本地视图偏好,App.vue 只做插槽集成;使用 v-show 保持两边状态,不触发页面跳转或表单关闭。菜单不再限制半屏高度;桌面默认 280px、拖拽范围 240–480px,菜单 14px/44px 行高,资源行高 38px,兼顾键盘与手机弹窗。保留原来的侧栏宽度 key,旧值按新下限夹取,无数据库迁移。

验证:前端生产构建通过;使用新构建的嵌入前端程序,sidebar-panels.spec.ts 两项 Playwright 用例通过,覆盖互斥可见、搜索保留、刷新恢复、键盘切换、宽度调整持久化、手机资源弹窗和无横向溢出。实际截图已检查。全量浏览器回归另见 docs/testing.md,不把局部通过等同于全量通过。multilingual-ui 所指的 Shopee i18n 目录/API 在本项目不存在,本次沿用现有中文约定,不新增翻译框架。

MongoDB 旧版握手与 SCRAM 结束交换兼容(2026-09-21)

原因:真实 K8s StatefulSet 目标拒绝 hello;切换认证库后,旧服务仍要求 SCRAM 最后一次空交换,原实现对已完成的 SCRAM conversation 再次 Step,误报认证失败。

结果:初次使用 isMaster + helloOk,后续按该连接协商结果发送 hello 或 isMaster;集群发现仅在 CommandNotFound 时回退 isMaster,不对网络或认证错误回退。初次握手按 authSource.username 查询 saslSupportedMechs,优先 SHA-256,否则按 MongoDB 默认规则使用 SHA-1(仅上游;网关客户端仍使用 SHA-256)。拒绝认证后不再尝试弱机制。旧服务额外空结束交换只在服务端证明已验证、载荷为空且最终 done=true 时接受,异常额外载荷仍拒绝。

范围与兼容性:修改 MongoDB 协议和集群探测,不改变 K8s 资源寻址、不关闭 TLS 校验、不新增数据库迁移。仍使用 OP_MSG,不宣称支持所有更旧线协议版本。修正 legacy ismaster 主节点识别。

实际验证:本地 fixture 覆盖 legacy/modern 握手、重复刷新、SHA-1/SHA-256、额外空结束交换与恶意额外数据拒绝;最新全量 Go 测试及 vet 通过,前端生产构建通过。此前一次 cluster MySQL fixture 间歇失败,后续全量通过,并未修改该 fixture。真实 wall-e-test/statefulset/mongo-shopee 目标经 port-forward、认证及 buildInfo 成功,返回 4.1.13、standalone、zlib;不是只做模拟验证。用户提供认证库后只更新已确认目标 ID 的 authSource 和账号凭据,完整 data 备份位于 artifacts/backups/mongo-compatibility-20260921-161726;保存后重新读取配置再次真实测试成功。未写 MongoDB 业务数据;密码不写入文档和诊断日志。浏览器回归结果见 docs/testing.md。

连接路径与明确失败阶段(2026-09-21)

原因:用户反馈 K8s StatefulSet/MongoDB 测试只显示 target_connection_or_protocol,无法判断网络还是账号密码问题。结果:测试弹窗显示配置路径、中文阶段、问题类型、诊断代码和固定排查提示;K8s 路径使用资产名称/context/命名空间/资源和容器内端口,不误导用户维护 Pod IP,也不把配置路径当成功探测记录。监控结果复用相同映射,复制脱敏诊断增加阶段代码。

后端在 MongoDB 的 TCP、TLS、hello、SCRAM 与 buildInfo 操作处添加结构化阶段;认证被拒与认证交换中断分开,认证后的版本权限失败与密码错误分开。旧未知分类明确说明证据不足。API 白名单提示及错误类型的 Error 文本均不包含服务器任意诊断,保留内部 cause 链但不回显。未修改认证方式、凭据、转发路由或数据库结构,未知阶段向后兼容。

影响范围:Mongo 协议诊断、gateway 错误分类、测试弹窗、脱敏复制和运维列表;细节见 docs/connection-diagnostics.md。gateway/Mongo/API 新增 fixture 测试已通过,前端纯函数断言与类型检查通过,Playwright 能发现 100 项用例。最终全量 Go 只有既有 MySQL group-replication fixture 间歇失败,单独重跑通过;go vet 通过。Vite/esbuild 仍被 spawn EPERM 阻止,未执行 E2E 或部署;详见 docs/testing.md。没有使用真实集群或修改真实配置。

资产与代理合并、K8s 资源归属目标(2026-09-21)

原因:用户最终要求 SSH/SOCKS5 统一维护到资产,删除代理页面;StatefulSet 等资源直接配置在目标,消除重复的代理层。本记录取代下方当日「代理独立修改项目」的界面行为。

结果:侧栏仅保留资产管理,文件资产和连接资产共用入口;连接资产表单、搜索与操作名称同步更新,管理列表不按项目隐藏且不再提供项目编辑。旧资源引用/工作区标签仍能打开对应资产类别,类别切换受未保存保护。目标两个连接入口共用内联 K8s 配置,保存/测试只发送资源元数据和资产 ID,后端不再自动创建 K8s 代理;空 IP、TLS 域名、直连校验按下方记录执行。补齐内联 Kubeconfig 的运行时解析、更新及恢复后的主机指纹清除。

范围与兼容:前端导航/资产/目标表单与校验,目标模型、资产解析及现有按 ID 存储流程。保留 outbounds API、加密记录和旧引用,不删除真实数据,不新增数据库迁移或事务。按数据库安全技能复用已有短事务及主键保存;不做批量重写。多语言技能的 Shopee 字典不适用于本仓库,沿用现有界面文本方式。

验证:新增目标内联 StatefulSet 保存、草稿测试、不创建代理、切回直连校验等 API fixture;更新 Kubeconfig 资产更新/恢复与脱敏测试,以及合并页面、跨项目可见、资源选择/重试、引用导航等 Playwright 用例。最终使用 Go 1.25.0 执行 go test ./... -count=1 -timeout=120s、go vet ./... 均通过;之前一轮有既有 MySQL group-replication fixture 偶发失败,单独重跑和最终全量均通过。Vue 类型检查及 Node 中执行的 TypeScript payload/校验断言通过,git diff --check 通过。npm.cmd --prefix web run build 在 Vite 启动 esbuild 时仍被环境以 spawn EPERM 拒绝,无法生成包含新界面的程序,未执行端到端浏览器测试、未部署。协议与 API 验证使用隔离 fixture,不代表真实集群连通性,真实数据未修改。

K8s 固定资源目标无需维护 IP(2026-09-21)

原因:StatefulSet 的 Pod 地址由 port-forward 自动定位,目标表单仍要求填写 IP,造成误导。结果:所有 K8s 固定资源代理的非 TLS 目标隐藏主机输入,显示资源定位信息;保存和草稿测试接受空地址,后端使用资源名称补齐协议内部地址。TLS/HTTPS 仍要求显式证书域名,直连及其他代理仍要求主机。已有地址不覆盖,切换代理不清空草稿。

范围与兼容:调整目标模型校验、前端保存/测试校验和目标表单,不修改转发路由、账号和数据库结构,无数据迁移。不自动判定 Mongo 主节点。新增后端地址补全、TLS/直连保护测试与前端校验测试,均纳入上方合并记录的最终检查;不涉及真实集群连接或真实数据修改。

代理出口默认跨范围可选、代理列表移除项目列(2026-09-21)

原因:代理出口仍按目标项目/环境隐藏选项,用户反馈不能选择;同时要求代理列表删除项目列。

结果与范围:目标两个代理入口默认显示全部已保存代理,移除范围开关和过滤提示,保留直连、不可用引用警告、已选代理归属和 K8s 限制说明。代理管理移除「项目 / 环境」列,仍可通过「更多操作 → 所属项目」修改项目。管理列表自身的项目筛选保持不变。

兼容:仅调整前端展示,不删除项目数据,不改变引用、后端权限或连接逻辑,无数据库迁移。补充跨项目/环境默认选择及移除列后菜单改项目的浏览器回归断言。

验证:npm.cmd --prefix web run build 中 Vue 类型检查通过,Vite 启动 esbuild 时被环境以 spawn EPERM 拒绝,未生成新前端包,未部署或修改真实数据。Playwright --list target-outbound-selection global-assets-proxy-project 成功发现 4 个用例;因无法生成包含新前端的可执行文件,未执行端到端验证。连接测试用例使用 fixture,不代表真实代理连通性验证。本次仅改前端与文档,未重跑后端测试。

资产取消项目归属、代理独立修改项目(2026-09-21)

原因:用户明确区分资产和代理:资产管理不需要项目,代理则保留项目但应能更新。原资产筛选和表单均绑定项目,代理运行时整个编辑入口禁用,无法只修改组织信息。

结果与范围:资产表单去掉项目字段,管理列表和搜索忽略项目筛选,环境设置/筛选保留;所有资产选择器按类型全局可用。API 忽略资产项目参数,存储读取、备份、历史恢复及同步兼容旧资产的项目字段但不再使用,保存时不写入项目;旧文件、引用和其他字段不变。代理列表保留独立「所属项目」入口和 PATCH 子接口;目标与网关完整连接编辑现也允许运行中保存,新连接使用新快照。共享资产的运行中影响保护保持不变。继续保持凭据脱敏、CSRF、历史、审计和目标引用。

并发与兼容:项目更新按主键读取当前加密 JSON,只改 project 并按同一 ID 更新,检查影响行数;使用短事务保证历史和加密配置一致,保留未知字段,避免根据旧页面快照覆盖并发变化,不在事务中执行外部操作。资产采用读取归一化,不做全库更新或破坏性迁移;显式保存的旧项目目录选项不会自动删除,但资产不再占用项目使用计数。无新依赖,无真实目标数据修改。多语言技能所指定的 Shopee 字典在此项目不存在,本次复用现有文案与组件,不新增翻译框架。

验证:Go 1.25.0 的 model/store/api 定向测试、go vet ./...、Windows 后端编译及前端 vue-tsc --noEmit 通过。覆盖运行中代理项目更新、拒绝混入连接参数、CSRF、凭据/未知字段/引用保留、历史、资产全局列举和旧备份归一化。两次全量 go test ./... -count=1 -timeout=120s 均仅在未改动的 internal/cluster/TestMySQLReplicationAndGroupDiscovery/mysql-group-replication fixture 报“cluster has no available primary or router”,其余包通过;该用例单独重跑通过,不将全量回归记为通过。测试仅使用隔离 SQLite/协议 fixture,没有连接真实上游。

前端验证限制:npm.cmd --prefix web run build 通过类型检查后在 Vite/esbuild 子进程启动处遭遇 spawn EPERM;Playwright 已指定新编译的 LINKPORT_E2E_BINARY 及隔离端口,同样在启动阶段受阻,未执行用例。已补充全局资产/代理修改项目的 Playwright 用例,并调整旧项目范围断言,但不宣称浏览器验收通过。验证程序位于 artifacts/project-asset-validation/linkport.exe,嵌入既有前端产物;本次未替换 bin/linkport.exe 或更改实际 data。相关使用说明见 文件资产 和 项目与环境。

跨平台单 SQLite 存储(2026-09-21)

原因:用户要求所有平台只需一个 SQLite,不保留 LINKPORT_MASTER_KEY 或独立 DPAPI 密钥依赖。仅移除密钥文件无法覆盖旧有审计分库和自动 TLS,因此本次同时统一其持久化位置。

结果与范围:新增单库启动入口,随机主密钥保存在内部元数据表;命令、输出、连接事件合并到主库,自动 TLS 身份入库。Windows 命名互斥量和 Linux/macOS 主文件 flock 替代新建锁文件。移除主密钥环境变量读取与 generate-key 命令;保留离线 migrate-data、交互 migrate-key,以及只导出公开证书的 export-ca。启动脚本同步备份锁,新库不生成 DPAPI/audit/tls/desktop.lock。

兼容与风险:旧 DPAPI 在原用户下读取,旧外部密钥通过一次性终端输入迁移;旧数据文件不自动删除。审计逐分库原子导入并标记,失败可重试,缺密钥或冲突不重置数据库。主密钥与密文同库,数据库持有者可解密凭据,须按敏感文件保护。运行时 WAL/SHM 不可忽略,正常停服后才可复制单个文件。详细流程与外部路径例外见 单 SQLite 持久化。

验证:Go 1.25.0 的 go test ./... -count=1 -timeout=120s 全量通过,go vet ./... 通过(环境中使用 GOFLAGS=-p=2 限制编译并行度);Windows/amd64、Linux/amd64、Darwin/amd64 编译通过,后两者仅交叉编译,未运行对应系统的程序。定向测试含真实 Windows DPAPI fixture、无文件运行锁、错误密钥/损坏元数据拒绝、审计冲突回滚、仅复制 SQLite 后恢复及保留期清理。新编译 Windows 程序的离线 migrate-data/export-ca 和只复制单文件后的 TLS 身份校验通过。协议测试为仓库 fixture,未连接真实上游。

验证限制:npm.cmd --prefix web run build 的类型检查完成,但 Vite 启动 esbuild 时因 spawn EPERM 失败;指定新可执行文件和隔离端口执行完整 Playwright 同样在启动阶段因 spawn EPERM 受阻,未执行用例。启动脚本回归完成 build-only 阶段,在 WMI Get-CimInstance 被拒绝访问处停止,不能称为全量通过。新 Windows 程序嵌入现有 web/dist,本次未成功重新生成前端资源。

本机升级:用户确认停服并明确要求删除密钥后,先备份完整旧 data 与旧程序到 artifacts/backups/single-file-migration-20260921-140105;副本演练后对本机库执行离线迁移,再仅复制 SQLite 到隔离目录验证成功。安装新 bin/linkport.exe,删除运行目录 data/master-key.dpapi,再次执行离线迁移成功且文件未重建。旧密钥只在升级前备份中保留以便恢复;旧审计/TLS 文件未删除,程序已不依赖这些迁移输入。服务保持停止,没有启动真实网关或修改目标服务器数据。

本文件记录本轮累计改动的原因、最终行为和验证边界。2026-09-18 为本次归档日期,不代表所有功能都在当天完成。具体操作方式以链接的功能文档为准;后续行为变更应同步补充原因,避免只留下“改了什么”。

新建目标直接选择代理(2026-09-21)

原因:用户要求新建目标服务时可以选择代理。原有 outboundId 引用、测试和保存已经支持代理,但选择器仅位于独立的「SSH 隧道/代理」页,而且静默过滤其他项目/环境的代理,首次创建不易发现。

结果与范围:新增复用的 TargetOutboundSelect 组件,在目标「连接信息」页的服务类型下直接显示代理出口,原代理页签保留同一入口;两处绑定同一个目标草稿引用。支持直连、SSH、SOCKS5、K8s,默认保留范围过滤,显式展开可选择其他项目/环境代理,选项显示归属,收起后保留已选引用。空列表提示创建代理;不可用引用明确提示且不自动降级直连。新建和编辑目标共用,网关编辑不新增此字段。

兼容与安全:不修改后端接口、代理校验、存储格式或权限,不复制代理密码、私钥或 Kubeconfig 正文到目标草稿。测试和保存沿用既有 outboundId;切换直连显式提交空引用。K8s 固定资源仍受单节点限制,不自动更改 MongoDB 部署模式。无新增依赖或数据库迁移。

实际验证:新增回归在上一轮新构建程序上复现「连接信息」页没有可见代理选择器。前端构建、Go 1.25.0 全量测试与 vet、21 项专项回归通过;全量浏览器检查及补跑合计 89 通过、4 项既有失败,包含在修改前程序上复现的列设置 checkbox 超时,详情见 测试记录。测试使用隔离配置和模拟远程响应,不作为真实 MongoDB、SSH、SOCKS5 或 Kubernetes 连通性证明;未操作真实数据或替换正在运行的程序。

新建代理的 Kubeconfig 资产可发现性(2026-09-21)

原因:用户反馈 Mongo 连接使用 Kubeconfig port-forward 时,在“新建代理”下拉找不到已上传资产。现有传输和资产引用链路已经支持 K8s;可复现的界面缺口是选择器按新代理的默认项目/环境静默过滤资产,既不说明其他范围还有资产,也没有刷新入口,容易被误判为不支持 Kubeconfig。

结果与范围:复用已有 AssetSelect,仅由 KubernetesFields 开启跨范围查看能力。默认仍按编辑资源范围过滤;显示当前范围、其他范围数量和资产类型空态,允许显式展开全部项目/环境,选项附带归属。已选跨范围引用保持可见;改变编辑范围后关闭展开状态,不把此偏好持久化。刷新只使用现有资产服务,失败提示可重试且不清空选择。Mongo 继续选择已保存的 K8s 代理,固定资源模式不绕过既有单节点限制。

兼容与安全:没有修改后端接口、存储格式、权限、凭据解析或 Kubernetes 传输,不增加依赖或数据库迁移。不把普通配置文件混入 Kubeconfig 列表,不自动修改资产/代理归属,也不对 SSH 私钥和 CA 选择器开放跨范围开关。仍只选择资产 ID,选项不读取或回显 Kubeconfig 内容。

实际验证:新增用例在修改前的新构建程序上复现缺少范围提示/展开入口;修改后前端类型检查、生产构建及 7 项专项 Playwright 用例通过,覆盖跨范围选择、类型隔离、代理保存、Mongo 引用回读、刷新失败重试和小屏回归。Go 1.25.0 全量测试与 vet 在串行复跑后通过;首次测试受 Playwright 清理输出目录的竞争影响,详情见 测试记录。全量浏览器检查为 79 通过、3 失败、8 未运行,失败与此前记录的账号小屏滚动、URL 参数和树导航用例一致,未扩展修复范围。命名空间/资源查询为模拟响应,配置存储使用隔离 API;没有真实 MongoDB/Kubernetes 连通性验证。没有操作用户真实数据或替换正在运行的程序。

合并本地输出目录(2026-09-21)

原因:用户希望将 artifacts 与 bin 合并,避免本地程序、打包产物和备份分散。统一使用 bin,根目录保留运行程序,dev-build、build-cache、releases、backups 子目录分别保存暂存程序、缓存与锁、发布产物和完整备份。同步修改 Windows/Unix 构建、启动和打包入口、CI 发布路径、离线整合工具及原有路径断言。

兼容与迁移:现有 artifacts 子项原样移入 bin,备份内容及真实 data 保留;不自动重写旧报告中的历史路径。数据路径选择、库内密钥及数据库格式不变。旧脚本和旧离线工具仍可能生成旧目录,需要使用新版;忽略规则继续覆盖旧路径。bin 现在包含完整备份,不能整体当缓存删除。目录说明见 本地输出目录,实际验证记录见 测试记录。

主密钥入库与指定历史目录整合(2026-09-21)

原因:用户进一步要求去掉独立 master-key,明确选择“密钥存入数据库,保留现有加密字段”,随后要求整合 C:\work\linkport\data 的历史数据库。本节取代下文暂定明文外置密钥方案;历史记录保留用于解释决策变化。

结果与范围:本地模式只在空库的事务中生成随机密钥,保存于 local_key,随后照常初始化加密配置表。正常启动不创建、读取或删除外置密钥。Windows 新建主库使用当前用户/SYSTEM ACL;Unix 使用 0600 并校验属主和文件类型。数据库已有密钥时,显式环境密钥必须匹配;记录缺失、损坏或旧库无库内密钥时拒绝启动,不生成替代密钥。数据库敏感字段仍为 AES-GCM 密文,但密钥与密文同库,数据库泄漏即可解密。独立审计库、TLS 和现有环境密钥服务器模式保留。详细行为见 跨平台支持。

兼容与迁移:用户此前“不需要兼容”的要求继续用于正常启动;新追加的指定历史整合由 Windows 专用离线工具 cmd/consolidate-data 完成,不把 DPAPI 兼容加回主程序。工具先锁定并完整备份源目录,在副本中解密、升级结构、合并独有资源、写入原密钥并校验;当前同 ID 配置优先,新增网关停止,旧管理员和全局设置不覆盖当前值。默认只产出副本,-apply 才在复核源文件哈希后原子替换主库。旧库、旧密钥、审计和 TLS 保留。完整语义与命令见 历史数据库整合。

实际数据边界:整合前主库含 6 个目标、2 个网关、1 个资产,旧库含 2 个目标、2 个网关且资源 ID 无交集,两库完整性检查通过。代理环境 DPAPI 解密失败后,用户在原 Windows 会话运行离线工具成功;终端及 consolidate-20260920T171719.754430900Z/report.json 确认已应用。复核该次完整备份 16 个文件及实际目录中 10 个保留文件的哈希通过;整合副本含 8 个目标、4 个网关、1 个资产,库内密钥、全部资源解密及完整性通过,2 个导入网关停止。实际安装主库因代理读取返回 EPERM 未直接检查,未放宽权限或启动真实服务。早期完整备份及旧库、DPAPI、审计、TLS 均保留,详细边界见 历史数据库整合。

实际验证:Go 1.25.0 全量测试与 vet 通过,新增验证数据库独立复制后凭据可解密、密钥丢失/损坏不替换、外置密钥不自动导入、不同显式密钥拒绝、离线合并优先级、备份和安装、旧文件保持。前端类型检查/Vite 构建与 Windows 新程序本地启动验收通过,涵盖无密钥文件、登录、重启、TLS 和搬移。六目标发布位于 artifacts/releases/2026-09-20T16-40-11-688Z-701d60e4/,Windows x64 原生冒烟通过;其余目标仅编译,远程 CI 未执行。浏览器完整结果见 测试记录。

工作区回归与小屏账号编辑(2026-09-21)

原因:此前 4 项浏览器失败继续定位后,发现资源搜索传给 Element Plus 的 role 没有落到输入框;两项用例尝试直接点击隐藏的原生 checkbox;表格表头的实际可访问角色与测试假设不同;小屏标签选择器换行挤占表单高度,白名单说明也增加额外滚动。

结果与范围:资源搜索使用 container-role 让输入框具备 combobox 语义;小屏标签选择器弹性收缩并保留关闭按钮,白名单文案缩短但保持限制语义。测试点击可见标签并断言复选框状态,检查实际表头 DOM;快捷键前等待搜索入口挂载;清理失败不再覆盖原始断言错误。未放宽滚动阈值,也未跳过用例。URL 参数保存/回读、搜索导航、表格偏好及 320×568 多账号所有页签专项通过。没有数据格式或 API 迁移。功能说明同步至 可用性。

最终验证:同步工作区 helper 的白名单文案断言后,使用新构建程序及重建的隔离数据库完整运行 Playwright,禁用重试,95 项全部通过(7.0 分钟)。首轮失败原因及产物路径保留在 测试记录。

三平台本地启动与未加密主密钥(2026-09-20)

原因:用户要求整个项目支持 Windows、macOS、Linux,并明确选择不加密密钥文件、不兼容 DPAPI。原来的 Windows 专用密钥封装和启动实现无法直接用于其他系统。

结果与范围:三个系统未设置 LINKPORT_MASTER_KEY 时均可直接启动,使用数据目录中的 master-key(32 字节随机密钥的 Base64 明文),无需解锁口令。数据库内的密码、私钥与资产内容继续按原逻辑加密。Windows 新建密钥限制 ACL 为当前用户和 SYSTEM;Unix 创建 0600 文件,检查所有者、文件类型和权限并拒绝符号链接,以 flock 防止同一目录多开。浏览器启动分别调用 Windows 系统工具、macOS open 和 Linux xdg-open;没有桌面时可使用终端打印的地址。

数据选择扩展到三个系统:显式路径优先,其次当前目录已有库,再次系统用户配置目录已有库;均无已有库时在当前目录新建。新建密钥失败会清理本次创建的文件;已有库缺密钥或密钥损坏直接失败,不生成替代密钥。新增 Unix 构建/启动入口、通用 Node 打包脚本、三系统原生 CI 和六目标编译 CI;前端构建根据宿主选择 npm,构建锁覆盖前端生成到 Go 嵌入。各目标目录交付单个可执行文件,多目标发布根目录附版本清单及 SHA256,现有 Windows PowerShell 单 EXE 入口保留。

兼容与迁移:这是有意的密钥格式变更,不读取、不转换 master-key.dpapi,下文历史 DPAPI 验证记录不代表新版本仍支持它。没有 SQLite 表结构迁移,未部署或修改实际数据目录。新格式可随完整离线数据备份复制到其他系统,Unix 需保留当前用户所有权和私有文件权限;数据库中指向外部文件的路径仍需按目标系统调整。详见 跨平台支持。

实际验证:Go 1.25.0 全量 go test ./... -count=1 -timeout=120s 和 go vet ./... 通过;强制前端生产构建(vue-tsc、Vite)通过并保留 .gitkeep。node scripts/package.mjs --all 成功生成 Windows/Linux/macOS × amd64/arm64 六个产物,逐文件 SHA256 与清单一致;Windows x64 原生打包冒烟和 verify-desktop.mjs 验收通过,覆盖内嵌网页、登录、TLS、明文密钥保持、重启及搬移数据。产物在 artifacts/releases/2026-09-20T13-38-02-849Z-dc352132/。Node 脚本语法与 Git Bash 的三个 shell 入口语法检查通过。

另对 Linux/macOS × amd64/arm64 执行 go test -c ./internal/desktop,四目标测试二进制均编译通过;CI YAML 解析和三系统矩阵检查通过。

验证限制:Windows 启动脚本 fixture 回归在 Get-CimInstance Win32_Process 被当前环境拒绝访问,未完成源码启动与备份阶段;这不计为通过。没有 macOS/Linux 本机运行环境,交叉编译不能替代原生启动、浏览器打开或文件权限验收;新增远程 CI 尚未执行。Go 协议测试使用隔离 fixture,未连接真实上游服务器。浏览器全量结果见 测试记录。

Windows 打包仅交付一个 EXE(2026-09-20)

原因:用户明确要求最终打包输出只保留一个 EXE。主程序已经内嵌前端并支持本地密钥、证书生成,原流程附带的 ZIP、证书工具、启动脚本、说明、版本及校验文件增加了分发文件数量。

结果与范围:package.cmd / scripts/package.ps1 保留版本注入、前端缓存、构建锁和隔离验证,最终新建的 artifacts/releases/<时间与唯一标识>/ 中只输出 linkport.exe。构建在独立缓存目录进行,验证通过后才将已核实处于仓库内的暂存目录移动到交付目录;失败时不会发布半成品或覆盖历史版本。校验器要求目录中恰有一个 EXE,从程序读取内嵌版本,并用独立临时数据验证启动、网页静态资源与登录。SHA-256 只打印到控制台,版本信息通过 --version --json 查询,文档和配置示例保留在仓库。

兼容与迁移:移除已无用途的 -Compression 参数;-Version 和 -RebuildWeb 保留。旧 ZIP 产物不自动删除。双击 EXE 沿用现有数据路径与自动生成密钥、证书的规则,不需要数据库迁移;运行产生的数据库、日志、密钥和 TLS 文件仍在选中的数据目录。“单文件”仅指交付产物。单 EXE 不执行源码启动脚本的升级备份流程,更新前仍须停服并完整备份数据。主程序逻辑、开发启动脚本和独立证书工具源码未变。

实际验证见 测试记录;使用说明见 Windows 单 EXE。

Windows 多路径数据发现与相对路径启动(2026-09-20)

原因:用户要求优先使用当前目录,同时兼容 AppData 多路径遍历,并明确启动脚本不再指定数据库路径。需要统一程序启动与备份的数据选择,避免找到旧库却备份了空的本地目录。

结果与范围:新增统一路径解析器;显式 LINKPORT_DATA 优先,否则 Windows 本地模式依次查找当前目录 data/linkport.sqlite 和 %APPDATA%\linkport\linkport.sqlite,复用第一个已有文件,均不存在时新建当前目录库。选中后不因缺密钥、占用或损坏而跳库。数据库、DPAPI 密钥、运行锁、审计和自动 TLS 文件保持同目录关联。新增无初始化副作用的 data-path CLI,供用户查询及启动脚本确定实际备份目录。CMD 入口先进入自身目录,以相对路径调用 PowerShell 并在退出时恢复调用者目录;PowerShell 也定位项目/解压根目录,但不设置或覆盖数据环境变量。源码模式以新构建程序查询,发布模式使用配套新版程序;停本项目旧服务后持锁备份选中目录,拒绝被其他实例占用的数据及包含备份目标的递归复制。

兼容与迁移:已有项目 data 优先,旧 AppData-only 用户直接复用原库;两个库都存在时选择当前目录,不合并、不移动、不删除。启动脚本现在保留用户显式数据路径,.env.example 的数据路径改为留空,程序仍不自动读取 .env。手动主密钥/非 Windows 模式保持当前目录默认且不遍历 AppData。无需 SQLite 表结构迁移,不改变 DPAPI 账户/机器绑定或丢失密钥保护。桌面验证脚本改用隔离工作目录和隔离 AppData,并将失效的管理员字段定位更新为实际页面上的“登录账号/登录密码”,以执行新增的旧库复用验收。详见 Windows 使用说明。

实际验证:Go 1.25.0 的 internal/desktop、cmd/linkport 测试、go vet ./...、启动脚本 fixture 回归、Vue 类型检查和前端生产构建通过;新构建 EXE 的 Edge 桌面验收通过当前目录新库、隔离 AppData 旧库、DPAPI 密钥保持、TLS 与原账号重启登录。全量 Go 测试未全绿:internal/cluster 的 TestMySQLReplicationAndGroupDiscovery 在全量及单包复跑中出现无可用主节点或拓扑不符,其余包通过,本次未改动集群实现。Playwright 使用同一新 EXE、隔离数据及 19091/19092 端口,结果为 77 通过、3 失败、8 未运行(达到 --max-failures=3 后停止):账号编辑器 320×568 权限页出现额外滚动,URL 参数和搜索/树导航两项用例超时;未改动这些前端实现。完整边界见 测试记录。脚本测试使用不启动服务的可执行 fixture,桌面验证使用实际新 EXE 和隔离目录;协议测试为本地 fixture,不接入真实上游服务,未停止实际用户服务、未操作真实数据。

UI 待办十一项实现(2026-09-20)

原因:用户指出仅统一 DBX 风格仍缺少 URL 参数等功能,随后要求把待办全部实现。本次从视觉参考扩展为工作区交互和具有后端运行语义的连接能力,不把“有输入框”当作功能生效。

结果与范围:

  • UI-001/002/006:从已有 API 资源摘要构造安全索引,提供范围感知的统一搜索、键盘/手机入口、资源树、侧栏缩放、最近资源和异常网关入口。复用现有资源刷新与导航保护,不索引凭据/资产正文;最近索引只保存类型、ID、时间。
  • UI-003:新增通用表格包装器与列设置状态,接入网关、连接/命令审计和资产;显隐、排序、表头/数值宽度、必选列、旧偏好合并和重置统一处理。布局存储只包含列 ID 和尺寸,不存业务行数据。
  • UI-004/005:标签以页面/资源 ID 去重,支持固定、关闭其他、编辑器内切换、筛选和滚动记忆。只挂载活动页面,含修改的编辑器在切换前确认放弃,不缓存隐藏凭据草稿或重复轮询。审计分页在标签间保留,概览活动不覆盖审计结果;会话失效清理索引/视图并使迟到刷新失效。统一点击/右键菜单复用现有操作、权限和确认;删除绑定开始时的资源类型,避免等待确认期间导航改变删除路径。
  • UI-007/008:独立 URL 参数与完整 URL 复用白名单解析;参数同步结构化字段,未知/重复/冲突或非法编码原子失败。测试/保存先处理未解析 URL,不再测试旧值;同时有两种待处理输入时提示先应用一项。MySQL charset 进入上游握手,PostgreSQL application_name 进入启动参数;TLS 仍验证身份,不接受随意降级。草稿与保存共用同一载荷构造器。
  • UI-009:新增目标 connectionOptions 与后端严格校验。连接超时进入出口拨号及支持的数据库握手;查询超时仅使用 PG 原生 statement_timeout;Mongo 空闲期限仅等待下一请求,不中断正在执行的查询;TCP 保活作用于直连、SOCKS5、SSH 底层连接,K8s 不支持并拒绝覆盖。前端禁用不支持项,避免把数据库工具的连接池/读超时直接套到 SSH、订阅或多协议会话。
  • UI-010/011:目标/网关分别保存颜色、备注与显示开关,复用资产原有备注,不让目标元数据覆盖网关。草稿测试新增内联摘要、失效提示、完整结果入口及白名单诊断复制;自由文本错误、地址、账号和密钥不进入复制诊断或浏览器偏好。

兼容:新增字段随既有加密 JSON 配置、历史、备份/恢复和同步快照流转,没有 SQLite 表结构迁移。旧配置的零值/缺省保持原行为;网关只引用目标选项,不持久化上游副本。数值范围及语义见 连接编辑器。修复 PATCH 深合并下“使用默认保活”无法清除旧值的问题:前端明确发送 keepAliveSeconds:null,模型只允许可空指针字段接受 null,普通字段/配置对象仍拒绝 null。使用新字段前应升级所有同步节点,不能保证旧版本保留未知字段。没有新增运行依赖、没有修改真实数据库或部署迁移。

实际验证:

  • GOTOOLCHAIN=go1.25.0、GOFLAGS=-p=1,临时目录和缓存位于工作区 tmp;最终 go test ./... -count=1 -timeout=120s 全包通过,go vet ./... 通过。首次完整回归发现可空保活清除被旧 exactFields 拒绝,修复后定向测试与完整回归均通过。
  • 新增 model/API/store 回归覆盖边界值、协议限制、精确字段校验、目标运行时继承、网关元数据隔离、草稿与已保存配置一致性、清除保活、加密备份恢复和同步替换。协议使用本地 fixture 验证 MySQL 握手字符集字节、PG 启动参数、Mongo 空闲关闭及长请求不被该空闲期限打断;未连接真实服务验证兼容性。
  • 锁定前端依赖下 vue-tsc --noEmit 通过,7 项新增纯逻辑测试函数在单进程通过,git diff --check 通过。新增浏览器场景能被 Playwright 发现,全套共 88 项用例;测试发现不是执行通过。
  • npm.cmd --prefix web run build 在 Vite 启动 esbuild 时被 spawn EPERM 阻塞;Playwright 域测试 runner 的 worker 也因 spawn EPERM 无法启动。没有新前端构建、没有新嵌入程序、没有完整 E2E 或本轮截图。web/dist/.gitkeep 保留,未用旧二进制替代验收,未启动或替换用户本地服务,未接触实际 data。

文档:操作与生命周期见 工作区交互,参数/协议/标识见 连接编辑器,实现清单 将十一项标为“代码完成、待浏览器验收”,UI-000 继续未勾选。下节是前序视觉阶段的历史记录,其早期依赖缺失不代表本轮环境和验证结果。

全站界面参考 DBX 统一

原因:用户指定本地 C:\work\github\dbx 作为全部 UI 的参考,原来的深绿侧栏、较大的卡片留白和圆角与 DBX 的紧凑桌面风格不一致。

结果:引入共享中性灰/石墨主题令牌与 Element Plus 控件外观,统一 13 个页面、登录、工具栏、导航图标、表格、表单、通知、抽屉和弹窗。侧栏与顶部工具栏缩小,主题选择移入工具栏;连接编辑器、命令输出、导入和同步面板统一字体及圆角。手机继续使用可滚动图标导航、独立表格滚动和固定弹窗操作区,保留可见焦点与减少动画设置。

范围与兼容:仅改前端展示、相应测试和文档;App 保留业务状态与事件,新增 AppIcon 和 ThemePicker 可复用组件。不增加运行依赖,不引入 DBX 的 Tauri 或数据库业务逻辑,不改变后端 API、账号、连接或持久化结构。主题存储键和四个偏好值沿用,只调整浅色/深色显示名称与色板;无需数据库或配置迁移。

实际验证:git diff --check 通过;离线缓存 Vue SFC 3.5.39/TypeScript 5.9.3 检查 109 个前端源码及测试文件的模板、脚本与 CSS 语法,错误为 0,24 个应用设计令牌引用均有定义;这不是锁定依赖下的生产构建、完整类型检查或测试用例执行。已新增全菜单主题、弹窗和登录回归用例,并更新原手机图标断言。npm ci 因锁定依赖未缓存及网络拒绝连接而失败;构建找不到 vue-tsc,Playwright 找不到可执行命令。Go 1.25.0 的测试和 vet 阻塞于工具链下载,未生成新二进制,未运行完整 E2E,也未生成或验收实际界面截图。未启动服务,未接触真实目标与数据目录。详细范围、维护入口及后续验证要求见 DBX 风格界面。

连接配置改为居中弹窗(2026-09-19)

原因:用户希望新建连接参照示例在弹窗中显示。目标与网关的新建、编辑改用统一居中弹窗,顶部固定标题和分组页签,底部固定测试、取消及保存,中间表单独立滚动;桌面提供更宽的编辑空间,手机按可视窗口缩放。账号页隐藏基础公共配置,沿用原有多账号编辑、字段定位、草稿连接测试和未保存确认。

范围与兼容:新增可复用 ConnectionEditorDialog.vue,App.vue 接入容器;网关账号切换后的滚动定位适配弹窗。无后端接口、配置或数据库迁移,原有字段和保存语义保持不变。功能说明见 界面自适应。

验证(2026-09-20 完成):前端构建、Go 1.25.0 编译及 go vet ./... 通过。go test ./... -count=1 -timeout=120s 仅复现原有 internal/desktop/TestLocalKeyPersistenceAndLock 失败(系统找不到指定文件),其余包通过。新构建程序上的完整 71 项 Playwright 回归为 70 项首次通过、主题测试因 browser.newContext 浏览器关闭而重试通过(1 flaky)。随后加强布局测试,测量实际弹窗面板而非全屏遮罩,并验证固定页脚和 Home/End 键盘切换;补跑两次发现动画期间即时取坐标的测试时序问题,改为等待面板坐标稳定后,响应式两项测试通过。已查看桌面和手机截图;320/390/768/1920px 下弹窗居中且操作可见,既有多账号小屏免滚动、未保存确认、字段定位和草稿测试回归通过。使用隔离数据库及协议 fixture,不代表真实上游服务验收;未改动实际项目数据。

本地 SQLite 文件管理(2026-09-19)

原因:用户需要管理本地 SQLite 文件并测试连接、查看表及查询数据。SQLite 不提供原生网络监听协议,因此新增独立的“SQLite 文件”页面,使用服务端文件绝对路径,以只读方式打开已有数据库。复用现有驱动和管理会话,支持表/视图及结构定义、单条 SELECT/WITH 查询、行数限制、64 位整数与 BLOB 展示,切换输入时清理旧结果并忽略迟到响应。只读连接、禁止附加库及多语句、执行超时和结果大小限制防止查询改变文件或持续占用资源。

范围与兼容:新增 internal/sqlitebrowser 模块、独立 API 域文件和 Vue 组件/状态模块;App.vue 与 server.go 仅接入导航和路由。无新增依赖、数据库迁移或网关协议变更,不读取或修改真实业务数据库做测试。页面路径和查询不持久化、不进入备份或同步;不支持加密 SQLite 文件和远程 SQLite 网关。操作与接口说明见 本地 SQLite 文件。

验证:SQLite 模块与 API 专项测试通过,使用隔离的真实 SQLite 文件(不是模拟 SQL 响应),覆盖只读保护、特殊字符路径、表/视图、结果类型、截断、取消、空数据库及 WAL 中已提交记录。npm.cmd --prefix web run build、Go 1.25.0 编译及 go vet ./... 通过。go test ./... -count=1 -timeout=120s 仅复现原有 internal/desktop/TestLocalKeyPersistenceAndLock 失败(系统找不到指定文件),其余包通过。使用新构建程序和隔离数据库运行 71 项 Playwright:70 项首次通过,主题测试因 browser.newContext 报浏览器已关闭而重试通过,报告 1 flaky。随后修正系统表前缀过滤,避免误隐藏 sqliteXuser 等用户表,模块测试及最终程序上的两项 SQLite 浏览器测试再次通过。浏览器验证覆盖真实文件、表结构、只读拒绝、空结果、截断、小屏幕和切换路径后的迟到响应;无真实业务数据库操作。最终可执行文件为 artifacts/sqlite-final/linkport.exe,测试实例已停止。

目标配置无需保存即可测试

此前新目标和修改后的目标必须先保存才能测试,MongoDB 连接串及其他协议排错因此会提前改变持久配置。现在测试读取点击时的草稿快照,各协议统一支持新建与编辑状态测试;不创建目标、不更新历史、不改变运行中网关映射。已有凭据按稳定账号 ID 复用,其他未完成账号不阻塞所选账号,SSH/SFTP 的新主机身份通过仅本次有效的指纹确认处理。前端保存与测试共用凭据处理规则,后端复用协议测试而不复用保存接口,无数据迁移。具体行为与验证边界见 未保存配置的连接测试。

验证时发现默认浏览器测试端口被其他测试进程占用,因此增加 LINKPORT_E2E_PORT、LINKPORT_E2E_AUTH_PORT 两个测试环境变量。默认仍是 18081/18082,独立验证可以更换端口并使用单独临时目录,无需停止其他服务;测试脚本及认证页面用例统一读取这两个值。

网关账号编辑无需反复下拉

原页面把所有账号的完整表单纵向排列。账号越多,页面越长,添加后需要滚动寻找新账号,编辑不同账号也要来回定位。用户进一步明确要求“不需要滚动”,因此改为选择账号后单独编辑,而不是只移动添加按钮。

改动 原因与结果
顶部可搜索的账号选择器,旁边固定放置添加、删除操作 直接定位账号;表单数量不再随账号总数增加。
一次只显示当前账号,新增后自动选中并聚焦用户名 添加后即可输入,不需要滚动寻找列表末尾。
登录、目标、权限、公钥(SSH/SFTP)、更多设置分组展示 单个账号也有较多字段,分组让每次操作保持紧凑;账号 ID 和到期设置放在“更多”。
账号页隐藏项目、环境、网关名称等公共配置 公共配置仍在“网关与访问”页编辑,进入账号页时无需先经过一段无关表单。
小屏幕把禁用开关和访问模式并排,账号 ID 使用紧凑标签 避免 320×568 窗口在权限及更多设置页出现额外滚动。
切换账号和分组保留内存中的草稿,仍由“保存配置”统一提交 浏览其他账号不应丢失刚输入的密码或映射,也不应偷偷保存尚未确认的配置。
校验失败先选择对应账号及设置分组,再聚焦字段 单账号视图中,错误可能属于当前未显示的账号;只滚动查找旧 DOM 无法定位错误。

实现集中在 GatewayAccounts.vue,App.vue 负责外层页签和校验协调。选择器的位置索引只用于界面导航,保存仍使用原有账号 ID、账号列表和凭据保留规则;本项改动不需要数据库迁移。目标服务的账号编辑器不属于本次免滚动调整范围。

验证使用 12 个已有账号,检查 1440×900、375×812、320×568 下各设置分组的内容高度;新增第 13 个账号后验证聚焦、跨账号草稿保留、错误定位和保存后的凭据状态。参见 account-editor.spec.ts。这是已验证窗口尺寸下的结果;更小窗口、放大字体、软键盘或较长错误清单仍允许必要滚动,不通过裁切内容隐藏控件。

网关账号独立路由与拖拽连线

一个网关端口需要让不同登录账号访问不同目标服务。只有网关级目标引用无法表达这一需求,因此真实账号各自保存目标引用;Redis、MongoDB、TCP 的空账号也作为明确端点。

改动 原因与结果
每个账号可指定同协议目标服务及其账号 登录后选择该账号的地址、出口、TLS 和上游凭据,实现一个监听端口对应多个后端。
每次指定目标时必须选择该目标自己的账号 不同目标可能使用相同账号 ID;复用网关级默认账号会产生错误映射。
允许没有默认目标,停用状态下允许逐条保存连线 用户可以先创建网关,再逐个账号配置;启动时仍要求所有启用账号的映射完整。
每个网关账号都有拖拽入口和独立连线 仅从整张网关卡片出线无法看出每个账号的去向;即使共享目标,也保留独立连线。
单条连线只更新选中账号,服务卡片只展示 多个账号需要共用目标时也逐条选择,避免整卡操作覆盖其他账号。
点击两端也能完成连线 手机触摸及键盘操作不依赖鼠标拖拽。
引用检查、备份、同步、会话审计和监控识别账号级目标 防止删除仍被使用的目标或资产,并让恢复配置及审计记录反映实际路由。

运行配置在新连接接受时取得快照,保存成功后才发布新映射。这样可以修复“界面已切换但重新连接仍访问旧服务”的问题,同时保留已有事务及 SSH/SFTP 会话。已建立的连接不会迁移;客户端重新连接后使用新目标。验证路由时同时检查目标服务自身保存的地址和 SSH 主机指纹,避免把错误地址误认为切换未生效。

MongoDB 和 RabbitMQ 的账号路由在本地认证后才连接所选目标,避免某个默认目标不可用阻塞所有账号;对应握手能力限制见 数据库集群。Redis 在同一连接上改为另一个目标的账号时要求重新连接,防止把流水线响应或事务状态混到不同目标。

操作与 API 说明见 目标与网关账号、运行中切换目标。双目标 SSH、HTTP TLS、MongoDB、RabbitMQ 等路由检查使用隔离协议 fixture;不等同真实生产数据库兼容验收。

其他累计改动的原因

范围 原因 最终行为及说明
密码解密 需要直接恢复 Navicat 密文,也要能调整普通密码解密参数,避免每次手动修改代码。 提供算法、模式、填充、Key、IV 和编码选项,Navicat 12 自动填入预设;见 密码解密。
全站自适应 固定尺寸的页面和弹窗在手机及低高度窗口中遮挡操作,问题不只出现在解密页。 统一处理导航、卡片、表单、弹窗和操作栏布局;宽表格、连线画布保留区域内滚动;见 响应式界面。
菜单搜索 菜单数量增加后逐项寻找功能不方便。 按名称及常用关键词筛选,手机也能打开搜索入口;见 响应式界面。
S3 多端同步 S3 的用途是多设备持续同步,单次上传备份无法处理多端修改;用户明确要求包含网关配置。 同步目标、代理、全部资产、凭据及网关监听与账号映射;处理冲突和删除传播,审计与个人登录信息留在设备本地;见 S3 同步。
配置管理入口 备份与同步属于配置迁移操作,混在监控功能中不便查找。 提供独立配置管理、多端同步入口;见 配置备份。
仅保留加密备份并包含全部资产 脱敏配置无法完整恢复凭据;漏掉文件或未引用资产会让恢复结果不完整;同时提供普通完整导出和加密导出又增加重复选项。 只提供口令加密的完整配置导出,保留所有资产内容、文件名、备注及引用;模板仍用于复用结构;见 配置备份。
Kubernetes StatefulSet MongoDB 等有状态服务常使用 StatefulSet,仅支持 Deployment/Pod 等资源不足以表达连接目标。 支持 statefulset/名称 并解析相应 Pod;见 Kubernetes。
Kubernetes 下拉查询 手输命名空间及资源名称容易写错,也无法得知实际存在的资源。 自动查询命名空间,资源通过查询后的下拉框选择,切换上级配置清除旧选择,失败可重试;见 Kubernetes。
资产备注 文件名不足以解释凭据的用途或归属。 创建及编辑资产可填写备注,备注随加密备份和同步保留,修改备注不替换文件;见 易用性。
项目与环境 所有资源需要按项目和环境组织;只固定“正式/测试”不能覆盖实际环境。 可维护多个项目和环境选项,每条资源选择一个项目、一个环境;已有缺少归属的数据按用户选择归入“默认项目 / 测试”;见 项目与环境。
个人使用模式 用户明确个人使用,不需要维护多用户管理角色。 删除用户与角色管理入口和相关接口,保留个人登录及 API Token;见 网关运维。
MongoDB 连接串及集群 MongoDB 连接地址可能包含多个域名或 IP、编码后的凭据、副本集与认证库,无法放入单一 IP 输入框。 解析支持的连接串并填入节点、账号、集群及 TLS 等字段,支持协议相应的集群发现;见 数据库集群。
SSH 命令与执行结果审计 只记录输入片段难以核对完整命令,输入记录也不能说明远端输出或执行结果。 保存完整输入及相应输出,区分 exec 的退出状态和交互终端输出边界;见 SSH 审计。
MySQL 查询结果审计 只有 SQL 文本不足以复核实际返回结果,多结果集和二进制值也需要保留类型信息。 关联保存返回列、数据行、影响行数和错误,提供分页预览及完整下载;见 MySQL 结果审计。

以上说明记录最终选择。功能限制、恢复范围和协议兼容边界以对应专题文档为准,不把测试用凭据或实际连接密码写入变更记录。

网关服务草稿连接测试(2026-09-28)

原因:网关列表虽然已有已保存配置的测试入口,但新建或编辑网关必须先保存才能验证监听配置、网关账号和目标映射。这样会把尚未确认的地址或凭据提前写入配置,也无法测试新建网关。

结果:网关编辑器底部增加“测试连接”,复用目标草稿测试的结果页和诊断脱敏。测试按当前网关账号选择目标映射;Redis 空客户端账号直接使用无认证入口。编辑草稿的省略密码按稳定网关账号 ID 从已保存配置恢复,新建草稿直接使用当前输入。服务端新增 POST /api/v1/proxies/test,只在内存合并、解析和验证草稿后调用现有协议测试,不落库、不写历史、不启动或修改运行中的网关;已保存网关列表测试接口保持不变。

兼容与范围:没有配置格式或数据库迁移。其他账号映射不完整时,测试只校验所选账号;保存和启动仍按完整网关配置校验。API 与前端验证使用隔离 fixture,未连接真实生产目标,也未修改真实 data 目录。

连接配置页签与 URL 参数(2026-09-20)

原因:连接信息、TLS、出口代理及高级设置混在同一页,除 MongoDB 外的连接 URL 不能直接填入配置。现在目标弹窗提供连接信息、TLS/SSL、SSH 隧道/代理、高级及账号分组,切换保留草稿;通用 URL 导入支持现有网络协议,解析账号、地址、数据库和受支持的 TLS 参数。不支持或有歧义的参数明确拒绝,避免静默丢弃配置含义。高级页归集已有设置,不新增超时或保活选项。详细范围见 连接配置。

兼容:目标/运行时新增可选 database 字段,用于 MySQL 默认数据库和 Redis SELECT;旧配置为空时保持原行为,无表结构迁移。MySQL 客户端显式指定数据库优先,Redis Cluster 仅支持 0。其他数据库沿用 authSource。凭据继续使用现有多账号、加密及留空保留规则,原始 URL 不持久化。只读权限仍在网关设置,代理连接仍选择已有出口。

验证:npm.cmd --prefix web run build 通过;Go 1.25.0 下 go vet ./... 通过。go test ./... -count=1 -timeout=120s 除已知 internal/desktop/TestLocalKeyPersistenceAndLock(系统找不到指定文件)外全部通过;新增模型校验/继承测试单独通过。MySQL/Redis 本地协议 fixture 验证认证后选择数据库、默认库与客户端指定库优先级、服务端拒绝及 DB0 兼容,不代表真实上游服务器验收。通过 LINKPORT_E2E_BINARY 指向新构建 artifacts/connection-tabs/linkport.exe,用随机管理端口和隔离数据库执行完整 Playwright:73 passed、1 failed。新增 URL 参数矩阵、页签草稿、测试请求、保存重开和脱敏用例均通过;SFTP 用例在打开编辑器后超时,自动重试因超时遗留同名数据触发严格定位错误。更换全新隔离数据库和浏览器,SSH/SFTP 两项专项复跑均通过(2 passed);全量首次运行不记为全部通过。测试服务均已停止,真实 data 目录未修改。

集群部署模式改为手动选择(2026-09-20)

原因:用户要求删除自动识别模式,明确选择实际部署类型。目标编辑器移除“自动识别”选项及“启用自动识别”按钮,只提供单节点、协议对应集群类型和多节点故障切换。手动点击的“识别集群”保留为只读诊断,查询结果不修改部署模式;明确模式下的主节点发现和路由仍按原协议行为运行。

兼容:已有 auto 记录不自动改写或清空,打开后显示待选择并保留节点、名称及账号;保存或草稿测试前必须手动选择。后端保留旧格式读取、运行和 API/备份兼容,不做数据迁移。MongoDB URI 明确 replicaSet 或 directConnection=true 时沿用其指定模式,其他 URI 使用仅在草稿中的待选择标记,未经手动选择不会发出保存或测试请求。详见 数据库集群。

验证:npm.cmd --prefix web run build、Go 1.25.0 的 go vet ./... 通过,新程序为 artifacts/manual-cluster/linkport.exe。go test ./... -count=1 -timeout=120s 仅已知 internal/desktop/TestLocalKeyPersistenceAndLock 失败(系统找不到指定文件),其余包通过。使用 LINKPORT_E2E_BINARY、随机端口和隔离数据库完成 75 项 Playwright,首次为 71 passed、4 failed:两个新增用例重复点击了校验时已展开的下拉框;RabbitMQ fixture 指定集群类型后仍断言未知类型;工作区用例按协议取第一条数据,受前面超时残留的 fixture 影响。修正下拉操作、RabbitMQ 改为手动故障切换模式,并让测试按自身目标名称定位。最终对集群、MongoDB、RabbitMQ 和工作区相关 7 项用例在全新隔离数据库复跑全部通过;保留首次全量失败记录,不宣称一次全量零失败。覆盖未选择时阻止保存/测试、选择后节点凭据保留及 MongoDB URI 手动选择。Redis/AMQP 使用本地协议 fixture,MongoDB 草稿测试模拟远端结果,未连接真实上游服务或修改实际 data。

.gitignore 维护(2026-09-20)

原因:用户要求维护忽略规则,现有规则尚未覆盖从根目录运行浏览器测试的输出、Playwright blob/cache、SQLite3 与回滚日志等本地产物。补充根目录/web 的测试输出与缓存、SQLite3/journal 侧文件、根目录临时 db 与可选 tls,并让依赖目录规则适用于所有层级。

范围与兼容:只影响未跟踪文件的 Git 可见性,不删除本地数据、不改 Git 索引、不批量忽略源码、文档或测试 fixture。保留 .env.example、锁文件和 web/dist/.gitkeep;不全局屏蔽所有证书、db 或归档。规则说明见 测试文档。实际验证:git check-ignore --no-index 的 41 个本地/生成路径均被忽略,16 个源码、示例、锁文件和 fixture 路径保持可见;git ls-files 确认检查的生成目录仅跟踪 web/dist/.gitkeep。git diff --check 通过。

手输环境后保存旧值修复(2026-09-20)

原因:网关、代理和资产编辑器共用的可创建下拉框把输入当作搜索词,只有按 Enter 或点击选项才更新值;用户输入 test 后直接保存,请求仍携带旧的 production,后端返回成功却未更改环境。已在三个编辑器用隔离数据分别复现,修复前新增用例均在请求值断言中失败(期望 test,实际 production)。

行为与范围:ScopeFields 将手输项目、环境同步到资源草稿,直接保存、切换焦点或页签均使用输入值;已有选项、中文环境别名、清空和取消保护继续生效,中文输入法在组合输入完成后更新。该共用组件影响目标、网关、代理、资产编辑器;不改变 API、数据库格式、共享资产的运行中引用保护、顶部筛选或目录管理,无迁移。说明见 项目与环境。

实际验证:

  • npm.cmd --prefix web run build 与 Go 1.25.0 的 go vet ./... 通过;前端构建后恢复 web/dist/.gitkeep,随后构建 artifacts/environment-save/linkport.exe。git diff --check 通过。
  • 新增 environment-save.spec.ts 的三个用例在修复前程序上均复现旧值提交,修复后均通过:检查实际 PUT 请求、后端回读以及刷新后显示;同时覆盖自定义项目和环境、未保存提示、选择正式环境、清空环境。测试使用隔离数据库,无真实目标服务连接或数据修改。
  • 使用上述新程序设置 LINKPORT_E2E_BINARY 运行全部 91 项 Playwright 用例(允许一次重试):86 项通过,1 项主题用例因浏览器上下文退出而重试通过,4 项失败。失败为账号编辑器在 320×568 下的权限页滚动高度断言,以及 workspace-features.spec.ts 的 URL、搜索树导航、表格列设置三个超时;四项都在修复前的 baseline.exe 上单独复现相同失败,未因本次环境输入修复而引入。结果位于 artifacts/.environment-save/ 的 test-results、baseline-layout、baseline-url、baseline-navigation。
  • Go 1.25.0 的 go test ./... -count=1 -timeout=120s 已执行;除 internal/desktop 外其他包通过。TestLocalDataDirectory 的四个子用例及 TestLocalKeyPersistenceAndLock 报 Windows “The system cannot find the file specified.”,全量后端测试未通过;本次未修改后端,协议测试结果不代表真实服务器联调。

保存成功后旧环境显示与请求诊断(2026-09-20)

原因与复现:用户提供的资产 PUT 包含 environment: test,现场只读回查详情及列表也均为 test,但用户仍看到旧环境。此前输入同步修复没有覆盖保存后的缓存刷新:编辑器忽略保存响应,等待五个接口的 Promise.all 完整成功才替换缓存。隔离测试中让项目环境目录 GET 返回 500,资产(Kubeconfig)、代理、网关三个入口都复现了 PUT 和后端回读为 test、列表仍显示「正式」的问题。该受控复现验证此故障路径;现场端口随后关闭,未捕获现场具体失败的刷新请求。

行为与范围:目标、网关、代理和资产的 POST/PUT 成功后,App 立即将服务端返回的完整资源视图写入对应缓存,并使保存前已启动的刷新失效,防止旧快照覆盖新值。列表、资源树和重开编辑器共享新值;后台刷新仍执行,失败仍报告。管理 API 错误新增独立的请求地址、路径和方法,HTTP、网络和解析错误都保留诊断,中文错误翻译继续生效,查询参数及请求凭据不加入诊断。无 API、数据库格式或迁移变更,资产文件更新时间语义不变。说明见 项目与环境 和 配置易用性。

实际验证:前端构建、类型检查及 Go 1.25.0 的 go vet ./... 通过,生成 artifacts/environment-save/linkport-refresh.exe。保存后刷新失败的三个用例在修改前均失败(后端 test、界面「正式」),修改后针对性运行共 7 项通过,覆盖手输环境、三个入口刷新失败后列表与重开编辑器、新增错误定位、中文翻译、网络错误和失败时保留草稿。请求诊断不包含测试文件内容或 CSRF 令牌。使用该新程序及 LINKPORT_E2E_BINARY 运行完整 95 项 Playwright(不自动重试):90 项通过,5 项失败;其中账号小屏权限布局和三个工作区用例与上一轮已在修复前程序复现的失败相同,主题用例遭遇浏览器退出,单独新开浏览器重跑通过。新增四项在全量运行中均通过,CSRF 过期重试、项目环境筛选及响应式布局也通过;全量仍非全绿。结果位于 artifacts/.environment-save/refresh-fixed、refresh-full、refresh-theme,修改前复现位于 stale-baseline。

后端 go test ./... -count=1 -timeout=120s 已执行:源码包除已知 internal/desktop 的 Windows 本地目录/密钥测试失败外均通过;本轮还遇到另一个打包任务清理 tmp/package-validation/go-build... 导致 ./... 枚举报错。首次全量 vet 同样受临时目录影响,源码包单独检查及随后全量 vet 重跑通过。测试使用隔离数据库与模拟失败响应,未改真实资产或连接真实上游服务。

验证与维护要求

最新执行结果统一记录在 测试文档的 2026-09-18 记录。记录应区分构建、静态检查、协议 fixture、浏览器测试及真实服务验证,也应保留失败和重跑情况。

后续每项行为变更同时说明:原问题或需求、改动原因、最终行为、影响范围、数据兼容或迁移要求,以及已执行的验证和已知限制。专题文档保留详细说明,本文件提供原因摘要和入口;不能只在提交标题或聊天中说明原因。

RabbitMQ 服务版本识别(2026-09-18)

原因:集群识别只读取 AMQP 握手的 cluster_name,连接测试把协议版本 AMQP 0-9-1 当作服务器版本显示,遗漏 broker 公布的 version。现在集群识别和连接测试共用 AMQP 探测,在账号认证和 vhost 访问成功后读取服务版本;集群类型无法完全识别时仍可展示当前节点版本。版本缺失或字段类型异常时不猜测版本,连接测试明确显示 server version unavailable。

范围:RabbitMQ 目标的集群识别、连接测试及复用该测试的健康检查。集群 API 增加可选 version 字段,连接测试的 version 优先返回 broker 版本;没有配置或数据库迁移,也不需要管理插件或额外管理权限。版本仅代表当前连接节点。实现使用现有 AMQP 客户端解析握手属性,复用目标 TLS、出口及凭据,避免维护两套认证探测和字段解析。功能说明见 数据库集群。

验证:隔离 AMQP fixture 覆盖自动/显式集群模式、备用节点、版本存在/缺失/类型异常、特殊字符 vhost,以及认证或 vhost 拒绝时不返回成功版本。Go 1.25.0 下 RabbitMQ/cluster 专项及 go vet ./... 通过;npm.cmd --prefix web run build 通过。全量 go test ./... -count=1 -timeout=120s 仅 internal/desktop 的 TestLocalKeyPersistenceAndLock 失败(系统找不到指定文件),单独重跑仍失败,其余包通过。使用新构建程序运行 68 项 Playwright 回归,输出两项失败且运行器收尾未正常退出,已停止;其中新增 fixture 的账号字段已修正,rabbit-version.spec.ts 单独重跑的用例结果为 passed,覆盖未知集群类型时的实际版本展示及版本缺失提示,运行器仍需手动结束。全量回归不记为通过。未对真实 RabbitMQ 集群做版本兼容验收。

Redis Sentinel 认证账号手动输入(2026-09-18)

原因:集群设置此前只能选择已有目标账号,Sentinel 使用独立凭据时必须离开当前设置到账号页创建,无法直接输入。现在在“Sentinel 认证账号”旁提供“手动输入新账号”,创建独立账号并选中,直接编辑可选账号备注、用户名和密码;已选账号也可原地编辑。仅密码认证使用 default 用户名,ACL 认证填写实际用户名。

范围与兼容:仅调整 Redis 目标集群设置界面,复用 accounts 和 cluster.sentinelAccountId、既有加密存储、API 隐藏及空密码保留规则。Redis 数据账号不被新建 Sentinel 账号替换;所选已有账号的编辑会同步到该账号。保存前为草稿,取消遵循已有未保存提示。切换自动认证/单节点仅清除引用,保留账号供后续使用。账号上限仍为 32,无数据库或配置迁移。操作说明见 数据库集群。

验证:新增隔离 RESP/Sentinel 浏览器 fixture,验证手动创建、保存后隐藏密码、留空保留凭据、ACL 与仅密码认证切换,以及发现主节点后使用 Redis 数据账号;专项及全量运行中的该用例均通过。npm.cmd --prefix web run build 和 Go 1.25.0 的 go vet ./... 通过;go test ./... -count=1 -timeout=120s 除已知的 internal/desktop/TestLocalKeyPersistenceAndLock(系统找不到指定文件)外全部通过。使用新构建程序、隔离数据库和 19181/19182 端口运行 69 项 Playwright 回归:68 项通过,最后一项主题测试在 browser.newContext 阶段报浏览器已关闭,换新浏览器单独重跑通过。测试服务由独立会话管理,避免前次 Windows 测试运行器收尾卡住;本次运行器正常返回。fixture 不等同真实 Redis/Sentinel 集群验收。

启动时自动分配管理端口(2026-09-18)

原因:固定 8080 容易与本机其他项目冲突。程序未指定 LINKPORT_HTTP_ADDR 时,以及 start-dev.cmd 未收到显式地址时,默认使用 127.0.0.1:0,由操作系统在实际绑定监听器时分配空闲端口;不会先探测端口再关闭重开。启动窗口打印实际管理 URL,本地模式的浏览器和首次设置地址继续取自已绑定监听器。

范围与兼容:改变管理 HTTP 默认端口;已有数据库、网关监听端口、目标配置和启动备份流程保持原行为,无数据库迁移。显式配置固定端口仍生效,启动脚本不再覆盖 LINKPORT_HTTP_ADDR;使用书签、API、反向代理或 Vite 固定代理的用户应显式设置固定地址。随机端口可能在不同启动之间重复,不保证每次都与上一次不同。使用说明同步到 README、Windows 包说明和 .env.example。

验证:新增 scripts/verify-random-port.mjs,使用新构建的真实可执行文件和隔离数据库,验证两个未配置监听地址的实例同时获得不同非零端口(本次为 11324、11327),打印的 URL 可访问页面和健康接口,重启时显式固定端口生效。scripts/start-dev.test.ps1、前端构建和 Go 1.25.0 的 go vet ./... 通过。go test ./... -count=1 -timeout=120s 仅已知的 internal/desktop/TestLocalKeyPersistenceAndLock 失败(系统找不到指定文件),其余包通过。使用 LINKPORT_E2E_BINARY 指向新程序、两个随机管理端口 8551/8552 和隔离数据库运行完整 Playwright:68 项首次通过,主题测试因浏览器上下文关闭失败后自动重试通过,报告为 1 flaky;运行器正常退出。启动冒烟使用测试主密钥,不读取实际项目数据,也不测试真实上游协议或 Windows DPAPI/浏览器自动打开流程。

目标保存后保持编辑与已保存连接测试(2026-09-28)

原因:目标编辑器保存成功后关闭编辑页返回目标列表,用户无法直接确认刚保存的账号密码或继续测试;目标底部测试按钮还会提交未保存草稿,连接结果可能与后端实际保存配置不一致。该行为导致 RabbitMQ 等目标的排错难以区分“草稿内容”和“已保存凭据”。

结果:目标保存成功后前端使用服务端返回的资源视图刷新当前编辑器并保持打开。目标连接测试仅调用 POST /api/v1/targets/{id}/test,读取后端保存的目标、账号、凭据和出口;新建目标或编辑器存在未保存修改时不发起测试请求,提示先保存。网关草稿测试保持原有行为。新增提示通过中文、英文、日文字典提供。范围仅涉及目标编辑器前端交互和说明文档,无 API、数据库格式或迁移变更。

验证:vue-tsc --noEmit 通过;Vite 构建在当前 Windows 环境中因 esbuild 子进程 spawn EPERM 未完成。目标 Playwright 回归用例需按新的“先保存、再测试”流程更新后执行;未连接真实 RabbitMQ,也未修改真实 data 目录。

拖拽连线协议筛选(2026-09-28)

原因:拖拽连线页面同时展示多种协议时,节点和连线过多,用户需要快速查看同协议的网关、目标及账号关联。

结果与范围:Connections.vue 增加包含全部协议和 TCP、MySQL、MongoDB、SSH、SFTP、HTTP、HTTPS、SQL Server、Redis、RabbitMQ、PostgreSQL 全部 11 种类型的下拉筛选。筛选同时作用于可见网关、目标、账号和连线;节点按统一协议顺序、名称和 ID 排列。切换筛选只改变当前视图,不修改服务绑定、已有拖拽位置、布局存储格式、后端接口或数据库,因此无需迁移。筛选控件文案加入中文、英文、日文资源字典。

验证:vue-tsc --noEmit -p web/tsconfig.json、git diff --check 和 8 项 connection-canvas.test.mjs 测试通过;Playwright 从正确的 web 配置发现 60 个文件中的 138 项测试,connection-canvas.spec.ts 逐项检查 11 种协议选项并覆盖三种筛选状态及连线数量。当前 Windows 环境 Vite 构建阶段仍受 esbuild spawn EPERM 阻断,未完成 Playwright 浏览器运行;测试未连接真实目标服务。

通用连接失败诊断细化(2026-09-28)

原因:RabbitMQ、Redis 及其他协议的连接测试在部分底层错误下只返回 target_connection_or_protocol,用户无法判断是端口未监听、网络超时、TLS/协议握手、认证、权限还是查询阶段失败。

结果:后端按已观察阶段返回稳定诊断码。TCP 连接可细分为拒绝、超时、DNS 解析失败、网络不可达和连接重置;其他协议统一区分 TLS、握手、认证、权限、协议会话、查询/健康检查及 HTTP 响应。诊断领域函数提供中文、英文、日文阶段标签和排查建议,当前界面默认使用中文;原始服务端错误仍不回显,避免泄露地址、账号、密码或业务数据。

兼容与范围:保留 target_connection_or_protocol、connection_timeout 等旧代码;旧历史记录不变,新版后端重新测试后才产生新代码。没有数据库或配置迁移,不改变连接逻辑、凭据保存或目标数据。

验证:Go 1.25.0 下 internal/gateway 定向测试通过;前端诊断 Playwright 单测 1/1 通过;vue-tsc --noEmit 和 git diff --check 通过。测试使用错误和诊断 fixture,未连接真实 RabbitMQ、Redis 或其他生产服务。

Redis and MongoDB anonymous accounts (2026-09-28)

Redis and MongoDB deployments can disable authentication. Empty target and gateway account lists now represent that mode across model validation, API tests, frontend drafts, startup readiness, and protocol serving. MongoDB anonymous handshakes skip SCRAM while configured gateway accounts retain local SCRAM and target-account mapping. No schema migration or production data change is required.

Redis password-only authentication and protocol audit (2026-09-28)

Reason. Redis has a protocol-level password-only form (AUTH password) in addition to ACL username/password authentication. The transport already emitted the correct one-argument command, but shared model and frontend validation still rejected an empty username. Treating every database alike therefore prevented a valid Redis configuration.

Resulting behavior. Redis target and gateway accounts now support three distinct modes: no authentication, password only, and username plus password. The password-only mode requires an exactly empty username and a non-empty secret; whitespace is rejected. A blank Redis gateway username maps to the protocol's default identity, and cannot coexist with an explicit default account. All other service types retain their protocol-specific username requirements. Non-SSH/SFTP targets now also reject privatekey and unknown authentication methods instead of saving fields their protocol handler would ignore.

Scope and compatibility. The change is limited to credential validation, Redis gateway identity lookup, frontend checks/examples, tests and documentation. Existing named Redis accounts and anonymous Redis/MongoDB configurations remain unchanged. There is no data migration, schema change, new dependency, production data modification or authentication fallback after a rejected login.

Validation. Go 1.25.0 model, API and Redis protocol fixture tests cover both target and gateway paths, including direct and Cluster connections. A full service-type matrix verifies that password-only accounts are accepted only for Redis. Cluster tests include the HELLO AUTH rewrite to the Redis default identity. Frontend validation, startup readiness, connection examples and legacy draft hydration have focused domain tests. The RESP checks use local net.Pipe fixtures and do not claim live Redis or Sentinel coverage. Detailed command results and environment limitations are recorded in testing.

One-to-one gateway-account associations (2026-09-28)

Reason: associating from either service card implicitly selected or replaced account mappings. Multi-account gateways could therefore overwrite unrelated routes, while account-free services had no explicit endpoint at all.

Result: both gateway and target service cards are display-only. Every editor, live-switch and canvas operation selects one gateway account and one target account, and changes only that route. Redis and MongoDB empty account lists use synthetic UI-only anonymous account rows; TCP uses synthetic empty-account rows. Their IDs remain empty strings and no credential record or fake identifier is created. Existing account, disabled-account, protocol and conflict validation remains unchanged.

Scope and compatibility: the gateway editor no longer exposes a service-level default. Editing or saving a legacy mapping with real gateway accounts expands the top-level target into each account and clears the top-level fields. Empty Redis, MongoDB and TCP gateway accounts keep the existing top-level persistence format. Existing stored data and backend compatibility remain readable, so no database migration is required.

Validation: focused domain tests cover all 11 protocol drafts, legacy expansion, and empty-account persistence. Playwright fixtures cover per-account mapping, both display-only service cards, Redis/MongoDB anonymous rows, TCP empty rows, and all 11 editor protocol choices. These are isolated configuration fixtures, not live upstream-server validation.

Live target switches disconnect existing clients (2026-09-28)

Reason: keeping accepted sessions pinned to the previous route made a successful target switch leave old-target connections active indefinitely. Operators could not rely on a client reconnect policy to move all traffic to the published route.

Result: Manager.SwitchTarget still validates and persists before publishing. After a successful publish it snapshots every accepted client of that gateway, marks registered sessions as disconnecting, and cancels/closes them outside the manager lock. The listener remains active, so reconnecting clients immediately capture the new route. A persistence or validation failure leaves the old route and all existing clients untouched. Switching one account changes only that account's mapping, but disconnects all current clients of the gateway so no old configuration snapshot remains in use.

Scope and compatibility: this applies to the shared gateway lifecycle and thus all supported protocols, including TCP and multi-channel SSH/SFTP. It changes the connection-interruption behavior of the existing target-switch endpoint without changing its request, response, storage format, or listener address. In-flight requests, transactions, tunnels, and sessions can be interrupted. There is no database or configuration migration.

Actual validation: Go 1.25.0 targeted gateway tests for generic relay, TCP, SSH and multi-account SSH routing passed, as did the API fixture for failed persistence, successful disconnect, stable listener and reconnect routing. The complete internal/gateway package passed. A broader internal/api run retained unrelated Windows sandbox failures where existing SSH and SOCKS5 fixtures could not establish their local test connections; the focused target-switch API test passed. These are isolated loopback protocol fixtures, not live database or broker validation. Frontend compilation and browser execution were not run for this development-stage adjustment at the user's request.

Persistent connections enabled for new targets (2026-09-28)

Reason: all supported target protocols now provide either a standby session, persistent tunnel or background probe, so requiring users to enable the same setting on every newly created target adds repetitive setup and leaves targets without background readiness checks by default.

Result: createConnectionDraft initializes connectionOptions.persistent to true for all 11 target types. Switching the protocol while creating a target rebuilds the draft with the same enabled default. The advanced settings text and labels use the Chinese, English and Japanese dictionaries.

Scope and compatibility: this is a new-draft UI default, not a storage migration. Existing targets use the value returned by the backend; a missing field or saved false remains off. Direct API clients that omit the field keep the backend's existing zero-value behavior. Enabling the setting can create periodic target connections only while a referencing gateway is running.

Validation: all 8 connection-draft tests and all 6 persistent-target component tests pass; the draft matrix checks the enabled default for all 11 types, confirms legacy targets do not inherit it, and the persistent matrix verifies every protocol's mode. Vue type checking also passes. All 16 single-process frontend domain test files and serial go vet -p=1 ./... pass as well. The browser fixture cycles through all 11 type controls before saving and reading back the enabled value, and Playwright discovers it from the web configuration. The browser run was not executed because Vite cannot spawn esbuild in the current Windows environment (spawn EPERM). Fixture checks do not establish live target availability.

All-protocol connection canvas filtering and ordering (2026-09-28)

Reason. The canvas filter was limited to MySQL and RabbitMQ, while the workspace supports TCP, MongoDB, SSH, SFTP, HTTP, HTTPS, SQL Server, Redis and PostgreSQL as well. Users also need the same project and environment scope selection that applies to the other workspace pages.

Resulting behavior. The connection canvas uses one dropdown containing all supported connection types plus an all-types option. The existing shared WorkspaceScopeFilter remains the only project/environment selector; its selection is applied before rows reach the canvas. Visible gateways and targets are sorted by the shared protocol order, then by name and ID for stable placement. Existing manually saved node positions remain respected; reset and new layouts follow the type order.

Scope and compatibility. This is a frontend-only view, sorting and translation change. Filtering and ordering do not alter bindings, credentials, backend requests, layout storage format or database data. No migration is required. All new protocol labels are present in the Chinese, English and Japanese dictionaries.

Validation. The in-memory canvas test covers all 11 protocol values, unknown types placed last, and stable name ordering. The Playwright fixture checks the dropdown options and MySQL/RabbitMQ filtering. It uses isolated fixtures and does not connect to live upstream services.

MySQL slow-query and full-scan highlighting (2026-09-29)

Reason. MySQL command audit stored result rows and server status values but did not expose execution duration or index-risk signals in the command list. Operators could not quickly identify a slow response or a server report that no index, or no suitable index, was used.

Resulting behavior. The gateway records elapsed duration observed from accepted command to complete, failed or interrupted response. It accumulates MySQL SERVER_STATUS_NO_INDEX_USED and SERVER_STATUS_NO_GOOD_INDEX_USED flags from OK and EOF packets. Command audit desktop and mobile views, plus query-result details, highlight queries at or above 3000 ms as slow, no-index reports as a red full-scan risk, and no-good- index reports as a warning. User-visible labels are available in Chinese, English and Japanese.

Scope and compatibility. Command-list reads now left-join the existing one-to-one encrypted result summary, avoiding per-row database reads. The new optional JSON fields require no SQLite migration, and old records remain readable with performance metrics unavailable. No EXPLAIN query is issued: the normal response cannot identify the exact index, and an automatic explain would add load, permissions and transaction side effects. The full-scan label is therefore explicitly a risk signal rather than a guaranteed execution-plan claim.

Validation. Protocol fixture tests were added for OK and EOF status-bit capture and observed duration, a store test covers list summary hydration, and a frontend domain test fixes the slow threshold at 3000 ms and covers risk classification and duration formatting. At the user's request for this development-stage adjustment, no compilation, test suite, server or browser was run. Static source review and git diff --check are the claimed validation; no live MySQL server or real data was used.

配置库与日志分片库分离(2026-09-29)

原因:审计、命令结果和连接事件只需要追加与查询,却会持续放大同时承载配置的 data/linkport.sqlite。大体积单库会增加配置备份、检查和空间回收成本;为只增不改的日志引入外部日志服务,又会破坏 LinkPort 的单程序、低运维部署方式。

实现结果:配置状态保留在 data/linkport.sqlite,命令审计、命令结果与输出、连接事件写入 data/audit/*.sqlite。活动日志分片使用 SQLite WAL;写入前按 .sqlite、-wal、-shm 当前总大小加本次估算值判断是否轮转。命令及其结果、输出固定在同一分片,不为满足上限而拆开。轮转依次执行 WAL checkpoint、切换 journal_mode=DELETE、关闭句柄、清理边车文件,再按同日已有最大 partNNNN 加一归档并创建新活动分片。默认阈值为 256 MiB,UI 可在 16 MiB 到 4 GiB 范围调整。完整行为见 配置库与日志库分离。

迁移:旧命令、结果、输出和事件按明确 ID 小批复制;目标端对持久化字段进行一致性校验并先提交,之后源端才按该批 ID 删除并核对影响行数。迁移使用 pending/done 标记保持可重试:旧表清空并删除后执行一次 VACUUM,只有压缩成功才完成 done 并清除 pending;压缩失败时,下一次启动会根据 pending 再次尝试,不重复或扩大源端删除。

范围与兼容:日志写入、查询、导出和清理已按分片工作,分片上限保存在配置库并由 UI 调整;旧配置缺少阈值时使用 256 MiB,调整阈值不重写旧分片。配置快照只包含 data/linkport.sqlite,不包含日志分片。完整运维备份必须同时包含配置库和所有日志分片;迁移后旧版本不能从新分片读取日志,回退必须恢复迁移前的完整数据目录,不能只回退程序。现有归档文件不会被轮转覆盖。

验证状态:日志拆分已有运行时代码。用户运行前端构建时,vue-tsc 在 OpsPanel.vue 的日志大小边界计算处报告可选值参与除法的类型错误;该处已改为显式存在性分支。静态审查还补充了仅剩 pending 标记时的重启恢复用例,修正事件旧表断言遗漏的查询错误检查,并将便携密钥迁移测试名称调整为其实际覆盖范围。修复后按用户要求未重跑类型检查、构建或测试,未启动服务,也未执行真实数据库迁移;当前仅完成实现源码与文档的一致性静态审查及 git diff --check。主代理此前已只读列出 data 下相关文件,本轮没有修改真实数据。

LinkPort 非 Go 项目名称收口(2026-09-29)

原因与结果:项目名称、命令目录、构建注入路径、图标路径和测试记录仍有旧名称残留,可能使构建脚本引用错误入口,也会让当前文档与产品名称不一致。本次将 scripts/**、deploy/**、根目录 README 和 docs/** 中的当前产品、命令及环境变量名称统一为 linkport、LinkPort 和 LINKPORT。

范围与兼容:只调整非 Go 文本和脚本中的项目名称引用,不修改 web/**、go.mod、任何 Go 源码、真实数据、历史备份、二进制或第三方产物。脚本现在引用 ./cmd/linkport 与 linkport/internal/buildinfo,文档引用 web/public/linkport.svg;这些路径需要与其他协作者负责的命令目录、模块路径和前端资产重命名一同落地,单独使用本批脚本会在对应文件尚未重命名时失败。配置和数据格式不受影响。

验证状态:按用户要求未运行构建、测试或服务。仅使用只读文本搜索复核指定范围,三种大小写形式均无残留;未读取或修改真实 data。

MongoDB 免认证连接心跳 EOF 修复(2026-09-30)

原因:免认证连接没有 SCRAM 完成步骤,连接建立时的 15 秒写截止时间未清除,后续 hello 响应写入超时导致驱动监控线程收到 EOF。

行为与范围:进入免认证会话时清除双向握手截止时间,随后仍按配置应用读取空闲超时。仅影响 MongoDB 网关免认证路径,不改变读写权限、SCRAM 校验或上游认证。无配置/数据迁移;新程序部署后需重新建立连接。详见 internal/protocol/mongoproxy/README.md。

验证:Go 1.25.0 下 MongoDB 包测试通过(18.604 秒),新增本地协议 fixture 在同一连接等待 16 秒后验证 hello 和 ping;不涉及真实 MongoDB、Java 驱动或业务写入。go vet -p=2 ./... 通过,git diff --check 通过。缓存及临时目录改为工作区内后,全量 go test ./... -count=1 -timeout=120s 中 MongoDB 与其他协议包通过;cmd/linkport、desktop、security、store 的文件权限测试及 API SQLite 快照测试失败,具体见 artifacts/mongo-deadline/tests.log。npm.cmd --prefix web run build 的类型检查完成,但 Vite/esbuild 报 spawn EPERM,因此未生成新前端产物,也未运行依赖新构建程序的 Playwright 套件。未部署、重启服务或修改真实数据。

MySQL 批量写入大小限制解除(2026-09-30)

原因:用户要求解除大批量 INSERT 触发 unsafe_sql 的大小限制。移除 CheckWriteSafety 的 1 MiB SQL 文本和 10,000 AST 节点上限;普通命令及二进制预处理均适用。保留其他安全规则、只读控制、协议及上游数据库限制。大请求的解析资源消耗随输入增长;无配置/数据迁移,部署新程序后生效。未执行真实业务写入。详见 docs/mysql-write-safety.md。

验证:Go 1.25.0 下 MySQL 包测试通过,覆盖超过 1 MiB 的 INSERT、12,001 行字面量/占位符 INSERT,同时检查只读拒绝以及后续无 WHERE DELETE 仍被拒绝。go vet -p=2 ./... 和 git diff --check 通过。全量测试 MySQL、MongoDB 包通过;仍有 Windows 文件权限/SQLite 快照失败,另有 pgproxy/TestPreparedRejectsDifferentIdentity/account 失败,日志 artifacts/mongo-deadline/mysql-limits-tests.log。测试为本地解析器及协议 fixture,未连接真实数据库。沿用本会话前端构建 spawn EPERM 的验证限制,未生成新前端产物或运行 Playwright;未部署或改动真实数据。

左侧菜单顺序优化(2026-09-30)

原因:菜单入口此前按功能加入顺序排列,概览、资源、审计和配置工具交错,增加了重复进入常用页面时的寻找成本。

结果:菜单固定为“运行概览 → 目标与网关 → 连线与资产 → 审计监控 → 配置工具”的顺序。菜单搜索沿用该顺序返回结果,入口 ID、权限、筛选和页面导航行为不变。

范围与兼容:仅调整前端展示顺序,无数据、接口或持久化格式变化;无需迁移。

验证:完成静态源码检查与 git diff --check;未启动服务,也未连接真实目标。

页面列表显示排序统一(2026-09-30)

原因:资产、代理及部分选择器直接使用接口返回顺序,同一批数据在不同页面的显示顺序可能变化,名称相近时不易查找。

结果:资产、代理、资产引用、监控目标与账号、资产选择器均按名称排序,并以 ID 作为同名稳定次序;筛选结果也遵循相同规则。协议、模式等固定业务选项继续保持产品定义顺序。

范围与兼容:仅调整前端展示顺序,不改变选中值、接口请求、权限或存储格式,无需迁移。

验证:npm.cmd --prefix web run build 通过,git diff --check 通过;未连接真实目标或修改真实数据。

双引号 INSERT 原样安全放行及 Go 工具链升级(2026-10-02)

原因:用户的导入 SQL 使用双引号引用库、表、列,不能修改原文;现有 Vitess 默认解析与固定上游 SQL 模式均不支持这些标识符,返回 unsafe_sql。用户同时要求升级旧的 Go 1.25 指定版本。

结果:安全读写模式增加 TiDB ANSI_QUOTES 完整解析的单条 INSERT VALUES 兼容路径,仅接纳字面量和占位符数据,转发前临时启用相同 SQL 模式,处理响应后恢复。原始 SQL/JSON/审计文本保持不变,切换不覆盖字符集和结果编码;上游 SQL 错误仍转发,模式设置失败关闭连接。只读、无 WHERE 更新删除、写入批次、动态 SQL及特殊注释控制保留。范围包括普通 SQL 与二进制预处理准备;详细兼容边界见 MySQL 安全写入。

范围与兼容:仅新增 MySQL INSERT 解析路径及上游临时模式切换,补齐现有 TiDB 解析器需要的 failpoint 间接依赖。Go 最低版本和当前协作/构建/测试说明统一为 1.27.1,构建脚本指定同一版本,保留历史验证记录中的实际版本。原 INSERT 的协议响应保留,但临时模式 SET 会影响后续单独查询的会话诊断信息,具体限制见功能文档。无数据库迁移,需使用新程序并重新连接;未部署或修改真实 data,也未执行真实业务 SQL。

实际验证:Go 1.27.1 下 MySQL 包全部测试通过,覆盖超过 1 MiB、12,001 行、JSON/转义字符串、原文转发与审计、普通/预处理、上游 SQL 错误后的模式恢复、启用/恢复失败关闭连接、只读拒绝、控制字节与附加危险请求不转发。测试使用本机协议 fixture,没有连接真实 MySQL。前端生产构建及 artifacts/ansi-insert/linkport.exe 新嵌入程序构建通过;Go 发现脚本 12 项断言通过。前端构建提示 Node 22.10.0 低于推荐的 22.12+,仍构建成功,并保留原有 chunk 体积提示;已恢复 web/dist/.gitkeep。

后端全量 go test ./... -count=1 -timeout=120s 未通过,串行 go test -p=1 ./... -count=1 -timeout=120s 复现相同业务失败:API 的 TestWebDAVSyncSettingsAndAuthorization(口令未保留);cluster 的 TestMySQLReplicationAndGroupDiscovery(fixture RSA 认证 nil panic);desktop 的路径解析和无效目录相关用例;syncjob 的 TestTwoDeviceSyncConflictsAndDeletion 与 TestWebDAVIndependentEncryptedBackupsDoNotChangeSyncBaseline(明文秘密断言)。MySQL 及其他协议包全部通过。并发 vet/测试首次遇到 Windows 子进程 Access denied/exit status 9;go vet -p=1 ./... 通过。不将全量后端记为通过。使用上述新程序及隔离数据库/28181、28182 端口执行完整 Playwright,在用户追加模式要求时停止,已运行 73/139 项并包含页面失败,不记为全套通过。

MySQL 只读、读写、全放行模式选择(2026-10-02)

原因:用户要求把三种策略明确拆成可选择的模式;原界面网关级仅有只读开关,第三种模式只在账号权限内提供,名称也不够明确。

结果与范围:MySQL 网关默认策略提供只读、读写、全放行三选一;账号权限提供相同选项及“继承网关”。网关与账号列表统一使用新名称。新建 MySQL 账号默认继承,已有账号显式策略不改变;网关只读仍优先于全部账号。策略使用现有 readonly/readwrite/unrestricted 值,无存储迁移。读写保留 WHERE 与解析保护以及双引号 INSERT 兼容,全放行跳过 SQL 策略但保留认证、来源限制、审计和协议检查。MongoDB 继续使用只读开关且不提供全放行。模式选项放在独立 GatewayAccessMode 组件,App.vue 只协调草稿。详见 MySQL 账号模式。

验证:Go 1.27.1 model/mysqlproxy/API 模式与写入安全专项通过,新增 API 回读覆盖三种网关默认策略及账号继承;前端模式和草稿 11 项 Node 测试通过。前端生产构建与新嵌入程序构建通过,go vet -p=1 ./... 通过,恢复 web/dist/.gitkeep。新程序运行 MySQL 模式 Playwright 专项通过,覆盖账号三种选择、继承显示、保存重开、320px 无横向溢出及网关只读优先;浏览器首次发现继承空字符串被 Element Plus 当作占位符,改为界面专用 inherit 值、保存映射回空值后通过。此前完整 Playwright 在用户追加模式要求时停止,已运行 73/139 项且包含页面断言/超时失败,未记为全套通过。协议和浏览器均使用 fixture 或隔离测试配置,不连接真实目标、不部署真实服务。

主题快捷切换(2026-10-02)

原因与结果:用户要求增加主题切换。现有四种主题下拉保留,登录页和工作区工具栏增加太阳/月亮一键切换按钮;跟随系统时按当前实际主题决定切换方向。继续复用原偏好存储键,刷新保留选择;仅改变主题状态和控件,无后端接口、数据或配置迁移。范围为 theme.ts 和 ThemePicker.vue,详见 UI 设计说明。

实际验证:前端生产构建通过,恢复 web/dist/.gitkeep;Go 1.27.1 构建新的 artifacts/ansi-insert/linkport.exe 后以 LINKPORT_E2E_BINARY 运行 theme-switch.spec.ts、dbx-ui.spec.ts、mysql-access-modes.spec.ts,5/5 通过。覆盖全部菜单的四种主题、登录页与工作区偏好一致性、系统主题变化、一键切换与刷新保留,以及 1440/390/320px 按钮可见和无横向溢出,输出相应截图。使用隔离临时数据库和 28181/28182 端口,未替换真实服务。git diff --check 通过。全套回归和后端失败沿用上方实际记录,不因专项通过而宣称全套通过。