Skip to content

feat(ostool): enable rustls native TLS roots for tokio-tungstenite - #161

Merged
ZR233 merged 6 commits into
mainfrom
fix/ostool-boardconnect-wss
Jul 31, 2026
Merged

feat(ostool): enable rustls native TLS roots for tokio-tungstenite#161
ZR233 merged 6 commits into
mainfrom
fix/ostool-boardconnect-wss

Conversation

@ZCShou

@ZCShou ZCShou commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

PR: 修复 WSS TLS 支持、统一 HTTP 传输并完善后端 API 文档

概述

本 PR 修复 ostool board connect 无法通过 wss:// 连接串口 WebSocket 的问题,将 OVMF 下载从 ureq 迁移到异步 reqwest,使 HTTP 与 WebSocket 传输复用同一套 rustls 0.23 + AWS-LC TLS 实现。同时补全 docs/api.md,使其覆盖认证后端、本地 ostool-server、Management API、Board REST API 和串口 WebSocket API 的完整契约。

背景与问题

main 分支中的 tokio-tungstenite 没有启用 TLS 特性,因此串口地址为 wss:// 时会直接失败并报告 TLS support not compiled in

与此同时,项目使用两套 HTTP 客户端:OAuth、Board REST API 和 Cargo 配置下载使用 reqwest,OVMF 镜像探测及下载使用同步 ureq。两套客户端带来重复的 HTTP/TLS 依赖,并可能通过 Cargo feature 合并为 Rustls 同时启用不同密码学 Provider,导致 Rustls 无法自动选择进程级 Provider。

reqwestureqtokio-tungstenite 本身是不同用途的传输组件:前两者处理 HTTP,后者处理 WebSocket。组件数量本身不会导致冲突,真正的问题是它们可以分别为同一个 rustls 0.23 依赖选择不同的密码学 Provider。reqwest 的标准 Rustls 配置使用 AWS-LC,而 ureq 的 Rustls 配置会引入 Ring;为 tokio-tungstenite 增加 WSS 支持后,它也会进入同一个 Rustls 依赖图。

Cargo 会对同一版本 crate 的 feature 取并集,而不会为每个上层组件分别构建一份相互隔离的 Rustls。因此,只要一条依赖路径启用 aws-lc-rs,另一条路径启用 ring,最终进程中的同一个 rustls crate 就会同时包含两种 Provider feature。

Rustls 0.23 只有在恰好启用一种 Provider feature 时才能自动确定进程级默认 Provider。两种 feature 同时启用时,Rustls 无法判断应该使用 Ring 还是 AWS-LC,会出现 Could not automatically determine the process-level CryptoProvider;如果上层组件使用 no-provider 模式但进程启动阶段没有显式安装默认 Provider,则会出现 No rustls crypto provider is configured。Provider 是进程级全局状态,依赖某个调用点提前执行 install_default() 会引入初始化顺序要求,并且 workspace 测试的 feature 组合发生变化时仍可能再次失败,因此不适合作为最终架构。

证书根与密码学 Provider 是两个独立概念:rustls-tls-native-roots 决定 WSS 使用哪些系统 CA 验证服务端证书,AWS-LC 或 Ring 则负责握手、签名和加解密算法。启用系统证书根只能解决证书信任问题,不能解决 Provider 冲突。本 PR 因此同时完成两项收敛:为 tokio-tungstenite 启用系统原生证书根,并删除 ureq/Ring 路径,使所有 TLS 使用同一个 rustls 0.23 + AWS-LC Provider。

现有 API 文档也只重点覆盖 OAuth Device Authorization 和 Board REST API,没有完整记录 ostool-server 已提供的 Management API、管理入口的安全边界、串口 WebSocket 生命周期和部分现有响应字段。

主要修改

1. 修复串口 WSS 连接

  • tokio-tungstenite 0.28 启用 rustls-tls-native-roots
  • ws:// 继续使用明文 WebSocket,wss:// 使用 Rustls 和系统原生 CA 根证书。
  • 没有增加跳过证书验证或接受无效证书的兼容路径;私有 CA 和自签名证书仍必须正确安装到系统信任库。
  • 新增回归测试,实际发起 wss:// 连接并确认失败原因不再是 TLS support not compiled in

2. 统一 HTTP/TLS 依赖

  • reqwest 改为关闭默认特性并显式启用 charsetformhttp2jsonrustlssystem-proxy
  • 使用 reqwest 的标准 rustls 特性选择 AWS-LC Provider。
  • 删除 ureq 依赖及其传输错误类型。
  • reqwesttokio-tungstenite 现在复用同一个 Rustls 版本和 AWS-LC Provider。
  • 保留 tokio-tungstenite,因为 reqwest 只处理普通 HTTP 请求,不提供 WebSocket 协议升级后的双向帧通信。

