#![allow(clippy::expect_used)]
use cuenv_1password::secrets::{core, wasm};
use std::path::PathBuf;
use std::sync::OnceLock;
const ONEPASSWORD_WASM_URL: &str =
"https://github.com/1Password/onepassword-sdk-go/raw/refs/tags/v0.3.1/internal/wasm/core.wasm";
const MIN_WASM_SIZE: u64 = 5_000_000;
static RUSTLS_PROVIDER_INSTALLED: OnceLock<()> = OnceLock::new();
fn ensure_rustls_crypto_provider() {
RUSTLS_PROVIDER_INSTALLED.get_or_init(|| {
if rustls::crypto::CryptoProvider::get_default().is_none()
&& rustls::crypto::ring::default_provider()
.install_default()
.is_err()
{
panic!("Failed to install rustls crypto provider");
}
});
}
#[allow(clippy::print_stderr)]
fn ensure_wasm_available() -> PathBuf {
let path = wasm::onepassword_wasm_path().expect("Should get WASM path");
if let Ok(metadata) = std::fs::metadata(&path)
&& metadata.len() >= MIN_WASM_SIZE
{
return path;
}
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).expect("Should create cache directory");
}
let temp_path = path.with_extension(format!("wasm.tmp.{}", std::process::id()));
eprintln!("Downloading 1Password WASM SDK to {}...", path.display());
ensure_rustls_crypto_provider();
let response = reqwest::blocking::get(ONEPASSWORD_WASM_URL).expect("Should download WASM");
assert!(
response.status().is_success(),
"Failed to download WASM: HTTP {}",
response.status()
);
let bytes = response.bytes().expect("Should read response body");
assert!(
bytes.len() as u64 >= MIN_WASM_SIZE,
"Downloaded WASM too small: {} bytes",
bytes.len()
);
std::fs::write(&temp_path, &bytes).expect("Should write temp WASM file");
if let Err(e) = std::fs::rename(&temp_path, &path) {
eprintln!("Rename failed (likely concurrent download): {e}");
let _ = std::fs::remove_file(&temp_path);
}
eprintln!("Downloaded {} bytes", bytes.len());
let final_metadata = std::fs::metadata(&path).expect("WASM file should exist after download");
assert!(
final_metadata.len() >= MIN_WASM_SIZE,
"Final WASM file too small: {} bytes",
final_metadata.len()
);
path
}
#[test]
#[allow(unsafe_code)]
fn test_wasm_loads_and_plugin_initializes() {
let path = ensure_wasm_available();
let temp_home = std::env::temp_dir().join("cuenv-wasm-test-home");
std::fs::create_dir_all(&temp_home).expect("Should create temp home");
unsafe { std::env::set_var("HOME", &temp_home) };
let bytes = std::fs::read(&path).expect("Should read WASM file");
let len = bytes.len();
assert!(
len > 1_000_000,
"WASM should be > 1MB (got {len} bytes) - file may be corrupt or incomplete"
);
let manifest = extism::Manifest::new([extism::Wasm::data(bytes)]).with_allowed_hosts(
["*.1password.com", "*.1password.ca", "*.1password.eu"]
.into_iter()
.map(String::from),
);
let host_functions = core::create_host_functions();
let plugin = extism::Plugin::new(&manifest, host_functions, true)
.expect("Extism plugin initialization should succeed");
assert!(
plugin.function_exists("init_client"),
"Plugin should export init_client function"
);
assert!(
plugin.function_exists("invoke"),
"Plugin should export invoke function"
);
assert!(
plugin.function_exists("release_client"),
"Plugin should export release_client function"
);
}
#[test]
fn test_wasm_file_size() {
let path = ensure_wasm_available();
let metadata = std::fs::metadata(&path).expect("Should get file metadata");
#[expect(clippy::cast_precision_loss)]
let size_mb = metadata.len() as f64 / (1024.0 * 1024.0);
assert!(
size_mb > 5.0 && size_mb < 20.0,
"WASM file should be 5-20 MB (got {size_mb:.2} MB)"
);
}
#[test]
#[allow(unsafe_code, clippy::significant_drop_tightening)]
fn test_shared_core_initializes() {
let wasm_path = ensure_wasm_available();
unsafe { std::env::set_var("ONEPASSWORD_WASM_PATH", &wasm_path) };
let temp_home = std::env::temp_dir().join("cuenv-wasm-test-home");
std::fs::create_dir_all(&temp_home).expect("Should create temp home");
unsafe { std::env::set_var("HOME", &temp_home) };
let core_mutex =
core::SharedCore::get_or_init().expect("SharedCore should initialize successfully");
let guard = core_mutex.lock().expect("Should acquire lock");
assert!(guard.is_some(), "SharedCore should be initialized");
}