#![deny(missing_docs)]
#![deny(warnings)]
use clap::ArgMatches;
use libc::VMADDR_CID_HOST;
#[cfg(test)]
use libc::VMADDR_CID_LOCAL;
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::str::FromStr;
use crate::common::{NitroCliErrorEnum, NitroCliFailure, NitroCliResult, VMADDR_CID_PARENT};
use crate::get_id_by_name;
use crate::new_nitro_cli_failure;
use crate::utils::PcrType;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunEnclavesArgs {
pub eif_path: String,
pub enclave_cid: Option<u64>,
pub memory_mib: u64,
pub cpu_ids: Option<Vec<u32>>,
#[serde(default)]
pub debug_mode: bool,
#[serde(default)]
pub attach_console: bool,
pub cpu_count: Option<u32>,
pub enclave_name: Option<String>,
}
impl RunEnclavesArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
if let Some(config_file) = args.get_one::<String>("config") {
let file = File::open(config_file).map_err(|err| {
new_nitro_cli_failure!(
&format!("Failed to open config file: {err:?}"),
NitroCliErrorEnum::FileOperationFailure
)
.add_info(vec![config_file, "Open"])
})?;
let mut json: RunEnclavesArgs = serde_json::from_reader(file).map_err(|err| {
new_nitro_cli_failure!(
&format!("Invalid JSON format for config file: {err:?}"),
NitroCliErrorEnum::SerdeError
)
})?;
if json.cpu_count.is_none() && json.cpu_ids.is_none() {
return Err(new_nitro_cli_failure!(
"Missing both `cpu-count` and `cpu-ids`",
NitroCliErrorEnum::MissingArgument
));
}
if json.cpu_count.is_some() && json.cpu_ids.is_some() {
return Err(new_nitro_cli_failure!(
"`cpu-count` and `cpu-ids` cannot be used together",
NitroCliErrorEnum::ConflictingArgument
));
}
json.debug_mode = json.debug_mode || json.attach_console;
Ok(json)
} else {
Ok(RunEnclavesArgs {
cpu_count: parse_cpu_count(args)
.map_err(|err| err.add_subaction("Parse CPU count".to_string()))?,
eif_path: parse_eif_path(args)
.map_err(|err| err.add_subaction("Parse EIF path".to_string()))?,
enclave_cid: parse_enclave_cid(args)
.map_err(|err| err.add_subaction("Parse enclave CID".to_string()))?,
memory_mib: parse_memory(args)
.map_err(|err| err.add_subaction("Parse memory".to_string()))?,
cpu_ids: parse_cpu_ids(args)
.map_err(|err| err.add_subaction("Parse CPU IDs".to_string()))?,
debug_mode: debug_mode(args),
attach_console: attach_console(args),
enclave_name: parse_enclave_name(args)
.map_err(|err| err.add_subaction("Parse enclave name".to_string()))?,
})
}
}
}
#[derive(Debug, Clone)]
pub struct BuildEnclavesArgs {
pub docker_uri: String,
pub docker_dir: Option<String>,
pub output: String,
pub signing_certificate: Option<String>,
pub private_key: Option<String>,
pub img_name: Option<String>,
pub img_version: Option<String>,
pub metadata: Option<String>,
}
impl BuildEnclavesArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
Ok(BuildEnclavesArgs {
docker_uri: parse_docker_tag(args).ok_or_else(|| {
new_nitro_cli_failure!(
"`docker-uri` argument not found",
NitroCliErrorEnum::MissingArgument
)
.add_info(vec!["docker-uri"])
})?,
docker_dir: parse_docker_dir(args),
output: parse_output(args).ok_or_else(|| {
new_nitro_cli_failure!(
"`output` argument not found",
NitroCliErrorEnum::MissingArgument
)
.add_info(vec!["output"])
})?,
signing_certificate: parse_signing_certificate(args),
private_key: parse_private_key(args),
img_name: parse_image_name(args),
img_version: parse_image_version(args),
metadata: parse_metadata(args),
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerminateEnclavesArgs {
pub enclave_id: String,
}
impl TerminateEnclavesArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
match parse_enclave_name(args)
.map_err(|e| e.add_subaction("Parse Enclave Name".to_string()))?
{
Some(name) => Ok(TerminateEnclavesArgs {
enclave_id: get_id_by_name(name)
.map_err(|e| e.add_subaction("Get ID by Name".to_string()))?,
}),
None => Ok(TerminateEnclavesArgs {
enclave_id: parse_enclave_id(args)
.map_err(|e| e.add_subaction("Parse enclave ID".to_string()))?,
}),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConsoleArgs {
pub enclave_id: String,
pub disconnect_timeout_sec: Option<u64>,
}
impl ConsoleArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
let enclave_id = match parse_enclave_name(args)
.map_err(|e| e.add_subaction("Parse Enclave Name".to_string()))?
{
Some(name) => {
get_id_by_name(name).map_err(|e| e.add_subaction("Get ID by Name".to_string()))?
}
None => parse_enclave_id(args)
.map_err(|e| e.add_subaction("Parse enclave ID".to_string()))?,
};
Ok(ConsoleArgs {
enclave_id,
disconnect_timeout_sec: parse_disconnect_timeout(args)
.map_err(|e| e.add_subaction("Parse disconnect timeout".to_string()))?,
})
}
}
#[derive(Serialize, Deserialize)]
pub struct EmptyArgs {}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DescribeEnclavesArgs {
pub metadata: bool,
}
impl DescribeEnclavesArgs {
pub fn new_with(args: &ArgMatches) -> Self {
DescribeEnclavesArgs {
metadata: args.get_flag("metadata"),
}
}
}
#[derive(Debug, Clone)]
pub struct ExplainArgs {
pub error_code_str: String,
}
impl ExplainArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
Ok(ExplainArgs {
error_code_str: parse_error_code_str(args)
.map_err(|e| e.add_subaction("Parse error code".to_string()))?,
})
}
}
pub struct PcrArgs {
pub path: String,
pub pcr_type: PcrType,
}
impl PcrArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
let (val_name, pcr_type) = match args.contains_id("signing-certificate") {
true => ("signing-certificate", PcrType::SigningCertificate),
false => ("input", PcrType::DefaultType),
};
let path = parse_file_path(args, val_name)
.map_err(|e| e.add_subaction("Parse PCR file".to_string()))?;
Ok(Self { path, pcr_type })
}
}
#[derive(Debug, Clone)]
pub struct SignEifArgs {
pub eif_path: String,
pub signing_certificate: Option<String>,
pub private_key: Option<String>,
}
impl SignEifArgs {
pub fn new_with(args: &ArgMatches) -> NitroCliResult<Self> {
let signing_certificate = parse_signing_certificate(args);
let private_key = parse_private_key(args);
Ok(SignEifArgs {
eif_path: parse_eif_path(args)
.map_err(|e| e.add_subaction("Parse EIF path".to_string()))?,
signing_certificate,
private_key,
})
}
}
fn parse_file_path(args: &ArgMatches, val_name: &str) -> NitroCliResult<String> {
let path = args.get_one::<String>(val_name).ok_or_else(|| {
new_nitro_cli_failure!(
"`input` or `signing-certificate` argument not found",
NitroCliErrorEnum::MissingArgument
)
})?;
Ok(path.into())
}
#[derive(Debug)]
enum MemoryUnit {
Mebibytes,
Gibibytes,
Tebibytes,
}
#[derive(Debug)]
struct UnknownMemoryUnitErr;
impl MemoryUnit {
fn to_mebibytes(&self) -> u64 {
match self {
MemoryUnit::Mebibytes => 1,
MemoryUnit::Gibibytes => 1024,
MemoryUnit::Tebibytes => 1024 * 1024,
}
}
}
impl FromStr for MemoryUnit {
type Err = UnknownMemoryUnitErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"M" | "m" | "" => Ok(MemoryUnit::Mebibytes),
"G" | "g" => Ok(MemoryUnit::Gibibytes),
"T" | "t" => Ok(MemoryUnit::Tebibytes),
_ => Err(UnknownMemoryUnitErr),
}
}
}
pub fn parse_memory(args: &ArgMatches) -> NitroCliResult<u64> {
let memory = args.get_one::<String>("memory").ok_or_else(|| {
new_nitro_cli_failure!(
"`memory` argument not found",
NitroCliErrorEnum::MissingArgument
)
})?;
let (num_str, size_str) = match memory.find(|c: char| !c.is_numeric()) {
Some(index) => memory.split_at(index),
None => (memory.as_str(), ""),
};
let num = num_str.parse::<u64>().map_err(|_| {
new_nitro_cli_failure!(
"`memory` argument does not contain a number",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["memory", memory])
})?;
let unit = size_str.parse::<MemoryUnit>().map_err(|_| {
new_nitro_cli_failure!(
"`memory` argument does not contain a valid size indicator",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["memory", memory])
})?;
Ok(num * unit.to_mebibytes())
}
fn parse_docker_tag(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("docker-uri").map(String::from)
}
fn parse_docker_dir(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("docker-dir").map(String::from)
}
fn parse_enclave_cid(args: &ArgMatches) -> NitroCliResult<Option<u64>> {
let enclave_cid = if let Some(enclave_cid) = args.get_one::<String>("enclave-cid") {
let enclave_cid: u64 = enclave_cid.parse().map_err(|_| {
new_nitro_cli_failure!(
"`enclave-cid` is not a number",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["enclave-cid", enclave_cid])
})?;
if enclave_cid == 0 {
eprintln!("The enclave CID will be auto-generated as the provided CID is 0");
}
if enclave_cid > 0 && enclave_cid <= VMADDR_CID_HOST as u64 {
return Err(new_nitro_cli_failure!(
&format!("CID {enclave_cid} is a well-known CID, not to be used for enclaves"),
NitroCliErrorEnum::InvalidArgument
));
}
if enclave_cid == u32::MAX as u64 {
return Err(new_nitro_cli_failure!(
&format!("CID {enclave_cid} is a well-known CID, not to be used for enclaves"),
NitroCliErrorEnum::InvalidArgument
));
}
if enclave_cid == VMADDR_CID_PARENT as u64 {
return Err(new_nitro_cli_failure!(
&format!(
"CID {enclave_cid} is the CID of the parent VM, not to be used for enclaves"
),
NitroCliErrorEnum::InvalidArgument
));
}
if enclave_cid > u32::MAX as u64 {
return Err(new_nitro_cli_failure!(
&format!(
"CID {enclave_cid} is higher than the maximum supported (u32 max) for a vsock device"
),
NitroCliErrorEnum::InvalidArgument
));
}
Some(enclave_cid)
} else {
None
};
Ok(enclave_cid)
}
fn parse_eif_path(args: &ArgMatches) -> NitroCliResult<String> {
let eif_path = args.get_one::<String>("eif-path").ok_or_else(|| {
new_nitro_cli_failure!(
"`eif-path` argument not found",
NitroCliErrorEnum::MissingArgument
)
})?;
Ok(eif_path.into())
}
fn parse_enclave_id(args: &ArgMatches) -> NitroCliResult<String> {
let enclave_id = args.get_one::<String>("enclave-id").ok_or_else(|| {
new_nitro_cli_failure!(
"`enclave-id` argument not found",
NitroCliErrorEnum::MissingArgument
)
})?;
Ok(enclave_id.into())
}
fn parse_disconnect_timeout(args: &ArgMatches) -> NitroCliResult<Option<u64>> {
let disconnect_timeout = match args.get_one::<String>("disconnect-timeout") {
Some(arg) => Some(arg.parse::<u64>().map_err(|_| {
new_nitro_cli_failure!(
"`disconnect-timeout` argument can't be parsed as a number",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["disconnect-timeout", arg])
})?),
None => None,
};
Ok(disconnect_timeout)
}
fn parse_cpu_ids(args: &ArgMatches) -> NitroCliResult<Option<Vec<u32>>> {
args.get_many::<String>("cpu-ids")
.map(|values| {
values
.map(|id| {
id.parse().map_err(|_| {
new_nitro_cli_failure!(
"`cpu-id` is not a number",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["cpu-id", id])
})
})
.collect()
})
.transpose()
}
fn parse_cpu_count(args: &ArgMatches) -> NitroCliResult<Option<u32>> {
args.get_one::<String>("cpu-count")
.map(|count| {
count.parse().map_err(|_| {
new_nitro_cli_failure!(
"`cpu-count` is not a number",
NitroCliErrorEnum::InvalidArgument
)
.add_info(vec!["cpu-count", count])
})
})
.transpose()
}
fn parse_output(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("output-file").map(String::from)
}
fn debug_mode(args: &ArgMatches) -> bool {
args.get_flag("debug-mode") || args.get_flag("attach-console")
}
fn attach_console(args: &ArgMatches) -> bool {
args.get_flag("attach-console")
}
fn parse_enclave_name(args: &ArgMatches) -> NitroCliResult<Option<String>> {
Ok(args.get_one::<String>("enclave-name").map(String::from))
}
fn parse_signing_certificate(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("signing-certificate")
.map(String::from)
}
fn parse_private_key(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("private-key").map(String::from)
}
fn parse_image_name(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("image_name").map(String::from)
}
fn parse_image_version(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("image_version").map(String::from)
}
fn parse_metadata(args: &ArgMatches) -> Option<String> {
args.get_one::<String>("metadata").map(String::from)
}
fn parse_error_code_str(args: &ArgMatches) -> NitroCliResult<String> {
let error_code_str = args.get_one::<String>("error-code").ok_or_else(|| {
new_nitro_cli_failure!(
"`error-code` argument not found",
NitroCliErrorEnum::MissingArgument
)
})?;
Ok(error_code_str.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::construct_error_message;
use crate::create_app;
use clap::{Arg, Command};
fn parse_config_file(args: &ArgMatches) -> NitroCliResult<String> {
let config_file = args
.get_one::<String>("config")
.ok_or(new_nitro_cli_failure!(
"`config` argument not found",
NitroCliErrorEnum::MissingArgument
))?;
Ok(config_file.into())
}
#[test]
fn test_parse_memory() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256_mb",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_memory(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"))
}
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_memory(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert_eq!(result, Ok(256));
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"100M",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_memory(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert_eq!(result, Ok(100));
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"10G",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_memory(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert_eq!(result, Ok(10_240));
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"2T",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_memory(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert_eq!(result, Ok(2 * 1024 * 1024));
}
#[test]
fn test_parse_docker_tag() {
let app = create_app!();
let args = vec![
"nitro-cli",
"build-enclave",
"--docker-uri",
"mytag",
"--docker-dir",
"/home/user/non_existing_dir",
"--output-file",
"sample_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_docker_tag(
matches
.as_ref()
.unwrap()
.subcommand_matches("build-enclave")
.unwrap(),
);
assert!(result.is_some());
assert_eq!(result.unwrap(), "mytag");
}
#[test]
fn test_parse_docker_dir() {
let app = create_app!();
let args = vec![
"nitro-cli",
"build-enclave",
"--docker-uri",
"mytag",
"--docker-dir",
"/home/user/non_existing_dir",
"--output-file",
"sample_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_docker_dir(
matches
.as_ref()
.unwrap()
.subcommand_matches("build-enclave")
.unwrap(),
);
assert!(result.is_some());
assert_eq!(result.unwrap(), "/home/user/non_existing_dir");
}
#[test]
fn test_parse_enclave_cid_correct() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
"10",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
if let Some(parsed_cid) = result.unwrap() {
assert_eq!(parsed_cid, 10);
}
}
#[test]
fn test_parse_enclave_cid_to_be_autogenerated() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
"0",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
if let Some(parsed_cid) = result.unwrap() {
assert_eq!(parsed_cid, 0);
}
}
#[test]
fn test_parse_enclave_cid_str() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
"0x1g",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"))
}
}
#[test]
fn test_parse_enclave_cid_well_known_cid_local() {
let app = create_app!();
let cid_local = VMADDR_CID_LOCAL.to_string();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
&cid_local,
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"));
}
}
#[test]
fn test_parse_enclave_cid_well_known_cid_host() {
let app = create_app!();
let cid_host = VMADDR_CID_HOST.to_string();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
&cid_host,
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"));
}
}
#[test]
fn test_parse_enclave_cid_parent_vm() {
let app = create_app!();
let parent_vm_cid = VMADDR_CID_PARENT.to_string();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
&parent_vm_cid,
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_cid(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"));
}
}
#[test]
fn test_parse_enclave_cid_negative() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--enclave-cid",
"-18",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_err());
}
#[test]
fn test_parse_eif_path() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"256",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_eif_path(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "non_existing_eif.eif");
}
#[test]
fn test_parse_enclave_id() {
let app = create_app!();
let args = vec![
"nitro-cli",
"terminate-enclave",
"--enclave-id",
"i-0000-enc-1234",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_enclave_id(
matches
.as_ref()
.unwrap()
.subcommand_matches("terminate-enclave")
.unwrap(),
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "i-0000-enc-1234");
}
#[test]
fn test_parse_cpu_ids_correct() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--cpu-ids",
"1",
"3",
"--eif-path",
"non_existing_eif.eif",
"--memory",
"64",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_cpu_ids(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
if let Some(parsed_cpu_ids) = result.unwrap() {
assert_eq!(parsed_cpu_ids.len(), 2);
assert_eq!(parsed_cpu_ids[0], 1);
assert_eq!(parsed_cpu_ids[1], 3);
}
}
#[test]
fn test_parse_cpu_ids_negative() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--cpu-ids",
"1",
"-5",
"--eif-path",
"non_existing_eif.eif",
"--memory 64",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_err());
}
#[test]
fn test_parse_cpu_ids_str() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--cpu-ids",
"1",
"three",
"--eif-path",
"non_existing_eif.eif",
"--memory",
"64",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_cpu_ids(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"));
}
}
#[test]
fn test_parse_cpu_count_correct() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--memory",
"64",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_cpu_count(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
if let Some(parsed_cpu_count) = result.unwrap() {
assert_eq!(parsed_cpu_count, 2);
}
}
#[test]
fn test_parse_cpu_count_str() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--cpu-count",
"2n",
"--eif-path",
"non_existing_eif.eif",
"--memory",
"64",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_cpu_count(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_err());
if let Err(err_info) = result {
let err_str = construct_error_message(&err_info);
assert!(err_str.contains("Invalid argument provided"));
}
}
#[test]
fn test_parse_output() {
let app = create_app!();
let args = vec![
"nitro-cli",
"build-enclave",
"--docker-uri",
"mytag",
"--docker-dir",
"/home/user/non_existing_dir",
"--output-file",
"sample_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_output(
matches
.as_ref()
.unwrap()
.subcommand_matches("build-enclave")
.unwrap(),
);
assert!(result.is_some());
assert_eq!(result.unwrap(), "sample_eif.eif");
}
#[test]
fn test_parse_output_not_supplied() {
let app = create_app!();
let args = vec![
"nitro-cli",
"build-enclave",
"--docker-uri",
"mytag",
"--docker-dir",
"/home/user/non_existing_dir",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_err());
}
#[test]
fn test_debug_mode_supplied() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"64",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
"--debug-mode",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = debug_mode(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result);
}
#[test]
fn test_debug_mode_not_supplied() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--memory",
"64",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = debug_mode(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(!result);
}
#[test]
fn test_attach_console_supplied() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--attach-console",
"--memory",
"64",
"--cpu-count",
"2",
"--eif-path",
"non_existing_eif.eif",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let matches = matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap();
let attach_console = attach_console(matches);
let debug_mode = debug_mode(matches);
assert!(attach_console);
assert!(debug_mode);
}
#[test]
fn test_parse_json_config() {
let app = create_app!();
let args = vec![
"nitro-cli",
"run-enclave",
"--config",
"non_existing_config.json",
];
let matches = app.try_get_matches_from(args);
assert!(matches.is_ok());
let result = parse_config_file(
matches
.as_ref()
.unwrap()
.subcommand_matches("run-enclave")
.unwrap(),
);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "non_existing_config.json");
}
}