diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 50261314..aa3777f2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -22,7 +22,7 @@ concurrency: env: CARGO_TERM_COLOR: always # Pinned toolchain for linting - ACTIONS_LINTS_TOOLCHAIN: 1.85.0 + ACTIONS_LINTS_TOOLCHAIN: 1.92.0 jobs: linting: diff --git a/Cargo.lock b/Cargo.lock index 295482fd..d017be43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -596,12 +596,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -620,11 +620,10 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", @@ -645,11 +644,11 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core 0.21.3", + "darling_core 0.23.0", "quote", "syn 2.0.110", ] @@ -945,9 +944,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "foreign-types" @@ -1178,21 +1177,15 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - [[package]] name = "hdrhistogram" version = "7.5.4" @@ -1260,15 +1253,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "hostname" version = "0.4.1" @@ -1774,9 +1758,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "0.7.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +checksum = "633a7320c4bb672863a3782e89b9094ad70285e097ff6832cddd0ec615beadfa" dependencies = [ "pest", "pest_derive", @@ -1812,12 +1796,12 @@ dependencies = [ [[package]] name = "k8s-openapi" -version = "0.26.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06d9e5e61dd037cdc51da0d7e2b2be10f497478ea7e120d85dad632adb99882b" +checksum = "05a6d6f3611ad1d21732adbd7a2e921f598af6c92d71ae6e2620da4b67ee1f0d" dependencies = [ "base64 0.22.1", - "chrono", + "jiff", "schemars", "serde", "serde_json", @@ -1825,9 +1809,9 @@ dependencies = [ [[package]] name = "kube" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e7bb0b6a46502cc20e4575b6ff401af45cfea150b34ba272a3410b78aa014e" +checksum = "0dae7229247e4215781e5c5104a056e1e2163943e577f9084cf8bba7b5248f7a" dependencies = [ "k8s-openapi", "kube-client", @@ -1838,16 +1822,14 @@ dependencies = [ [[package]] name = "kube-client" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4987d57a184d2b5294fdad3d7fc7f278899469d21a4da39a8f6ca16426567a36" +checksum = "010875e291a9c0a4e076f4f9c35b97d82fd2372cb3bc713252c3d08b7e73ce5b" dependencies = [ "base64 0.22.1", "bytes", - "chrono", "either", "futures", - "home", "http 1.4.0", "http-body 1.0.1", "http-body-util", @@ -1855,6 +1837,7 @@ dependencies = [ "hyper-openssl", "hyper-timeout", "hyper-util", + "jiff", "jsonpath-rust", "k8s-openapi", "kube-core", @@ -1874,14 +1857,14 @@ dependencies = [ [[package]] name = "kube-core" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914bbb770e7bb721a06e3538c0edd2babed46447d128f7c21caa68747060ee73" +checksum = "1ac76281aa698dd34111e25b21f5f6561932a30feabab5357152be273f8a81bb" dependencies = [ - "chrono", "derive_more", "form_urlencoded", "http 1.4.0", + "jiff", "json-patch", "k8s-openapi", "schemars", @@ -1893,11 +1876,11 @@ dependencies = [ [[package]] name = "kube-derive" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03dee8252be137772a6ab3508b81cd797dee62ee771112a2453bc85cbbe150d2" +checksum = "599c09721efcccc0e6a26e93df28c587da60ff5e099c657626fff2af0ae4cbb8" dependencies = [ - "darling 0.21.3", + "darling 0.23.0", "proc-macro2", "quote", "serde", @@ -1907,9 +1890,9 @@ dependencies = [ [[package]] name = "kube-runtime" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aea4de4b562c5cc89ab10300bb63474ae1fa57ff5a19275f2e26401a323e3fd" +checksum = "6db43d26700f564baf850f681f3cb0f1195d2699bd379bfa70750ecec4dcb209" dependencies = [ "ahash", "async-broadcast", @@ -1917,7 +1900,7 @@ dependencies = [ "backon", "educe", "futures", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "hostname", "json-patch", "k8s-openapi", @@ -2361,6 +2344,7 @@ version = "0.1.0" dependencies = [ "anyhow", "base64 0.22.1", + "chrono", "clevis-pin-trustee-lib", "compute-pcrs-lib", "env_logger", @@ -3187,9 +3171,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.148" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", @@ -3698,9 +3682,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -4230,15 +4214,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" diff --git a/Cargo.toml b/Cargo.toml index 87d9752a..5988d5d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ resolver = "3" [workspace.package] edition = "2024" -rust-version = "1.85" +rust-version = "1.92" [workspace.dependencies] anyhow = "1.0.100" @@ -19,8 +19,8 @@ compute-pcrs-lib = { git = "https://github.com/trusted-execution-clusters/comput env_logger = "0.11.8" http = "1.4.0" ignition-config = "0.5.0" -k8s-openapi = { version = "0.26.1", features = ["v1_33", "schemars"] } -kube = { version = "2.0.1", default-features = false, features = ["derive", "runtime", "openssl-tls"] } +k8s-openapi = { version = "0.27.0", features = ["v1_33", "schemars"] } +kube = { version = "3.0.0", default-features = false, features = ["derive", "runtime", "openssl-tls"] } log = "0.4.29" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.148" diff --git a/attestation-key-register/src/main.rs b/attestation-key-register/src/main.rs index 165d686e..8a764973 100644 --- a/attestation-key-register/src/main.rs +++ b/attestation-key-register/src/main.rs @@ -40,7 +40,7 @@ async fn handle_registration( client: Client, addr: Option, ) -> Result { - info!("Received registration request: {:?}", registration); + info!("Received registration request: {registration:?}"); let api: Api = Api::default_namespaced(client); @@ -50,8 +50,7 @@ async fn handle_registration( if key.spec.public_key == registration.public_key { let existing_name = key.metadata.name.unwrap_or_default(); error!( - "Duplicate public key detected: already exists in AttestationKey '{}'", - existing_name + "Duplicate public key detected: already exists in AttestationKey '{existing_name}'" ); return Ok(reply::with_status( reply::json(&serde_json::json!({ @@ -64,11 +63,11 @@ async fn handle_registration( } } Err(e) => { - error!("Failed to list AttestationKeys: {}", e); + error!("Failed to list AttestationKeys: {e}"); return Ok(reply::with_status( reply::json(&serde_json::json!({ "status": "error", - "message": format!("Failed to check for existing keys: {}", e), + "message": format!("Failed to check for existing keys: {e}"), })), StatusCode::INTERNAL_SERVER_ERROR, )); @@ -106,11 +105,11 @@ async fn handle_registration( )) } Err(e) => { - error!("Failed to create AttestationKey: {}", e); + error!("Failed to create AttestationKey: {e}"); Ok(reply::with_status( reply::json(&serde_json::json!({ "status": "error", - "message": format!("Failed to create AttestationKey: {}", e), + "message": format!("Failed to create AttestationKey: {e}"), })), StatusCode::INTERNAL_SERVER_ERROR, )) @@ -145,7 +144,7 @@ async fn main() -> anyhow::Result<()> { .and_then(handle_registration); let addr = SocketAddr::from(([0, 0, 0, 0], args.port)); - info!("Listening on {}", addr); + info!("Listening on {addr}"); warp::serve(register).run(addr).await; diff --git a/compute-pcrs/src/main.rs b/compute-pcrs/src/main.rs index 2509e2c0..db1f5f0d 100644 --- a/compute-pcrs/src/main.rs +++ b/compute-pcrs/src/main.rs @@ -6,7 +6,7 @@ use anyhow::{Context, Result}; use clap::Parser; use compute_pcrs_lib::*; -use k8s_openapi::{api::core::v1::ConfigMap, chrono::Utc}; +use k8s_openapi::{api::core::v1::ConfigMap, jiff::Timestamp}; use kube::{Api, Client}; use trusted_cluster_operator_lib::{conditions::INSTALLED_REASON, reference_values::*, *}; @@ -57,7 +57,7 @@ async fn main() -> Result<()> { let mut image_pcrs: ImagePcrs = serde_json::from_str(image_pcrs_str)?; let image_pcr = ImagePcr { - first_seen: Utc::now(), + first_seen: Timestamp::now(), reference: args.image, pcrs, }; diff --git a/lib/src/lib.rs b/lib/src/lib.rs index 33a79304..5ab81afb 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -8,6 +8,7 @@ pub mod reference_values; mod kopium; #[allow(clippy::all)] mod vendor_kopium; +use k8s_openapi::jiff::Timestamp; pub use kopium::approvedimages::*; pub use kopium::attestationkeys::*; pub use kopium::machines::*; @@ -17,7 +18,6 @@ pub use vendor_kopium::virtualmachines; use conditions::*; use k8s_openapi::apimachinery::pkg::apis::meta::v1::{Condition, Time}; -use k8s_openapi::chrono::Utc; #[macro_export] macro_rules! update_status { @@ -50,7 +50,7 @@ pub fn committed_condition(reason: &str, generation: Option) -> Condition { _ => "", } .to_string(), - last_transition_time: Time(Utc::now()), + last_transition_time: Time(Timestamp::now()), observed_generation: generation, } } diff --git a/lib/src/reference_values.rs b/lib/src/reference_values.rs index 0e6361f4..80661bf9 100644 --- a/lib/src/reference_values.rs +++ b/lib/src/reference_values.rs @@ -4,7 +4,7 @@ // SPDX-License-Identifier: MIT use compute_pcrs_lib::Pcr; -use k8s_openapi::chrono::{DateTime, Utc}; +use k8s_openapi::jiff::Timestamp; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -13,7 +13,7 @@ pub const PCR_CONFIG_FILE: &str = "image-pcrs.json"; #[derive(Deserialize, Serialize)] pub struct ImagePcr { - pub first_seen: DateTime, + pub first_seen: Timestamp, pub pcrs: Vec, pub reference: String, } diff --git a/operator/Cargo.toml b/operator/Cargo.toml index 0db4174e..85ddbba1 100644 --- a/operator/Cargo.toml +++ b/operator/Cargo.toml @@ -11,6 +11,7 @@ rust-version.workspace = true [dependencies] anyhow.workspace = true base64 = "0.22.1" +chrono = "0.4.42" clevis-pin-trustee-lib.workspace = true trusted-cluster-operator-lib = { path = "../lib" } compute-pcrs-lib.workspace = true diff --git a/operator/src/attestation_key_register.rs b/operator/src/attestation_key_register.rs index 5f56fa54..e126d5a4 100644 --- a/operator/src/attestation_key_register.rs +++ b/operator/src/attestation_key_register.rs @@ -135,13 +135,13 @@ async fn ak_reconcile( client: Arc, ) -> Result { let ak_name = ak.metadata.name.clone().unwrap_or_default(); - info!("Attestation Key reconciliation for: {}", ak_name); + info!("Attestation Key reconciliation for: {ak_name}"); let client = Arc::unwrap_or_clone(client); let machines: Api = Api::default_namespaced(client.clone()); let lp = ListParams::default(); let machine_list: ObjectList = machines.list(&lp).await.map_err(|e| { - eprintln!("Error fetching machine list: {}", e); + eprintln!("Error fetching machine list: {e}"); ControllerError::Anyhow(e.into()) })?; for machine in &machine_list.items { @@ -182,15 +182,15 @@ async fn machine_reconcile( let aks: Api = Api::default_namespaced(client.clone()); let lp = ListParams::default(); let ak_list: ObjectList = aks.list(&lp).await.map_err(|e| { - eprintln!("Error fetching attestation key list: {}", e); + eprintln!("Error fetching attestation key list: {e}"); ControllerError::Anyhow(e.into()) })?; for ak in ak_list.items { - if let Some(ak_address) = &ak.spec.address { - if *ak_address == machine_address { - approve_ak(&ak, &machine, client.clone()).await?; - return Ok(Action::await_change()); - } + if let Some(ak_address) = &ak.spec.address + && *ak_address == machine_address + { + approve_ak(&ak, &machine, client.clone()).await?; + return Ok(Action::await_change()); } } Ok(Action::await_change()) @@ -315,10 +315,7 @@ async fn secret_reconcile( return Ok(Action::await_change()); } - info!( - "Secret reconciliation for AttestationKey secret: {}", - secret_name - ); + info!("Secret reconciliation for AttestationKey secret: {secret_name}"); let secrets: Api = Api::default_namespaced(Arc::unwrap_or_clone(client.clone())); finalizer(&secrets, ATTESTATION_KEY_SECRET_FINALIZER, secret, |ev| async move { @@ -330,15 +327,14 @@ async fn secret_reconcile( .await .map(|_| Action::await_change()) .map_err(|e| { - eprintln!("Error updating attestation key volumes on secret apply: {}", e); + eprintln!("Error updating attestation key volumes on secret apply: {e}"); finalizer::Error::::ApplyFailed(e.into()) }) } Event::Cleanup(secret) => { let secret_name = secret.metadata.name.clone().unwrap_or_default(); info!( - "AttestationKey secret {} is being deleted, updating trustee deployment volumes", - secret_name + "AttestationKey secret {secret_name} is being deleted, updating trustee deployment volumes" ); let client = Arc::unwrap_or_clone(client); // Update trustee deployment - secrets with deletion_timestamp will be filtered out @@ -347,8 +343,7 @@ async fn secret_reconcile( .map(|_| Action::await_change()) .map_err(|e| { eprintln!( - "Error updating attestation key volumes during secret deletion: {}", - e + "Error updating attestation key volumes during secret deletion: {e}" ); finalizer::Error::::CleanupFailed(e.into()) }) diff --git a/operator/src/conditions.rs b/operator/src/conditions.rs index ae2b0fab..f969b059 100644 --- a/operator/src/conditions.rs +++ b/operator/src/conditions.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use k8s_openapi::apimachinery::pkg::apis::meta::v1::{Condition, Time}; -use k8s_openapi::chrono::Utc; +use k8s_openapi::jiff::Timestamp; use trusted_cluster_operator_lib::{condition_status, conditions::*}; pub fn known_trustee_address_condition(known: bool, generation: Option) -> Condition { @@ -18,7 +18,7 @@ pub fn known_trustee_address_condition(known: bool, generation: Option) -> status: condition_status(known), reason: reason.to_string(), message: message.to_string(), - last_transition_time: Time(Utc::now()), + last_transition_time: Time(Timestamp::now()), observed_generation: generation, } } @@ -38,7 +38,7 @@ pub fn installed_condition(reason: &str, generation: Option) -> Condition { _ => "", } .to_string(), - last_transition_time: Time(Utc::now()), + last_transition_time: Time(Timestamp::now()), observed_generation: generation, } } @@ -55,7 +55,7 @@ pub fn attestation_key_approved_condition(reason: &str, generation: Option) _ => "", } .to_string(), - last_transition_time: Time(Utc::now()), + last_transition_time: Time(Timestamp::now()), observed_generation: generation, } } diff --git a/operator/src/main.rs b/operator/src/main.rs index a0ada3ff..ce4916f5 100644 --- a/operator/src/main.rs +++ b/operator/src/main.rs @@ -261,7 +261,7 @@ async fn main() -> Result<()> { #[cfg(test)] mod tests { use http::{Method, Request, StatusCode}; - use k8s_openapi::{apimachinery::pkg::apis::meta::v1::Time, chrono::Utc}; + use k8s_openapi::{apimachinery::pkg::apis::meta::v1::Time, jiff::Timestamp}; use kube::api::ObjectList; use kube::client::Body; @@ -320,7 +320,7 @@ mod tests { }; count_check!(1, clos, |client| { let mut cluster = dummy_cluster(); - cluster.metadata.deletion_timestamp = Some(Time(Utc::now())); + cluster.metadata.deletion_timestamp = Some(Time(Timestamp::now())); let result = reconcile(Arc::new(cluster), Arc::new(dummy_cluster_ctx(client))).await; assert_eq!(result.unwrap(), Action::await_change()); }); diff --git a/operator/src/reference_values.rs b/operator/src/reference_values.rs index 29bd6485..2795054e 100644 --- a/operator/src/reference_values.rs +++ b/operator/src/reference_values.rs @@ -15,7 +15,7 @@ use k8s_openapi::{ }, }, apimachinery::pkg::apis::meta::v1::OwnerReference, - chrono::Utc, + jiff::Timestamp, }; use kube::api::{DeleteParams, ObjectMeta}; use kube::runtime::{ @@ -297,13 +297,13 @@ pub async fn handle_new_image( let config_maps: Api = Api::default_namespaced(ctx.client.clone()); let mut image_pcrs_map = config_maps.get(PCR_CONFIG_MAP).await?; let mut image_pcrs = get_image_pcrs(image_pcrs_map.clone())?; - if let Some(pcr) = image_pcrs.0.get(resource_name) { - if pcr.reference == boot_image { - info!("Image {boot_image} was to be allowed, but already was allowed"); - return trustee::update_reference_values(ctx) - .await - .map(|_| COMMITTED_REASON); - } + if let Some(pcr) = image_pcrs.0.get(resource_name) + && pcr.reference == boot_image + { + info!("Image {boot_image} was to be allowed, but already was allowed"); + return trustee::update_reference_values(ctx) + .await + .map(|_| COMMITTED_REASON); } let image_ref: oci_client::Reference = boot_image.parse()?; if image_ref.digest().is_none() { @@ -321,7 +321,7 @@ pub async fn handle_new_image( } let image_pcr = ImagePcr { - first_seen: Utc::now(), + first_seen: Timestamp::now(), pcrs: label.unwrap(), reference: boot_image.to_string(), }; @@ -377,7 +377,7 @@ mod tests { ..Default::default() }, status: Some(JobStatus { - completion_time: Some(Time(Utc::now())), + completion_time: Some(Time(Timestamp::now())), ..Default::default() }), ..Default::default() diff --git a/operator/src/test_utils.rs b/operator/src/test_utils.rs index 6d8e5717..a9c0241d 100644 --- a/operator/src/test_utils.rs +++ b/operator/src/test_utils.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT use compute_pcrs_lib::Pcr; -use k8s_openapi::{api::core::v1::ConfigMap, chrono::Utc}; +use k8s_openapi::{api::core::v1::ConfigMap, jiff::Timestamp}; use kube::Client; use operator::RvContextData; use std::collections::BTreeMap; @@ -15,7 +15,7 @@ pub fn dummy_pcrs() -> ImagePcrs { ImagePcrs(BTreeMap::from([( "cos".to_string(), ImagePcr { - first_seen: Utc::now(), + first_seen: Timestamp::now(), pcrs: vec![ Pcr { id: 0, diff --git a/operator/src/trustee.rs b/operator/src/trustee.rs index 74ad65d2..aaf0f00c 100644 --- a/operator/src/trustee.rs +++ b/operator/src/trustee.rs @@ -6,6 +6,7 @@ use anyhow::{Context, Result}; use base64::{Engine as _, engine::general_purpose}; +use chrono::{DateTime, TimeDelta, Utc}; use clevis_pin_trustee_lib::Key as ClevisKey; use k8s_openapi::api::apps::v1::{Deployment, DeploymentSpec}; use k8s_openapi::api::core::v1::{ @@ -17,7 +18,6 @@ use k8s_openapi::apimachinery::pkg::{ apis::meta::v1::{LabelSelector, OwnerReference}, util::intstr::IntOrString, }; -use k8s_openapi::chrono::{DateTime, TimeDelta, Utc}; use kube::{ Api, Client, Resource, api::{ObjectMeta, Patch, PatchParams}, @@ -254,7 +254,7 @@ pub async fn update_attestation_keys(client: Client) -> Result<()> { name: secret_name.to_string(), items: Some(vec![KeyToPath { key: "public_key".to_string(), - path: format!("{}.pub", secret_name), + path: format!("{secret_name}.pub"), ..Default::default() }]), ..Default::default() diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs index 60bd4d87..ee7fd4d9 100644 --- a/test_utils/src/lib.rs +++ b/test_utils/src/lib.rs @@ -225,13 +225,12 @@ impl TestContext { async move { let deployment = api.get(&name).await?; - if let Some(status) = &deployment.status { - if let Some(available_replicas) = status.available_replicas { - if available_replicas == 1 { - test_info!(&tn, "{} deployment has 1 available replica", name); - return Ok(()); - } - } + if let Some(status) = &deployment.status + && let Some(available_replicas) = status.available_replicas + && available_replicas == 1 + { + test_info!(&tn, "{} deployment has 1 available replica", name); + return Ok(()); } Err(anyhow::anyhow!( @@ -357,14 +356,14 @@ impl TestContext { let sa_src = workspace_root.join("config/rbac/service_account.yaml"); let sa_content = std::fs::read_to_string(&sa_src)? - .replace("namespace: system", &format!("namespace: {}", ns)); + .replace("namespace: system", &format!("namespace: {ns}")); let sa_dst = rbac_temp_dir.join("service_account.yaml"); std::fs::write(&sa_dst, sa_content)?; let role_path = rbac_temp_dir.join("role.yaml"); let role_content = std::fs::read_to_string(&role_path)?.replace( "name: trusted-cluster-operator-role", - &format!("name: {}-trusted-cluster-operator-role", ns), + &format!("name: {ns}-trusted-cluster-operator-role"), ); std::fs::write(&role_path, role_content)?; @@ -372,25 +371,25 @@ impl TestContext { let rb_content = std::fs::read_to_string(&rb_src)? .replace( "name: manager-rolebinding", - &format!("name: {}-manager-rolebinding", ns), + &format!("name: {ns}-manager-rolebinding"), ) .replace( "name: trusted-cluster-operator-role", - &format!("name: {}-trusted-cluster-operator-role", ns), + &format!("name: {ns}-trusted-cluster-operator-role"), ) - .replace("namespace: system", &format!("namespace: {}", ns)); + .replace("namespace: system", &format!("namespace: {ns}")); let rb_dst = rbac_temp_dir.join("role_binding.yaml"); std::fs::write(&rb_dst, rb_content)?; let le_role_src = workspace_root.join("config/rbac/leader_election_role.yaml"); let le_role_content = std::fs::read_to_string(&le_role_src)? - .replace("namespace: system", &format!("namespace: {}", ns)); + .replace("namespace: system", &format!("namespace: {ns}")); let le_role_dst = rbac_temp_dir.join("leader_election_role.yaml"); std::fs::write(&le_role_dst, le_role_content)?; let le_rb_src = workspace_root.join("config/rbac/leader_election_role_binding.yaml"); let le_rb_content = std::fs::read_to_string(&le_rb_src)? - .replace("namespace: system", &format!("namespace: {}", ns)); + .replace("namespace: system", &format!("namespace: {ns}")); let le_rb_dst = rbac_temp_dir.join("leader_election_role_binding.yaml"); std::fs::write(&le_rb_dst, le_rb_content)?; @@ -399,7 +398,7 @@ impl TestContext { r#"# SPDX-FileCopyrightText: Generated for testing # SPDX-License-Identifier: CC0-1.0 -namespace: {} +namespace: {ns} resources: - service_account.yaml @@ -407,8 +406,7 @@ resources: - role_binding.yaml - leader_election_role.yaml - leader_election_role_binding.yaml -"#, - ns +"# ); let temp_kustomization_path = rbac_temp_dir.join("kustomization.yaml"); @@ -436,19 +434,19 @@ resources: &self.test_name, "Updating CR manifest with publicTrusteeAddr" ); - let trustee_addr = format!("kbs-service.{}.svc.cluster.local:8080", ns); + let trustee_addr = format!("kbs-service.{ns}.svc.cluster.local:8080"); let cr_manifest_path = manifests_path.join("trusted_execution_cluster_cr.yaml"); let cr_content = std::fs::read_to_string(&cr_manifest_path)?; let mut cr_value: serde_yaml::Value = serde_yaml::from_str(&cr_content)?; - if let Some(spec) = cr_value.get_mut("spec") { - if let Some(spec_map) = spec.as_mapping_mut() { - spec_map.insert( - serde_yaml::Value::String("publicTrusteeAddr".to_string()), - serde_yaml::Value::String(trustee_addr.clone()), - ); - } + if let Some(spec) = cr_value.get_mut("spec") + && let Some(spec_map) = spec.as_mapping_mut() + { + spec_map.insert( + serde_yaml::Value::String("publicTrusteeAddr".to_string()), + serde_yaml::Value::String(trustee_addr.clone()), + ); } let updated_content = serde_yaml::to_string(&cr_value)?; @@ -494,8 +492,7 @@ resources: .with_timeout(Duration::from_secs(60)) .with_interval(Duration::from_secs(5)) .with_error_message(format!( - "image-pcrs ConfigMap in the namespace {} not found", - ns + "image-pcrs ConfigMap in the namespace {ns} not found" )); let test_name_owned = self.test_name.clone(); diff --git a/test_utils/src/mock_client.rs b/test_utils/src/mock_client.rs index 4118aa52..068eeb92 100644 --- a/test_utils/src/mock_client.rs +++ b/test_utils/src/mock_client.rs @@ -5,7 +5,8 @@ use http::{Method, Request, Response, StatusCode}; use kube::api::ObjectMeta; -use kube::{Client, client::Body, error::ErrorResponse}; +use kube::core::{Status, response::StatusSummary}; +use kube::{Client, client::Body}; use serde::Serialize; use std::fmt::Debug; use std::sync::atomic::{AtomicU32, Ordering}; @@ -58,11 +59,12 @@ async fn create_response>>( StatusCode::BAD_REQUEST => ("bad request", "BadRequest"), _ => (unknown_msg.as_str(), "Unknown"), }; - let error_response = ErrorResponse { - status: "Failure".to_string(), + let error_response = Status { + status: Some(StatusSummary::Failure), message: message.to_string(), reason: reason.to_string(), code: status_code.as_u16(), + ..Default::default() }; let error_json = serde_json::to_string(&error_response).unwrap(); (Body::from(error_json.into_bytes()), status_code) @@ -152,7 +154,7 @@ async fn test_error< count_check!(1, server, |client| { let err = action(client).await.unwrap_err(); let msg = "internal server error"; - assert_kube_api_error!(err, 500, "ServerTimeout", msg, "Failure"); + assert_kube_api_error!(err, 500, "ServerTimeout", msg, Some(StatusSummary::Failure)); }); } diff --git a/test_utils/src/virt.rs b/test_utils/src/virt.rs index 9ba3aace..82b9b23e 100644 --- a/test_utils/src/virt.rs +++ b/test_utils/src/virt.rs @@ -49,10 +49,7 @@ pub fn generate_ssh_key_pair() -> anyhow::Result<(String, String, std::path::Pat let stderr = String::from_utf8_lossy(&ssh_add_output.stderr); // Clean up the key file if ssh-add fails let _ = fs::remove_file(&key_path); - return Err(anyhow::anyhow!( - "Failed to add SSH key to agent: {}", - stderr - )); + return Err(anyhow::anyhow!("Failed to add SSH key to agent: {stderr}")); } Ok((private_key_str, public_key_str, key_path)) @@ -138,10 +135,8 @@ pub fn generate_ignition_config( serde_json::to_value(&config).expect("Failed to serialize ignition config"); // Add attestation key registration field - let attestation_url = format!( - "http://attestation-key-register.{}.svc.cluster.local:8001/register-ak", - namespace - ); + let attestation_url = + format!("http://attestation-key-register.{namespace}.svc.cluster.local:8001/register-ak"); if let Some(obj) = ignition_json.as_object_mut() { obj.insert( @@ -303,8 +298,7 @@ pub async fn wait_for_vm_running( .with_timeout(Duration::from_secs(timeout_secs)) .with_interval(Duration::from_secs(5)) .with_error_message(format!( - "VirtualMachine {} did not reach Running phase after {} seconds", - vm_name, timeout_secs + "VirtualMachine {vm_name} did not reach Running phase after {timeout_secs} seconds" )); poller @@ -315,17 +309,15 @@ pub async fn wait_for_vm_running( let vm = api.get(&name).await?; // Check VM status phase - if let Some(status) = vm.status { - if let Some(phase) = status.printable_status { - if phase.as_str() == "Running" { - return Ok(()); - } - } + if let Some(status) = vm.status + && let Some(phase) = status.printable_status + && phase.as_str() == "Running" + { + return Ok(()); } Err(anyhow::anyhow!( - "VirtualMachine {} is not in Running phase yet", - name + "VirtualMachine {name} is not in Running phase yet" )) } }) @@ -344,7 +336,7 @@ pub async fn virtctl_ssh_exec( )); } - let _vm_target = format!("core@vmi/{}/{}", vm_name, namespace); + let _vm_target = format!("core@vmi/{vm_name}/{namespace}"); let full_cmd = format!( "virtctl ssh -i {} core@vmi/{}/{} -t '-o IdentitiesOnly=yes' -t '-o StrictHostKeyChecking=no' --known-hosts /dev/null -c '{}'", key_path.display(), @@ -356,7 +348,7 @@ pub async fn virtctl_ssh_exec( let output = Command::new("sh").arg("-c").arg(full_cmd).output().await?; if !output.status.success() { let stderr = String::from_utf8_lossy(&output.stderr); - return Err(anyhow::anyhow!("virtctl ssh command failed: {}", stderr)); + return Err(anyhow::anyhow!("virtctl ssh command failed: {stderr}")); } Ok(String::from_utf8_lossy(&output.stdout).to_string()) @@ -392,8 +384,7 @@ async fn wait_for_vm_ssh( .with_timeout(Duration::from_secs(timeout_secs)) .with_interval(Duration::from_secs(10)) .with_error_message(format!( - "SSH access to VM {}/{} did not become {}available after {} seconds", - namespace, vm_name, avail_prefix, timeout_secs + "SSH access to VM {namespace}/{vm_name} did not become {avail_prefix}available after {timeout_secs} seconds", )); poller diff --git a/tests/attestation.rs b/tests/attestation.rs index 2947ef26..9d78e9cc 100644 --- a/tests/attestation.rs +++ b/tests/attestation.rs @@ -46,17 +46,15 @@ impl SingleAttestationContext { let (_private_key, public_key, key_path) = virt::generate_ssh_key_pair()?; test_ctx.info(format!( - "Generated SSH key pair and added to ssh-agent: {:?}", - key_path + "Generated SSH key pair and added to ssh-agent: {key_path:?}" )); let register_server_url = format!( - "http://register-server.{}.svc.cluster.local:8000/ignition-clevis-pin-trustee", - namespace + "http://register-server.{namespace}.svc.cluster.local:8000/ignition-clevis-pin-trustee" ); let image = "quay.io/trusted-execution-clusters/fedora-coreos-kubevirt:20260129"; - test_ctx.info(format!("Creating VM: {}", vm_name)); + test_ctx.info(format!("Creating VM: {vm_name}")); virt::create_kubevirt_vm( client, namespace, @@ -67,11 +65,11 @@ impl SingleAttestationContext { ) .await?; - test_ctx.info(format!("Waiting for VM {} to reach Running state", vm_name)); + test_ctx.info(format!("Waiting for VM {vm_name} to reach Running state")); virt::wait_for_vm_running(client, namespace, vm_name, 300).await?; - test_ctx.info(format!("VM {} is Running", vm_name)); + test_ctx.info(format!("VM {vm_name} is Running")); - test_ctx.info(format!("Waiting for SSH access to VM {}", vm_name)); + test_ctx.info(format!("Waiting for SSH access to VM {vm_name}")); virt::wait_for_vm_ssh_ready(namespace, vm_name, &key_path, 600).await?; test_ctx.info("SSH access is ready"); @@ -124,8 +122,7 @@ async fn test_parallel_vm_attestation() -> anyhow::Result<()> { test_ctx.info("Generated SSH key pairs for both VMs"); let register_server_url = format!( - "http://register-server.{}.svc.cluster.local:8000/ignition-clevis-pin-trustee", - namespace + "http://register-server.{namespace}.svc.cluster.local:8000/ignition-clevis-pin-trustee" ); let image = "quay.io/trusted-execution-clusters/fedora-coreos-kubevirt:20260129"; @@ -233,7 +230,7 @@ async fn test_vm_reboot_attestation() -> anyhow::Result<()> { // Perform multiple reboots let num_reboots = 3; for i in 1..=num_reboots { - test_ctx.info(format!("Performing reboot {} of {}", i, num_reboots)); + test_ctx.info(format!("Performing reboot {i} of {num_reboots}")); // Reboot the VM via SSH let _reboot_result = virt::virtctl_ssh_exec( @@ -244,27 +241,25 @@ async fn test_vm_reboot_attestation() -> anyhow::Result<()> { ) .await; - test_ctx.info(format!("Waiting for lack of SSH access after reboot {}", i)); + test_ctx.info(format!("Waiting for lack of SSH access after reboot {i}")); virt::wait_for_vm_ssh_unavail(namespace, vm_name, &att_ctx.key_path, 30).await?; - test_ctx.info(format!("Waiting for SSH access after reboot {}", i)); + test_ctx.info(format!("Waiting for SSH access after reboot {i}")); virt::wait_for_vm_ssh_ready(namespace, vm_name, &att_ctx.key_path, 300).await?; // Verify encrypted root is still present after reboot - test_ctx.info(format!("Verifying encrypted root after reboot {}", i)); + test_ctx.info(format!("Verifying encrypted root after reboot {i}")); let has_encrypted_root = virt::verify_encrypted_root(namespace, vm_name, &att_ctx.key_path, &att_ctx.root_key).await?; assert!( has_encrypted_root, - "VM should have encrypted root device after reboot {}", - i + "VM should have encrypted root device after reboot {i}" ); - test_ctx.info(format!("Reboot {}: attestation successful", i)); + test_ctx.info(format!("Reboot {i}: attestation successful")); } test_ctx.info(format!( - "VM successfully rebooted {} times with encrypted root device maintained", - num_reboots + "VM successfully rebooted {num_reboots} times with encrypted root device maintained" )); test_ctx.cleanup().await?; diff --git a/tests/trusted_execution_cluster.rs b/tests/trusted_execution_cluster.rs index 6a60cd49..abd0fc9c 100644 --- a/tests/trusted_execution_cluster.rs +++ b/tests/trusted_execution_cluster.rs @@ -60,14 +60,12 @@ async fn test_image_pcrs_configmap_updates() -> anyhow::Result<()> { async move { let cm = api.get("image-pcrs").await?; - if let Some(data) = &cm.data { - if let Some(image_pcrs_json) = data.get("image-pcrs.json") { - if let Ok(image_pcrs) = serde_json::from_str::(image_pcrs_json) { - if !image_pcrs.0.is_empty() { - return Ok(()); - } - } - } + if let Some(data) = &cm.data + && let Some(image_pcrs_json) = data.get("image-pcrs.json") + && let Ok(image_pcrs) = serde_json::from_str::(image_pcrs_json) + && !image_pcrs.0.is_empty() + { + return Ok(()); } Err(anyhow::anyhow!("image-pcrs ConfigMap not yet populated with image-pcrs.json data")) @@ -167,12 +165,11 @@ async fn test_image_disallow() -> anyhow::Result<()> { let api = configmap_api.clone(); async move { let cm = api.get("trustee-data").await?; - if let Some(data) = &cm.data { - if let Some(reference_values_json) = data.get("reference-values.json") { - if !reference_values_json.contains(EXPECTED_PCR4) { - return Ok(()); - } - } + if let Some(data) = &cm.data + && let Some(reference_values_json) = data.get("reference-values.json") + && !reference_values_json.contains(EXPECTED_PCR4) + { + return Ok(()); } Err(anyhow::anyhow!("Reference value not yet removed")) }