diff --git a/.cargo/config.toml b/.cargo/config.toml index 16ffd9ddd66272691827108c29444b998a9ee51d..cfedd0addb30fb62320b1a21e59cf3242ece0c3f 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -22,3 +22,84 @@ registry = "https://code.aliyun.com/rustcc/crates.io-index.git" [net] git-fetch-with-cli = true + +# add the below section to `.cargo/config.toml` + +[target.'cfg(all())'] +rustflags = [ + # BEGIN - Embark standard lints v6 for Rust 1.55+ + # do not change or add/remove here, but one can add exceptions after this section + # for more info see: + # "-Dunsafe_code", + "-Wclippy::all", + "-Wclippy::await_holding_lock", + "-Wclippy::char_lit_as_u8", + "-Wclippy::checked_conversions", + "-Wclippy::dbg_macro", + "-Wclippy::debug_assert_with_mut_call", + "-Wclippy::doc_markdown", + "-Wclippy::empty_enum", + "-Wclippy::enum_glob_use", + "-Wclippy::exit", + "-Wclippy::expl_impl_clone_on_copy", + "-Wclippy::explicit_deref_methods", + "-Wclippy::explicit_into_iter_loop", + "-Wclippy::fallible_impl_from", + "-Wclippy::filter_map_next", + "-Wclippy::flat_map_option", + "-Wclippy::float_cmp_const", + "-Wclippy::fn_params_excessive_bools", + "-Wclippy::from_iter_instead_of_collect", + "-Wclippy::if_let_mutex", + "-Wclippy::implicit_clone", + "-Wclippy::imprecise_flops", + "-Wclippy::inefficient_to_string", + "-Wclippy::invalid_upcast_comparisons", + "-Wclippy::large_digit_groups", + "-Wclippy::large_stack_arrays", + "-Wclippy::large_types_passed_by_value", + "-Wclippy::let_unit_value", + "-Wclippy::linkedlist", + "-Wclippy::lossy_float_literal", + "-Wclippy::macro_use_imports", + "-Wclippy::manual_ok_or", + "-Wclippy::map_err_ignore", + "-Wclippy::map_flatten", + "-Wclippy::map_unwrap_or", + "-Wclippy::match_on_vec_items", + "-Wclippy::match_same_arms", + "-Wclippy::match_wild_err_arm", + "-Wclippy::match_wildcard_for_single_variants", + "-Wclippy::mem_forget", + "-Wclippy::missing_enforced_import_renames", + "-Wclippy::mut_mut", + "-Wclippy::mutex_integer", + "-Wclippy::needless_borrow", + "-Wclippy::needless_continue", + "-Wclippy::needless_for_each", + "-Wclippy::option_option", + "-Wclippy::path_buf_push_overwrite", + "-Wclippy::ptr_as_ptr", + "-Wclippy::rc_mutex", + "-Wclippy::ref_option_ref", + "-Wclippy::rest_pat_in_fully_bound_structs", + "-Wclippy::same_functions_in_if_condition", + "-Wclippy::semicolon_if_nothing_returned", + "-Wclippy::single_match_else", + "-Wclippy::string_add_assign", + "-Wclippy::string_add", + "-Wclippy::string_lit_as_bytes", + "-Wclippy::string_to_string", + "-Wclippy::todo", + "-Wclippy::trait_duplication_in_bounds", + "-Wclippy::unimplemented", + "-Wclippy::unnested_or_patterns", + "-Wclippy::unused_self", + "-Wclippy::useless_transmute", + "-Wclippy::verbose_file_reads", + "-Wclippy::zero_sized_map_values", + "-Wfuture_incompatible", + "-Wnonstandard_style", + "-Wrust_2018_idioms", + # END - Embark standard lints v6 for Rust 1.55+ +] diff --git a/attestation_agent/agent/src/main.rs b/attestation_agent/agent/src/main.rs index 63b30e510c307b97d242186d4cd98ddc4e5b2dc2..b54384c9be72e181db892899a7c18bab4dd19273 100644 --- a/attestation_agent/agent/src/main.rs +++ b/attestation_agent/agent/src/main.rs @@ -74,7 +74,6 @@ async fn main() -> Result<(), AgentError> { let log_level = match config.logging.level.to_lowercase().as_str() { "debug" => LevelFilter::Debug, - "info" => LevelFilter::Info, "warn" => LevelFilter::Warn, "error" => LevelFilter::Error, "off" => LevelFilter::Off, @@ -134,19 +133,19 @@ async fn main() -> Result<(), AgentError> { Client::configure(client_config)?; - let challenge_config = match config.schedulers.iter().find(|config| config.name == "challenge".to_string()) { - Some(config) => config, - None => { + let challenge_config = + if let Some(config) = config.schedulers.iter().find(|config| config.name == "challenge") { + config + } else { log::error!("Challenge scheduler not found in configuration, skipping challenge initialization"); if let Err(e) = service.stop_server().await { error!("Failed to stop server: {}", e); } return Err(AgentError::ConfigError("Challenge scheduler not configured".to_string())); - }, - }; + }; let initial_delay = - challenge_config.initial_delay.clone().unwrap_or_else(|| InitialDelayConfig { min_seconds: 0, max_seconds: 0 }); + challenge_config.initial_delay.clone().unwrap_or(InitialDelayConfig { min_seconds: 0, max_seconds: 0 }); let max_retries = challenge_config.max_retries.unwrap_or(1); // start scheduler let scheduler_config = SchedulerConfig::new() diff --git a/attestation_agent/agent/src/scheduler.rs b/attestation_agent/agent/src/scheduler.rs index fc1a4bbc159696f0d56d87076450589d3210cec4..e7a9d8d9a21ea913b9f186fd28e8e4530274871a 100644 --- a/attestation_agent/agent/src/scheduler.rs +++ b/attestation_agent/agent/src/scheduler.rs @@ -141,7 +141,7 @@ impl SchedulerConfig { /// Sets the maximum delay before the first execution. /// /// This defines the upper bound of the delay range, where the actual delay will be - /// randomly chosen between min_delay and max_delay. + /// randomly chosen between `min_delay` and `max_delay`. /// /// # Arguments /// @@ -182,7 +182,7 @@ impl SchedulerConfig { /// Sets the maximum delay between retry attempts. /// /// This defines the upper bound of the retry delay range, where the actual delay will be - /// randomly chosen between min_delay and max_delay. + /// randomly chosen between `min_delay` and `max_delay`. /// /// # Arguments /// @@ -319,7 +319,7 @@ struct SingleTaskScheduler { } impl SingleTaskScheduler { - /// Creates a new SingleTaskScheduler with the provided configuration. + /// Creates a new `SingleTaskScheduler` with the provided configuration. /// /// # Arguments /// @@ -327,7 +327,7 @@ impl SingleTaskScheduler { /// /// # Returns /// - /// A new SingleTaskScheduler instance + /// A new `SingleTaskScheduler` instance fn new(config: SchedulerConfig, task: BoxedTask) -> Self { let (tx, rx) = mpsc::channel(3); @@ -379,7 +379,7 @@ impl SingleTaskScheduler { } if config.enabled { - Self::handle_cron_execution(task, config, state, rx, queue_size).await; + Self::handle_execution(task, config, state, rx, queue_size).await; } else { Self::finish_execution(&state, &config.name).await; info!("The {} task is not scheduled to run periodically", config.name); @@ -446,7 +446,7 @@ impl SingleTaskScheduler { } info!("Executing first run of task: {}", config.name); - let result = Self::execute_task(&task).await; + let result = Self::execute_task(task).await; match result { Ok(_) => { @@ -461,7 +461,7 @@ impl SingleTaskScheduler { return Err(AgentError::ExecutionError("Retry not enabled".to_string())); } - return Self::handle_first_execution_retry(task, config, state, &rx).await; + return Self::handle_first_execution_retry(task, config, state, rx).await; }, } } @@ -476,7 +476,7 @@ impl SingleTaskScheduler { let mut attempts = 0; while attempts < config.retry_max_attempts { - let total_delay = Self::calculate_delay(&retry_config); + let total_delay = Self::calculate_delay(retry_config); debug!( "Waiting {:?} before retrying first execution of task: {} (range: {:?} to {:?})", @@ -523,7 +523,7 @@ impl SingleTaskScheduler { Err(AgentError::ExecutionError("All retry attempts exhausted".to_string())) } - async fn handle_cron_execution( + async fn handle_execution( task: Arc, config: SchedulerConfig, state: Arc>, @@ -534,8 +534,13 @@ impl SingleTaskScheduler { while !Self::should_stop(&state).await { match Self::wait_and_execute(&task, &config, &rx, &queue_size).await { - Ok(true) => break, // Stop the scheduler - Ok(false) => continue, // Continue the loop + Ok(true) => { + info!("Stopping scheduled execution of task '{}'", config.name); + break; + }, + Ok(false) => { + info!("Continuing scheduled execution of task '{}'", config.name); + }, Err(e) => { error!("Error during task execution: {}", e); break; @@ -598,9 +603,10 @@ impl SingleTaskScheduler { select! { _ = sleep_future => Ok(WaitResult::TimeToExecute), - cmd = rx_guard.recv() => match cmd { - Some(_) => Ok(WaitResult::StopRequested), - None => { + cmd = rx_guard.recv() => { + if cmd.is_some() { + Ok(WaitResult::StopRequested) + } else { error!("Command channel closed unexpectedly, all senders have been dropped"); Err(AgentError::ExecutionError("Command channel closed unexpectedly".to_string())) } diff --git a/attestation_agent/agent_restful/src/get_evidence_controller.rs b/attestation_agent/agent_restful/src/get_evidence_controller.rs index 9f964593818a04d65ba9094b8b953fd4b26a7531..08ab45e80f71db62c3a68af6ff3d739df93e2b6d 100644 --- a/attestation_agent/agent_restful/src/get_evidence_controller.rs +++ b/attestation_agent/agent_restful/src/get_evidence_controller.rs @@ -10,11 +10,11 @@ * See the Mulan PSL v2 for more details. */ -use actix_web::{HttpResponse, http::StatusCode}; -use log::info; -use serde_json::Value; use crate::response_error::create_error_response; +use actix_web::{http::StatusCode, HttpResponse}; use challenge::evidence::{EvidenceManager, GetEvidenceRequest}; +use log::info; +use serde_json::Value; use std::thread; @@ -29,14 +29,12 @@ pub fn get_evidence(body: Option) -> HttpResponse { Ok(req) => req.sanitize(), Err(e) => { return create_error_response(e, StatusCode::BAD_REQUEST); - } + }, }, None => GetEvidenceRequest::default(), }; - let handle = thread::spawn(move || { - EvidenceManager::get_evidence(&evidence_request) - }); + let handle = thread::spawn(move || EvidenceManager::get_evidence(&evidence_request)); match handle.join() { Ok(result) => match result { @@ -45,4 +43,4 @@ pub fn get_evidence(body: Option) -> HttpResponse { }, Err(_) => create_error_response("Thread execution failed", StatusCode::INTERNAL_SERVER_ERROR), } -} \ No newline at end of file +} diff --git a/attestation_agent/agent_restful/src/lib.rs b/attestation_agent/agent_restful/src/lib.rs index ae49fcc7f77e2dc1ffde44cf4c0b013d3bb67acc..2c9571940ab5f2124374cbbba973064a7a5f90f6 100644 --- a/attestation_agent/agent_restful/src/lib.rs +++ b/attestation_agent/agent_restful/src/lib.rs @@ -10,10 +10,10 @@ * See the Mulan PSL v2 for more details. */ +pub mod get_evidence_controller; pub mod middlewares; +pub mod response_error; pub mod rest; pub mod token_controller; -pub mod get_evidence_controller; -pub mod response_error; pub use rest::{RestService, ServiceConfig}; diff --git a/attestation_agent/agent_restful/src/middlewares/mod.rs b/attestation_agent/agent_restful/src/middlewares/mod.rs index 8a10a1cdcbb06735400d45696ed034056ce4e93d..0b24653c228ea5278c69fb0c3225ab2fa5573f1b 100644 --- a/attestation_agent/agent_restful/src/middlewares/mod.rs +++ b/attestation_agent/agent_restful/src/middlewares/mod.rs @@ -10,7 +10,7 @@ * See the Mulan PSL v2 for more details. */ +pub mod rate_limit; pub mod request_logger; pub mod security_headers; pub mod trusted_proxies; -pub mod rate_limit; \ No newline at end of file diff --git a/attestation_agent/agent_restful/src/middlewares/request_logger.rs b/attestation_agent/agent_restful/src/middlewares/request_logger.rs index eced50bbb74a5a45dc11d11baa6bd9a424bec5e1..5feac412cf855abbb068bca1e31e7740a5a252aa 100644 --- a/attestation_agent/agent_restful/src/middlewares/request_logger.rs +++ b/attestation_agent/agent_restful/src/middlewares/request_logger.rs @@ -33,6 +33,12 @@ impl RequestLogger { } } +impl Default for RequestLogger { + fn default() -> Self { + Self::new() + } +} + impl Transform for RequestLogger where S: Service, Error = Error>, diff --git a/attestation_agent/agent_restful/src/middlewares/security_headers.rs b/attestation_agent/agent_restful/src/middlewares/security_headers.rs index 407d88732b60e5832d394dbca91e9b30c030c520..46cd9acda18204ef161c080288d2314fb6ef2c43 100644 --- a/attestation_agent/agent_restful/src/middlewares/security_headers.rs +++ b/attestation_agent/agent_restful/src/middlewares/security_headers.rs @@ -36,6 +36,12 @@ impl SecurityHeaders { } } +impl Default for SecurityHeaders { + fn default() -> Self { + Self::new() + } +} + impl Transform for SecurityHeaders where S: Service, Error = actix_web::Error>, diff --git a/attestation_agent/agent_restful/src/response_error.rs b/attestation_agent/agent_restful/src/response_error.rs index d588e1ac3ccb681fdedb7ee3895bccd980ae5d0d..971395f62dfe42bb2e90ae2f6e53c198421ed855 100644 --- a/attestation_agent/agent_restful/src/response_error.rs +++ b/attestation_agent/agent_restful/src/response_error.rs @@ -10,21 +10,21 @@ * See the Mulan PSL v2 for more details. */ -use actix_web::{HttpResponse, http::StatusCode}; +use actix_web::{http::StatusCode, HttpResponse}; use log::error; use serde_json::json; /// Creates a standardized error response for HTTP endpoints -/// +/// /// # Arguments /// * `error` - Any error type that implements Display trait /// * `status` - HTTP status code for the response -/// +/// /// # Returns /// * `HttpResponse` - JSON formatted error response with message -/// +/// /// # Behavior -/// - For BAD_REQUEST (400), logs as request validation failure +/// - For `BAD_REQUEST` (400), logs as request validation failure /// - For other status codes, logs as operation failure /// - Returns JSON response with error message and appropriate status code pub fn create_error_response(error: impl std::fmt::Display, status: StatusCode) -> HttpResponse { diff --git a/attestation_agent/agent_restful/src/rest.rs b/attestation_agent/agent_restful/src/rest.rs index f2c419b2fa0c3e80c6c7a6b7574c2a0accf64146..eba9b631ba8d9295c47776701efc60aea693b0ad 100644 --- a/attestation_agent/agent_restful/src/rest.rs +++ b/attestation_agent/agent_restful/src/rest.rs @@ -43,6 +43,7 @@ pub struct CertConfig { pub key_path: Option, } +#[derive(Default)] #[derive(Validate)] #[derive(Clone, Debug)] pub struct ServiceConfig { @@ -61,18 +62,6 @@ pub struct ServiceConfig { pub cert_config: Option, } -impl Default for ServiceConfig { - fn default() -> Self { - ServiceConfig { - enable_https: false, - port: None, - bind_address: None, - trusted_proxies: Vec::new(), - cert_config: None, - } - } -} - impl ServiceConfig { /// Creates a new empty server configuration with default values. /// @@ -243,9 +232,9 @@ impl RestService { } } - /// Gets or creates the singleton instance of RestService. + /// Gets or creates the singleton instance of `RestService`. /// - /// This method ensures only one instance of RestService exists in the application. + /// This method ensures only one instance of `RestService` exists in the application. /// The first call creates the instance, subsequent calls return references to the same instance. /// /// # Returns @@ -335,8 +324,8 @@ impl RestService { /// /// * `method` - The HTTP method (GET, POST, PUT, DELETE) /// * `path` - The URL path pattern (e.g., "/api/users/{id}") - /// * `handler` - A function taking an HttpRequest and optional JSON payload, - /// returning an HttpResponse + /// * `handler` - A function taking an `HttpRequest` and optional JSON payload, + /// returning an `HttpResponse` /// /// # Returns /// @@ -360,12 +349,11 @@ impl RestService { F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { let handler = Arc::new(handler); - let handler_fn = self.create_method_handler(method.clone(), handler)?; + let handler_fn = RestService::create_method_handler(method.clone(), handler)?; self.add_route(method.clone(), path, handler_fn) } fn create_method_handler( - &self, method: Method, handler: Arc, ) -> Result actix_web::Route + Send + Sync>, AgentError> @@ -373,10 +361,10 @@ impl RestService { F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { let handler_fn = match method { - Method::GET => self.create_get_handler(handler), - Method::POST => self.create_post_handler(handler), - Method::PUT => self.create_put_handler(handler), - Method::DELETE => self.create_delete_handler(handler), + Method::GET => RestService::create_get_handler(handler), + Method::POST => RestService::create_post_handler(handler), + Method::PUT => RestService::create_put_handler(handler), + Method::DELETE => RestService::create_delete_handler(handler), _ => { return Err(AgentError::ConfigError(format!("Unsupported method: {}", method))); }, @@ -385,7 +373,7 @@ impl RestService { Ok(handler_fn) } - fn create_get_handler(&self, handler: Arc) -> Arc actix_web::Route + Send + Sync> + fn create_get_handler(handler: Arc) -> Arc actix_web::Route + Send + Sync> where F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { @@ -398,7 +386,7 @@ impl RestService { }) } - fn create_post_handler(&self, handler: Arc) -> Arc actix_web::Route + Send + Sync> + fn create_post_handler(handler: Arc) -> Arc actix_web::Route + Send + Sync> where F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { @@ -412,7 +400,7 @@ impl RestService { }) } - fn create_put_handler(&self, handler: Arc) -> Arc actix_web::Route + Send + Sync> + fn create_put_handler(handler: Arc) -> Arc actix_web::Route + Send + Sync> where F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { @@ -426,7 +414,7 @@ impl RestService { }) } - fn create_delete_handler(&self, handler: Arc) -> Arc actix_web::Route + Send + Sync> + fn create_delete_handler(handler: Arc) -> Arc actix_web::Route + Send + Sync> where F: Fn(HttpRequest, Option) -> HttpResponse + Send + Sync + 'static, { @@ -475,7 +463,7 @@ impl RestService { fn check_route_conflicts(&self, path: &str, method: &Method) -> Result<(), AgentError> { if let Ok(routes) = self.get_routes() { for route in routes { - if self.routes_conflict(&route.path, path) && &route.method == method { + if RestService::routes_conflict(&route.path, path) && route.method == method { return Err(AgentError::ConfigError(format!( "Route conflict detected: '{} {}' conflicts with existing route. \ Registration rejected.", @@ -488,7 +476,7 @@ impl RestService { Ok(()) } - fn routes_conflict(&self, path1: &str, path2: &str) -> bool { + fn routes_conflict(path1: &str, path2: &str) -> bool { if path1 == path2 { return true; } @@ -557,20 +545,14 @@ impl RestService { .as_ref() .ok_or_else(|| AgentError::ConfigError("Bind address not configured".to_string()))?; - let routes = self.get_routes()?; + let addr = format!("{}:{}", bind_address, config.port.unwrap()); if config.enable_https { - let https_addr = format!("{}:{}", bind_address, config.port.unwrap()); - info!("Starting HTTPS server on {}", https_addr); - - let cert_path = PathBuf::from(config.cert_config.as_ref().unwrap().cert_path.as_ref().unwrap()); - let key_path = PathBuf::from(config.cert_config.as_ref().unwrap().key_path.as_ref().unwrap()); - - self.start_https_server(&https_addr, &cert_path, &key_path, rx, config.clone()).await?; + info!("Starting HTTPS server on {}", addr); + self.start_https_server(&addr, rx.resubscribe(), config.clone()).await?; } else { - let http_addr = format!("{}:{}", bind_address, config.port.unwrap()); - info!("Starting HTTP server on {}", http_addr); - self.start_http_server(&http_addr, routes.clone(), rx.resubscribe(), config.clone()).await?; + info!("Starting HTTP server on {}", addr); + self.start_http_server(&addr, rx.resubscribe(), config.clone()).await?; } self.is_running.store(true, Ordering::SeqCst); @@ -581,34 +563,26 @@ impl RestService { async fn start_https_server( &self, https_addr: &str, - cert_path: &PathBuf, - key_path: &PathBuf, rx: tokio::sync::broadcast::Receiver<()>, config: ServiceConfig, ) -> Result<(), AgentError> { - let routes = match self.get_routes() { - Ok(routes) => routes, - Err(e) => { - error!("Failed to get routes: {}", e); - return Err(e); - }, - }; + let cert_path = PathBuf::from(config.cert_config.as_ref().unwrap().cert_path.as_ref().unwrap()); + let key_path = PathBuf::from(config.cert_config.as_ref().unwrap().key_path.as_ref().unwrap()); - let ssl_builder = match self.create_ssl_builder(cert_path, key_path) { + let ssl_builder = match RestService::create_ssl_builder(&cert_path, &key_path) { Ok(builder) => builder, Err(e) => { error!("Failed to create ssl builder: {}", e); return Err(e); }, }; - + let routes = self.get_routes()?; info!("Starting HTTPS server on {}", https_addr); - self.start_https_server_impl(https_addr, ssl_builder, routes, rx, config) + RestService::start_https_server_impl(https_addr, ssl_builder, routes, rx, config) } fn start_https_server_impl( - &self, https_addr: &str, ssl_builder: SslAcceptorBuilder, routes: Vec, @@ -645,7 +619,7 @@ impl RestService { Ok(()) } - fn create_ssl_builder(&self, cert_path: &PathBuf, key_path: &PathBuf) -> Result { + fn create_ssl_builder(cert_path: &PathBuf, key_path: &PathBuf) -> Result { let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()) .map_err(|e| AgentError::ConfigError(format!("Failed to create SSL configuration: {}", e)))?; @@ -698,19 +672,16 @@ impl RestService { return Ok(()); } - match self.take_broadcast_shutdown_sender()? { - Some(sender) => { - self.is_running.store(false, Ordering::SeqCst); - self.send_broadcast_shutdown_signal(sender).await?; - info!("Server stopped successfully"); - Ok(()) - }, - None => { - let err = AgentError::ServerStateError("Shutdown signal not found".to_string()); - error!("{}", err); - self.is_running.store(false, Ordering::SeqCst); - Err(err) - }, + if let Some(sender) = self.take_broadcast_shutdown_sender()? { + self.is_running.store(false, Ordering::SeqCst); + self.send_broadcast_shutdown_signal(sender).await?; + info!("Server stopped successfully"); + Ok(()) + } else { + let err = AgentError::ServerStateError("Shutdown signal not found".to_string()); + error!("{}", err); + self.is_running.store(false, Ordering::SeqCst); + Err(err) } } @@ -737,13 +708,13 @@ impl RestService { async fn start_http_server( &self, http_addr: &str, - routes: Vec, rx: tokio::sync::broadcast::Receiver<()>, config: ServiceConfig, ) -> Result<(), AgentError> { info!("Starting HTTP server on {}", http_addr); let http_addr = http_addr.to_string(); let mut rx = rx; + let routes = self.get_routes()?; tokio::spawn(async move { let server = HttpServer::new(move || create_app(&config, &routes)) @@ -1014,7 +985,7 @@ mod tests { let (https_tx, https_rx) = tokio::sync::broadcast::channel::<()>(1); let (cert_path, key_path, _temp_dir) = generate_test_certificate(); - let ssl_builder = service.create_ssl_builder(&cert_path, &key_path).unwrap(); + let ssl_builder = RestService::create_ssl_builder(&cert_path, &key_path).unwrap(); let https_listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); let https_addr = format!("127.0.0.1:{}", https_listener.local_addr().unwrap().port()); diff --git a/attestation_agent/agent_restful/src/token_controller.rs b/attestation_agent/agent_restful/src/token_controller.rs index 6c8cb972302c164f7320d8b0eae20e5496c16d9f..3a35098f24e68a6f1817ea5df6af05d9102098df 100644 --- a/attestation_agent/agent_restful/src/token_controller.rs +++ b/attestation_agent/agent_restful/src/token_controller.rs @@ -10,14 +10,14 @@ * See the Mulan PSL v2 for more details. */ -use actix_web::{HttpResponse, http::StatusCode}; -use log::{error, info}; -use serde_json::{json, Value}; use crate::response_error::create_error_response; -use challenge::token::{TokenManager, TokenRequest}; +use actix_web::{http::StatusCode, HttpResponse}; use challenge::challenge_error::ChallengeError; -use tokio::runtime::Runtime; +use challenge::token::{TokenManager, TokenRequest}; +use log::{error, info}; +use serde_json::{json, Value}; use std::thread; +use tokio::runtime::Runtime; // Asynchronous part of token processing async fn process_token_request(token_request: TokenRequest) -> Result { @@ -26,7 +26,7 @@ async fn process_token_request(token_request: TokenRequest) -> Result { error!("Failed to get token: {}", error); Err(ChallengeError::TokenError(error)) - } + }, } } @@ -41,7 +41,7 @@ pub fn get_token(body: Option) -> HttpResponse { Ok(req) => req.sanitize(), Err(e) => { return create_error_response(e, StatusCode::BAD_REQUEST); - } + }, }, None => TokenRequest::default(), }; @@ -50,7 +50,7 @@ pub fn get_token(body: Option) -> HttpResponse { let rt = Runtime::new().unwrap(); rt.block_on(process_token_request(token_request)) }); - + match handle.join() { Ok(result) => match result { Ok(token) => HttpResponse::Ok().json(json!({ "token": token })), diff --git a/attestation_agent/attester/tpm/boot/src/attester.rs b/attestation_agent/attester/tpm/boot/src/attester.rs index 7760a349dfba7ef33637c6775502fd7fc1b6b1e3..d0c17317ba6feeedb773df3c14a72d8c60b2376c 100644 --- a/attestation_agent/attester/tpm/boot/src/attester.rs +++ b/attestation_agent/attester/tpm/boot/src/attester.rs @@ -13,9 +13,7 @@ // TPM Boot plugin implementation use tpm_common_attester::{TpmPluginBase, TpmPluginConfig, Log}; use plugin_manager::{AgentPlugin, PluginError, PluginBase, QueryConfigurationFn, AgentHostFunctions}; -use serde_json; use std::fs::File; -use std::io::Read; use base64::{Engine as _, engine::general_purpose::STANDARD}; #[derive(Debug)] @@ -79,9 +77,7 @@ impl TpmPluginBase for TpmBootPlugin { } // Read file contents into a buffer - let mut buffer = Vec::new(); - let mut file = file; // Need to rebind since file was moved in metadata() call - file.read_to_end(&mut buffer).map_err(|e| { + let buffer = std::fs::read(&self.config.log_file_path).map_err(|e| { PluginError::InternalError(format!("Failed to read boot log file: {}", e)) })?; diff --git a/attestation_agent/attester/tpm/ima/src/attester.rs b/attestation_agent/attester/tpm/ima/src/attester.rs index 35950c90367d27953d4a8f02547f31b2852ad839..6a42da31d47707d958b1292a8b0dbf9dbe988bb0 100644 --- a/attestation_agent/attester/tpm/ima/src/attester.rs +++ b/attestation_agent/attester/tpm/ima/src/attester.rs @@ -13,9 +13,9 @@ // TPM IMA plugin implementation use tpm_common_attester::{TpmPluginBase, TpmPluginConfig, Log}; use plugin_manager::{AgentPlugin, PluginError, PluginBase, QueryConfigurationFn, AgentHostFunctions}; -use serde_json; use std::fs::File; -use std::io::{Read, BufRead, BufReader}; +use std::fs; +use std::io::{BufRead, BufReader}; use base64::{Engine as _, engine::general_purpose::STANDARD}; /// Maximum number of lines allowed in an IMA log file diff --git a/attestation_agent/challenge/src/challenge.rs b/attestation_agent/challenge/src/challenge.rs index 4d62b704f83c7e597ff0ba9794d2f7db2453250a..b883dcba84d14c369c475d1d803e1554c007a6c0 100644 --- a/attestation_agent/challenge/src/challenge.rs +++ b/attestation_agent/challenge/src/challenge.rs @@ -10,17 +10,17 @@ * See the Mulan PSL v2 for more details. */ -use serde::{Deserialize, Serialize}; -use crate::challenge_error::ChallengeError; use crate::acquire_process_lock; +use crate::challenge_error::ChallengeError; +use agent_utils::Client; +use config::{PluginConfig, AGENT_CONFIG}; use log; -use config::{AGENT_CONFIG, PluginConfig}; -use plugin_manager::{PluginManagerInstance, AgentPlugin, AgentHostFunctions, PluginManager}; -use std::sync::{Arc, Mutex}; +use once_cell::sync::Lazy; +use plugin_manager::{AgentHostFunctions, AgentPlugin, PluginManager, PluginManagerInstance}; use reqwest::Method; -use agent_utils::Client; +use serde::{Deserialize, Serialize}; use serde_json::Value; -use once_cell::sync::Lazy; +use std::sync::{Arc, Mutex}; use base64::engine::general_purpose::STANDARD; use base64::Engine; @@ -116,7 +116,7 @@ pub fn set_cached_tokens(tokens: &[NodeToken]) { *global = tokens.to_vec(); } -/// Get the cached token for current node_id as serde_json::Value (sync) +/// Get the cached token for current `node_id` as `serde_json::Value` (sync) pub fn get_cached_token_for_current_node() -> Option { let node_id = get_node_id().ok()?; let global = GLOBAL_TOKENS.lock().unwrap(); @@ -125,24 +125,21 @@ pub fn get_cached_token_for_current_node() -> Option { /// Get the node ID (UUID) from configuration pub fn get_node_id() -> Result { - let config = AGENT_CONFIG.get_instance() - .map_err(|e| { - log::error!("Failed to get AGENT_CONFIG instance: {}", e); - ChallengeError::ConfigError(e.to_string()) - })?; - - config.agent.uuid - .clone() - .ok_or_else(|| { - log::error!("Agent UUID not configured"); - ChallengeError::ConfigError("Agent UUID not configured".to_string()) - }) + let config = AGENT_CONFIG.get_instance().map_err(|e| { + log::error!("Failed to get AGENT_CONFIG instance: {}", e); + ChallengeError::ConfigError(e.clone()) + })?; + + config.agent.uuid.clone().ok_or_else(|| { + log::error!("Agent UUID not configured"); + ChallengeError::ConfigError("Agent UUID not configured".to_string()) + }) } /// Get all enabled attester types from the plugin manager and config fn get_enabled_attester_types() -> Result, ChallengeError> { let plugin_manager = PluginManager::::get_instance(); - + if !plugin_manager.is_initialized() { log::error!("Plugin manager not initialized"); return Err(ChallengeError::InternalError("Plugin manager not initialized".to_string())); @@ -154,14 +151,13 @@ fn get_enabled_attester_types() -> Result, ChallengeError> { return Err(ChallengeError::NoEnabledPlugins); } - let config = AGENT_CONFIG.get_instance() - .map_err(|e| { - log::error!("Failed to get AGENT_CONFIG instance: {}", e); - ChallengeError::ConfigError(e.to_string()) - })?; + let config = AGENT_CONFIG.get_instance().map_err(|e| { + log::error!("Failed to get AGENT_CONFIG instance: {}", e); + ChallengeError::ConfigError(e.clone()) + })?; let mut enabled_attester_types = Vec::new(); - + for plugin_name in &enabled_plugins { if let Some(plugin_config) = config.plugins.iter().find(|p| &p.name == plugin_name) { if let Some(params) = &plugin_config.params { @@ -182,23 +178,24 @@ fn get_enabled_attester_types() -> Result, ChallengeError> { Ok(enabled_attester_types) } -/// Find the plugin and config that matches the given attester_type -fn find_plugin_for_attester_type( - attester_type: &str -) -> Result<(Arc, PluginConfig), ChallengeError> { - let config = AGENT_CONFIG.get_instance() - .map_err(|e| { - log::error!("Failed to get AGENT_CONFIG instance: {}", e); - ChallengeError::ConfigError(e.to_string()) - })?; - let plugin_config = config.plugins.iter() - .find(|p| p.enabled && p.params.as_ref().map_or(false, |params| { - match (params, attester_type) { - (config::PluginParams::TpmBoot(_), "tpm_boot") => true, - (config::PluginParams::TpmIma(_), "tpm_ima") => true, - _ => false - } - })) +/// Find the plugin and config that matches the given `attester_type` +fn find_plugin_for_attester_type(attester_type: &str) -> Result<(Arc, PluginConfig), ChallengeError> { + let config = AGENT_CONFIG.get_instance().map_err(|e| { + log::error!("Failed to get AGENT_CONFIG instance: {}", e); + ChallengeError::ConfigError(e.clone()) + })?; + let plugin_config = config + .plugins + .iter() + .find(|p| { + p.enabled + && p.params.as_ref().is_some_and(|params| { + matches!( + (params, attester_type), + (config::PluginParams::TpmBoot(_), "tpm_boot") | (config::PluginParams::TpmIma(_), "tpm_ima") + ) + }) + }) .ok_or_else(|| { log::error!("Plugin not found for attester_type: {}", attester_type); ChallengeError::PluginNotFound(attester_type.to_string()) @@ -210,16 +207,15 @@ fn find_plugin_for_attester_type( log::error!("Plugin manager not initialized"); return Err(ChallengeError::InternalError("Plugin manager not initialized".to_string())); } - let plugin = plugin_manager.get_plugin(&plugin_config.name) - .ok_or_else(|| { - log::error!("Plugin instance not found: {}", plugin_config.name); - ChallengeError::PluginNotFound(plugin_config.name.clone()) - })?; + let plugin = plugin_manager.get_plugin(&plugin_config.name).ok_or_else(|| { + log::error!("Plugin instance not found: {}", plugin_config.name); + ChallengeError::PluginNotFound(plugin_config.name.clone()) + })?; Ok((plugin, plugin_config)) } -/// Validate if the attester_type exists and is enabled +/// Validate if the `attester_type` exists and is enabled fn validate_attester_type(attester_type: &str) -> Result { // Attempt to fetch the plugin; success confirms it exists and is enabled. find_plugin_for_attester_type(attester_type)?; @@ -227,10 +223,7 @@ fn validate_attester_type(attester_type: &str) -> Result { } /// Collect evidence for a specific attester type and nonce -fn collect_evidence( - attester_type: &str, - nonce_value: Option, -) -> Result { +fn collect_evidence(attester_type: &str, nonce_value: Option) -> Result { let (plugin, _) = find_plugin_for_attester_type(attester_type)?; let node_id = get_node_id()?; let nonce_bytes = nonce_value.as_ref().map(|s| { @@ -249,23 +242,23 @@ fn collect_evidence( Err(e) => { log::error!("Failed to collect evidence for '{}': {}", attester_type, e); Err(ChallengeError::EvidenceCollectionFailed(e.to_string())) - } + }, } } /// Get policy IDs based on the calling context /// -/// For collect_from_attester_info scenario: -/// - If user-provided policy_ids count > 10: error -/// - If user-provided policy_ids empty: return None -/// - If user-provided policy_ids count 1-10: use them -/// - If user didn't provide policy_ids (None): return None directly +/// For `collect_from_attester_info` scenario: +/// - If user-provided `policy_ids` count > 10: error +/// - If user-provided `policy_ids` empty: return None +/// - If user-provided `policy_ids` count 1-10: use them +/// - If user didn't provide `policy_ids` (None): return None directly /// -/// For collect_from_enabled_plugins scenario: -/// - Get policy_ids from config file -/// - If config policy_ids count > 10: error -/// - If config policy_ids empty: return None -/// - If config policy_ids count 1-10: use them +/// For `collect_from_enabled_plugins` scenario: +/// - Get `policy_ids` from config file +/// - If config `policy_ids` count > 10: error +/// - If config `policy_ids` empty: return None +/// - If config `policy_ids` count 1-10: use them fn get_policy_ids( attester_type: &str, input_policy_ids: &Option>, @@ -276,19 +269,18 @@ fn get_policy_ids( // Case: User provided policy_ids if let Some(ids) = input_policy_ids { if ids.len() > MAX_POLICY_IDS { - log::error!("Too many policy_ids for attester_type '{}', max allowed is {}", - attester_type, MAX_POLICY_IDS); + log::error!("Too many policy_ids for attester_type '{}', max allowed is {}", attester_type, MAX_POLICY_IDS); return Err(ChallengeError::InternalError(format!( - "Too many policy_ids for attester_type '{}', max allowed is {}", + "Too many policy_ids for attester_type '{}', max allowed is {}", attester_type, MAX_POLICY_IDS ))); } - + // If user provided empty policy_ids, return None if ids.is_empty() { return Ok(None); } - + // User provided valid policy_ids (1-10), use them return Ok(Some(ids.clone())); } @@ -304,10 +296,13 @@ fn get_policy_ids( let (_, plugin_config) = find_plugin_for_attester_type(attester_type)?; if plugin_config.policy_id.len() > MAX_POLICY_IDS { - log::error!("Too many policy_ids in config for attester_type '{}', max allowed is {}", - attester_type, MAX_POLICY_IDS); + log::error!( + "Too many policy_ids in config for attester_type '{}', max allowed is {}", + attester_type, + MAX_POLICY_IDS + ); return Err(ChallengeError::InternalError(format!( - "Too many policy_ids in config for attester_type '{}', max allowed is {}", + "Too many policy_ids in config for attester_type '{}', max allowed is {}", attester_type, MAX_POLICY_IDS ))); } @@ -329,27 +324,24 @@ fn collect_evidences_for_types( use_config: bool, ) -> Result, ChallengeError> where - I: IntoIterator>)> { + I: IntoIterator>)>, +{ let mut all_evidences = Vec::new(); for (attester_type, policy_ids_hint) in attester_iter { if need_validate { validate_attester_type(&attester_type)?; } - let evidence_value = collect_evidence(&attester_type, nonce_value.clone()) - .map_err(|e| { - log::error!("Failed to collect evidence for '{}': {}", attester_type, e); - ChallengeError::EvidenceCollectionFailed( - format!("Failed to collect evidence for '{}': {}", attester_type, e) - ) - })?; + let evidence_value = collect_evidence(&attester_type, nonce_value.clone()).map_err(|e| { + log::error!("Failed to collect evidence for '{}': {}", attester_type, e); + ChallengeError::EvidenceCollectionFailed(format!( + "Failed to collect evidence for '{}': {}", + attester_type, e + )) + })?; let policy_ids = get_policy_ids(&attester_type, &policy_ids_hint, use_config)?; - all_evidences.push(EvidenceWithPolicy { - attester_type, - evidence: evidence_value, - policy_ids, - }); + all_evidences.push(EvidenceWithPolicy { attester_type, evidence: evidence_value, policy_ids }); } if all_evidences.is_empty() { log::error!("No valid evidence collected for any attester_type"); @@ -361,19 +353,15 @@ where /// Collect evidence from provided attester info list fn collect_from_attester_info( info: &[AttesterInfo], - nonce_value: &Option + nonce_value: &Option, ) -> Result, ChallengeError> { - let attester_iter = info.iter().filter_map(|a| { - a.attester_type.as_ref().map(|t| (t.clone(), a.policy_ids.clone())) - }); + let attester_iter = info.iter().filter_map(|a| a.attester_type.as_ref().map(|t| (t.clone(), a.policy_ids.clone()))); // For collect_from_attester_info, use_config is false collect_evidences_for_types(attester_iter, nonce_value, true, false) } /// Collect evidence from all enabled plugins -fn collect_from_enabled_plugins( - nonce_value: &Option -) -> Result, ChallengeError> { +fn collect_from_enabled_plugins(nonce_value: &Option) -> Result, ChallengeError> { let enabled_types = get_enabled_attester_types()?; let attester_iter = enabled_types.into_iter().map(|t| (t, None)); // For collect_from_enabled_plugins, use_config is true @@ -387,9 +375,10 @@ pub fn collect_evidences_core( ) -> Result, ChallengeError> { match attester_info { Some(info) if !info.is_empty() => { - let all_types_empty = info.iter() - .all(|attester| attester.attester_type.is_none() || attester.attester_type.as_ref().unwrap().is_empty()); - + let all_types_empty = info.iter().all(|attester| { + attester.attester_type.is_none() || attester.attester_type.as_ref().unwrap().is_empty() + }); + if all_types_empty { log::info!("All attester_types empty, collecting from enabled plugins"); // Case 1: All attester_types are empty @@ -405,25 +394,23 @@ pub fn collect_evidences_core( _ => { log::info!("No attester_info provided, collecting from enabled plugins"); collect_from_enabled_plugins(nonce_value) - } + }, } } -/// Validate Nonce fields, return ChallengeError if invalid +/// Validate Nonce fields, return `ChallengeError` if invalid pub fn validate_nonce_fields(nonce: &Nonce) -> Result<(), ChallengeError> { - if nonce.value.trim().is_empty() || - nonce.signature.trim().is_empty() || - nonce.iat == 0 { + if nonce.value.trim().is_empty() || nonce.signature.trim().is_empty() || nonce.iat == 0 { return Err(ChallengeError::NonceInvalid("One or more nonce fields are empty".to_string())); } - let value_len = nonce.value.as_bytes().len(); - if value_len < 64 || value_len > 1024 { + let value_len = nonce.value.len(); + if !(64..=1024).contains(&value_len) { return Err(ChallengeError::NonceInvalid(format!( "nonce.value length must be between 64 and 1024 bytes, got {} bytes", value_len ))); } - let sig_len = nonce.signature.as_bytes().len(); + let sig_len = nonce.signature.len(); if sig_len < 64 { return Err(ChallengeError::NonceInvalid(format!( "nonce.signature length must be at least 64 bytes, got {} bytes", @@ -440,10 +427,8 @@ async fn get_nonce_from_server( ) -> Result { let attester_types = match attester_info { Some(info) if !info.is_empty() => { - let filtered: Vec<_> = info.iter() - .filter_map(|a| a.attester_type.clone()) - .filter(|s| !s.trim().is_empty()) - .collect(); + let filtered: Vec<_> = + info.iter().filter_map(|a| a.attester_type.clone()).filter(|s| !s.trim().is_empty()).collect(); if filtered.is_empty() { get_enabled_attester_types()? } else { @@ -466,13 +451,10 @@ async fn get_nonce_from_server( log::error!("Failed to get nonce from server: {}", e); ChallengeError::NetworkError(format!("Failed to get nonce: {}", e)) })?; - let json_value = response - .json::() - .await - .map_err(|e| { - log::error!("Failed to parse nonce response: {}", e); - ChallengeError::RequestParseError(format!("Failed to parse nonce response: {}", e)) - })?; + let json_value = response.json::().await.map_err(|e| { + log::error!("Failed to parse nonce response: {}", e); + ChallengeError::RequestParseError(format!("Failed to parse nonce response: {}", e)) + })?; if let Some(msg) = json_value.get("message").and_then(|v| v.as_str()) { if !msg.is_empty() { log::error!("Server returned error message for nonce: {}", msg); @@ -480,13 +462,12 @@ async fn get_nonce_from_server( } } - let nonce: Nonce = match json_value.get("nonce") { - Some(nonce_val) => serde_json::from_value(nonce_val.clone()) - .map_err(|e| ChallengeError::RequestParseError(format!("Failed to parse nonce: {}", e)))?, - None => { - log::error!("Failed to get nonce from Server, nonce is null"); - return Err(ChallengeError::ServerError("Failed to get nonce from Server, nonce is null".to_string())); - }, + let nonce: Nonce = if let Some(nonce_val) = json_value.get("nonce") { + serde_json::from_value(nonce_val.clone()) + .map_err(|e| ChallengeError::RequestParseError(format!("Failed to parse nonce: {}", e)))? + } else { + log::error!("Failed to get nonce from Server, nonce is not a string"); + return Err(ChallengeError::ServerError("Failed to get nonce from Server, nonce is not a string".to_string())); }; validate_nonce_fields(&nonce)?; log::info!("Successfully obtained and validated nonce from server"); @@ -494,9 +475,7 @@ async fn get_nonce_from_server( } /// Send the evidence to the attestation server and extract all node tokens from the response. -async fn get_tokens_from_server( - evidence: &GetEvidenceResponse -) -> Result, ChallengeError> { +async fn get_tokens_from_server(evidence: &GetEvidenceResponse) -> Result, ChallengeError> { let client = Client::instance(); // Send the evidence to the attestation server let response = client @@ -508,13 +487,10 @@ async fn get_tokens_from_server( })?; log::info!("Received token response from server"); // Parse the server's JSON response - let json_value = response - .json::() - .await - .map_err(|e| { - log::error!("Failed to parse token response: {}", e); - ChallengeError::RequestParseError(format!("Failed to parse verify response: {}", e)) - })?; + let json_value = response.json::().await.map_err(|e| { + log::error!("Failed to parse token response: {}", e); + ChallengeError::RequestParseError(format!("Failed to parse verify response: {}", e)) + })?; // Check for error message in the response if let Some(msg) = json_value.get("message").and_then(|v| v.as_str()) { @@ -525,20 +501,23 @@ async fn get_tokens_from_server( } // Extract the tokens array from the response - let tokens = match json_value.get("tokens") { - Some(val) => val.as_array().ok_or_else(|| { + let tokens = if let Some(val) = json_value.get("tokens") { + val.as_array().ok_or_else(|| { log::error!("tokens field is not array in server response"); ChallengeError::RequestParseError("tokens field is not array".to_string()) - })?, - None => { - log::error!("No tokens field in server response"); - return Err(ChallengeError::TokenNotReceived); - }, + })? + } else { + log::error!("No tokens field in server response"); + return Err(ChallengeError::TokenNotReceived); }; let mut node_tokens = Vec::new(); // For each token, extract node_id and token value for t in tokens { - let node_id = t.get("node_id").and_then(|v| v.as_str()).ok_or_else(|| ChallengeError::RequestParseError("token.node_id missing or not string".to_string()))?.to_string(); + let node_id = t + .get("node_id") + .and_then(|v| v.as_str()) + .ok_or_else(|| ChallengeError::RequestParseError("token.node_id missing or not string".to_string()))? + .to_string(); let token_val = t.get("token").cloned().unwrap_or(serde_json::Value::Null); node_tokens.push(NodeToken { node_id, token: token_val }); } @@ -553,15 +532,9 @@ pub async fn do_challenge( ) -> Result { log::info!("Starting challenge request."); - let nonce = get_nonce_from_server( - env!("CARGO_PKG_VERSION"), - attester_info, - ).await?; + let nonce = get_nonce_from_server(env!("CARGO_PKG_VERSION"), attester_info).await?; - let evidences = match collect_evidences_core( - attester_info, - &Some(nonce.value.clone()), - ) { + let evidences = match collect_evidences_core(attester_info, &Some(nonce.value.clone())) { Ok(evidences) => { log::info!("Successfully collected evidences"); evidences @@ -569,7 +542,7 @@ pub async fn do_challenge( Err(e) => { log::error!("Failed to collect evidences: {}", e); return Err(e); - } + }, }; let node_id = get_node_id()?; @@ -596,4 +569,4 @@ pub async fn do_challenge( log::error!("Token for node_id {} not found in server response", node_id); Err(ChallengeError::TokenNotReceived) -} \ No newline at end of file +} diff --git a/attestation_agent/challenge/src/challenge_error.rs b/attestation_agent/challenge/src/challenge_error.rs index 87a9a9d39beeeca3e6e40d990658d1e697ebe4da..ba8097efee6e32e2b7d02602ef5d3538cfa342f4 100644 --- a/attestation_agent/challenge/src/challenge_error.rs +++ b/attestation_agent/challenge/src/challenge_error.rs @@ -23,12 +23,12 @@ pub enum ChallengeError { PluginNotFound(String), /// No enabled plugins found in the system NoEnabledPlugins, - + /// Errors during evidence collection, includes failure reason EvidenceCollectionFailed(String), /// No valid evidence collected, includes specific reason NoValidEvidence(String), - + /// Nonce type error, includes invalid nonce type information NonceTypeError(String), /// Nonce value is empty @@ -39,17 +39,17 @@ pub enum ChallengeError { UserNonceNotProvided, /// Nonce is invalid NonceInvalid(String), - + /// Token not received in server response TokenNotReceived, - + /// Request parsing error, includes parsing failure reason RequestParseError(String), /// Network communication error, includes specific error message NetworkError(String), /// Server-side error, includes server returned error message ServerError(String), - + /// Internal system error, includes specific error message InternalError(String), @@ -95,11 +95,11 @@ impl fmt::Display for ChallengeError { Self::ConfigError(msg) => write!(f, "Configuration error: {}", msg), Self::PluginNotFound(name) => write!(f, "Plugin not found: {}", name), Self::NoEnabledPlugins => write!(f, "No enabled plugins found in configuration"), - + // Evidence collection errors Self::EvidenceCollectionFailed(msg) => write!(f, "Failed to collect evidence: {}", msg), Self::NoValidEvidence(msg) => write!(f, "No valid evidence collected: {}", msg), - + // Nonce related errors Self::NonceTypeError(msg) => write!(f, "Invalid nonce type: {}", msg), Self::NonceValueEmpty => write!(f, "Nonce value cannot be empty"), @@ -114,7 +114,7 @@ impl fmt::Display for ChallengeError { Self::RequestParseError(msg) => write!(f, "Failed to parse request: {}", msg), Self::NetworkError(msg) => write!(f, "Network error: {}", msg), Self::ServerError(msg) => write!(f, "Server error: {}", msg), - + // Other errors Self::InternalError(msg) => write!(f, "Internal error: {}", msg), diff --git a/attestation_agent/challenge/src/evidence.rs b/attestation_agent/challenge/src/evidence.rs index 727c82c6c5e2761e3d7dad1dbda62fab55a4cee6..ff23dc84e7d929a045f5f57b469ea2d794a0ff67 100644 --- a/attestation_agent/challenge/src/evidence.rs +++ b/attestation_agent/challenge/src/evidence.rs @@ -10,15 +10,14 @@ * See the Mulan PSL v2 for more details. */ -use serde::Deserialize; -use serde_json; -use crate::challenge_error::ChallengeError; use crate::challenge::{ - AttesterInfo, GetEvidenceResponse, Nonce, collect_evidences_core, get_node_id, validate_nonce_fields + collect_evidences_core, get_node_id, validate_nonce_fields, AttesterInfo, GetEvidenceResponse, Nonce, }; +use crate::challenge_error::ChallengeError; +use serde::Deserialize; /// Request structure for evidence collection, including nonce and attester info -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Default)] pub struct GetEvidenceRequest { // Optional list of attester types to collect evidence from #[serde(default)] @@ -61,17 +60,6 @@ impl GetEvidenceRequest { attester_data: self.attester_data.filter(|d| !d.is_null()), } } - - /// Creates a default instance with all fields set to None - pub fn default() -> Self { - Self { - attester_types: None, - nonce_type: None, - user_nonce: None, - nonce: None, - attester_data: None, - } - } } /// Manager for evidence collection logic @@ -85,22 +73,19 @@ impl EvidenceManager { user_nonce: Option<&String>, nonce: Option<&Nonce>, ) -> Result<(String, Option), ChallengeError> { - let nonce_type = nonce_type - .map(|t| t.to_lowercase()) - .unwrap_or_else(|| "default".to_string()); + let nonce_type = nonce_type.map_or_else(|| "default".to_string(), |t| t.to_lowercase()); let nonce_value = match nonce_type.as_str() { "ignore" => None, "user" => { - let user_nonce_str = match user_nonce { - Some(n) => n, - None => { - log::error!("User nonce not provided but nonce_type is 'user'"); - return Err(ChallengeError::UserNonceNotProvided); - } + let user_nonce_str = if let Some(n) = user_nonce { + n + } else { + log::error!("User nonce not provided but nonce_type is 'user'"); + return Err(ChallengeError::UserNonceNotProvided); }; - let user_nonce_len = user_nonce_str.as_bytes().len(); - if user_nonce_len < 64 || user_nonce_len > 1024 { + let user_nonce_len = user_nonce_str.len(); + if !(64..=1024).contains(&user_nonce_len) { log::error!("user_nonce length invalid: {} bytes", user_nonce_len); return Err(ChallengeError::NonceInvalid(format!( "user_nonce length must be between 64 and 1024 bytes, got {} bytes", @@ -110,12 +95,11 @@ impl EvidenceManager { user_nonce_str.clone().into() }, "default" => { - let nonce = match nonce { - Some(n) => n, - None => { - log::error!("Nonce not provided but nonce_type is 'default'"); - return Err(ChallengeError::NonceNotProvided); - } + let nonce = if let Some(n) = nonce { + n + } else { + log::error!("Nonce not provided but nonce_type is 'default'"); + return Err(ChallengeError::NonceNotProvided); }; if let Err(e) = validate_nonce_fields(nonce) { log::error!("Nonce validation failed: {}", e); @@ -125,10 +109,11 @@ impl EvidenceManager { }, _ => { log::error!("Invalid nonce_type: '{}'", nonce_type); - return Err(ChallengeError::NonceTypeError( - format!("Invalid nonce_type: '{}'. Must be one of: ignore, user, default", nonce_type) - )); - } + return Err(ChallengeError::NonceTypeError(format!( + "Invalid nonce_type: '{}'. Must be one of: ignore, user, default", + nonce_type + ))); + }, }; Ok((nonce_type, nonce_value)) @@ -138,23 +123,14 @@ impl EvidenceManager { pub fn get_evidence(request: &GetEvidenceRequest) -> Result { log::info!("Starting evidence collection"); - let (nonce_type, nonce_value) = Self::process_nonce( - request.nonce_type.as_deref(), - request.user_nonce.as_ref(), - request.nonce.as_ref(), - )?; + let (nonce_type, nonce_value) = + Self::process_nonce(request.nonce_type.as_deref(), request.user_nonce.as_ref(), request.nonce.as_ref())?; let attester_info = request.attester_types.as_ref().map(|types| { - types.iter().map(|t| AttesterInfo { - attester_type: Some(t.clone()), - policy_ids: None, - }).collect::>() + types.iter().map(|t| AttesterInfo { attester_type: Some(t.clone()), policy_ids: None }).collect::>() }); - let evidences = collect_evidences_core( - &attester_info, - &nonce_value, - )?; + let evidences = collect_evidences_core(&attester_info, &nonce_value)?; let node_id = get_node_id()?; @@ -168,4 +144,4 @@ impl EvidenceManager { evidences, )) } -} \ No newline at end of file +} diff --git a/attestation_agent/challenge/src/lib.rs b/attestation_agent/challenge/src/lib.rs index b7fcec681f1a1accf1f1724be0d9b8a9b221781d..a6a1bcc48202e79416d93997d0b523339da23dde 100644 --- a/attestation_agent/challenge/src/lib.rs +++ b/attestation_agent/challenge/src/lib.rs @@ -12,10 +12,10 @@ pub mod challenge; pub mod challenge_error; -pub mod token; pub mod evidence; pub mod process_lock; +pub mod token; -pub use challenge::{AttesterInfo, do_challenge, get_cached_token_for_current_node, set_cached_tokens}; +pub use challenge::{do_challenge, get_cached_token_for_current_node, set_cached_tokens, AttesterInfo}; pub use challenge_error::ChallengeError; -pub use process_lock::platform::acquire_process_lock; \ No newline at end of file +pub use process_lock::platform::acquire_process_lock; diff --git a/attestation_agent/challenge/src/process_lock.rs b/attestation_agent/challenge/src/process_lock.rs index e344973358f005af9fb568e3dfeb94d7f1925943..bddc0b507b2a9274b1a1db140bcc1d6ffe623a92 100644 --- a/attestation_agent/challenge/src/process_lock.rs +++ b/attestation_agent/challenge/src/process_lock.rs @@ -11,8 +11,8 @@ */ // Cross-platform process lock trait and Linux implementation (POSIX semaphore). To extend for Windows, add implementation in this file. -use std::time::Duration; use crate::challenge_error::ChallengeError; +use std::time::Duration; /// Process lock guard trait pub trait LockGuard {} @@ -26,24 +26,22 @@ pub trait TpmLock: Send + Sync { #[cfg(target_os = "linux")] pub mod platform { use super::*; + use libc::{sem_open, sem_post, sem_t, sem_trywait, O_CREAT, O_RDWR, SEM_FAILED, S_IRUSR, S_IWUSR}; use std::ffi::CString; use std::os::raw::c_uint; use std::sync::Arc; - use std::time::{Duration, Instant}; - use std::thread::sleep; - use libc::{sem_t, sem_open, sem_trywait, sem_post, O_CREAT, O_RDWR, S_IRUSR, S_IWUSR, SEM_FAILED}; use std::sync::Mutex; + use std::thread::sleep; + use std::time::{Duration, Instant}; struct SemPtr(*mut sem_t); unsafe impl Send for SemPtr {} unsafe impl Sync for SemPtr {} pub struct GlibcSemaphoreLock { sem: Arc>, - name: CString, } pub struct GlibcSemaphoreGuard { sem: Arc>, - name: CString, } impl LockGuard for GlibcSemaphoreGuard {} @@ -62,19 +60,12 @@ pub mod platform { impl GlibcSemaphoreLock { pub fn new() -> Result { let c_name = CString::new("/tpm_lock").unwrap(); - let sem = unsafe { - sem_open( - c_name.as_ptr(), - O_CREAT | O_RDWR, - S_IRUSR | S_IWUSR, - 1 as c_uint, - ) - }; + let sem = unsafe { sem_open(c_name.as_ptr(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 1 as c_uint) }; if sem == SEM_FAILED { log::error!("Failed to open POSIX semaphore"); return Err(ChallengeError::InternalError("Failed to open POSIX semaphore".to_string())); } - Ok(Self { sem: Arc::new(Mutex::new(SemPtr(sem))), name: c_name }) + Ok(Self { sem: Arc::new(Mutex::new(SemPtr(sem))) }) } } @@ -86,10 +77,7 @@ pub mod platform { let ret = unsafe { sem_trywait(sem.0) }; drop(sem); if ret == 0 { - return Ok(Box::new(GlibcSemaphoreGuard { - sem: Arc::clone(&self.sem), - name: self.name.clone(), - })); + return Ok(Box::new(GlibcSemaphoreGuard { sem: Arc::clone(&self.sem) })); } else { sleep(Duration::from_millis(50)); } @@ -111,6 +99,8 @@ pub mod platform { use super::*; pub fn acquire_process_lock() -> Result, ChallengeError> { log::error!("acquire_process_lock is only supported on Linux platform, not implemented on other platforms!"); - Err(ChallengeError::InternalError("acquire_process_lock is only supported on Linux platform, not implemented on other platforms!".to_string())) + Err(ChallengeError::InternalError( + "acquire_process_lock is only supported on Linux platform, not implemented on other platforms!".to_string(), + )) } -} \ No newline at end of file +} diff --git a/attestation_agent/challenge/src/token.rs b/attestation_agent/challenge/src/token.rs index ce247c0378097e55634edebaa84f940a8f6e0c84..5957fbaf7017a4fb668ee6943a4c3f51510b42d6 100644 --- a/attestation_agent/challenge/src/token.rs +++ b/attestation_agent/challenge/src/token.rs @@ -10,12 +10,12 @@ * See the Mulan PSL v2 for more details. */ +use crate::challenge::{do_challenge, get_cached_token_for_current_node, AttesterInfo}; use crate::challenge_error::TokenError; -use crate::challenge::{AttesterInfo, do_challenge, get_cached_token_for_current_node}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; /// Request structure for token acquisition, including attester info and challenge flag -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Default)] pub struct TokenRequest { // Optional vector of attester information for the token request #[serde(default)] @@ -36,9 +36,9 @@ pub struct TokenRequest { impl TokenRequest { /// Sanitizes the request by removing empty values for robust processing /// Sanitizes the request by removing empty values: - /// - Converts empty attester_info vector to None + /// - Converts empty `attester_info` vector to None /// - Keeps challenge flag as is (Option is already well-handled) - /// - Converts empty or whitespace-only attester_data to None + /// - Converts empty or whitespace-only `attester_data` to None pub fn sanitize(self) -> Self { TokenRequest { attester_info: self.attester_info.and_then(|info| if info.is_empty() { None } else { Some(info) }), @@ -46,15 +46,6 @@ impl TokenRequest { attester_data: self.attester_data.and_then(|data| if data.is_null() { None } else { Some(data) }), } } - - /// Creates a default instance with all fields set to None - pub fn default() -> Self { - Self { - attester_info: None, - challenge: None, - attester_data: None, - } - } } /// Manager for token acquisition logic @@ -72,10 +63,9 @@ impl TokenManager { match do_challenge(&token_request.attester_info, &token_request.attester_data).await { Ok(token) => Ok(token), Err(e) => { - log::error!("Challenge failed, {}", e.to_string()); + log::error!("Challenge failed, {}", e); Err(TokenError::challenge_error(e.to_string())) }, } } } - diff --git a/attestation_agent/config/src/config.rs b/attestation_agent/config/src/config.rs index 29948583444577022e7f91e1a2bf5c669e6469e8..3746637abe5f886209b66dae952f3587685f80d7 100644 --- a/attestation_agent/config/src/config.rs +++ b/attestation_agent/config/src/config.rs @@ -153,9 +153,7 @@ impl Config { // 4. Validate plugin configuration for (idx, plugin) in self.plugins.iter().enumerate() { - if let Err(err) = self.validate_plugin(plugin, idx) { - return Err(err); - } + self.validate_plugin(plugin, idx)?; } // 5. Validate scheduler configuration @@ -207,15 +205,11 @@ impl Config { match params { PluginParams::TpmBoot(config) => { // Validate TPM base configuration - if let Err(err) = Self::validate_tpm_base_config(&config.tpm_base, &plugin.name, idx) { - return Err(err); - } + Self::validate_tpm_base_config(&config.tpm_base, &plugin.name, idx)?; }, PluginParams::TpmIma(config) => { // Validate TPM base configuration - if let Err(err) = Self::validate_tpm_base_config(&config.tpm_base, &plugin.name, idx) { - return Err(err); - } + Self::validate_tpm_base_config(&config.tpm_base, &plugin.name, idx)?; // Validate IMA log path if config.log_file_path.is_empty() { @@ -241,7 +235,7 @@ impl Config { // Validate AK handle if let Some(handle) = tpm_base.ak_handle { - if handle < TPM_KEY_HANDLE_MIN || handle > TPM_KEY_HANDLE_MAX { + if !(TPM_KEY_HANDLE_MIN..=TPM_KEY_HANDLE_MAX).contains(&handle) { return Err(format!( "Plugin #{} '{}' has AK handle value 0x{:x} outside valid range (0x{:x}-0x{:x})", idx, plugin_name, handle, TPM_KEY_HANDLE_MIN, TPM_KEY_HANDLE_MAX @@ -251,7 +245,7 @@ impl Config { // Validate NV index if let Some(index) = tpm_base.ak_nv_index { - if index < TPM_NV_INDEX_MIN || index > TPM_NV_INDEX_MAX { + if !(TPM_NV_INDEX_MIN..=TPM_NV_INDEX_MAX).contains(&index) { return Err(format!( "Plugin #{} '{}' has NV index value 0x{:x} outside valid range (0x{:x}-0x{:x})", idx, plugin_name, index, TPM_NV_INDEX_MIN, TPM_NV_INDEX_MAX @@ -320,8 +314,8 @@ impl Config { /// /// The configuration file is loaded using the following priority order: /// 1. Command line specified path (if provided and the file exists) -/// 2. Current working directory: ./agent_config.yaml -/// 3. System-wide configuration: /etc/attestation_agent/agent_config.yaml +/// 2. Current working directory: ./`agent_config.yaml` +/// 3. System-wide configuration: /`etc/attestation_agent/agent_config.yaml` /// /// If no configuration file is found in any of these locations, an error is returned. pub static AGENT_CONFIG: ConfigSingleton = ConfigSingleton::new(); @@ -339,7 +333,7 @@ impl ConfigManager { // Use simple validation method instead of complex validator validation AGENT_CONFIG.get_instance().and_then(|config| { - config.validate().map_err(|e| format!("Configuration validation failed: {}", e).into()) + config.validate().map_err(|e| format!("Configuration validation failed: {}", e)) })?; Ok(Self { config_path: actual_path }) diff --git a/attestation_agent/utils/Cargo.toml b/attestation_agent/utils/Cargo.toml index 0972155c4e597a0703bcefd6465a67cfd43181f4..138e9afeeea4014e95548c4916de91cb266346fc 100644 --- a/attestation_agent/utils/Cargo.toml +++ b/attestation_agent/utils/Cargo.toml @@ -16,7 +16,7 @@ config = { path = "../config" } plugin_manager = { path = "../../plugin_manager" } [features] -default = ["errors"] +default = ["errors", "log"] errors = ["log"] validate = ["errors", "validator", "regex"] client = ["reqwest", "errors", "validate", "once_cell", "serde_json", "openssl"] \ No newline at end of file diff --git a/attestation_agent/utils/src/load_plugins.rs b/attestation_agent/utils/src/load_plugins.rs index dea45103c38d9f34780b0adc31b0043880b9001e..865767b80f2e9e7041c5bc549a268c75b8c8ddf8 100644 --- a/attestation_agent/utils/src/load_plugins.rs +++ b/attestation_agent/utils/src/load_plugins.rs @@ -33,7 +33,7 @@ pub fn query_configuration(plugin_name: String) -> Option { let plugin = config.plugins.iter().find(|p| p.name == plugin_name)?; // Get and serialize the plugin parameters to JSON string - let params = match &plugin.params { + match &plugin.params { Some(params) => match ConfigManager::to_json(params) { Ok(json) => Some(json), Err(e) => { @@ -41,10 +41,8 @@ pub fn query_configuration(plugin_name: String) -> Option { None }, }, - None => Some("null".to_string()), // If no params, return JSON null - }; - - params + None => Some("null".to_string()), // If no params, return JSON nullclear + } } /// Load and initialize plugins based on configuration diff --git a/plugin_manager/src/manager.rs b/plugin_manager/src/manager.rs index 451ab3c3cbd37fbe80cf69f46f06aa8cdb10c1a0..583f88725bb927723df2cb98a92189b51c272235 100644 --- a/plugin_manager/src/manager.rs +++ b/plugin_manager/src/manager.rs @@ -88,7 +88,7 @@ impl PluginManager { .map_err(|e| format!("Failed to load library {}: {}", path, e))?; // Try to get the create_plugin symbol - let constructor = lib.get::>>(b"create_plugin") + let constructor = lib.get::>>(b"create_plugin") .map_err(|e| format!("Failed to find create_plugin symbol: {}", e))?; // Try to create the plugin