fix(ci): unblock dependabot dependency PR checks (#658)
This commit is contained in:
parent
5be4fd9138
commit
42f1d40f1f
5 changed files with 84 additions and 49 deletions
10
.github/workflows/feature-matrix.yml
vendored
10
.github/workflows/feature-matrix.yml
vendored
|
|
@ -37,12 +37,16 @@ jobs:
|
||||||
include:
|
include:
|
||||||
- name: no-default-features
|
- name: no-default-features
|
||||||
args: --no-default-features
|
args: --no-default-features
|
||||||
|
install_libudev: false
|
||||||
- name: all-features
|
- name: all-features
|
||||||
args: --all-features
|
args: --all-features
|
||||||
|
install_libudev: true
|
||||||
- name: hardware-only
|
- name: hardware-only
|
||||||
args: --no-default-features --features hardware
|
args: --no-default-features --features hardware
|
||||||
|
install_libudev: false
|
||||||
- name: browser-native
|
- name: browser-native
|
||||||
args: --no-default-features --features browser-native
|
args: --no-default-features --features browser-native
|
||||||
|
install_libudev: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||||
|
|
||||||
|
|
@ -54,6 +58,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
key: features-${{ matrix.name }}
|
key: features-${{ matrix.name }}
|
||||||
|
|
||||||
|
- name: Install Linux system dependencies for all-features
|
||||||
|
if: matrix.install_libudev
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends libudev-dev pkg-config
|
||||||
|
|
||||||
- name: Check feature combination
|
- name: Check feature combination
|
||||||
run: cargo check --locked ${{ matrix.args }}
|
run: cargo check --locked ${{ matrix.args }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use zeroclaw::agent::agent::Agent;
|
use zeroclaw::agent::agent::Agent;
|
||||||
use zeroclaw::agent::dispatcher::{NativeToolDispatcher, XmlToolDispatcher, ToolDispatcher};
|
use zeroclaw::agent::dispatcher::{NativeToolDispatcher, ToolDispatcher, XmlToolDispatcher};
|
||||||
use zeroclaw::config::MemoryConfig;
|
use zeroclaw::config::MemoryConfig;
|
||||||
use zeroclaw::memory;
|
use zeroclaw::memory;
|
||||||
use zeroclaw::memory::{Memory, MemoryCategory};
|
use zeroclaw::memory::{Memory, MemoryCategory};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//! This module uses the pure-Rust `landlock` crate for filesystem access control.
|
//! This module uses the pure-Rust `landlock` crate for filesystem access control.
|
||||||
|
|
||||||
#[cfg(all(feature = "sandbox-landlock", target_os = "linux"))]
|
#[cfg(all(feature = "sandbox-landlock", target_os = "linux"))]
|
||||||
use landlock::{AccessFS, Ruleset, RulesetCreated};
|
use landlock::{AccessFs, PathBeneath, PathFd, Ruleset, RulesetAttr, RulesetCreatedAttr};
|
||||||
|
|
||||||
use crate::security::traits::Sandbox;
|
use crate::security::traits::Sandbox;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
@ -26,9 +26,11 @@ impl LandlockSandbox {
|
||||||
/// Create a Landlock sandbox with a specific workspace directory
|
/// Create a Landlock sandbox with a specific workspace directory
|
||||||
pub fn with_workspace(workspace_dir: Option<std::path::PathBuf>) -> std::io::Result<Self> {
|
pub fn with_workspace(workspace_dir: Option<std::path::PathBuf>) -> std::io::Result<Self> {
|
||||||
// Test if Landlock is available by trying to create a minimal ruleset
|
// Test if Landlock is available by trying to create a minimal ruleset
|
||||||
let test_ruleset = Ruleset::new().set_access_fs(AccessFS::read_file | AccessFS::write_file);
|
let test_ruleset = Ruleset::default()
|
||||||
|
.handle_access(AccessFs::ReadFile | AccessFs::WriteFile)
|
||||||
|
.and_then(|ruleset| ruleset.create());
|
||||||
|
|
||||||
match test_ruleset.create() {
|
match test_ruleset {
|
||||||
Ok(_) => Ok(Self { workspace_dir }),
|
Ok(_) => Ok(Self { workspace_dir }),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::debug!("Landlock not available: {}", e);
|
tracing::debug!("Landlock not available: {}", e);
|
||||||
|
|
@ -47,49 +49,75 @@ impl LandlockSandbox {
|
||||||
|
|
||||||
/// Apply Landlock restrictions to the current process
|
/// Apply Landlock restrictions to the current process
|
||||||
fn apply_restrictions(&self) -> std::io::Result<()> {
|
fn apply_restrictions(&self) -> std::io::Result<()> {
|
||||||
let mut ruleset = Ruleset::new().set_access_fs(
|
let mut ruleset = Ruleset::default()
|
||||||
AccessFS::read_file
|
.handle_access(
|
||||||
| AccessFS::write_file
|
AccessFs::ReadFile
|
||||||
| AccessFS::read_dir
|
| AccessFs::WriteFile
|
||||||
| AccessFS::remove_dir
|
| AccessFs::ReadDir
|
||||||
| AccessFS::remove_file
|
| AccessFs::RemoveDir
|
||||||
| AccessFS::make_char
|
| AccessFs::RemoveFile
|
||||||
| AccessFS::make_sock
|
| AccessFs::MakeChar
|
||||||
| AccessFS::make_fifo
|
| AccessFs::MakeSock
|
||||||
| AccessFS::make_block
|
| AccessFs::MakeFifo
|
||||||
| AccessFS::make_reg
|
| AccessFs::MakeBlock
|
||||||
| AccessFS::make_sym,
|
| AccessFs::MakeReg
|
||||||
);
|
| AccessFs::MakeSym,
|
||||||
|
)
|
||||||
|
.and_then(|ruleset| ruleset.create())
|
||||||
|
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
|
||||||
// Allow workspace directory (read/write)
|
// Allow workspace directory (read/write)
|
||||||
if let Some(ref workspace) = self.workspace_dir {
|
if let Some(ref workspace) = self.workspace_dir {
|
||||||
if workspace.exists() {
|
if workspace.exists() {
|
||||||
ruleset = ruleset.add_path(
|
let workspace_fd =
|
||||||
workspace,
|
PathFd::new(workspace).map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
AccessFS::read_file | AccessFS::write_file | AccessFS::read_dir,
|
ruleset = ruleset
|
||||||
)?;
|
.add_rule(PathBeneath::new(
|
||||||
|
workspace_fd,
|
||||||
|
AccessFs::ReadFile | AccessFs::WriteFile | AccessFs::ReadDir,
|
||||||
|
))
|
||||||
|
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow /tmp for general operations
|
// Allow /tmp for general operations
|
||||||
ruleset = ruleset.add_path(
|
let tmp_fd =
|
||||||
Path::new("/tmp"),
|
PathFd::new(Path::new("/tmp")).map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
AccessFS::read_file | AccessFS::write_file,
|
ruleset = ruleset
|
||||||
)?;
|
.add_rule(PathBeneath::new(
|
||||||
|
tmp_fd,
|
||||||
|
AccessFs::ReadFile | AccessFs::WriteFile,
|
||||||
|
))
|
||||||
|
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
|
||||||
// Allow /usr and /bin for executing commands
|
// Allow /usr and /bin for executing commands
|
||||||
ruleset = ruleset.add_path(Path::new("/usr"), AccessFS::read_file | AccessFS::read_dir)?;
|
let usr_fd =
|
||||||
ruleset = ruleset.add_path(Path::new("/bin"), AccessFS::read_file | AccessFS::read_dir)?;
|
PathFd::new(Path::new("/usr")).map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
ruleset = ruleset
|
||||||
|
.add_rule(PathBeneath::new(
|
||||||
|
usr_fd,
|
||||||
|
AccessFs::ReadFile | AccessFs::ReadDir,
|
||||||
|
))
|
||||||
|
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
|
||||||
|
let bin_fd =
|
||||||
|
PathFd::new(Path::new("/bin")).map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
ruleset = ruleset
|
||||||
|
.add_rule(PathBeneath::new(
|
||||||
|
bin_fd,
|
||||||
|
AccessFs::ReadFile | AccessFs::ReadDir,
|
||||||
|
))
|
||||||
|
.map_err(|e| std::io::Error::other(e.to_string()))?;
|
||||||
|
|
||||||
// Apply the ruleset
|
// Apply the ruleset
|
||||||
match ruleset.create() {
|
match ruleset.restrict_self() {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
tracing::debug!("Landlock restrictions applied successfully");
|
tracing::debug!("Landlock restrictions applied successfully");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!("Failed to apply Landlock restrictions: {}", e);
|
tracing::warn!("Failed to apply Landlock restrictions: {}", e);
|
||||||
Err(std::io::Error::new(std::io::ErrorKind::Other, e))
|
Err(std::io::Error::other(e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +125,7 @@ impl LandlockSandbox {
|
||||||
|
|
||||||
#[cfg(all(feature = "sandbox-landlock", target_os = "linux"))]
|
#[cfg(all(feature = "sandbox-landlock", target_os = "linux"))]
|
||||||
impl Sandbox for LandlockSandbox {
|
impl Sandbox for LandlockSandbox {
|
||||||
fn wrap_command(&self, cmd: &mut std::process::Command) -> std::io::Result<()> {
|
fn wrap_command(&self, _cmd: &mut std::process::Command) -> std::io::Result<()> {
|
||||||
// Apply Landlock restrictions before executing the command
|
// Apply Landlock restrictions before executing the command
|
||||||
// Note: This affects the current process, not the child process
|
// Note: This affects the current process, not the child process
|
||||||
// Child processes inherit the Landlock restrictions
|
// Child processes inherit the Landlock restrictions
|
||||||
|
|
@ -106,9 +134,9 @@ impl Sandbox for LandlockSandbox {
|
||||||
|
|
||||||
fn is_available(&self) -> bool {
|
fn is_available(&self) -> bool {
|
||||||
// Try to create a minimal ruleset to verify availability
|
// Try to create a minimal ruleset to verify availability
|
||||||
Ruleset::new()
|
Ruleset::default()
|
||||||
.set_access_fs(AccessFS::read_file)
|
.handle_access(AccessFs::ReadFile)
|
||||||
.create()
|
.and_then(|ruleset| ruleset.create())
|
||||||
.is_ok()
|
.is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,9 @@ impl ScreenshotTool {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Reject filenames with shell-breaking characters to prevent injection in sh -c
|
// Reject filenames with shell-breaking characters to prevent injection in sh -c
|
||||||
const SHELL_UNSAFE: &[char] =
|
const SHELL_UNSAFE: &[char] = &[
|
||||||
&['\'', '"', '`', '$', '\\', ';', '|', '&', '\n', '\0', '(', ')'];
|
'\'', '"', '`', '$', '\\', ';', '|', '&', '\n', '\0', '(', ')',
|
||||||
|
];
|
||||||
if safe_name.contains(SHELL_UNSAFE) {
|
if safe_name.contains(SHELL_UNSAFE) {
|
||||||
return Ok(ToolResult {
|
return Ok(ToolResult {
|
||||||
success: false,
|
success: false,
|
||||||
|
|
@ -307,10 +308,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(!result.success);
|
assert!(!result.success);
|
||||||
assert!(result
|
assert!(result.error.unwrap().contains("unsafe for shell execution"));
|
||||||
.error
|
|
||||||
.unwrap()
|
|
||||||
.contains("unsafe for shell execution"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,12 @@ struct CountingTool {
|
||||||
impl CountingTool {
|
impl CountingTool {
|
||||||
fn new() -> (Self, Arc<Mutex<usize>>) {
|
fn new() -> (Self, Arc<Mutex<usize>>) {
|
||||||
let count = Arc::new(Mutex::new(0));
|
let count = Arc::new(Mutex::new(0));
|
||||||
(Self { count: count.clone() }, count)
|
(
|
||||||
|
Self {
|
||||||
|
count: count.clone(),
|
||||||
|
},
|
||||||
|
count,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,10 +168,7 @@ fn tool_response(calls: Vec<ToolCall>) -> ChatResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_agent(
|
fn build_agent(provider: Box<dyn Provider>, tools: Vec<Box<dyn Tool>>) -> Agent {
|
||||||
provider: Box<dyn Provider>,
|
|
||||||
tools: Vec<Box<dyn Tool>>,
|
|
||||||
) -> Agent {
|
|
||||||
Agent::builder()
|
Agent::builder()
|
||||||
.provider(provider)
|
.provider(provider)
|
||||||
.tools(tools)
|
.tools(tools)
|
||||||
|
|
@ -178,10 +180,7 @@ fn build_agent(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_agent_xml(
|
fn build_agent_xml(provider: Box<dyn Provider>, tools: Vec<Box<dyn Tool>>) -> Agent {
|
||||||
provider: Box<dyn Provider>,
|
|
||||||
tools: Vec<Box<dyn Tool>>,
|
|
||||||
) -> Agent {
|
|
||||||
Agent::builder()
|
Agent::builder()
|
||||||
.provider(provider)
|
.provider(provider)
|
||||||
.tools(tools)
|
.tools(tools)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue