// SPDX-License-Identifier: MIT // // Copyright IBM Corp. 2025 //! Handlers for processing CLI flags and subcommands use std::io::{self, Write}; use std::path::{Path, PathBuf}; use crate::constants::*; use crate::io_utils::{collect_bit_messages, collect_version_flags, read_hex_from_file}; use crate::strings::*; // Represents metadata for a supported content file. struct Content { file: &'static str, label: &'static str, desc_content: Option<&'static str>, } impl Content { // Reads a hex file, then prints either: // bit messages or version flags fn handle_flag(&self, writer: &mut dyn Write, query_dir: &Path) -> io::Result { let hex = match read_hex_from_file(query_dir.join(self.file), self.label) { Some(h) => h, None => { return Ok(String::new()); } }; let mut output = String::new(); let header = format!("\n{}:", self.label); writeln!(writer, "{header}")?; output.push_str(&header); match self.desc_content { Some(desc) => { for msg in collect_bit_messages(hex, desc) { writeln!(writer, "{msg}")?; output.push_str(&format!("\n{msg}")); } } None => { for v in collect_version_flags(hex) { writeln!(writer, "{v}")?; output.push_str(&format!("\n{v}")); } } } Ok(output) } } // Define constants for each supported flag group const SUPP_SECRET_C: Content = Content { file: SUPP_SECRET_TYPES, label: "Supported Secret types", desc_content: Some(SUPP_SECRET_TYPES_DESC), }; const SUPP_ADD_SECRET_REQ_C: Content = Content { file: SUPP_ADD_SECRET_REQ_VER, label: "Supported Add Secret Request Versions", desc_content: None, }; const SUPP_ADD_SECRET_PCF_C: Content = Content { file: SUPP_ADD_SECRET_PCF, label: "Supported Plaintext Add Secret Flags", desc_content: Some(SUPP_ADD_SECRET_PCF_DESC), }; const SUPP_ATT_PFLAGS_C: Content = Content { file: SUPP_ATT_PFLAGS, label: "Supported Plaintext Attestation Flags", desc_content: Some(SUPP_ATT_PFLAGS_DESC), }; const SUPP_ATT_REQ_HDR_VER_C: Content = Content { file: SUPP_ATT_REQ_HDR_VER, label: "Supported Attestation Request Versions", desc_content: None, }; const SUPP_SE_HDR_VER_C: Content = Content { file: SUPP_SE_HDR_VER, label: "Supported SE Header Versions", desc_content: None, }; const SUPP_SE_HDR_PCF_C: Content = Content { file: SUPP_SE_HDR_PCF, label: "Supported Plaintext Control Flags", desc_content: Some(SUPP_SE_HDR_PCF_DESC), }; // Main entry point for handling the supported-flags subcommand. pub fn handle_supported_flags( writer: &mut dyn Write, secret: bool, attestation: bool, header: bool, query_dir: PathBuf, ) -> io::Result> { let mut results = Vec::new(); if secret { results.push(SUPP_SECRET_C.handle_flag(writer, &query_dir)?); results.push(SUPP_ADD_SECRET_REQ_C.handle_flag(writer, &query_dir)?); results.push(SUPP_ADD_SECRET_PCF_C.handle_flag(writer, &query_dir)?); } if attestation { results.push(SUPP_ATT_PFLAGS_C.handle_flag(writer, &query_dir)?); results.push(SUPP_ATT_REQ_HDR_VER_C.handle_flag(writer, &query_dir)?); } if header { results.push(SUPP_SE_HDR_VER_C.handle_flag(writer, &query_dir)?); results.push(SUPP_SE_HDR_PCF_C.handle_flag(writer, &query_dir)?); } if results.is_empty() { let mut all_results = handle_supported_flags(writer, true, true, true, query_dir)?; results.append(&mut all_results); } Ok(results) } // Unit Tests for handlers #[cfg(test)] mod test { use std::fs; use tempfile::tempdir; use super::*; // Verifies that handle_supported_flags correctly processes all #[test] fn test_handle_supported_flags_with_buffer() { let dir = tempdir().unwrap(); // Creating files fs::write(dir.path().join(SUPP_SECRET_TYPES), "1").unwrap(); fs::write(dir.path().join(SUPP_ADD_SECRET_REQ_VER), "1").unwrap(); fs::write(dir.path().join(SUPP_ADD_SECRET_PCF), "1").unwrap(); fs::write(dir.path().join(SUPP_ATT_PFLAGS), "1").unwrap(); fs::write(dir.path().join(SUPP_ATT_REQ_HDR_VER), "1").unwrap(); fs::write(dir.path().join(SUPP_SE_HDR_VER), "1").unwrap(); fs::write(dir.path().join(SUPP_SE_HDR_PCF), "1").unwrap(); // Capture output into buffer let mut buffer = Vec::new(); let results = handle_supported_flags(&mut buffer, true, true, true, dir.path().to_path_buf()) .unwrap(); // Convert buffer to string let printed = String::from_utf8(buffer).unwrap(); let normalized: String = printed .lines() .map(|line| line.trim()) .filter(|line| !line.is_empty()) .collect::>() .join(" "); let expected = [ "Supported Secret types:", "Supported Add Secret Request Versions:", "Supported Plaintext Add Secret Flags:", "Supported Plaintext Attestation Flags:", "Supported Attestation Request Versions:", "Supported SE Header Versions:", "Supported Plaintext Control Flags:", ]; for label in &expected { assert!( normalized.contains(label), "{label} missing in printed output!\nNormalized buffer:\n{normalized}" ); assert!( results.iter().any(|r| r.contains(label)), "{label} missing in results Vec!" ); } } }