From 2f6f8e549da244ea323d2fd03c0ae2c21cbdaa23 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 9 Jul 2026 11:02:04 +0800 Subject: [PATCH] refactor(code-runner): default CODE_RUNNER_LANGUAGES to all-open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CODE_RUNNER_LANGUAGES 未设置时,白名单不再默认为 python,node, 而是放行 LANGUAGES 注册表里的全部语言。该环境变量变为「可选的收窄开关」: 新增语言到注册表即可默认启用,无需再同步运维白名单(避免两边脱节, 如本次 go/rust 就因 .env 未同步白名单导致 is_supported_lang 拒绝)。 - RunnerConfig.languages: Vec → Option>, None 表示不限制 - is_supported_lang: Option 为 None 时直接放行注册表语言 - 测试 is_supported_lang_default_whitelist → is_supported_lang_default_all_open, 断言 go/rust 在默认(未设白名单)下可用 --- .env.example | 3 ++- AGENTS.md | 2 +- src/api/code_runner/languages.rs | 27 ++++++++++++++++++--------- src/infra/runner_config.rs | 13 +++++++++---- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.env.example b/.env.example index bfd3c58..7657b07 100644 --- a/.env.example +++ b/.env.example @@ -140,7 +140,8 @@ CODE_RUNNER_MAX_CPU_CORES=2.0 CODE_RUNNER_MAX_MEMORY_MB=1024 CODE_RUNNER_MAX_TIMEOUT_SECS=30 CODE_RUNNER_MAX_OUTPUT_BYTES=1048576 -CODE_RUNNER_LANGUAGES=python,node,go,rust +# 默认全开:注册表里的语言均可用。设置则收窄到逗号分隔列表(如 python,node)。 +# CODE_RUNNER_LANGUAGES=python,node DOCKER_SOCKET_PATH=/var/run/docker.sock # Rate limits (governor keyed limiters) diff --git a/AGENTS.md b/AGENTS.md index 755148a..a6e61ae 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -97,7 +97,7 @@ CODE_RUNNER_MAX_OUTPUT_BYTES=1048576 # hard cap on stdout+stderr captured CODE_RUNNER_MAX_SOURCE_BYTES=65536 # max source size accepted by StartExec CODE_RUNNER_QUEUE_TIMEOUT_SECS=30 # how long a task waits for a container slot before failing CODE_RUNNER_TASK_TTL_SECS=300 # DashMap task entry lifetime (gc_old_tasks) -CODE_RUNNER_LANGUAGES=python,node # ops whitelist (must also exist in LANGUAGES registry) +CODE_RUNNER_LANGUAGES= # unset = all registered langs; set a comma-list to narrow (e.g. python,node) DOCKER_SOCKET_PATH=/var/run/docker.sock ``` diff --git a/src/api/code_runner/languages.rs b/src/api/code_runner/languages.rs index 9cc3172..72d82e0 100644 --- a/src/api/code_runner/languages.rs +++ b/src/api/code_runner/languages.rs @@ -4,8 +4,8 @@ //! [`parse_fence_info`] 解析 markdown 围栏代码块的信息串,识别 `runnable` 标记与 //! 可选的 JSON 资源覆盖(如 `python runnable {"timeout_secs":10}`)。 //! -//! 实际可用语言还受 `RUNNER_CONFIG.languages`(环境变量 `CODE_RUNNER_LANGUAGES`)双重约束: -//! 既要在注册表中存在,也要在运维白名单中启用,才视为支持([`is_supported_lang`])。 +//! 实际可用语言默认即注册表里的全部;若设置了 `CODE_RUNNER_LANGUAGES` +//! 环境变量,则进一步收窄到该白名单内([`is_supported_lang`])。 use std::collections::HashMap; use std::sync::LazyLock; @@ -24,8 +24,8 @@ pub struct LanguageDef { pub allow_network: bool, } -/// 内置语言注册表。新增语言时在此 `insert`,并在 `.env.example` / `CODE_RUNNER_LANGUAGES` -/// 中默认启用。 +/// 内置语言注册表。新增语言时在此 `insert` 即可默认启用; +/// 若运维需要收窄,设置 `CODE_RUNNER_LANGUAGES` 为逗号分隔列表。 pub static LANGUAGES: LazyLock> = LazyLock::new(|| { let mut m = HashMap::new(); @@ -106,10 +106,16 @@ pub static LANGUAGES: LazyLock> = LazyLock::new(|| m }); -/// 同时存在于注册表与运维白名单 (`RUNNER_CONFIG.languages`) 才视为支持。 +/// 是否支持该语言:必须在 LANGUAGES 注册表中存在。 +/// 若设置了 `CODE_RUNNER_LANGUAGES`,还需同时在该白名单内(用于收窄可用语言); +/// 未设置则注册表里的语言全部放行。 pub fn is_supported_lang(lang: &str) -> bool { let clean = lang.trim().to_lowercase(); - RUNNER_CONFIG.languages.iter().any(|l| l == &clean) && LANGUAGES.contains_key(&clean) + LANGUAGES.contains_key(&clean) + && RUNNER_CONFIG + .languages + .as_ref() + .is_none_or(|list| list.iter().any(|l| l == &clean)) } /// 解析围栏代码块的 info string。 @@ -202,11 +208,14 @@ mod tests { } #[test] - fn is_supported_lang_default_whitelist() { - // 默认 CODE_RUNNER_LANGUAGES=python,node + fn is_supported_lang_default_all_open() { + // 默认未设 CODE_RUNNER_LANGUAGES:注册表里的语言全部放行。 assert!(is_supported_lang("python")); assert!(is_supported_lang("node")); - assert!(!is_supported_lang("rust")); + assert!(is_supported_lang("go")); + assert!(is_supported_lang("rust")); + // 未注册的语言仍不支持。 + assert!(!is_supported_lang("ruby")); assert!(!is_supported_lang("")); } diff --git a/src/infra/runner_config.rs b/src/infra/runner_config.rs index ca27417..26fedd9 100644 --- a/src/infra/runner_config.rs +++ b/src/infra/runner_config.rs @@ -25,7 +25,9 @@ pub struct RunnerConfig { pub queue_timeout_secs: u64, pub task_ttl_secs: u64, pub docker_socket_path: String, - pub languages: Vec, + /// 语言白名单。`None` 表示不限制——注册表里的所有语言均视为支持; + /// `Some(list)` 表示收窄到列表内(仍须同时在 LANGUAGES 注册表存在)。 + pub languages: Option>, } #[cfg(feature = "server")] @@ -36,8 +38,11 @@ fn parse_allow_network(v: &str) -> bool { #[cfg(feature = "server")] pub static RUNNER_CONFIG: LazyLock = LazyLock::new(|| { - let languages_str = env::var("CODE_RUNNER_LANGUAGES").unwrap_or_else(|_| "python,node".to_string()); - let languages = languages_str.split(',').map(|s| s.trim().to_lowercase()).collect(); + // CODE_RUNNER_LANGUAGES 未设置时默认全开(None):注册表里的语言均可用, + // 新增语言无需同步白名单。设置为逗号分隔列表则收窄到这些语言。 + let languages = env::var("CODE_RUNNER_LANGUAGES").ok().map(|s| { + s.split(',').map(|t| t.trim().to_lowercase()).filter(|t| !t.is_empty()).collect() + }); RunnerConfig { max_cpu_cores: env::var("CODE_RUNNER_MAX_CPU_CORES").ok().and_then(|v| v.parse().ok()).unwrap_or(2.0), @@ -118,7 +123,7 @@ mod tests { queue_timeout_secs: 1, task_ttl_secs: 1, docker_socket_path: "".to_string(), - languages: vec![], + languages: None, }; let raw = ResourceLimits { cpu_cores: 1.0,