use crate::vault::{VaultClient, VaultError};
use tracing::info;
pub async fn seal_vault(addr: &str, token: &str) -> Result<(), VaultError> {
info!("Sealing vault at {}", addr);
let client = VaultClient::new(addr, token)?;
let _ = client
.put_with_body("/v1/sys/seal", serde_json::json!({}))
.await?;
info!("Successfully sealed vault at {}", addr);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::init_logging;
use crate::vault::init::unseal_vault;
use crate::vault::status::get_vault_status;
use crate::vault::test_utils::{setup_vault_container, VaultMode};
#[tokio::test]
async fn test_seal_vault_invalid_token() -> Result<(), Box<dyn std::error::Error>> {
let invalid_token = "invalid-token";
let result = seal_vault("http://127.0.0.1:8200", invalid_token).await;
assert!(result.is_err(), "Expected error with invalid token");
match result {
Err(VaultError::HttpStatus(status_code, _)) => {
assert_eq!(
status_code, 403,
"Expected 403 Forbidden with invalid token"
);
}
Err(VaultError::Connection(_)) => {
println!(
"Connection error (Vault not running) - this is expected in standalone tests"
);
}
Err(VaultError::Network(_)) => {
println!(
"Network error (Vault not running) - this is expected in standalone tests"
);
}
_ => {
panic!(
"Expected VaultError::HttpStatus, VaultError::Connection, or VaultError::Network, got {:?}",
result
);
}
}
Ok(())
}
#[tokio::test]
async fn test_seal_vault_with_real_vault() -> Result<(), Box<dyn std::error::Error>> {
init_logging();
let vault_container = setup_vault_container(VaultMode::Regular).await;
let port = match vault_container.get_host_port_ipv4(8200).await {
Ok(p) => p,
Err(e) => {
return Err(format!("Failed to get container port: {}", e).into());
}
};
let vault_addr = format!("http://127.0.0.1:{}", port);
let client = reqwest::Client::new();
let health_url = format!("{}/v1/sys/health", vault_addr);
for attempt in 1..=30 {
match client.get(&health_url).send().await {
Ok(_) => {
info!("Vault is responsive after {} attempts", attempt);
break;
}
Err(e) => {
info!(
"Waiting for Vault to be responsive... attempt {}: {}",
attempt, e
);
if attempt == 30 {
return Err(format!(
"Vault container not responsive after 30 attempts: {}",
e
)
.into());
}
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
}
}
}
use crate::vault::init::init_vault;
let init_result = match init_vault(&vault_addr, 1, 1, None, None).await {
Ok(result) => result,
Err(e) => return Err(format!("Failed to initialize vault: {}", e).into()),
};
let root_token = init_result.root_token.clone();
let unseal_keys = init_result.keys.clone();
if let Err(e) = unseal_vault(&vault_addr, &unseal_keys).await {
return Err(format!("Failed to unseal vault: {}", e).into());
}
let status = match get_vault_status(&vault_addr).await {
Ok(s) => s,
Err(e) => return Err(format!("Failed to get vault status: {}", e).into()),
};
assert!(status.initialized, "Vault should be initialized");
assert!(
!status.sealed,
"Vault should be unsealed after initialization"
);
if let Err(e) = seal_vault(&vault_addr, &root_token).await {
return Err(format!("Failed to seal vault: {}", e).into());
}
let status = match get_vault_status(&vault_addr).await {
Ok(s) => s,
Err(e) => return Err(format!("Failed to get vault status after sealing: {}", e).into()),
};
assert!(status.sealed, "Vault should be sealed after seal operation");
if let Err(e) = unseal_vault(&vault_addr, &unseal_keys).await {
return Err(format!("Failed to unseal vault after sealing: {}", e).into());
}
let status = match get_vault_status(&vault_addr).await {
Ok(s) => s,
Err(e) => {
return Err(format!("Failed to get vault status after unsealing: {}", e).into())
}
};
assert!(
!status.sealed,
"Vault should be unsealed after unseal operation"
);
Ok(())
}
}