style: apply cargo fmt across entire Rust codebase
- Remove Rust formatting check from CI workflow since formatting is now applied - Standardize import ordering and organization throughout codebase - Fix indentation, spacing, and line breaks for consistency - Clean up trailing whitespace and formatting inconsistencies - Apply rustfmt to all Rust source files including checkpoint, sandbox, commands, and test modules This establishes a consistent code style baseline for the project.
This commit is contained in:
@@ -3,7 +3,7 @@ use crate::sandbox::common::*;
|
||||
use crate::skip_if_unsupported;
|
||||
use claudia_lib::sandbox::executor::SandboxExecutor;
|
||||
use claudia_lib::sandbox::profile::ProfileBuilder;
|
||||
use gaol::profile::{Profile, Operation, PathPattern};
|
||||
use gaol::profile::{Operation, PathPattern, Profile};
|
||||
use serial_test::serial;
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -12,21 +12,21 @@ use tempfile::TempDir;
|
||||
#[serial]
|
||||
fn test_allowed_file_read() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_file_read {
|
||||
eprintln!("Skipping test: file read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile allowing project path access
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -34,13 +34,13 @@ fn test_allowed_file_read() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads from allowed path
|
||||
let test_code = test_code::file_read(&test_fs.project_path.join("main.rs").to_string_lossy());
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_file_read", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -63,21 +63,21 @@ fn test_allowed_file_read() {
|
||||
#[serial]
|
||||
fn test_forbidden_file_read() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_file_read {
|
||||
eprintln!("Skipping test: file read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile allowing only project path (not forbidden path)
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -85,14 +85,14 @@ fn test_forbidden_file_read() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads from forbidden path
|
||||
let forbidden_file = test_fs.forbidden_path.join("secret.txt");
|
||||
let test_code = test_code::file_read(&forbidden_file.to_string_lossy());
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_forbidden_read", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -105,7 +105,9 @@ fn test_forbidden_file_read() {
|
||||
// On some platforms (like macOS), gaol might not block all file reads
|
||||
// so we check if the operation failed OR if it's a platform limitation
|
||||
if status.success() {
|
||||
eprintln!("WARNING: File read was not blocked - this might be a platform limitation");
|
||||
eprintln!(
|
||||
"WARNING: File read was not blocked - this might be a platform limitation"
|
||||
);
|
||||
// Check if we're on a platform where this is expected
|
||||
let platform_config = PlatformConfig::current();
|
||||
if !platform_config.supports_file_read {
|
||||
@@ -124,15 +126,15 @@ fn test_forbidden_file_read() {
|
||||
#[serial]
|
||||
fn test_file_write_always_forbidden() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile with file read permissions (write should still be blocked)
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -140,14 +142,14 @@ fn test_file_write_always_forbidden() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that tries to write a file
|
||||
let write_path = test_fs.project_path.join("test_write.txt");
|
||||
let test_code = test_code::file_write(&write_path.to_string_lossy());
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_file_write", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -177,28 +179,28 @@ fn test_file_write_always_forbidden() {
|
||||
#[serial]
|
||||
fn test_file_metadata_operations() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_metadata_read && !platform.supports_file_read {
|
||||
eprintln!("Skipping test: metadata read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile with metadata read permission
|
||||
let operations = if platform.supports_metadata_read {
|
||||
vec![
|
||||
Operation::FileReadMetadata(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
]
|
||||
vec![Operation::FileReadMetadata(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))]
|
||||
} else {
|
||||
// On Linux, metadata is allowed if file read is allowed
|
||||
vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
]
|
||||
vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))]
|
||||
};
|
||||
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -206,14 +208,14 @@ fn test_file_metadata_operations() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads file metadata
|
||||
let test_file = test_fs.project_path.join("main.rs");
|
||||
let test_code = test_code::file_metadata(&test_file.to_string_lossy());
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_metadata", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -224,7 +226,10 @@ fn test_file_metadata_operations() {
|
||||
Ok(mut child) => {
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
if platform.supports_metadata_read || platform.supports_file_read {
|
||||
assert!(status.success(), "Metadata read should succeed when allowed");
|
||||
assert!(
|
||||
status.success(),
|
||||
"Metadata read should succeed when allowed"
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -238,33 +243,32 @@ fn test_file_metadata_operations() {
|
||||
#[serial]
|
||||
fn test_template_variable_expansion() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_file_read {
|
||||
eprintln!("Skipping test: file read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test database and profile
|
||||
let test_db = TEST_DB.lock();
|
||||
test_db.reset().expect("Failed to reset database");
|
||||
|
||||
|
||||
// Create a profile with template variables
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
let rules = vec![
|
||||
TestRule::file_read("{{PROJECT_PATH}}", true),
|
||||
];
|
||||
|
||||
let profile_id = test_db.create_test_profile("template_test", rules)
|
||||
let rules = vec![TestRule::file_read("{{PROJECT_PATH}}", true)];
|
||||
|
||||
let profile_id = test_db
|
||||
.create_test_profile("template_test", rules)
|
||||
.expect("Failed to create test profile");
|
||||
|
||||
|
||||
// Load and build the profile
|
||||
let db_rules = claudia_lib::sandbox::profile::load_profile_rules(&test_db.conn, profile_id)
|
||||
.expect("Failed to load profile rules");
|
||||
|
||||
|
||||
let builder = ProfileBuilder::new(test_fs.project_path.clone())
|
||||
.expect("Failed to create profile builder");
|
||||
|
||||
|
||||
let profile = match builder.build_profile(db_rules) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -272,13 +276,13 @@ fn test_template_variable_expansion() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads from project path
|
||||
let test_code = test_code::file_read(&test_fs.project_path.join("main.rs").to_string_lossy());
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_template", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -294,4 +298,4 @@ fn test_template_variable_expansion() {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,8 +4,8 @@ mod file_operations;
|
||||
#[cfg(test)]
|
||||
mod network_operations;
|
||||
#[cfg(test)]
|
||||
mod system_info;
|
||||
#[cfg(test)]
|
||||
mod process_isolation;
|
||||
#[cfg(test)]
|
||||
mod violations;
|
||||
mod system_info;
|
||||
#[cfg(test)]
|
||||
mod violations;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
use crate::sandbox::common::*;
|
||||
use crate::skip_if_unsupported;
|
||||
use claudia_lib::sandbox::executor::SandboxExecutor;
|
||||
use gaol::profile::{Profile, Operation, AddressPattern};
|
||||
use gaol::profile::{AddressPattern, Operation, Profile};
|
||||
use serial_test::serial;
|
||||
use std::net::TcpListener;
|
||||
use tempfile::TempDir;
|
||||
@@ -10,7 +10,10 @@ use tempfile::TempDir;
|
||||
/// Get an available port for testing
|
||||
fn get_available_port() -> u16 {
|
||||
let listener = TcpListener::bind("127.0.0.1:0").expect("Failed to bind to 0");
|
||||
let port = listener.local_addr().expect("Failed to get local addr").port();
|
||||
let port = listener
|
||||
.local_addr()
|
||||
.expect("Failed to get local addr")
|
||||
.port();
|
||||
drop(listener); // Release the port
|
||||
port
|
||||
}
|
||||
@@ -20,21 +23,19 @@ fn get_available_port() -> u16 {
|
||||
#[serial]
|
||||
fn test_allowed_network_all() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_network_all {
|
||||
eprintln!("Skipping test: network all not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile allowing all network access
|
||||
let operations = vec![
|
||||
Operation::NetworkOutbound(AddressPattern::All),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::NetworkOutbound(AddressPattern::All)];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -42,18 +43,18 @@ fn test_allowed_network_all() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that connects to localhost
|
||||
let port = get_available_port();
|
||||
let test_code = test_code::network_connect(&format!("127.0.0.1:{}", port));
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_network", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Start a listener on the port
|
||||
let listener = TcpListener::bind(format!("127.0.0.1:{}", port))
|
||||
.expect("Failed to bind listener");
|
||||
|
||||
let listener =
|
||||
TcpListener::bind(format!("127.0.0.1:{}", port)).expect("Failed to bind listener");
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -66,9 +67,12 @@ fn test_allowed_network_all() {
|
||||
std::thread::spawn(move || {
|
||||
let _ = listener.accept();
|
||||
});
|
||||
|
||||
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
assert!(status.success(), "Network connection should succeed when allowed");
|
||||
assert!(
|
||||
status.success(),
|
||||
"Network connection should succeed when allowed"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
@@ -81,15 +85,15 @@ fn test_allowed_network_all() {
|
||||
#[serial]
|
||||
fn test_forbidden_network() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile without network permissions
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(gaol::profile::PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(gaol::profile::PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -97,13 +101,13 @@ fn test_forbidden_network() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that tries to connect
|
||||
let test_code = test_code::network_connect("google.com:80");
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_no_network", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -137,19 +141,19 @@ fn test_network_tcp_port_specific() {
|
||||
eprintln!("Skipping test: TCP port filtering not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Get two ports - one allowed, one forbidden
|
||||
let allowed_port = get_available_port();
|
||||
let forbidden_port = get_available_port();
|
||||
|
||||
|
||||
// Create profile allowing only specific port
|
||||
let operations = vec![
|
||||
Operation::NetworkOutbound(AddressPattern::Tcp(allowed_port)),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::NetworkOutbound(AddressPattern::Tcp(
|
||||
allowed_port,
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -157,17 +161,17 @@ fn test_network_tcp_port_specific() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Test 1: Allowed port
|
||||
{
|
||||
let test_code = test_code::network_connect(&format!("127.0.0.1:{}", allowed_port));
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_allowed_port", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
let listener = TcpListener::bind(format!("127.0.0.1:{}", allowed_port))
|
||||
.expect("Failed to bind listener");
|
||||
|
||||
|
||||
let executor = SandboxExecutor::new(profile.clone(), test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
&binary_path.to_string_lossy(),
|
||||
@@ -178,23 +182,26 @@ fn test_network_tcp_port_specific() {
|
||||
std::thread::spawn(move || {
|
||||
let _ = listener.accept();
|
||||
});
|
||||
|
||||
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
assert!(status.success(), "Connection to allowed port should succeed");
|
||||
assert!(
|
||||
status.success(),
|
||||
"Connection to allowed port should succeed"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Test 2: Forbidden port
|
||||
{
|
||||
let test_code = test_code::network_connect(&format!("127.0.0.1:{}", forbidden_port));
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_forbidden_port", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
&binary_path.to_string_lossy(),
|
||||
@@ -203,7 +210,10 @@ fn test_network_tcp_port_specific() {
|
||||
) {
|
||||
Ok(mut child) => {
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
assert!(!status.success(), "Connection to forbidden port should fail");
|
||||
assert!(
|
||||
!status.success(),
|
||||
"Connection to forbidden port should fail"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
@@ -218,28 +228,26 @@ fn test_network_tcp_port_specific() {
|
||||
#[cfg(unix)]
|
||||
fn test_local_socket_connections() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
let socket_path = test_fs.project_path.join("test.sock");
|
||||
|
||||
|
||||
// Create appropriate profile based on platform
|
||||
let operations = if platform.supports_network_local {
|
||||
vec![
|
||||
Operation::NetworkOutbound(AddressPattern::LocalSocket(socket_path.clone())),
|
||||
]
|
||||
vec![Operation::NetworkOutbound(AddressPattern::LocalSocket(
|
||||
socket_path.clone(),
|
||||
))]
|
||||
} else if platform.supports_network_all {
|
||||
// Fallback to allowing all network
|
||||
vec![
|
||||
Operation::NetworkOutbound(AddressPattern::All),
|
||||
]
|
||||
vec![Operation::NetworkOutbound(AddressPattern::All)]
|
||||
} else {
|
||||
eprintln!("Skipping test: no network support on this platform");
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -247,7 +255,7 @@ fn test_local_socket_connections() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that connects to local socket
|
||||
let test_code = format!(
|
||||
r#"
|
||||
@@ -267,15 +275,15 @@ fn main() {{
|
||||
"#,
|
||||
socket_path.to_string_lossy()
|
||||
);
|
||||
|
||||
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_local_socket", &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Create Unix socket listener
|
||||
use std::os::unix::net::UnixListener;
|
||||
let listener = UnixListener::bind(&socket_path).expect("Failed to bind Unix socket");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -287,15 +295,18 @@ fn main() {{
|
||||
std::thread::spawn(move || {
|
||||
let _ = listener.accept();
|
||||
});
|
||||
|
||||
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
assert!(status.success(), "Local socket connection should succeed when allowed");
|
||||
assert!(
|
||||
status.success(),
|
||||
"Local socket connection should succeed when allowed"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Clean up socket file
|
||||
let _ = std::fs::remove_file(&socket_path);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
use crate::sandbox::common::*;
|
||||
use crate::skip_if_unsupported;
|
||||
use claudia_lib::sandbox::executor::SandboxExecutor;
|
||||
use gaol::profile::{Profile, Operation, PathPattern, AddressPattern};
|
||||
use gaol::profile::{AddressPattern, Operation, PathPattern, Profile};
|
||||
use serial_test::serial;
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -11,16 +11,16 @@ use tempfile::TempDir;
|
||||
#[serial]
|
||||
fn test_process_spawn_forbidden() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile with various permissions (process spawn should still be blocked)
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
Operation::NetworkOutbound(AddressPattern::All),
|
||||
];
|
||||
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -28,13 +28,13 @@ fn test_process_spawn_forbidden() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that tries to spawn a process
|
||||
let test_code = test_code::spawn_process();
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_spawn", test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -49,7 +49,10 @@ fn test_process_spawn_forbidden() {
|
||||
eprintln!("WARNING: Process spawning was not blocked");
|
||||
// macOS sandbox might have limitations
|
||||
if std::env::consts::OS != "linux" {
|
||||
eprintln!("Process spawning might not be fully blocked on {}", std::env::consts::OS);
|
||||
eprintln!(
|
||||
"Process spawning might not be fully blocked on {}",
|
||||
std::env::consts::OS
|
||||
);
|
||||
} else {
|
||||
panic!("Process spawning should be blocked on Linux");
|
||||
}
|
||||
@@ -67,15 +70,15 @@ fn test_process_spawn_forbidden() {
|
||||
#[cfg(unix)]
|
||||
fn test_fork_forbidden() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create minimal profile
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -83,14 +86,19 @@ fn test_fork_forbidden() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that tries to fork
|
||||
let test_code = test_code::fork_process();
|
||||
|
||||
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary_with_deps("test_fork", test_code, binary_dir.path(), &[("libc", "0.2")])
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
let binary_path = create_test_binary_with_deps(
|
||||
"test_fork",
|
||||
test_code,
|
||||
binary_dir.path(),
|
||||
&[("libc", "0.2")],
|
||||
)
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -120,15 +128,15 @@ fn test_fork_forbidden() {
|
||||
#[cfg(unix)]
|
||||
fn test_exec_forbidden() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create minimal profile
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -136,14 +144,19 @@ fn test_exec_forbidden() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that tries to exec
|
||||
let test_code = test_code::exec_process();
|
||||
|
||||
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary_with_deps("test_exec", test_code, binary_dir.path(), &[("libc", "0.2")])
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
let binary_path = create_test_binary_with_deps(
|
||||
"test_exec",
|
||||
test_code,
|
||||
binary_dir.path(),
|
||||
&[("libc", "0.2")],
|
||||
)
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -172,15 +185,15 @@ fn test_exec_forbidden() {
|
||||
#[serial]
|
||||
fn test_thread_creation_allowed() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create minimal profile
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -188,7 +201,7 @@ fn test_thread_creation_allowed() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that creates threads
|
||||
let test_code = r#"
|
||||
use std::thread;
|
||||
@@ -211,11 +224,11 @@ fn main() {
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_thread", test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -231,4 +244,4 @@ fn main() {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
use crate::sandbox::common::*;
|
||||
use crate::skip_if_unsupported;
|
||||
use claudia_lib::sandbox::executor::SandboxExecutor;
|
||||
use gaol::profile::{Profile, Operation};
|
||||
use gaol::profile::{Operation, Profile};
|
||||
use serial_test::serial;
|
||||
use tempfile::TempDir;
|
||||
|
||||
@@ -11,21 +11,19 @@ use tempfile::TempDir;
|
||||
#[serial]
|
||||
fn test_system_info_read() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_system_info {
|
||||
eprintln!("Skipping test: system info read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile allowing system info read
|
||||
let operations = vec![
|
||||
Operation::SystemInfoRead,
|
||||
];
|
||||
|
||||
let operations = vec![Operation::SystemInfoRead];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -33,13 +31,13 @@ fn test_system_info_read() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads system info
|
||||
let test_code = test_code::system_info();
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_sysinfo", test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -49,7 +47,10 @@ fn test_system_info_read() {
|
||||
) {
|
||||
Ok(mut child) => {
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
assert!(status.success(), "System info read should succeed when allowed");
|
||||
assert!(
|
||||
status.success(),
|
||||
"System info read should succeed when allowed"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
@@ -64,12 +65,12 @@ fn test_system_info_read() {
|
||||
fn test_forbidden_system_info() {
|
||||
// Create test project
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile without system info permission
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(gaol::profile::PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(gaol::profile::PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -77,13 +78,13 @@ fn test_forbidden_system_info() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that reads system info
|
||||
let test_code = test_code::system_info();
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_no_sysinfo", test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -118,27 +119,33 @@ fn test_forbidden_system_info() {
|
||||
#[serial]
|
||||
fn test_platform_specific_system_info() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
|
||||
|
||||
match std::env::consts::OS {
|
||||
"linux" => {
|
||||
// On Linux, system info is never allowed
|
||||
assert!(!platform.supports_system_info,
|
||||
"Linux should not support system info read");
|
||||
assert!(
|
||||
!platform.supports_system_info,
|
||||
"Linux should not support system info read"
|
||||
);
|
||||
}
|
||||
"macos" => {
|
||||
// On macOS, system info can be allowed
|
||||
assert!(platform.supports_system_info,
|
||||
"macOS should support system info read");
|
||||
assert!(
|
||||
platform.supports_system_info,
|
||||
"macOS should support system info read"
|
||||
);
|
||||
}
|
||||
"freebsd" => {
|
||||
// On FreeBSD, system info is always allowed (can't be restricted)
|
||||
assert!(platform.supports_system_info,
|
||||
"FreeBSD always allows system info read");
|
||||
assert!(
|
||||
platform.supports_system_info,
|
||||
"FreeBSD always allows system info read"
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("Unknown platform behavior for system info");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
use crate::sandbox::common::*;
|
||||
use crate::skip_if_unsupported;
|
||||
use claudia_lib::sandbox::executor::SandboxExecutor;
|
||||
use gaol::profile::{Profile, Operation, PathPattern};
|
||||
use gaol::profile::{Operation, PathPattern, Profile};
|
||||
use serial_test::serial;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tempfile::TempDir;
|
||||
@@ -27,19 +27,19 @@ impl ViolationCollector {
|
||||
violations: Arc::new(Mutex::new(Vec::new())),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn record(&self, operation_type: &str, pattern_value: Option<&str>, process_name: &str) {
|
||||
let event = ViolationEvent {
|
||||
operation_type: operation_type.to_string(),
|
||||
pattern_value: pattern_value.map(|s| s.to_string()),
|
||||
process_name: process_name.to_string(),
|
||||
};
|
||||
|
||||
|
||||
if let Ok(mut violations) = self.violations.lock() {
|
||||
violations.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_violations(&self) -> Vec<ViolationEvent> {
|
||||
self.violations.lock().unwrap().clone()
|
||||
}
|
||||
@@ -50,22 +50,22 @@ impl ViolationCollector {
|
||||
#[serial]
|
||||
fn test_violation_detection() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_file_read {
|
||||
eprintln!("Skipping test: file read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
let collector = ViolationCollector::new();
|
||||
|
||||
|
||||
// Create profile allowing only project path
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -73,19 +73,31 @@ fn test_violation_detection() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Test various forbidden operations
|
||||
let test_cases = vec![
|
||||
("file_read", test_code::file_read(&test_fs.forbidden_path.join("secret.txt").to_string_lossy()), "file_read_forbidden"),
|
||||
("file_write", test_code::file_write(&test_fs.project_path.join("new.txt").to_string_lossy()), "file_write_forbidden"),
|
||||
("process_spawn", test_code::spawn_process().to_string(), "process_spawn_forbidden"),
|
||||
(
|
||||
"file_read",
|
||||
test_code::file_read(&test_fs.forbidden_path.join("secret.txt").to_string_lossy()),
|
||||
"file_read_forbidden",
|
||||
),
|
||||
(
|
||||
"file_write",
|
||||
test_code::file_write(&test_fs.project_path.join("new.txt").to_string_lossy()),
|
||||
"file_write_forbidden",
|
||||
),
|
||||
(
|
||||
"process_spawn",
|
||||
test_code::spawn_process().to_string(),
|
||||
"process_spawn_forbidden",
|
||||
),
|
||||
];
|
||||
|
||||
|
||||
for (op_type, test_code, binary_name) in test_cases {
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary(binary_name, &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
let executor = SandboxExecutor::new(profile.clone(), test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
&binary_path.to_string_lossy(),
|
||||
@@ -104,7 +116,7 @@ fn test_violation_detection() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Verify violations were detected
|
||||
let violations = collector.get_violations();
|
||||
// On some platforms (like macOS), sandbox might not block all operations
|
||||
@@ -122,25 +134,25 @@ fn test_violation_detection() {
|
||||
#[serial]
|
||||
fn test_violation_patterns() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
let platform = PlatformConfig::current();
|
||||
if !platform.supports_file_read {
|
||||
eprintln!("Skipping test: file read not supported on this platform");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create profile with specific allowed paths
|
||||
let allowed_dir = test_fs.root.path().join("allowed_specific");
|
||||
std::fs::create_dir_all(&allowed_dir).expect("Failed to create allowed dir");
|
||||
|
||||
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
Operation::FileReadAll(PathPattern::Literal(allowed_dir.join("file.txt"))),
|
||||
];
|
||||
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -148,21 +160,25 @@ fn test_violation_patterns() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Test accessing different forbidden paths
|
||||
let forbidden_db_path = test_fs.forbidden_path.join("data.db").to_string_lossy().to_string();
|
||||
let forbidden_db_path = test_fs
|
||||
.forbidden_path
|
||||
.join("data.db")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let forbidden_paths = vec![
|
||||
("/etc/passwd", "system_file"),
|
||||
("/tmp/test.txt", "temp_file"),
|
||||
(forbidden_db_path.as_str(), "forbidden_db"),
|
||||
];
|
||||
|
||||
|
||||
for (path, test_name) in forbidden_paths {
|
||||
let test_code = test_code::file_read(path);
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary(test_name, &test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
let executor = SandboxExecutor::new(profile.clone(), test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
&binary_path.to_string_lossy(),
|
||||
@@ -173,7 +189,10 @@ fn test_violation_patterns() {
|
||||
let status = child.wait().expect("Failed to wait for child");
|
||||
// Some platforms might not block all file access
|
||||
if status.success() {
|
||||
eprintln!("WARNING: Access to {} was allowed (possible platform limitation)", path);
|
||||
eprintln!(
|
||||
"WARNING: Access to {} was allowed (possible platform limitation)",
|
||||
path
|
||||
);
|
||||
if std::env::consts::OS == "linux" && path.starts_with("/etc") {
|
||||
panic!("Access to {} should be denied on Linux", path);
|
||||
}
|
||||
@@ -191,15 +210,15 @@ fn test_violation_patterns() {
|
||||
#[serial]
|
||||
fn test_multiple_violations_sequence() {
|
||||
skip_if_unsupported!();
|
||||
|
||||
|
||||
// Create test file system
|
||||
let test_fs = TestFileSystem::new().expect("Failed to create test filesystem");
|
||||
|
||||
|
||||
// Create minimal profile
|
||||
let operations = vec![
|
||||
Operation::FileReadAll(PathPattern::Subpath(test_fs.project_path.clone())),
|
||||
];
|
||||
|
||||
let operations = vec![Operation::FileReadAll(PathPattern::Subpath(
|
||||
test_fs.project_path.clone(),
|
||||
))];
|
||||
|
||||
let profile = match Profile::new(operations) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
@@ -207,7 +226,7 @@ fn test_multiple_violations_sequence() {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Create test binary that attempts multiple forbidden operations
|
||||
let test_code = r#"
|
||||
use std::fs;
|
||||
@@ -249,11 +268,11 @@ fn main() {{
|
||||
}}
|
||||
}}
|
||||
"#;
|
||||
|
||||
|
||||
let binary_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let binary_path = create_test_binary("test_multi_violations", test_code, binary_dir.path())
|
||||
.expect("Failed to create test binary");
|
||||
|
||||
|
||||
// Execute in sandbox
|
||||
let executor = SandboxExecutor::new(profile, test_fs.project_path.clone());
|
||||
match executor.execute_sandboxed_spawn(
|
||||
@@ -275,4 +294,4 @@ fn main() {{
|
||||
eprintln!("Sandbox execution failed: {} (may be expected in CI)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user