57 lines
1.7 KiB
Rust
57 lines
1.7 KiB
Rust
//! 危险命令检测(架构 §4.2)
|
||
//!
|
||
//! 默认禁止 shell 拼接:管道、重定向、`$()`、反引号、`&&` 链、`;`、`\`。
|
||
//! 适配器声明里的所有 `command` argv 都必须在加载期通过本检测,
|
||
//! 否则整条适配器拒载并给出中文错误。
|
||
|
||
/// shell 元字符集合(架构 §4.2;`(` `)` 覆盖 `$()`,反引号覆盖命令替换)
|
||
const SHELL_METACHARS: &[char] = &['|', '&', ';', '$', '\\', '>', '<', '(', ')', '`'];
|
||
|
||
/// 返回第一个命中的 shell 元字符;无则返回 None。
|
||
pub fn first_shell_metachar(s: &str) -> Option<char> {
|
||
s.chars().find(|c| SHELL_METACHARS.contains(c))
|
||
}
|
||
|
||
/// 判断一个字符串是否含 shell 元字符。
|
||
pub fn contains_shell_metachar(s: &str) -> bool {
|
||
first_shell_metachar(s).is_some()
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn detects_common_metachars() {
|
||
for (sample, expected) in [
|
||
("curl | sh", Some('|')),
|
||
("a && b", Some('&')),
|
||
("a; rm -rf /", Some(';')),
|
||
("$(id)", Some('$')),
|
||
("echo `whoami`", Some('`')),
|
||
("ls > out", Some('>')),
|
||
("cat < in", Some('<')),
|
||
("a\\b", Some('\\')),
|
||
("echo (x)", Some('(')),
|
||
("echo )", Some(')')),
|
||
] {
|
||
assert_eq!(first_shell_metachar(sample), expected, "样本 {sample:?}");
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn allows_plain_argv() {
|
||
for sample in [
|
||
"npm",
|
||
"install",
|
||
"-g",
|
||
"@openai/codex",
|
||
"codex",
|
||
"--version",
|
||
"https://example.com/install.ps1",
|
||
] {
|
||
assert!(!contains_shell_metachar(sample), "普通参数 {sample:?} 不应被判危险");
|
||
}
|
||
}
|
||
}
|