From 211cf7449fa8c60621e3f9124ada397e3b82db66 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Thu, 26 Oct 2023 21:17:27 +0000 Subject: [PATCH] Update to AWS-LC-FIPS-2.0.0, update tag selection logic --- Makefile | 5 +- aws-lc-fips-sys/aws-lc | 2 +- .../openssl/boringssl_prefix_symbols.h | 2 + .../openssl/boringssl_prefix_symbols_asm.h | 2 + .../openssl/boringssl_prefix_symbols_nasm.inc | 4 + aws-lc-fips-sys/src/linux_aarch64_crypto.rs | 12 ++- .../src/linux_aarch64_crypto_ssl.rs | 12 ++- aws-lc-fips-sys/src/linux_x86_64_crypto.rs | 12 ++- .../src/linux_x86_64_crypto_ssl.rs | 12 ++- aws-lc-fips-sys/symbols/linux_aarch64.txt | 2 + aws-lc-fips-sys/symbols/linux_x86_64.txt | 2 + scripts/tools/semver.rs | 74 +++++++++++++++---- 12 files changed, 116 insertions(+), 25 deletions(-) diff --git a/Makefile b/Makefile index 1edb97a844e..dd91aa085b0 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,15 @@ init: init-submodules update-aws-lc-fips-sys: git submodule update --init --remote --checkout -- aws-lc-fips-sys/aws-lc + cd aws-lc-fips-sys/aws-lc && \ + git fetch --all && \ + git tag -l | xargs ../../scripts/tools/semver.rs fips-v2 | xargs git checkout update-aws-lc-sys: git submodule update --init --remote --checkout -- aws-lc-sys/aws-lc cd aws-lc-sys/aws-lc && \ git fetch --all && \ - git tag -l | xargs ../../scripts/tools/semver.rs | xargs git checkout + git tag -l | xargs ../../scripts/tools/semver.rs main | xargs git checkout update-submodules: update-aws-lc-fips-sys update-aws-lc-sys diff --git a/aws-lc-fips-sys/aws-lc b/aws-lc-fips-sys/aws-lc index 04d51fcb2db..329d23ce93d 160000 --- a/aws-lc-fips-sys/aws-lc +++ b/aws-lc-fips-sys/aws-lc @@ -1 +1 @@ -Subproject commit 04d51fcb2db829df438c1a760017f2e4e717e88d +Subproject commit 329d23ce93d42b9017502ac24ca073ebdaa7660f diff --git a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols.h b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols.h index 2d3e344f1ac..c13a337462c 100644 --- a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols.h +++ b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols.h @@ -217,6 +217,8 @@ #define AUTHORITY_KEYID_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AUTHORITY_KEYID_new) #define AWSLC_non_fips_pkey_evp_asn1_methods BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AWSLC_non_fips_pkey_evp_asn1_methods) #define AWSLC_non_fips_pkey_evp_methods BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AWSLC_non_fips_pkey_evp_methods) +#define AWSLC_thread_local_clear BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AWSLC_thread_local_clear) +#define AWSLC_thread_local_shutdown BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, AWSLC_thread_local_shutdown) #define BASIC_CONSTRAINTS_free BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_free) #define BASIC_CONSTRAINTS_it BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_it) #define BASIC_CONSTRAINTS_new BORINGSSL_ADD_PREFIX(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_new) diff --git a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_asm.h b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_asm.h index 0a109ce655d..4ec491b5781 100644 --- a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_asm.h +++ b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_asm.h @@ -222,6 +222,8 @@ #define _AUTHORITY_KEYID_new BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, AUTHORITY_KEYID_new) #define _AWSLC_non_fips_pkey_evp_asn1_methods BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, AWSLC_non_fips_pkey_evp_asn1_methods) #define _AWSLC_non_fips_pkey_evp_methods BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, AWSLC_non_fips_pkey_evp_methods) +#define _AWSLC_thread_local_clear BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, AWSLC_thread_local_clear) +#define _AWSLC_thread_local_shutdown BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, AWSLC_thread_local_shutdown) #define _BASIC_CONSTRAINTS_free BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_free) #define _BASIC_CONSTRAINTS_it BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_it) #define _BASIC_CONSTRAINTS_new BORINGSSL_ADD_PREFIX_MAC_ASM(BORINGSSL_PREFIX, BASIC_CONSTRAINTS_new) diff --git a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_nasm.inc b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_nasm.inc index fa1035a5dd0..3c0f48c78ad 100644 --- a/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_nasm.inc +++ b/aws-lc-fips-sys/generated-include/openssl/boringssl_prefix_symbols_nasm.inc @@ -214,6 +214,8 @@ %xdefine _AUTHORITY_KEYID_new _ %+ BORINGSSL_PREFIX %+ _AUTHORITY_KEYID_new %xdefine _AWSLC_non_fips_pkey_evp_asn1_methods _ %+ BORINGSSL_PREFIX %+ _AWSLC_non_fips_pkey_evp_asn1_methods %xdefine _AWSLC_non_fips_pkey_evp_methods _ %+ BORINGSSL_PREFIX %+ _AWSLC_non_fips_pkey_evp_methods +%xdefine _AWSLC_thread_local_clear _ %+ BORINGSSL_PREFIX %+ _AWSLC_thread_local_clear +%xdefine _AWSLC_thread_local_shutdown _ %+ BORINGSSL_PREFIX %+ _AWSLC_thread_local_shutdown %xdefine _BASIC_CONSTRAINTS_free _ %+ BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_free %xdefine _BASIC_CONSTRAINTS_it _ %+ BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_it %xdefine _BASIC_CONSTRAINTS_new _ %+ BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_new @@ -4073,6 +4075,8 @@ %xdefine AUTHORITY_KEYID_new BORINGSSL_PREFIX %+ _AUTHORITY_KEYID_new %xdefine AWSLC_non_fips_pkey_evp_asn1_methods BORINGSSL_PREFIX %+ _AWSLC_non_fips_pkey_evp_asn1_methods %xdefine AWSLC_non_fips_pkey_evp_methods BORINGSSL_PREFIX %+ _AWSLC_non_fips_pkey_evp_methods +%xdefine AWSLC_thread_local_clear BORINGSSL_PREFIX %+ _AWSLC_thread_local_clear +%xdefine AWSLC_thread_local_shutdown BORINGSSL_PREFIX %+ _AWSLC_thread_local_shutdown %xdefine BASIC_CONSTRAINTS_free BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_free %xdefine BASIC_CONSTRAINTS_it BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_it %xdefine BASIC_CONSTRAINTS_new BORINGSSL_PREFIX %+ _BASIC_CONSTRAINTS_new diff --git a/aws-lc-fips-sys/src/linux_aarch64_crypto.rs b/aws-lc-fips-sys/src/linux_aarch64_crypto.rs index 4c25c93569b..2d21b621a5a 100644 --- a/aws-lc-fips-sys/src/linux_aarch64_crypto.rs +++ b/aws-lc-fips-sys/src/linux_aarch64_crypto.rs @@ -109,7 +109,7 @@ pub const AWSLC_VERSION_NAME: &[u8; 7] = b"AWS-LC\0"; pub const OPENSSL_VERSION_NUMBER: i32 = 269488255; pub const SSLEAY_VERSION_NUMBER: i32 = 269488255; pub const AWSLC_API_VERSION: i32 = 20; -pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"1.4.0\0"; +pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"2.0.0\0"; pub const ERR_FLAG_STRING: i32 = 1; pub const ERR_FLAG_MALLOCED: i32 = 2; pub const ERR_R_FATAL: i32 = 64; @@ -3538,7 +3538,7 @@ pub const RIPEMD160_CBLOCK: i32 = 64; pub const RIPEMD160_LBLOCK: i32 = 16; pub const RIPEMD160_DIGEST_LENGTH: i32 = 20; pub const AWSLC_MODE_STRING: &[u8; 8] = b"AWS-LC \0"; -pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 1.4.0\0"; +pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 2.0.0\0"; pub const TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_R_KEYGEN_FAILURE: i32 = 100; @@ -5602,6 +5602,14 @@ impl Default for crypto_mutex_st { } pub type CRYPTO_MUTEX = crypto_mutex_st; pub type CRYPTO_refcount_t = u32; +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_clear"] + pub fn AWSLC_thread_local_clear() -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_shutdown"] + pub fn AWSLC_thread_local_shutdown() -> ::std::os::raw::c_int; +} extern "C" { #[link_name = "\u{1}aws_lc_fips_0_11_0_CRYPTO_num_locks"] pub fn CRYPTO_num_locks() -> ::std::os::raw::c_int; diff --git a/aws-lc-fips-sys/src/linux_aarch64_crypto_ssl.rs b/aws-lc-fips-sys/src/linux_aarch64_crypto_ssl.rs index 5f1296edaa1..e9c0428830c 100644 --- a/aws-lc-fips-sys/src/linux_aarch64_crypto_ssl.rs +++ b/aws-lc-fips-sys/src/linux_aarch64_crypto_ssl.rs @@ -109,7 +109,7 @@ pub const AWSLC_VERSION_NAME: &[u8; 7] = b"AWS-LC\0"; pub const OPENSSL_VERSION_NUMBER: i32 = 269488255; pub const SSLEAY_VERSION_NUMBER: i32 = 269488255; pub const AWSLC_API_VERSION: i32 = 20; -pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"1.4.0\0"; +pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"2.0.0\0"; pub const ERR_FLAG_STRING: i32 = 1; pub const ERR_FLAG_MALLOCED: i32 = 2; pub const ERR_R_FATAL: i32 = 64; @@ -3538,7 +3538,7 @@ pub const RIPEMD160_CBLOCK: i32 = 64; pub const RIPEMD160_LBLOCK: i32 = 16; pub const RIPEMD160_DIGEST_LENGTH: i32 = 20; pub const AWSLC_MODE_STRING: &[u8; 8] = b"AWS-LC \0"; -pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 1.4.0\0"; +pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 2.0.0\0"; pub const TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_R_KEYGEN_FAILURE: i32 = 100; @@ -6594,6 +6594,14 @@ impl Default for crypto_mutex_st { } pub type CRYPTO_MUTEX = crypto_mutex_st; pub type CRYPTO_refcount_t = u32; +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_clear"] + pub fn AWSLC_thread_local_clear() -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_shutdown"] + pub fn AWSLC_thread_local_shutdown() -> ::std::os::raw::c_int; +} extern "C" { #[link_name = "\u{1}aws_lc_fips_0_11_0_CRYPTO_num_locks"] pub fn CRYPTO_num_locks() -> ::std::os::raw::c_int; diff --git a/aws-lc-fips-sys/src/linux_x86_64_crypto.rs b/aws-lc-fips-sys/src/linux_x86_64_crypto.rs index e6ae7fb33d2..d8539558211 100644 --- a/aws-lc-fips-sys/src/linux_x86_64_crypto.rs +++ b/aws-lc-fips-sys/src/linux_x86_64_crypto.rs @@ -109,7 +109,7 @@ pub const AWSLC_VERSION_NAME: &[u8; 7] = b"AWS-LC\0"; pub const OPENSSL_VERSION_NUMBER: i32 = 269488255; pub const SSLEAY_VERSION_NUMBER: i32 = 269488255; pub const AWSLC_API_VERSION: i32 = 20; -pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"1.4.0\0"; +pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"2.0.0\0"; pub const ERR_FLAG_STRING: i32 = 1; pub const ERR_FLAG_MALLOCED: i32 = 2; pub const ERR_R_FATAL: i32 = 64; @@ -3538,7 +3538,7 @@ pub const RIPEMD160_CBLOCK: i32 = 64; pub const RIPEMD160_LBLOCK: i32 = 16; pub const RIPEMD160_DIGEST_LENGTH: i32 = 20; pub const AWSLC_MODE_STRING: &[u8; 8] = b"AWS-LC \0"; -pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 1.4.0\0"; +pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 2.0.0\0"; pub const TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_R_KEYGEN_FAILURE: i32 = 100; @@ -5602,6 +5602,14 @@ impl Default for crypto_mutex_st { } pub type CRYPTO_MUTEX = crypto_mutex_st; pub type CRYPTO_refcount_t = u32; +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_clear"] + pub fn AWSLC_thread_local_clear() -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_shutdown"] + pub fn AWSLC_thread_local_shutdown() -> ::std::os::raw::c_int; +} extern "C" { #[link_name = "\u{1}aws_lc_fips_0_11_0_CRYPTO_num_locks"] pub fn CRYPTO_num_locks() -> ::std::os::raw::c_int; diff --git a/aws-lc-fips-sys/src/linux_x86_64_crypto_ssl.rs b/aws-lc-fips-sys/src/linux_x86_64_crypto_ssl.rs index cabd34afb50..d2b04817cd0 100644 --- a/aws-lc-fips-sys/src/linux_x86_64_crypto_ssl.rs +++ b/aws-lc-fips-sys/src/linux_x86_64_crypto_ssl.rs @@ -109,7 +109,7 @@ pub const AWSLC_VERSION_NAME: &[u8; 7] = b"AWS-LC\0"; pub const OPENSSL_VERSION_NUMBER: i32 = 269488255; pub const SSLEAY_VERSION_NUMBER: i32 = 269488255; pub const AWSLC_API_VERSION: i32 = 20; -pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"1.4.0\0"; +pub const AWSLC_VERSION_NUMBER_STRING: &[u8; 6] = b"2.0.0\0"; pub const ERR_FLAG_STRING: i32 = 1; pub const ERR_FLAG_MALLOCED: i32 = 2; pub const ERR_R_FATAL: i32 = 64; @@ -3538,7 +3538,7 @@ pub const RIPEMD160_CBLOCK: i32 = 64; pub const RIPEMD160_LBLOCK: i32 = 16; pub const RIPEMD160_DIGEST_LENGTH: i32 = 20; pub const AWSLC_MODE_STRING: &[u8; 8] = b"AWS-LC \0"; -pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 1.4.0\0"; +pub const AWSLC_VERSION_STRING: &[u8; 13] = b"AWS-LC 2.0.0\0"; pub const TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE: i32 = 512; pub const TRUST_TOKEN_R_KEYGEN_FAILURE: i32 = 100; @@ -6594,6 +6594,14 @@ impl Default for crypto_mutex_st { } pub type CRYPTO_MUTEX = crypto_mutex_st; pub type CRYPTO_refcount_t = u32; +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_clear"] + pub fn AWSLC_thread_local_clear() -> ::std::os::raw::c_int; +} +extern "C" { + #[link_name = "\u{1}aws_lc_fips_0_11_0_AWSLC_thread_local_shutdown"] + pub fn AWSLC_thread_local_shutdown() -> ::std::os::raw::c_int; +} extern "C" { #[link_name = "\u{1}aws_lc_fips_0_11_0_CRYPTO_num_locks"] pub fn CRYPTO_num_locks() -> ::std::os::raw::c_int; diff --git a/aws-lc-fips-sys/symbols/linux_aarch64.txt b/aws-lc-fips-sys/symbols/linux_aarch64.txt index 663b44564e2..92b150e4681 100644 --- a/aws-lc-fips-sys/symbols/linux_aarch64.txt +++ b/aws-lc-fips-sys/symbols/linux_aarch64.txt @@ -194,6 +194,8 @@ AUTHORITY_KEYID_it AUTHORITY_KEYID_new AWSLC_non_fips_pkey_evp_asn1_methods AWSLC_non_fips_pkey_evp_methods +AWSLC_thread_local_clear +AWSLC_thread_local_shutdown BASIC_CONSTRAINTS_free BASIC_CONSTRAINTS_it BASIC_CONSTRAINTS_new diff --git a/aws-lc-fips-sys/symbols/linux_x86_64.txt b/aws-lc-fips-sys/symbols/linux_x86_64.txt index 6a3c67b7238..fc1ea0761a6 100644 --- a/aws-lc-fips-sys/symbols/linux_x86_64.txt +++ b/aws-lc-fips-sys/symbols/linux_x86_64.txt @@ -194,6 +194,8 @@ AUTHORITY_KEYID_it AUTHORITY_KEYID_new AWSLC_non_fips_pkey_evp_asn1_methods AWSLC_non_fips_pkey_evp_methods +AWSLC_thread_local_clear +AWSLC_thread_local_shutdown BASIC_CONSTRAINTS_free BASIC_CONSTRAINTS_it BASIC_CONSTRAINTS_new diff --git a/scripts/tools/semver.rs b/scripts/tools/semver.rs index 738d8265182..d3a5a70bbd8 100755 --- a/scripts/tools/semver.rs +++ b/scripts/tools/semver.rs @@ -3,38 +3,82 @@ //! SPDX-License-Identifier: Apache-2.0 OR ISC //! ```cargo //! [dependencies] -//! clap = { version = "4.2.2", features = ["derive"] } -//! regex = "1.7.3" -//! semver = "1.0.17" +//! clap = { version = "4", features = ["derive"] } +//! regex = "1" +//! semver = "1" //! ``` -use clap::Parser; +use clap::{Parser, Subcommand}; +use regex::Regex; +use std::error::Error; #[derive(Parser)] #[command(about)] struct Args { - tags: Vec, + #[command(subcommand)] + release: Release, } -fn main() { +#[derive(Subcommand, Clone)] +enum Release { + Main { tags: Vec }, + FipsV2 { tags: Vec }, +} + +// regex from https://semver.org/ +const SEMVER: &str = r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"; + +fn main() -> Result<(), Box> { let args = Args::parse(); - let input: Vec = args.tags; + let latest = match args.release { + Release::Main { tags } => get_latest_main(tags)?, + Release::FipsV2 { tags } => get_latest_fips(tags, 2)?, + }; + + println!("{latest}"); + Ok(()) +} + +fn get_latest_main(tags: Vec) -> Result> { + let re = Regex::new(SEMVER)?; + let mut tags: Vec = tags + .into_iter() + .filter(|t| t.starts_with("v")) + .map(|t| String::from(t.strip_prefix("v").expect("prefix must be present"))) + .filter(|t| re.is_match(t)) + .map(|t| semver::Version::parse(&t).expect("semver parse must not fail")) + .collect(); + + tags.sort(); + + let latest = tags.pop().ok_or("latest tag not found")?; + + Ok(format!("v{latest}")) +} + +fn get_latest_fips(tags: Vec, major: u64) -> Result> { + const FIPS_TAG_PREFIX: &str = "AWS-LC-FIPS-"; - // Modified regex from https://semver.org/ - let re = regex::Regex::new( - r"^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$", - ).unwrap(); + let re = Regex::new(SEMVER)?; - let mut tags: Vec = input + let mut tags: Vec = tags .into_iter() + .filter(|t| t.starts_with(FIPS_TAG_PREFIX)) + .map(|t| { + String::from( + t.strip_prefix(FIPS_TAG_PREFIX) + .expect("prefix must be present"), + ) + }) .filter(|t| re.is_match(t)) - .map(|t| semver::Version::parse(t.strip_prefix("v").unwrap()).unwrap()) + .map(|t| semver::Version::parse(&t).unwrap()) + .filter(|t| t.major == major) .collect(); tags.sort(); - let latest = tags.pop().unwrap(); + let latest = tags.pop().ok_or("latest tag not found")?; - println!("v{latest}") + Ok(format!("{FIPS_TAG_PREFIX}{latest}")) }