diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 606b5c0..9fb11fd 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"] readme = "README.md" [dependencies] -clap.workspace = true +clap = { workspace = true, features=["env"] } color-eyre.workspace = true displaydoc.workspace = true serde.workspace = true diff --git a/cli/src/cli.rs b/cli/src/cli.rs index a48b570..6518533 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -27,6 +27,11 @@ pub struct Cli { #[clap(flatten)] pub verbose: Verbosity, + /// Enable mock SGX mode for testing purposes. + /// This flag disables the use of an Intel SGX processor and allows the system to run without remote attestations. + #[clap(long, env)] + pub mock_sgx: bool, + /// Main command #[command(subcommand)] pub command: Command, @@ -36,8 +41,28 @@ pub struct Cli { pub enum Command { /// Create an empty Quartz app from a template Init { - /// path to create & init a quartz app, defaults to current path if unspecified + /// path to create & init a Quartz app, defaults to current path if unspecified #[clap(long)] path: Option, }, + /// Subcommands for handling the Quartz app enclave + Enclave { + #[command(subcommand)] + enclave_command: EnclaveCommand, + }, } + +#[derive(Debug, Clone, Subcommand)] +pub enum EnclaveCommand { + /// Build the Quartz app's enclave + Build { + /// path to Cargo.toml file of the Quartz app's enclave package, defaults to './enclave/Cargo.toml' if unspecified + #[arg(long, default_value = "./enclave/Cargo.toml")] + manifest_path: PathBuf, + }, + // Run the Quartz app's enclave + Start { + #[clap(long)] + path: Option, + }, +} \ No newline at end of file diff --git a/cli/src/error.rs b/cli/src/error.rs index 18b2efe..c43012e 100644 --- a/cli/src/error.rs +++ b/cli/src/error.rs @@ -5,4 +5,6 @@ use thiserror::Error; pub enum Error { /// specified path `{0}` is not a directory PathNotDir(String), + /// {0} + GenericErr(String), } diff --git a/cli/src/handler.rs b/cli/src/handler.rs index 8377c68..85916c7 100644 --- a/cli/src/handler.rs +++ b/cli/src/handler.rs @@ -1,21 +1,23 @@ -use crate::{cli::Verbosity, error::Error, request::Request, response::Response}; +use crate::{error::Error, request::Request, response::Response, Config}; +pub mod enclave_build; pub mod init; pub trait Handler { type Error; type Response; - fn handle(self, verbosity: Verbosity) -> Result; + fn handle(self, config: Config) -> Result; } impl Handler for Request { type Error = Error; type Response = Response; - fn handle(self, verbosity: Verbosity) -> Result { + fn handle(self, config: Config) -> Result { match self { - Request::Init(request) => request.handle(verbosity), + Request::Init(request) => request.handle(config), + Request::EnclaveBuild(request) => request.handle(config), } .map(Into::into) } diff --git a/cli/src/handler/enclave_build.rs b/cli/src/handler/enclave_build.rs new file mode 100644 index 0000000..aa7eb74 --- /dev/null +++ b/cli/src/handler/enclave_build.rs @@ -0,0 +1,42 @@ +use std::process::Command; + +use tracing::{debug, trace}; + +use crate::{ + error::Error, + handler::Handler, + request::enclave_build::EnclaveBuildRequest, + response::{enclave_build::EnclaveBuildResponse, Response}, + Config, +}; + +impl Handler for EnclaveBuildRequest { + type Error = Error; + type Response = Response; + + fn handle(self, config: Config) -> Result { + let mut cargo = Command::new("cargo"); + let command = cargo + .args(["build", "--release"]) + .args(["--manifest-path", &self.manifest_path.display().to_string()]); + + if config.mock_sgx { + debug!("Building with mock-sgx enabled"); + command.arg("--features=mock-sgx"); + } + + trace!("🚧 Building enclave ..."); + let status = command + .status() + .map_err(|e| Error::GenericErr(e.to_string()))?; + + if !status.success() { + return Err(Error::GenericErr(format!( + "Couldn't build enclave. {:?}", + status + ))); + } + + Ok(EnclaveBuildResponse.into()) + } +} diff --git a/cli/src/handler/init.rs b/cli/src/handler/init.rs index e7f251f..cd672b9 100644 --- a/cli/src/handler/init.rs +++ b/cli/src/handler/init.rs @@ -1,15 +1,14 @@ use tracing::trace; use crate::{ - cli::Verbosity, error::Error, handler::Handler, request::init::InitRequest, - response::init::InitResponse, + error::Error, handler::Handler, request::init::InitRequest, response::Response, Config, }; impl Handler for InitRequest { type Error = Error; - type Response = InitResponse; + type Response = Response; - fn handle(self, _verbosity: Verbosity) -> Result { + fn handle(self, _config: Config) -> Result { trace!("initializing directory structure..."); todo!() } diff --git a/cli/src/main.rs b/cli/src/main.rs index 9288ca9..4a0889b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -25,6 +25,10 @@ use tracing_subscriber::{util::SubscriberInitExt, EnvFilter}; use crate::{cli::Cli, handler::Handler, request::Request}; +pub struct Config { + pub mock_sgx: bool, +} + fn main() -> Result<()> { color_eyre::install()?; @@ -48,7 +52,9 @@ fn main() -> Result<()> { // Each `Request` defines an associated `Handler` (i.e. logic) and `Response`. All handlers are // free to log to the terminal and these logs are sent to `stderr`. - let response = request.handle(args.verbose)?; + let response = request.handle(Config { + mock_sgx: args.mock_sgx, + })?; // `Handlers` must use `Responses` to output to `stdout`. println!( diff --git a/cli/src/request.rs b/cli/src/request.rs index 07b90a7..b698d0c 100644 --- a/cli/src/request.rs +++ b/cli/src/request.rs @@ -1,10 +1,16 @@ -use crate::{cli::Command, error::Error, request::init::InitRequest}; +use crate::{ + cli::{Command, EnclaveCommand}, + error::Error, + request::{enclave_build::EnclaveBuildRequest, init::InitRequest}, +}; +pub mod enclave_build; pub mod init; #[derive(Clone, Debug)] pub enum Request { Init(InitRequest), + EnclaveBuild(EnclaveBuildRequest), } impl TryFrom for Request { @@ -12,8 +18,13 @@ impl TryFrom for Request { fn try_from(cmd: Command) -> Result { match cmd { - Command::Init { path } => InitRequest::try_from(path), + Command::Init { path } => InitRequest::try_from(path).map(Into::into), + Command::Enclave { enclave_command } => match enclave_command { + EnclaveCommand::Build { manifest_path } => { + Ok(EnclaveBuildRequest { manifest_path }.into()) + } + _ => todo!(), + }, } - .map(Into::into) } } diff --git a/cli/src/request/enclave_build.rs b/cli/src/request/enclave_build.rs new file mode 100644 index 0000000..f7e9629 --- /dev/null +++ b/cli/src/request/enclave_build.rs @@ -0,0 +1,14 @@ +use std::path::PathBuf; + +use crate::request::Request; + +#[derive(Clone, Debug)] +pub struct EnclaveBuildRequest { + pub manifest_path: PathBuf, +} + +impl From for Request { + fn from(request: EnclaveBuildRequest) -> Self { + Self::EnclaveBuild(request) + } +} diff --git a/cli/src/response.rs b/cli/src/response.rs index 5e53a5d..2509121 100644 --- a/cli/src/response.rs +++ b/cli/src/response.rs @@ -1,10 +1,12 @@ use serde::Serialize; -use crate::response::init::InitResponse; +use crate::response::{enclave_build::EnclaveBuildResponse, init::InitResponse}; +pub mod enclave_build; pub mod init; #[derive(Clone, Debug, Serialize)] pub enum Response { Init(InitResponse), + EnclaveBuild(EnclaveBuildResponse), } diff --git a/cli/src/response/enclave_build.rs b/cli/src/response/enclave_build.rs new file mode 100644 index 0000000..c904076 --- /dev/null +++ b/cli/src/response/enclave_build.rs @@ -0,0 +1,12 @@ +use serde::Serialize; + +use crate::response::Response; + +#[derive(Clone, Debug, Serialize)] +pub struct EnclaveBuildResponse; + +impl From for Response { + fn from(response: EnclaveBuildResponse) -> Self { + Self::EnclaveBuild(response) + } +}