mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-14 04:59:28 +08:00
89 lines
3.1 KiB
Rust
89 lines
3.1 KiB
Rust
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
#![cfg(feature = "e2e-local-container-driver")]
|
|
|
|
//! GNU Make must launch recipes without changing the workload identity.
|
|
|
|
use openshell_e2e::harness::binary::openshell_cmd;
|
|
use openshell_e2e::harness::container::ImageGuard;
|
|
use openshell_e2e::harness::sandbox::SandboxGuard;
|
|
|
|
const DOCKERFILE: &str = r"FROM ubuntu:24.04
|
|
RUN apt-get update && apt-get install -y --no-install-recommends make python3 \
|
|
&& rm -rf /var/lib/apt/lists/* \
|
|
&& groupadd -g 10002 sandbox \
|
|
&& useradd -u 10001 -g sandbox -m sandbox
|
|
WORKDIR /sandbox
|
|
USER sandbox
|
|
";
|
|
|
|
const RECIPE: &str = r#"set -eu
|
|
test "$(id -u):$(id -g)" = 10001:10002
|
|
/usr/bin/true
|
|
printf 'all: ; @true\n' > /tmp/Makefile
|
|
make -f /tmp/Makefile
|
|
python3 -c 'import os; assert os.getresuid() == (10001,)*3; assert os.getresgid() == (10002,)*3'
|
|
printf 'MAKE_RECIPE_OK\n'
|
|
"#;
|
|
|
|
#[tokio::test]
|
|
async fn make_launches_recipes_as_non_root_oci_user() {
|
|
let context = tempfile::tempdir().expect("create image context");
|
|
let dockerfile = context.path().join("Dockerfile");
|
|
std::fs::write(&dockerfile, DOCKERFILE).expect("write Make workload Dockerfile");
|
|
let image = ImageGuard::build("make-identity", &dockerfile, context.path())
|
|
.expect("build Ubuntu GNU Make image");
|
|
|
|
// A distinct UID and GID ensure each filter uses the correct identity.
|
|
// Start a persistent workload so both canonical launch and exec exercise
|
|
// the filter installed by the real sandbox runtime. Keep the main process
|
|
// alive on failure so the regression retains Make's error output.
|
|
let startup = format!(
|
|
"({RECIPE})\nstatus=$?\nprintf 'MAKE_STARTUP_STATUS=%s\\n' \"$status\"\nsleep infinity"
|
|
);
|
|
let mut sandbox = SandboxGuard::create_keep_with_args(
|
|
&["--from", image.tag(), "--no-tty"],
|
|
&["sh", "-c", &startup],
|
|
"MAKE_STARTUP_STATUS=",
|
|
)
|
|
.await
|
|
.expect("GNU Make recipe must run during workload startup");
|
|
|
|
let output = sandbox
|
|
.exec(&["sh", "-c", RECIPE])
|
|
.await
|
|
.expect("GNU Make recipe must run through sandbox exec");
|
|
assert!(output.contains("MAKE_RECIPE_OK"), "recipe output: {output}");
|
|
assert!(
|
|
sandbox.create_output.contains("MAKE_STARTUP_STATUS=0"),
|
|
"startup recipe failed: {}",
|
|
sandbox.create_output
|
|
);
|
|
|
|
let terminal = openshell_cmd()
|
|
.args([
|
|
"sandbox",
|
|
"exec",
|
|
"--name",
|
|
&sandbox.name,
|
|
"--tty",
|
|
"--",
|
|
"sh",
|
|
"-c",
|
|
RECIPE,
|
|
])
|
|
.stdin(std::process::Stdio::null())
|
|
.output()
|
|
.await
|
|
.expect("run GNU Make with a terminal");
|
|
assert!(
|
|
terminal.status.success(),
|
|
"terminal recipe failed: {}{}",
|
|
String::from_utf8_lossy(&terminal.stdout),
|
|
String::from_utf8_lossy(&terminal.stderr)
|
|
);
|
|
assert!(String::from_utf8_lossy(&terminal.stdout).contains("MAKE_RECIPE_OK"));
|
|
sandbox.cleanup().await;
|
|
}
|