Prhub

#43942 [Rust Frontend] Add /server_info to Rust frontend

原始 PR 作者 Xunzhuo 合并时间 2026-06-03 19:30 文件变更 11 提交数 10 评论 12 代码增减 +274 / -15

执行摘要

为 Rust 前端添加 /server_info 端点

PR 正文指出:'Adds /server_info to the Rust HTTP frontend alongside the existing /version route. The endpoint follows the Python frontend's top-level response shape with vllm_config, vllm_env, and system_env.' 目的是在 Rust 前端提供与 Python 前端一致的调试与监控信息接口。

该 PR 设计良好,实现了与 Python 前端一致的功能,并考虑了安全防护(dev_mode 门控、敏感过滤)。实现结构清晰,适合作为 Rust 前端新增功能的参考。建议开发者关注其中状态集成和序列化简化的技巧。

讨论亮点
  • Copilot 评论建议将端点限制在 dev_mode,开发者已采纳并提交 'Gate server info route behind dev mode'。
  • Copilot 和 depthfirst-app 评论指出 denylist 不足以防止敏感环境变量泄漏,建议使用 allowlist。PR 最终保留了 denylist 方式,但添加了常见敏感词模式(KEY、SECRET、TOKEN 等)。
  • BugenZhao 建议将构造逻辑分离到独立模块,并建议使用 Serialize 派生代替手动序列化,最终由 BugenZhao 提交简化 commit。

实现拆解

  1. 新增 server_info.rs 模块,定义 ServerInfoSnapshot 结构和 render_config_textcollect_vllm_envcollect_system_env 等核心函数。ServerInfoSnapshot::from_configConfig 快照构造,包含文本和 JSON 两种格式的配置表示。
  2. routes/server_info.rs 中新增路由处理函数 server_info,解析可选的 config_format 查询参数(默认 Text),通过 State 获取 AppState 中的快照并响应。
  3. 修改 state.rsAppState 中添加 server_info 字段(Option<ServerInfoSnapshot>)和 with_server_info 构建方法,以及 server_info_response 查询方法;修改 config.rsengine-core-client/src/client.rs 为相关结构体添加 Serialize 派生,以简化 JSON 序列化。
  4. tests.rs 中添加两个集成测试:验证在 dev_mode 未启用时返回 404,以及在 dev_mode 启用但未设置快照时也返回 404(边界情况)。
文件 模块 状态 重要度
rust/src/server/src/server_info.rs 服务器信息 added 9.0
rust/src/server/src/routes/server_info.rs 信息路由 added 8.5
rust/src/server/src/routes/tests.rs 集成测试 modified 7.36
rust/src/server/src/state.rs 共享状态 modified 6.21

关键符号

render_config_text render_config_text_value collect_vllm_env is_public_vllm_env_key collect_system_env ServerInfoSnapshot::from_config ServerInfoSnapshot::response server_info (route handler) with_server_info server_info_response

关键源码片段

rust/src/server/src/server_info.rs core-logic

核心模块,定义了 ServerInfoSnapshot 结构和所有收集 / 渲染函数,是新增端点的数据支撑。

use std::collections::BTreeMap;
use serde_json::{Value, json};
use crate::config::Config;// 敏感环境变量 key 的通用模式(大小写不敏感)
const SENSITIVE_VLLM_ENV_PATTERNS: &[&str] =
    &["KEY", "SECRET", "TOKEN", "PASSWORD", "CREDENTIAL", "AUTH"];/// 输出格式:文本或 JSON
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ServerInfoConfigFormat {
    Text,
    Json,
}/// `/server_info` 返回的快照
#[derive(Debug, Clone)]
pub(crate) struct ServerInfoSnapshot {
    vllm_config_text: String,
    vllm_config_json: Value,
    vllm_env: BTreeMap<String, String>,
    system_env: BTreeMap<String, String>,
}impl ServerInfoSnapshot {
    /// 从配置构造快照
    pub(crate) fn from_config(config: &Config) -> Self {
        let vllm_config_json =
            serde_json::to_value(config).expect("server info value must serialize");
        Self {
            vllm_config_text: render_config_text(&vllm_config_json),
            vllm_config_json,
            vllm_env: collect_vllm_env(),
            system_env: collect_system_env(),
        }
    }    /// 按格式返回响应体
    pub(crate) fn response(&self, config_format: ServerInfoConfigFormat) -> Value {
        let vllm_config = match config_format {
            ServerInfoConfigFormat::Text => Value::String(self.vllm_config_text.clone()),
            ServerInfoConfigFormat::Json => self.vllm_config_json.clone(),
        };
        json!({ "vllm_config": vllm_config, "vllm_env": self.vllm_env.clone(), "system_env": self.system_env.clone() })
    }
}/// 将配置值渲染为文本行(key=value)
fn render_config_text(config: &Value) -> String {
    match config {
        Value::Object(fields) => fields
            .iter()
            .map(|(key, value)| format!("{key}={}", render_config_text_value(value)))
            .collect::<Vec<_>>()
            .join("\n"),
        _ => render_config_text_value(config),
    }
}/// 将单个值渲染为文本
fn render_config_text_value(value: &Value) -> String {
    match value {
        Value::Null => "None".to_string(),
        Value::String(value) => value.clone(),
        _ => value.to_string(),
    }
}/// 收集所有公开的 VLLM 环境变量(排除敏感 key)
fn collect_vllm_env() -> BTreeMap<String, String> {
    std::env::vars().filter(|(key, _)| is_public_vllm_env_key(key)).collect()
}/// 判断是否为公开的环境变量 key:以 `VLLM_` 开头且不包含敏感模式
fn is_public_vllm_env_key(key: &str) -> bool {
    let key = key.to_ascii_uppercase();
    key.starts_with("VLLM_") && !SENSITIVE_VLLM_ENV_PATTERNS.iter().any(|p| key.contains(p))
}/// 收集静态系统环境信息
fn collect_system_env() -> BTreeMap<String, String> {
    BTreeMap::from([
        ("arch".to_string(), std::env::consts::ARCH.to_string()),
        ("family".to_string(), std::env::consts::FAMILY.to_string()),
        ("os".to_string(), std::env::consts::OS.to_string()),
    ])
}
rust/src/server/src/routes/server_info.rs entrypoint

