test(conformance): use Alpine workload image

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar
2026-09-21 12:04:33 +02:00
parent 26e3e5f07d
commit d2da8bbc04
8 changed files with 72 additions and 31 deletions
@@ -141,8 +141,6 @@ async fn create_running_sandbox(
"create",
"--name",
sandbox_name,
"--from",
"base",
"--detach",
"--no-tty",
"--",
@@ -55,15 +55,7 @@ async fn run_smoke_inner(runner: &mut OpenShellRunner) -> Result<(), String> {
.step("create")
.description("sandbox creation succeeds")
.with_timeout(CREATE_TIMEOUT)
.run(&[
"sandbox",
"create",
"--name",
&sandbox_name,
"--from",
"base",
"--detach",
])
.run(&["sandbox", "create", "--name", &sandbox_name, "--detach"])
.await
.map_err(|error| error.to_string())?;
create.require_success()?;
+5
View File
@@ -988,6 +988,7 @@ pub fn restrictive_default_policy() -> SandboxPolicy {
filesystem: Some(FilesystemPolicy {
include_workdir: true,
read_only: vec![
"/bin".into(),
"/usr".into(),
"/lib".into(),
"/proc".into(),
@@ -2128,6 +2129,10 @@ network_policies:
let policy = restrictive_default_policy();
let fs = policy.filesystem.expect("must have filesystem policy");
assert!(fs.include_workdir);
assert!(
fs.read_only.iter().any(|p| p == "/bin"),
"read_only should contain /bin"
);
assert!(
fs.read_only.iter().any(|p| p == "/usr"),
"read_only should contain /usr"
@@ -69,12 +69,13 @@ impl LocalBoundaryExec {
let (session_user, session_home) =
crate::process::session_user_and_home(&self.policy, effective_workdir);
let path = std::env::var("PATH").unwrap_or_else(|_| "/usr/local/bin:/usr/bin:/bin".into());
let shell = openshell_core::shell::detect_login_shell();
command
.env_clear()
.env(openshell_core::sandbox_env::SANDBOX, "1")
.env("HOME", session_home)
.env("USER", session_user)
.env("SHELL", "/bin/bash")
.env("SHELL", shell)
.env("PATH", path)
.env("TERM", if spec.pty { "xterm-256color" } else { "dumb" });
for (key, value) in &self.user_environment {
@@ -302,7 +302,6 @@ fn prepare_with_path_open_mode(
let result: Result<PreparedRuleset> = (|| {
let access_all = AccessFs::from_all(abi);
let access_read = AccessFs::from_read(abi);
let mut ruleset = Ruleset::default();
ruleset = ruleset
@@ -315,7 +314,8 @@ fn prepare_with_path_open_mode(
for path in &read_only {
if let Some(path_fd) = try_open_path(path, compatibility, path_open_mode)? {
let allowed_access = access_for_path_fd(&path_fd, access_read, abi)?;
let allowed_access =
access_for_path_fd(&path_fd, read_only_access(path, abi), abi)?;
debug!(path = %path.display(), "Landlock allow read-only");
ruleset = ruleset
.add_rule(PathBeneath::new(path_fd, allowed_access))
@@ -434,6 +434,17 @@ pub fn enforce(prepared: PreparedRuleset) -> Result<()> {
Ok(())
}
/// The baseline permits execution only from Alpine's `/bin`. Other read-only
/// paths, including `/proc` and `/etc`, remain non-executable.
fn read_only_access(path: &Path, abi: ABI) -> BitFlags<AccessFs> {
let access = AccessFs::from_read(abi);
if path == Path::new("/bin") {
access | AccessFs::Execute
} else {
access
}
}
/// Tailor a rule's access mask to the inode referenced by its already-open FD.
///
/// Landlock directory-only rights such as `ReadDir` are invalid for regular
@@ -727,6 +738,12 @@ mod tests {
);
}
#[test]
fn only_bin_read_only_access_includes_execute() {
assert!(read_only_access(Path::new("/bin"), ABI::V3).contains(AccessFs::Execute));
assert!(!read_only_access(Path::new("/usr"), ABI::V3).contains(AccessFs::Execute));
}
#[test]
fn access_for_path_fd_limits_regular_file_access() {
let file = tempfile::NamedTempFile::new().unwrap();
+45 -15
View File
@@ -892,21 +892,11 @@ impl SshHandler {
let no_login_shell = state.no_login_shell;
let pty = state.pty_request.take();
let pty_requested = pty.is_some();
let (program, args) = command.map_or_else(
|| {
if pty_requested {
("/bin/bash".to_string(), vec!["-i".to_string()])
} else {
("/bin/bash".to_string(), vec![])
}
},
|command| {
(
"/bin/bash".to_string(),
vec![login_shell_flag(no_login_shell).to_string(), command],
)
},
);
// The supervisor shares the workload filesystem, so select a shell
// that actually exists in the image. Alpine and other minimal images
// provide `/bin/sh` but not `/bin/bash`.
let shell = openshell_core::shell::detect_login_shell();
let (program, args) = shell_command(shell, command, pty_requested, no_login_shell);
let env = pty
.as_ref()
.map(|request| vec![("TERM".to_string(), request.term.clone())])
@@ -1084,6 +1074,25 @@ const fn login_shell_flag(no_login_shell: bool) -> &'static str {
if no_login_shell { "-c" } else { "-lc" }
}
fn shell_command(
shell: String,
command: Option<String>,
pty_requested: bool,
no_login_shell: bool,
) -> (String, Vec<String>) {
let args = command.map_or_else(
|| {
if pty_requested {
vec!["-i".to_string()]
} else {
Vec::new()
}
},
|command| vec![login_shell_flag(no_login_shell).to_string(), command],
);
(shell, args)
}
#[allow(dead_code)]
#[derive(Clone)]
struct PtyRequest {
@@ -1400,6 +1409,27 @@ mod tests {
main_session.end_terminal_attachment();
}
#[test]
fn shell_command_uses_the_resolved_image_shell() {
let (program, args) = shell_command(
"/bin/sh".to_string(),
Some("printf ready".to_string()),
false,
false,
);
assert_eq!(program, "/bin/sh");
assert_eq!(args, ["-lc", "printf ready"]);
}
#[test]
fn interactive_shell_uses_the_resolved_image_shell() {
let (program, args) = shell_command("/bin/sh".to_string(), None, true, false);
assert_eq!(program, "/bin/sh");
assert_eq!(args, ["-i"]);
}
#[cfg(unix)]
fn file_mode(path: &Path) -> u32 {
use std::os::unix::fs::PermissionsExt;
@@ -4,7 +4,6 @@
{% block driver %}
[openshell.drivers.docker]
socket_path = "{{ openshell_runtime_socket }}"
default_image = "ghcr.io/nvidia/openshell-community/sandboxes/base:latest"
image_pull_policy = "if_not_present"
sandbox_label = "tmachine"
grpc_endpoint = "http://127.0.0.1:17670"
@@ -4,7 +4,6 @@
{% block driver %}
[openshell.drivers.podman]
socket_path = "{{ openshell_runtime_socket }}"
default_image = "ghcr.io/nvidia/openshell-community/sandboxes/base:latest"
image_pull_policy = "if_not_present"
sandbox_runtime_image = "docker.io/openshell/sandbox:tmachine"
supervisor_image = "docker.io/openshell/supervisor:tmachine"