use std::process::{Command, Output}; fn run(source: &str, args: &[&str]) -> (tempfile::TempDir, Output) { let dir = tempfile::tempdir().unwrap(); std::fs::write(dir.path().join("main.ts"), source).unwrap(); let output = Command::new(env!("CARGO_BIN_EXE_avril")) .current_dir(dir.path()) .arg("run") .args(args) .arg("main.ts") .output() .unwrap(); (dir, output) } fn success(output: &Output) -> String { assert!( output.status.success(), "{}", String::from_utf8_lossy(&output.stderr) ); String::from_utf8(output.stdout.clone()).unwrap() } #[test] fn process_and_runtime_report_this_host() { let (dir, output) = run( r#" import { process, runtime } from 'avril:std'; console.log(process.pid > 0, process.cwd(), process.hostname().length > 0, process.osRelease().length > 0, process.uptime() >= 0, process.loadavg().length === 3, process.loadavg().every((value) => value >= 0)); console.log(runtime.os, runtime.arch, runtime.version, runtime.v8.length > 0); console.log(Object.isFrozen(process), Object.isFrozen(runtime)); "#, &[], ); let text = success(&output); let lines: Vec<&str> = text.lines().collect(); assert_eq!(lines.len(), 3); assert_eq!( lines[0], format!( "true {} true true true true true", dir.path().canonicalize().unwrap().display() ) ); assert_eq!( lines[1], format!( "{} {} {} true", std::env::consts::OS, std::env::consts::ARCH, env!("CARGO_PKG_VERSION") ) ); assert_eq!(lines[2], "true true"); } #[test] fn sys_and_cwd_are_gated_independently() { let (_dir, output) = run( r#" import { errors, process, runtime } from 'avril:std'; function denied(call) { try { call(); return false; } catch (error) { return error instanceof errors.PermissionDenied; } } console.log(process.pid > 0, runtime.os.length > 0); console.log(denied(() => process.cwd()), denied(() => process.hostname()), process.uptime() >= 0, denied(() => process.loadavg())); "#, &["-0", "--allow-sys=uptime"], ); assert_eq!(success(&output), "true true\ntrue true true true\n"); } #[test] fn grants_and_pledges_narrow_sys_and_cwd() { let (_dir, output) = run( r#" import { pledge, process } from 'avril:std'; function denied(call) { try { call(); return false; } catch (error) { return error.name === 'PermissionDenied'; } } console.log(process.cwd().length > 0, process.hostname().length > 0); pledge({ sys: { allow: ['hostname'] } }); console.log(process.hostname().length > 0, denied(() => process.osRelease()), denied(() => process.uptime())); pledge({ read: false }); console.log(denied(() => process.cwd()), process.hostname().length > 0); pledge({ sys: false }); console.log(denied(() => process.hostname())); try { pledge({ sys: { allow: ['bogus'] } }); console.log('accepted'); } catch (error) { console.log(error instanceof TypeError); } "#, &[], ); assert_eq!( success(&output), "true true\ntrue true true\ntrue true\ntrue\ntrue\n" ); } #[test] fn unknown_sys_names_are_rejected_at_startup() { let (_dir, output) = run( "import { process } from 'avril:std'; console.log(process.hostname());", &["-0", "--allow-sys=bogus"], ); assert!(!output.status.success()); assert!( String::from_utf8_lossy(&output.stderr).contains("Unknown system information name: bogus"), "{}", String::from_utf8_lossy(&output.stderr) ); }