新增路由处理文件,定义端点入口、查询参数解析和格式转换。

use std::sync::Arc;
use axum::Json;
use axum::extract::{Query, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::Deserialize;
use crate::server_info::ServerInfoConfigFormat;
use crate::state::AppState;/// 查询参数中可用的格式
#[derive(Debug, Clone, Copy, Deserialize)]
#[serde(rename_all = "lowercase")]
enum ConfigFormat {
    Text,
    Json,
}/// 将查询格式转换为内部格式
impl From<ConfigFormat> for ServerInfoConfigFormat {
    fn from(value: ConfigFormat) -> Self {
        match value {
            ConfigFormat::Text => Self::Text,
            ConfigFormat::Json => Self::Json,
        }
    }
}/// 默认格式为 Text
fn default_config_format() -> ConfigFormat {
    ConfigFormat::Text
}/// 查询参数结构
#[derive(Debug, Deserialize)]
pub(crate) struct ServerInfoParams {
    #[serde(default = "default_config_format")]
    config_format: ConfigFormat,
}/// 处理 `/server_info` 请求
pub async fn server_info(
    State(state): State<Arc<AppState>>,
    Query(params): Query<ServerInfoParams>,
) -> Response {
    match state.server_info_response(params.config_format.into()) {
        Some(response) => Json(response).into_response(),
        None => StatusCode::NOT_FOUND.into_response(),
    }
}

评论区精华

端点安全门控 安全

Copilot 评论建议将端点限制在 dev_mode,否则可能泄露环境 / 配置信息。

结论:开发者采纳建议,添加 dev_mode 门控,仅在 dev_mode 启用时注册路由。 · 已解决

环境变量过滤方式 安全

Copilot 和 depthfirst-app 机器人指出 denylist 模式可能遗漏敏感变量(如 VLLM_TOKEN),建议改用 allowlist 或更严格的过滤。

结论:PR 保留了 denylist,但扩大了敏感模式列表(KEY、SECRET、TOKEN、PASSWORD、CREDENTIAL、AUTH),且端点仅在 dev_mode 有效,降低风险。 · addressed

简化序列化实现 设计

BugenZhao 建议使用 `Serialize` 派生代替手动格式转换,简化代码。

结论:由 BugenZhao 在最终提交中实现,为 Config、TransportMode 等结构添加 Serialize 派生。 · 已解决

风险与影响

  • 环境变量泄漏:虽然使用了 denylist 过滤敏感模式,但仍有遗漏可能(如自定义变量不匹配模式)。由于端点仅在 dev_mode 启用,风险降低,但 dev_mode 下仍可能暴露敏感信息。
  • 端点仅在 dev_mode 启用,但 dev_mode 下的访问控制依赖于部署配置,若错误启用 dev_mode 则可能公开信息。
  • 新端点不影响现有路由,无回归风险。
  • 用户:新增 /server_info 端点,可用于调试和监控,默认关闭(dev_mode 需要显式启用)。
  • 系统:轻微性能影响,每次请求从内存中读取已缓存的快照,无额外计算开销。
  • 团队:增强了 Rust 前端的自描述能力,与 Python 前端功能对齐,便于统一运维接口。
端点仅在 dev_mode 可用 依赖 denylist 过滤敏感 env 无身份验证

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论