Skip to content

Commit b0b0ebd

Browse files
committed
fix(sandbox): skip procfs-dependent tests when /proc/<pid>/root/ is inaccessible
The Linux-specific symlink resolution tests depend on /proc/<pid>/root/ being readable, which requires CAP_SYS_PTRACE or permissive ptrace scope. This is unavailable in CI containers, rootless containers, and hardened hosts. Add a procfs_root_accessible() guard that skips these tests gracefully instead of failing.
1 parent ab7f6a2 commit b0b0ebd

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

  • crates/openshell-sandbox/src

crates/openshell-sandbox/src/opa.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3270,9 +3270,25 @@ network_policies:
32703270
);
32713271
}
32723272

3273+
/// Check if `/proc/<pid>/root/` is accessible for the current process.
3274+
/// In CI containers or restricted environments, this path may not be
3275+
/// readable even for the process's own PID. Tests that depend on
3276+
/// procfs root access should skip gracefully when this returns false.
3277+
#[cfg(target_os = "linux")]
3278+
fn procfs_root_accessible() -> bool {
3279+
let pid = std::process::id();
3280+
let probe = format!("/proc/{pid}/root/tmp");
3281+
std::fs::symlink_metadata(&probe).is_ok()
3282+
}
3283+
32733284
#[cfg(target_os = "linux")]
32743285
#[test]
32753286
fn resolve_binary_with_real_symlink() {
3287+
if !procfs_root_accessible() {
3288+
eprintln!("Skipping: /proc/<pid>/root/ not accessible in this environment");
3289+
return;
3290+
}
3291+
32763292
// Create a real symlink in a temp directory and verify resolution
32773293
// works through /proc/self/root (which maps to / on the host)
32783294
use std::os::unix::fs::symlink;
@@ -3304,6 +3320,11 @@ network_policies:
33043320
#[cfg(target_os = "linux")]
33053321
#[test]
33063322
fn resolve_binary_non_symlink_returns_none() {
3323+
if !procfs_root_accessible() {
3324+
eprintln!("Skipping: /proc/<pid>/root/ not accessible in this environment");
3325+
return;
3326+
}
3327+
33073328
// A regular file should return None (no expansion needed)
33083329
use std::io::Write;
33093330
let mut tmp = tempfile::NamedTempFile::new().unwrap();
@@ -3323,6 +3344,11 @@ network_policies:
33233344
#[cfg(target_os = "linux")]
33243345
#[test]
33253346
fn resolve_binary_multi_level_symlink() {
3347+
if !procfs_root_accessible() {
3348+
eprintln!("Skipping: /proc/<pid>/root/ not accessible in this environment");
3349+
return;
3350+
}
3351+
33263352
// Test multi-level symlink resolution: python3 -> python3.11 -> cpython3.11
33273353
use std::os::unix::fs::symlink;
33283354
let dir = tempfile::tempdir().unwrap();
@@ -3349,6 +3375,11 @@ network_policies:
33493375
#[cfg(target_os = "linux")]
33503376
#[test]
33513377
fn from_proto_with_pid_expands_symlinks_in_container() {
3378+
if !procfs_root_accessible() {
3379+
eprintln!("Skipping: /proc/<pid>/root/ not accessible in this environment");
3380+
return;
3381+
}
3382+
33523383
// End-to-end test: create a symlink, build engine with our PID,
33533384
// verify the resolved path is allowed
33543385
use std::os::unix::fs::symlink;
@@ -3420,6 +3451,11 @@ network_policies:
34203451
#[cfg(target_os = "linux")]
34213452
#[test]
34223453
fn reload_from_proto_with_pid_resolves_symlinks() {
3454+
if !procfs_root_accessible() {
3455+
eprintln!("Skipping: /proc/<pid>/root/ not accessible in this environment");
3456+
return;
3457+
}
3458+
34233459
// Test hot-reload path: initial engine at pid=0, then reload with
34243460
// real PID to trigger symlink resolution
34253461
use std::os::unix::fs::symlink;

0 commit comments

Comments
 (0)