最终职责如下:

场景 组件
OAuth Device Authorization reqwest
Board REST API reqwest
Cargo 配置下载 reqwest
OVMF 镜像探测和下载 reqwest
串口 WebSocket tokio-tungstenite
TLS 和密码学 Provider rustls 0.23 + AWS-LC

3. 将 OVMF 下载迁移到异步 reqwest

  • 镜像 Range 探测和完整下载全部改为异步 reqwest,不再在 Tokio 运行时中执行阻塞式 HTTP I/O。
  • 复用 reqwest::Client,分别配置探测和完整下载的连接、响应、读取及总超时。
  • 对非成功 HTTP 状态统一调用 error_for_status(),避免将 4xx/5xx 响应误当作镜像内容。
  • 根据 Content-Length 提前拒绝超过 10 MiB 的响应,并在流式读取过程中再次执行大小限制。
  • 保留以下原有行为:
    • 对所有镜像进行测速并按吞吐量排序;
    • 首选镜像失败后自动回退到后续镜像;
    • 显示下载进度;
    • 验证压缩包 SHA-256 后再解压;
    • 所有镜像失败时汇总每次失败原因;
    • 在获得并验证新镜像前不删除现有缓存。
  • Prebuilt::fetch 改为异步函数,并在 QEMU UEFI 准备流程中使用 .await

4. 消除 ostool-server 测试中的重复 HTTP 客户端

  • 删除 ostool-serverreqwest dev-dependency,避免 workspace 测试构建时因依赖 feature 合并而引入额外 TLS 初始化要求。
  • WebSocket 生命周期测试仍通过真实 TCP listener 测试 WebSocket 握手、串口数据、关闭和异常断开流程。
  • 会话创建和释放断言改为通过 tower::ServiceExt::oneshot 直接调用 Axum Router
  • 服务就绪检查改为 TCP 连接探测,因此这些局域网服务测试不再依赖额外的 HTTP/TLS 客户端。

5. 完善 docs/api.md

文档标题和开头说明改为描述两类独立后端:

  • 本地局域网模式使用 auth_mode = "disabled",CLI 直接连接 ostool-serverostool-server 提供 Board REST、串口 WebSocket、Management API 和管理后台,但不提供登录认证。
  • 认证模式使用 auth_mode = "required",CLI 连接独立认证后端;该后端提供 OAuth Device Authorization,并按相同契约提供受认证的 Board REST 和串口 WebSocket 服务。

新增或补充的 API 文档包括:

  • Management API 接口索引及安全警告;当前 ostool-server 没有为 /admin/api/v1/admin/... 安装认证、授权或 CSRF 中间件,部署时必须使用可信内网、防火墙或带认证的反向代理保护。
  • 管理概览:开发板、会话、TFTP 和服务器状态。
  • 开发板管理:创建、读取、更新、重命名、删除、配置约束、电源状态和租约状态。
  • 硬件发现:串口稳定标识和网络接口枚举。
  • DTB 管理:上传、读取、重命名、替换、引用同步和删除约束。
  • 活动会话管理:列表、异步释放和 releasing 状态。
  • TFTP 管理:内置 provider、systemd tftpd-hpa provider、状态和 reconcile。
  • 服务器配置管理:只读字段、可编辑网络配置和会话文件上传限制。
  • Board REST API:TFTP provider 名称、http_url、上传大小限制及共享文件行为。
  • 串口 WebSocket API:URL 解析、同源认证限制、握手错误、单连接约束、opened/closed/error/tx/close 控制消息、二进制帧、Ping/Pong 和会话释放流程。
  • REST API 错误结构、常见错误码以及 Axum 在进入业务处理器前可能返回的框架错误。

文档明确区分“CLI 调用的接口”和“仅由本地管理页面使用的接口”,不再暗示单个后端必须实现文档中的全部路由。

破坏性变更

本 PR 不保留旧实现兼容层:

  • Prebuilt::fetch 从同步函数变为异步函数,调用方必须使用 .await
  • 不保留同步 OVMF 下载包装函数。
  • 不保留 ureq 传输实现。
  • OVMF 请求错误的 source 类型从 ureq::Error 改为 reqwest::Error

仓库内 QEMU UEFI 准备流程的调用点已同步更新;直接调用公开 Prebuilt::fetch API 的下游代码需要增加 .await

安全与依赖结果

  • wss:// 使用系统信任根验证服务端证书,不会静默降级到 ws://
  • 认证模式下跨 origin WebSocket 仍会被拒绝,Bearer Token 不会发送到不同源地址。
  • OAuth 和 Board HTTP 客户端仍禁止自动跟随重定向。
  • 有效的 ostool 编译依赖树中不存在 ureq,也不存在启用中的 Ring Provider。
  • reqwesttokio-tungstenite 通过同一个 Rustls 实例使用 AWS-LC。

