kcode-k1-web-podman 0.1.2

Fresh rootless Podman execution leaf for one K1 Web check.
Documentation
use super::*;
use tempfile::tempdir;

fn report() -> Vec<u8> {
    format!(concat!(
        "{{\"schema\":{schema},\"outcome\":{{\"kind\":\"success\"}},\"diagnostics\":",
        "{{\"browser_stdout\":[],\"browser_stderr\":[],\"browser_exit\":null,\"page_error\":null,\"server_errors\":[],\"cleanup_errors\":[]}},",
        "\"timings\":{{\"validation_ms\":0,\"server_ms\":0,\"browser_ms\":0,\"cleanup_ms\":0,\"total_ms\":0}}}}\n"
    ), schema = SCHEMA_VERSION).into_bytes()
}

fn executable(path: &Path, contents: &str) {
    fs::write(path, contents).unwrap();
    fs::set_permissions(path, fs::Permissions::from_mode(0o700)).unwrap();
}

fn quote(path: &Path) -> String {
    format!("'{}'", path.display())
}

#[test]
fn frozen_command_mounts_both_views_and_routes_only_admitted() {
    let root = tempdir().unwrap();
    let path = |name| root.path().join(name);
    let podman_path = path("podman");
    let checker = path("checker");
    let candidate = path("candidate");
    let admitted = path("admitted");
    let public = path("public");
    let log = path("log");
    let request = path("request");
    let output = path("output");
    for directory in [&candidate, &admitted, &public] {
        fs::create_dir(directory).unwrap();
    }
    fs::write(&output, report()).unwrap();
    executable(&checker, "#!/bin/sh\nexit 2\n");
    let script = format!(
        "#!/bin/sh\nprintf 'CALL\\n' >> {0}\nprintf '%s\\n' \"$@\" >> {0}\ncat > {1}\ncat {2}\nprintf diagnostic >&2\nexit 0\n",
        quote(&log),
        quote(&request),
        quote(&output),
    );
    executable(&podman_path, &script);
    let config = WebPodmanConfig {
        podman: podman_path,
        image: format!("registry.invalid/checker@sha256:{}", "a".repeat(64)),
        checker: checker.clone(),
        chromium: PathBuf::from("/usr/bin/chromium"),
        chromium_version: "123.4".to_owned(),
        cpu_millis: 1000,
        memory_bytes: 268_435_456,
        pids_limit: 64,
        tmpfs_bytes: 67_108_864,
        shm_bytes: 67_108_864,
        checker_timeout: Duration::from_millis(100),
        wall_timeout: Duration::from_secs(2),
    };
    let podman = WebPodman::new(config).unwrap();
    let input = || CheckInput {
        candidate: WebIdInput {
            authority: "0".repeat(24),
            name: "demo".to_owned(),
            version: "1.0.0".to_owned(),
        },
        candidate_root: candidate.clone(),
        projection_root: admitted.clone(),
        entry: "entry.js".to_owned(),
        tests: "tests.js".to_owned(),
        selections: Vec::new(),
    };
    podman.check_frozen(input(), &public).unwrap();
    let fixed = [
        "--remote=false",
        "run",
        "--rm",
        "--pull=never",
        "--network=none",
        "--read-only",
        "--userns=keep-id",
        "--cap-drop=ALL",
        "--security-opt=no-new-privileges",
        "--http-proxy=false",
        "--ipc=private",
        "--workdir=/tmp",
        "--env=HOME=/tmp/home",
        "--env=TMPDIR=/tmp",
        "--cpus=1.000",
        "--memory=268435456",
        "--memory-swap=268435456",
        "--pids-limit=64",
        "--tmpfs=/tmp:rw,nosuid,nodev,noexec,size=67108864",
        "--shm-size=67108864",
    ];
    assert_eq!(
        podman
            .args
            .iter()
            .map(|value| value.to_str().unwrap())
            .collect::<Vec<_>>(),
        fixed
    );
    let expected = format!(
        "CALL\n{}\n--volume\n{}:{}:{}\n--volume\n{}:{}:{}\n--volume\n{}:{}:{}\n--volume\n{}:{}:{}\n--\n{}\n{}\n",
        fixed.join("\n"),
        candidate.display(),
        CANDIDATE,
        DATA_OPTIONS,
        admitted.display(),
        ADMITTED,
        DATA_OPTIONS,
        public.display(),
        PROJECTION,
        DATA_OPTIONS,
        checker.display(),
        CHECKER,
        CHECKER_OPTIONS,
        podman.config.image,
        CHECKER,
    );
    assert_eq!(fs::read_to_string(&log).unwrap(), expected);
    let request =
        kcode_k1_web_checker_protocol::decode_request(&fs::read(&request).unwrap()).unwrap();
    assert_eq!(request.candidate_root, Path::new(CANDIDATE));
    assert_eq!(request.projection_root, Path::new(ADMITTED));
    assert_ne!(
        podman.command_policy_identity(),
        podman.frozen_command_policy_identity()
    );
    assert!(matches!(
        podman.check_frozen(input(), &admitted),
        Err(WebPodmanError::InvalidInput { field: "paths", .. })
    ));
}