diff --git a/src/contract.rs b/src/contract.rs index f4dcd65..ad7d655 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -1,6 +1,6 @@ use crate::{ stable_json::stable_stringify, - types::{HtxPhala, Result, WatchdogError}, + types::{HtxIntelTdx, Result, WatchdogError}, }; use ethers::{ prelude::*, @@ -61,7 +61,7 @@ impl ContractClient { Ok(count.as_u64()) } - pub async fn submit_htx(&self, htx: &HtxPhala) -> Result<(String, String)> { + pub async fn submit_htx(&self, htx: &HtxIntelTdx) -> Result<(String, String)> { // Serialize HTX to stable JSON let json_string = stable_stringify(htx)?; tracing::debug!("HTX JSON: {}", json_string); diff --git a/src/main.rs b/src/main.rs index 9579a33..15dfad9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod contract; mod db; mod phala; +mod secret; mod stable_json; mod types; @@ -8,6 +9,7 @@ use crate::{ contract::ContractClient, db::SupabaseClient, phala::extract_phala_htx, + secret::extract_secret_htx, types::{Result, Workload}, }; use std::time::Duration; @@ -113,40 +115,44 @@ async fn process_single_workload( db_client: &SupabaseClient, contract_client: &ContractClient, ) -> Result<()> { - match workload.provider.as_str() { - "phala" => { + let htx = match workload.provider.as_str() { + "phala" | "secret" => { let cvm_url = workload.get_cvm_url().ok_or_else(|| { types::WatchdogError::Other("Missing cvmUrl in config".to_string()) })?; - - info!("🔄 Processing Phala workload: {}", workload.name); - - // Extract HTX - let htx = extract_phala_htx(&cvm_url).await?; - - // Check node count - let node_count = contract_client.node_count().await?; - if node_count == 0 { - warn!("⚠️ No nodes registered, skipping HTX submission"); - return Ok(()); - } - - // Submit HTX - let (tx_hash, htx_id) = contract_client.submit_htx(&htx).await?; - info!( - "📤 HTX submitted - txHash: {}, htxId: {}, nodeCount: {}", - tx_hash, htx_id, node_count + "🔄 Processing workload: {} (provider: {})", + workload.name, workload.provider ); - - // Update last heartbeat - db_client.update_heartbeat(&workload.id).await?; - - Ok(()) + match workload.provider.as_str() { + "phala" => extract_phala_htx(&cvm_url).await?, + "secret" => extract_secret_htx(&cvm_url).await?, + _ => unreachable!(), + } } other => { warn!("⚠️ Provider '{}' not yet supported", other); - Ok(()) + return Ok(()); } + }; + + // Check node count + let node_count = contract_client.node_count().await?; + if node_count == 0 { + warn!("⚠️ No nodes registered, skipping HTX submission"); + return Ok(()); } + + // Submit HTX + let (tx_hash, htx_id) = contract_client.submit_htx(&htx).await?; + + info!( + "📤 HTX submitted - txHash: {}, htxId: {}, nodeCount: {}", + tx_hash, htx_id, node_count + ); + + // Update last heartbeat + db_client.update_heartbeat(&workload.id).await?; + + Ok(()) } diff --git a/src/phala.rs b/src/phala.rs index d24b9d9..1e3dc57 100644 --- a/src/phala.rs +++ b/src/phala.rs @@ -1,7 +1,7 @@ -use crate::types::{AttestData, HtxPhala, PhalaAttestationResponse, PhalaInfoResponse, Result}; +use crate::types::{AttestData, HtxIntelTdx, PhalaAttestationResponse, PhalaInfoResponse, Result}; use reqwest::Client; -pub async fn extract_phala_htx(cvm_url: &str) -> Result { +pub async fn extract_phala_htx(cvm_url: &str) -> Result { let client = Client::new(); let base_url = cvm_url.trim_end_matches('/'); @@ -14,7 +14,7 @@ pub async fn extract_phala_htx(cvm_url: &str) -> Result { let attestation: PhalaAttestationResponse = client.get(&attestation_url).send().await?.json().await?; - Ok(HtxPhala { + Ok(HtxIntelTdx { provider: "phala".to_string(), app_compose: info.tcb_info.app_compose, attest_data: AttestData { diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 0000000..a650dea --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,27 @@ +use crate::types::{ + AttestData, HtxIntelTdx, Result, SecretAttestationResponse, SecretSelfResponse, +}; +use reqwest::Client; + +pub async fn extract_secret_htx(cvm_url: &str) -> Result { + let client = Client::new(); + let base_url = cvm_url.trim_end_matches('/'); + + // Fetch /info endpoint + let info_url = format!("{}/self", base_url); + let info: SecretSelfResponse = client.get(&info_url).send().await?.json().await?; + + // Fetch /attestation endpoint + let attestation_url = format!("{}/cpu", base_url); + let attestation: SecretAttestationResponse = + client.get(&attestation_url).send().await?.json().await?; + + Ok(HtxIntelTdx { + provider: "secret".to_string(), + app_compose: info.tcb_info.app_compose, + attest_data: AttestData { + quote: attestation.quote, + event_log: attestation.event_log, + }, + }) +} diff --git a/src/types.rs b/src/types.rs index 79475ad..9472159 100644 --- a/src/types.rs +++ b/src/types.rs @@ -28,7 +28,7 @@ impl Workload { } #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct HtxPhala { +pub struct HtxIntelTdx { pub provider: String, pub app_compose: String, pub attest_data: AttestData, @@ -45,6 +45,11 @@ pub struct PhalaInfoResponse { pub tcb_info: TcbInfo, } +#[derive(Debug, Deserialize)] +pub struct SecretSelfResponse { + pub tcb_info: TcbInfo, +} + #[derive(Debug, Deserialize)] pub struct TcbInfo { pub app_compose: String, @@ -58,6 +63,14 @@ pub struct PhalaAttestationResponse { pub vm_config: String, // Ignored - not included in HTX } +#[derive(Debug, Deserialize)] +pub struct SecretAttestationResponse { + pub quote: String, + pub event_log: String, + #[allow(dead_code)] + pub vm_config: String, // Ignored - not included in HTX +} + #[derive(thiserror::Error, Debug)] pub enum WatchdogError { #[error("HTTP error: {0}")]