Cargo.lock 可能仍记录 Ring package,因为 reqwest 的可选 QUIC/Quinn 元数据包含 Ring 依赖;cargo tree -p ostool --target x86_64-unknown-linux-gnu -i ring 没有输出,说明 Ring 不在当前目标的有效依赖树中,不会被编译或注册为第二个 TLS Provider。

测试与验证

以下与 CI 对应的检查已通过:

cargo fmt --all -- --check
cargo clippy --target x86_64-unknown-linux-gnu --all-features
cargo build --target x86_64-unknown-linux-gnu --all-features
cargo test --target x86_64-unknown-linux-gnu -- --nocapture

验证结果包括:

  • ostool 253 个单元测试通过。
  • ostool-server 101 个单元测试通过。
  • ostool-server/tests/session_ws_lifecycle.rs 中 3 个 WebSocket 生命周期测试全部通过。
  • 所有 workspace 集成测试和文档测试通过。
  • WSS TLS 回归测试通过。
  • OVMF 镜像排序、失败回退、缓存保护和聚合错误测试通过。
  • cargo tree 确认 AWS-LC 是当前目标有效依赖树中的唯一 Rustls Provider。

cargo publish --workspace --dry-run --locked --allow-dirty 已成功打包 fitimagehttpboot-protocoljkconfiguboot-shellostool,在准备 ostool-server 时因 crates.io 返回 HTTP/2 framing error 中断。该失败发生在依赖下载阶段,与本 PR 的代码或打包内容无关。

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本 PR 仅为 ostooltokio-tungstenite 0.28 启用 rustls-tls-native-roots,并同步更新锁文件,使现有 board 串口 WebSocket 调用可通过系统原生根证书校验 wss:// 服务端证书。该变更影响共享的串口终端、U-Boot 与 HTTP boot 的 WebSocket 连接路径;未改动调用接口、协议或服务器端实现,影响范围看起来隔离且与现有 wss:// 配置支持一致。

验证:已用审查辅助脚本确认工作区 HEAD 为 e903c374558dc0c30f4a699f4f725a1f5df4fd39、基线为 origin/maingit diff --check 通过,且依赖锁定内容与所启用 feature 一致。GitHub 上该 HEAD 的两次 check (stable, x86_64-unknown-linux-gnu) 均为成功;检查注释中的 target/tests 目录缺失信息未使检查失败,且与本次两处依赖配置改动无直接关联。本地环境未安装 cargo,因此无法在此环境重复运行 cargo fmt --check、clippy 和测试。

未发现既有审查或 PR 评论;关键词检索未发现直接重叠的在审 PR。未发现遗留问题、额外风险或测试缺口。

Powered by gpt-5.6-terra

Introduce a centralized http_client module that installs the Ring crypto
provider before constructing any reqwest client, ensuring rustls is
consistently configured across auth, board, and build pipelines. Switch
reqwest and ureq dependencies to rustls-based TLS without the aws-lc-rs
provider, and add the workspace rustls dependency to ostool. Update
docs/api.md to cover the Management API surface.

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本 PR 为 ostool 统一 Rustls provider,并为 tokio-tungstenite 启用原生系统根证书,目标是让 board 串口、U-Boot 与 HTTP Boot 的 wss:// 连接可用。它会影响共享 HTTP 客户端和 WebSocket 传输路径,但未改变 REST/WebSocket 协议或服务端接口。

需要修改

当前 head 的两次 Quality Check 都在 Unit test 阶段以 exit code 101 失败(格式、Clippy 和 Build 已通过;注释还显示测试期间缺少 target/tests/target)。请先在 CI 环境复现并修复该失败,再合并此 TLS/provider 重构;当前无法确认新增安全 WebSocket 路径及其测试实际可用。

验证情况:审查辅助脚本确认工作区为 15e679278c3d78e98d94f019d3bb938d72f8aef1,基线为 origin/maingit diff --check 通过。本地环境未安装 cargo,所以无法在本地重跑 fmt、clippy 或测试。已检查此前审查:其批准针对前一 commit e903c37,不覆盖当前 head;没有既有行级或 PR 评论需要处理。关键词检索未发现重叠的在审 PR。

除上述 CI 阻塞项外,本次审查没有发现额外未解决的实现问题。

