Skip to content

Commit

Permalink
feat: allow use of unknown arches through commandline
Browse files Browse the repository at this point in the history
  • Loading branch information
j-lanson committed Sep 20, 2024
1 parent 0036c7c commit 30c56ce
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 54 deletions.
11 changes: 7 additions & 4 deletions hipcheck/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
error::Context,
error::Result,
hc_error,
plugin::SupportedArch,
plugin::Arch,
session::pm,
shell::{color_choice::ColorChoice, verbosity::Verbosity},
source,
Expand All @@ -19,7 +19,10 @@ use crate::{
use clap::{Parser as _, ValueEnum};
use hipcheck_macros as hc;
use pathbuf::pathbuf;
use std::path::{Path, PathBuf};
use std::{
path::{Path, PathBuf},
str::FromStr,
};
use url::Url;

/// Automatated supply chain risk assessment of software packages.
Expand Down Expand Up @@ -417,8 +420,8 @@ pub struct CheckArgs {
#[clap(subcommand)]
command: Option<CheckCommand>,

#[arg(long = "arch")]
pub arch: Option<SupportedArch>,
#[arg(long = "arch", value_parser = Arch::from_str)]
pub arch: Option<Arch>,

#[arg(short = 't', long = "target")]
pub target_type: Option<TargetType>,
Expand Down
3 changes: 2 additions & 1 deletion hipcheck/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ pub fn start_plugins(
)?;

let current_arch = try_get_current_arch()?;
println!("CURRENT ARCH: {}", current_arch);

// retrieve, verify and extract all required plugins
let required_plugin_names = retrieve_plugins(&policy_file.plugins.0, plugin_cache)?;
Expand All @@ -248,7 +249,7 @@ pub fn start_plugins(
let contents = read_string(&plugin_kdl)?;
let plugin_manifest = PluginManifest::from_str(contents.as_str())?;
let entrypoint = plugin_manifest
.get_entrypoint(current_arch)
.get_entrypoint(&current_arch)
.ok_or_else(|| {
hc_error!(
"Could not find {} entrypoint for {}/{} {}",
Expand Down
2 changes: 1 addition & 1 deletion hipcheck/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ fn main() -> ExitCode {
/// Run the `check` command.
fn cmd_check(args: &CheckArgs, config: &CliConfig) -> ExitCode {
// Before we do any analysis, set the user-provided arch
if let Some(arch) = args.arch {
if let Some(arch) = &args.arch {
if let Err(e) = try_set_arch(arch) {
Shell::print_error(&e, Format::Human);
return ExitCode::FAILURE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{fmt::Display, result::Result as StdResult, str::FromStr, sync::OnceLoc
/// Officially supported target triples, as of RFD #0004
///
/// NOTE: these architectures correspond to the offically supported Rust platforms
pub enum SupportedArch {
pub enum KnownArch {
/// Used for macOS running on "Apple Silicon" running on a 64-bit ARM Instruction Set Architecture (ISA)
Aarch64AppleDarwin,
/// Used for macOS running on the Intel 64-bit ISA
Expand All @@ -18,22 +18,32 @@ pub enum SupportedArch {
X86_64PcWindowsMsvc,
/// Used for Linux operating systems running on the Intel 64-bit ISA with a GNU toolchain for compilation
X86_64UnknownLinuxGnu,
/// Used for Linux operating systems running on a 64-bit ARM ISA
Aarch64UnknownLinuxGnu,
}

pub const DETECTED_ARCH: Option<SupportedArch> = {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Arch {
Known(KnownArch),
Unknown(String),
}

pub const DETECTED_ARCH: Option<KnownArch> = {
if cfg!(target_arch = "x86_64") {
if cfg!(target_os = "macos") {
Some(SupportedArch::X86_64AppleDarwin)
Some(KnownArch::X86_64AppleDarwin)
} else if cfg!(target_os = "linux") {
Some(SupportedArch::X86_64UnknownLinuxGnu)
Some(KnownArch::X86_64UnknownLinuxGnu)
} else if cfg!(target_os = "windows") {
Some(SupportedArch::X86_64PcWindowsMsvc)
Some(KnownArch::X86_64PcWindowsMsvc)
} else {
None
}
} else if cfg!(target_arch = "aarch64") {
if cfg!(target_os = "macos") {
Some(SupportedArch::Aarch64AppleDarwin)
Some(KnownArch::Aarch64AppleDarwin)
} else if cfg!(target_os = "linux") {
Some(KnownArch::Aarch64UnknownLinuxGnu)
} else {
None
}
Expand All @@ -42,34 +52,34 @@ pub const DETECTED_ARCH: Option<SupportedArch> = {
}
};

pub static USER_PROVIDED_ARCH: OnceLock<SupportedArch> = OnceLock::new();
pub static USER_PROVIDED_ARCH: OnceLock<Arch> = OnceLock::new();

/// Get the target architecture for plugins. If the user provided a target,
/// return that. Otherwise, if the `hc` binary was compiled for a supported
/// architecture, return that. Otherwise return None.
pub fn get_current_arch() -> Option<SupportedArch> {
pub fn get_current_arch() -> Option<Arch> {
if let Some(arch) = USER_PROVIDED_ARCH.get() {
Some(*arch)
} else if DETECTED_ARCH.is_some() {
DETECTED_ARCH
Some(arch.clone())
} else if let Some(known_arch) = DETECTED_ARCH {
Some(Arch::Known(known_arch))
} else {
None
}
}

/// Like `get_current_arch()`, but returns an error message suggesting the
/// user specifies a target on the CLI
pub fn try_get_current_arch() -> Result<SupportedArch> {
pub fn try_get_current_arch() -> Result<Arch> {
if let Some(arch) = get_current_arch() {
Ok(arch)
} else {
Err(hc_error!("Could not resolve the current machine to one of the Hipcheck supported architectures. Please specify --arch on the commandline."))
Err(hc_error!("Could not resolve the current machine to one of the Hipcheck known architectures. Please specify --arch on the commandline."))
}
}

pub fn try_set_arch(arch: SupportedArch) -> Result<()> {
let set_arch = USER_PROVIDED_ARCH.get_or_init(|| arch);
if *set_arch == arch {
pub fn try_set_arch(arch: &Arch) -> Result<()> {
let set_arch = USER_PROVIDED_ARCH.get_or_init(|| arch.clone());
if set_arch == arch {
Ok(())
} else {
Err(hc_error!(
Expand All @@ -80,12 +90,13 @@ pub fn try_set_arch(arch: SupportedArch) -> Result<()> {
}
}

impl FromStr for SupportedArch {
impl FromStr for KnownArch {
type Err = crate::Error;

fn from_str(s: &str) -> StdResult<Self, Self::Err> {
match s {
"aarch64-apple-darwin" => Ok(Self::Aarch64AppleDarwin),
"aarch64-unknown-linux-gnu" => Ok(Self::Aarch64UnknownLinuxGnu),
"x86_64-apple-darwin" => Ok(Self::X86_64AppleDarwin),
"x86_64-pc-windows-msvc" => Ok(Self::X86_64PcWindowsMsvc),
"x86_64-unknown-linux-gnu" => Ok(Self::X86_64UnknownLinuxGnu),
Expand All @@ -94,14 +105,36 @@ impl FromStr for SupportedArch {
}
}

impl Display for SupportedArch {
impl Display for KnownArch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let target_triple = match self {
SupportedArch::Aarch64AppleDarwin => "aarch64-apple-darwin",
SupportedArch::X86_64AppleDarwin => "x86_64-apple-darwin",
SupportedArch::X86_64PcWindowsMsvc => "x86_64-pc-windows-msvc",
SupportedArch::X86_64UnknownLinuxGnu => "x86_64-unknown-linux-gnu",
KnownArch::Aarch64AppleDarwin => "aarch64-apple-darwin",
KnownArch::Aarch64UnknownLinuxGnu => "aarch64-unknown-linux-gnu",
KnownArch::X86_64AppleDarwin => "x86_64-apple-darwin",
KnownArch::X86_64PcWindowsMsvc => "x86_64-pc-windows-msvc",
KnownArch::X86_64UnknownLinuxGnu => "x86_64-unknown-linux-gnu",
};
write!(f, "{}", target_triple)
}
}

impl FromStr for Arch {
type Err = std::convert::Infallible;

fn from_str(s: &str) -> StdResult<Self, Self::Err> {
if let Ok(known_arch) = FromStr::from_str(s) {
Ok(Arch::Known(known_arch))
} else {
Ok(Arch::Unknown(s.to_owned()))
}
}
}

impl Display for Arch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Arch::Known(known_arch) => known_arch.fmt(f),
Arch::Unknown(arch_str) => arch_str.fmt(f),
}
}
}
12 changes: 6 additions & 6 deletions hipcheck/src/plugin/download_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
hc_error,
plugin::{
retrieval::{download_plugin, extract_plugin},
supported_arch::SupportedArch,
arch::KnownArch,
try_get_current_arch,
},
util::kdl::{extract_data, ParseKdlNode},
Expand Down Expand Up @@ -225,7 +225,7 @@ pub struct DownloadManifestEntry {
/// but only a specific concrete version
pub version: PluginVersion,
/// The target architecture for a plugin
pub arch: SupportedArch,
pub arch: KnownArch,
/// The URL of the archive file to download containing the plugin executable artifact and
/// plugin manifest.
pub url: url::Url,
Expand All @@ -251,7 +251,7 @@ impl ParseKdlNode for DownloadManifestEntry {
// Per RFD #0004, version is of type String
let version = PluginVersion(node.get("version")?.value().as_string()?.to_string());
// Per RFD #0004, arch is of type String
let arch = SupportedArch::from_str(node.get("arch")?.value().as_string()?).ok()?;
let arch = KnownArch::from_str(node.get("arch")?.value().as_string()?).ok()?;

// there should be one child for each plugin and it should contain the url, hash, compress
// and size information
Expand Down Expand Up @@ -564,7 +564,7 @@ mod test {

let expected_entry = DownloadManifestEntry {
version: PluginVersion(version.to_string()),
arch: SupportedArch::from_str(arch).unwrap(),
arch: KnownArch::from_str(arch).unwrap(),
url: Url::parse(url).unwrap(),
hash: HashWithDigest::new(
HashAlgorithm::try_from(hash_alg).unwrap(),
Expand Down Expand Up @@ -605,7 +605,7 @@ plugin version="0.1.0" arch="x86_64-apple-darwin" {
assert_eq!(
&DownloadManifestEntry {
version: PluginVersion("0.1.0".to_owned()),
arch: SupportedArch::Aarch64AppleDarwin,
arch: KnownArch::Aarch64AppleDarwin,
url: Url::parse("https://github.com/mitre/hipcheck/releases/download/hipcheck-v3.4.0/hipcheck-aarch64-apple-darwin.tar.xz").unwrap(),
hash: HashWithDigest::new(HashAlgorithm::Sha256, "b8e111e7817c4a1eb40ed50712d04e15b369546c4748be1aa8893b553f4e756b".to_owned()),
compress: Compress::new(ArchiveFormat::TarXz),
Expand All @@ -618,7 +618,7 @@ plugin version="0.1.0" arch="x86_64-apple-darwin" {
assert_eq!(
&DownloadManifestEntry {
version: PluginVersion("0.1.0".to_owned()),
arch: SupportedArch::X86_64AppleDarwin,
arch: KnownArch::X86_64AppleDarwin,
url: Url::parse("https://github.com/mitre/hipcheck/releases/download/hipcheck-v3.4.0/hipcheck-x86_64-apple-darwin.tar.xz").unwrap(),
hash: HashWithDigest::new(HashAlgorithm::Sha256, "ddb8c6d26dd9a91e11c99b3bd7ee2b9585aedac6e6df614190f1ba2bfe86dc19".to_owned()),
compress: Compress::new(ArchiveFormat::TarXz),
Expand Down
4 changes: 2 additions & 2 deletions hipcheck/src/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod manager;
mod plugin_id;
mod plugin_manifest;
mod retrieval;
mod supported_arch;
mod arch;
mod types;

use crate::error::Result;
Expand All @@ -15,7 +15,7 @@ pub use plugin_manifest::{PluginManifest, PluginName, PluginPublisher, PluginVer
pub use retrieval::retrieve_plugins;
use serde_json::Value;
use std::collections::HashMap;
pub use supported_arch::{try_get_current_arch, try_set_arch, SupportedArch};
pub use arch::{try_get_current_arch, try_set_arch, Arch};
use tokio::sync::Mutex;

pub async fn initialize_plugins(
Expand Down
Loading

0 comments on commit 30c56ce

Please sign in to comment.