diff --git a/docker/Dockerfile.tool-builder b/docker/Dockerfile.tool-builder index 577138d..9b73538 100644 --- a/docker/Dockerfile.tool-builder +++ b/docker/Dockerfile.tool-builder @@ -1,10 +1,13 @@ # ias-tool-builder — tool_manager 编译 Rust 工具的隔离环境 # 预缓存 serde_json(tool_manager 生成工具的唯一依赖),支持 --network none 离线编译。 +# CARGO_HOME=/tmp/cargo 并 chmod 777,使任意 uid(--user 运行)都能复用缓存。 # 运行时由 tool_manager 挂载 tool_dir 到 /work,cargo 在 /work 内编译,产物写回宿主。 FROM rust:1.88-slim +ENV CARGO_HOME=/tmp/cargo RUN cargo new /tmp/seed && cd /tmp/seed \ && printf 'serde_json = "1.0"\n' >> Cargo.toml \ && cargo build --release \ - && rm -rf /tmp/seed + && rm -rf /tmp/seed \ + && chmod -R 777 /tmp/cargo WORKDIR /work ENTRYPOINT [] diff --git a/tools/tool_manager/src/main.rs b/tools/tool_manager/src/main.rs index 2df91c6..6e26360 100644 --- a/tools/tool_manager/src/main.rs +++ b/tools/tool_manager/src/main.rs @@ -126,6 +126,7 @@ fn build_tool(tool_dir: &Path, tool_name: &str) -> Result<(), String> { .ok() .as_deref() == Some("1"); + let (uid, gid) = current_uid_gid(); // 启用 builder 容器时在隔离环境内离线编译,挂载 tool_dir 到 /work,产物写回宿主; // 否则本地 cargo(受 timeout 限制) @@ -138,11 +139,14 @@ fn build_tool(tool_dir: &Path, tool_name: &str) -> Result<(), String> { .arg("--pids-limit").arg("128") .arg("--cap-drop").arg("ALL") .arg("--security-opt").arg("no-new-privileges") + .arg("--user").arg(format!("{}:{}", uid, gid)) .arg("-v").arg(format!("{}:/work", tool_dir.display())) .arg("-w").arg("/work") + .arg("-e").arg("CARGO_NET_OFFLINE=true") + .arg("-e").arg("CARGO_HOME=/tmp/cargo") .arg("ias-tool-builder") .arg("timeout").arg(BUILD_TIMEOUT_SECS.to_string()) - .arg("cargo").arg("build").arg("--release") + .arg("cargo").arg("build").arg("--release").arg("--offline") .output() } else { Command::new("timeout") @@ -309,6 +313,21 @@ fn truthy(value: Option<&Value>) -> bool { } } +/// 获取当前进程的 uid:gid,用于 builder 容器 --user,使容器内进程能写 bind mount 的宿主目录 +fn current_uid_gid() -> (String, String) { + let uid = String::from_utf8_lossy( + &Command::new("id").arg("-u").output().map(|o| o.stdout).unwrap_or_default(), + ) + .trim() + .to_string(); + let gid = String::from_utf8_lossy( + &Command::new("id").arg("-g").output().map(|o| o.stdout).unwrap_or_default(), + ) + .trim() + .to_string(); + (uid, gid) +} + /// 追加审计日志到 tools 根目录下的 .tool_audit.log fn audit( tools_root: &Path,