Powered by gpt-5.6-terra

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本 PR 在原有 wss:// 支持基础上统一 Rustls provider:ostool 的 reqwest 客户端改由共享构造器创建,并为 tokio-tungstenite 启用原生系统根证书;同时将 server 生命周期集成测试的 REST 部分改为进程内 Axum 路由调用。这样会影响 OAuth、Board REST、配置下载以及串口终端、U-Boot、HTTP Boot 的共享传输路径,但未改变 REST/WebSocket 协议或服务端实现,影响范围与 TLS 初始化目标相符。

审查确认:工作区 HEAD 为 5baf4ce84796cb043720afcbaf26c9aa7f92914b,相对 origin/maingit diff --check 通过;辅助脚本已确认受影响 crate 为 ostoolostool-server,并生成对应 fmt、clippy、测试计划。当前 HEAD 的两项 check (stable, x86_64-unknown-linux-gnu) 均成功。检查注释仍包含 target/tests/target 缺失信息,但未令 CI 失败,且本次提交以进程内路由替代该集成测试中的 reqwest 调用,未见由本 PR 导致的当前 CI 失败。本地环境未安装 cargo,因此无法在此环境复跑 cargo fmt --check、clippy 和测试。

已核对此前审查:前一轮“请求修改”针对旧 HEAD 的单元测试失败;当前成功 CI 及生命周期测试重构表明该阻塞已解除。没有既有行级或 PR 评论待处理;关键词检索未发现直接重叠的在审 PR。未发现遗留问题、额外风险或测试缺口。

Powered by gpt-5.6-terra

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本 PR 修复 wss:// 串口连接的 TLS 根证书支持,并将 OVMF 预构建固件下载从阻塞式 ureq 迁移为异步 reqwest;同时将服务器生命周期测试的 REST 断言改为进程内 Axum Router 调用,并补全后端 API 文档。改动会覆盖 OAuth、Board REST、OVMF 下载及串口 WebSocket 的传输依赖路径,但 REST/WebSocket 协议和服务器实现接口未改变;检查调用点、错误处理、下载大小/超时限制及缓存更新顺序后,影响范围与目标一致,未发现跨功能回归。

验证:审查辅助脚本和 git rev-parse 确认工作区为 c7b4827cedda2c42f7d6de3e44f18c32e8446d57、基线为 origin/maingit diff --check origin/main...HEAD 通过。GitHub 上此 HEAD 的两项 check (stable, x86_64-unknown-linux-gnu) 均成功。检查注释仍报告 target/tests/target 目录缺失,但并未导致 CI 失败,且未见其由本次改动引入。本地环境未安装 cargo/rustc,因此无法在此环境复跑 cargo fmt --check、Clippy 和测试;辅助脚本自身的 7 项测试通过。

已核对既有审查:此前对旧 HEAD 的单元测试失败请求修改是合理的;当前 HEAD 的 CI 已成功,该阻塞已解除。没有既有行级或 PR 评论待处理。关键词与路径检索未发现与本 PR 重叠的其他在审 PR。

未发现遗留问题、额外风险或测试缺口。

Powered by gpt-5.6-terra

@mai-team-app mai-team-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本 PR 为 wss:// 串口连接启用系统原生 TLS 根证书,并将 OVMF 固件镜像探测/下载从阻塞式 ureq 迁移到异步 reqwest;同时收敛 Rustls provider、调整服务器 WebSocket 生命周期测试,并补全文档中的认证、Board 与 Management API 契约。改动影响 OAuth、Board REST、OVMF 下载及串口 WebSocket 等共享传输路径;检查调用点、超时/下载大小限制、镜像回退、哈希校验和缓存更新顺序后,未见协议或既有行为回归,影响范围与目标一致。

验证:审查辅助脚本的 7 项测试通过,并确认工作区 HEAD 为 a04d602f8cffb46fb8446c52a45b7cc3cc46d8ff、基线为 origin/maingit diff --check origin/main...HEAD 通过。GitHub 上该 HEAD 的两项 check (stable, x86_64-unknown-linux-gnu) 均成功,未见由本 PR 导致的 CI 失败。本地环境未安装 cargorustc,因此无法复跑 cargo fmt --check、Clippy 或测试。

已核对既有审查:先前针对旧 HEAD 的单元测试失败请求修改合理;当前 HEAD 的 CI 已成功,且 PR 已加入对应的生命周期与 WSS 回归测试,该阻塞已解除。没有既有行级评论或 PR 评论待处理。关键词及路径检索未发现相关的重叠在审 PR。

未发现遗留问题、额外风险或测试缺口。

Powered by gpt-5.6-terra

@ZR233
ZR233 merged commit 62d6bff into main Jul 31, 2026
2 checks passed
@ZR233
ZR233 deleted the fix/ostool-boardconnect-wss branch July 31, 2026 06:03
@github-actions github-actions Bot mentioned this pull request Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants