use std::fmt;
use std::path::PathBuf;
use ring::rand::{SecureRandom, SystemRandom};
pub fn generate_ci_passphrase() -> String {
let rng = SystemRandom::new();
let mut bytes = [0u8; 24];
#[allow(clippy::expect_used)]
rng.fill(&mut bytes).expect("system CSPRNG unavailable");
let mut out: String = bytes.iter().map(|b| format!("{b:02x}")).collect();
out.push_str("-A9");
out
}
#[derive(Debug, Clone)]
pub enum CiEnvironment {
GitHubActions,
GitLabCi,
Custom {
name: String,
},
Unknown,
}
#[derive(Clone)]
pub struct CiIdentityConfig {
pub ci_environment: CiEnvironment,
pub registry_path: PathBuf,
pub keychain_file: PathBuf,
pub passphrase: String,
}
impl fmt::Debug for CiIdentityConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CiIdentityConfig")
.field("ci_environment", &self.ci_environment)
.field("registry_path", &self.registry_path)
.field("keychain_file", &self.keychain_file)
.field("passphrase", &"[REDACTED]")
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ci_passphrase_is_unique_per_call() {
assert_ne!(generate_ci_passphrase(), generate_ci_passphrase());
}
#[test]
fn ci_passphrase_passes_policy() {
let p = generate_ci_passphrase();
assert!(
auths_core::crypto::encryption::validate_passphrase(&p).is_ok(),
"generated CI passphrase must clear the strength policy: {p:?}"
);
}
}