v0.5.2-pre.002
This commit is contained in:
184
ks-wallet/tests/legacy_characterization.rs
Normal file
184
ks-wallet/tests/legacy_characterization.rs
Normal file
@@ -0,0 +1,184 @@
|
||||
// file: ks-wallet/tests/legacy_characterization.rs
|
||||
// version: 1
|
||||
|
||||
//! External characterization tests for the legacy Solana JSON wallet format.
|
||||
|
||||
use solana_signer::Signer; // rust-rules: trait-import
|
||||
use zeroize::Zeroize; // rust-rules: trait-import
|
||||
|
||||
fn write_legacy_fixture(path: &std::path::Path, keypair: &solana_keypair::Keypair) {
|
||||
let mut keypair_bytes = keypair.to_bytes();
|
||||
let encoded = serde_json::to_vec(keypair_bytes.as_slice())
|
||||
.unwrap_or_else(|error| panic!("legacy fixture must serialize: {error}"));
|
||||
keypair_bytes.zeroize();
|
||||
std::fs::write(path, encoded)
|
||||
.unwrap_or_else(|error| panic!("legacy fixture must be writable: {error}"));
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import
|
||||
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600))
|
||||
.unwrap_or_else(|error| panic!("legacy fixture permissions must be set: {error}"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_path_is_alias_json() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let alias = ks_wallet::WalletAlias::parse("legacy-name")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
assert_eq!(
|
||||
store.wallet_path(&alias).file_name(),
|
||||
std::option::Option::Some(std::ffi::OsStr::new("legacy-name.json"))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_standard_json_fixture_preserves_public_key() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let alias = ks_wallet::WalletAlias::parse("legacy-fixture")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let expected = solana_keypair::Keypair::new();
|
||||
write_legacy_fixture(&store.wallet_path(&alias), &expected);
|
||||
let loaded = store
|
||||
.load(alias)
|
||||
.await
|
||||
.unwrap_or_else(|error| panic!("legacy fixture must load: {error}"));
|
||||
assert_eq!(loaded.public_key(), expected.pubkey().to_string());
|
||||
assert_eq!(loaded.persistence(), ks_wallet::WalletPersistence::Persistent);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_missing_file_preserves_current_error_contract() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let alias = ks_wallet::WalletAlias::parse("missing")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let error = store
|
||||
.load(alias)
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("missing legacy wallet must fail"));
|
||||
assert_eq!(error.code(), "wallet_file_metadata_failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_corrupted_json_and_short_keypair_are_distinct() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let corrupted_alias = ks_wallet::WalletAlias::parse("corrupted-json")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let corrupted_path = store.wallet_path(&corrupted_alias);
|
||||
std::fs::write(&corrupted_path, b"not-json")
|
||||
.unwrap_or_else(|error| panic!("corrupted fixture must be writable: {error}"));
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import
|
||||
std::fs::set_permissions(&corrupted_path, std::fs::Permissions::from_mode(0o600))
|
||||
.unwrap_or_else(|error| panic!("fixture permissions must be set: {error}"));
|
||||
}
|
||||
let corrupted_error = store
|
||||
.load(corrupted_alias)
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("corrupted JSON must fail"));
|
||||
assert_eq!(corrupted_error.code(), "wallet_keypair_json_invalid");
|
||||
let short_alias = ks_wallet::WalletAlias::parse("short-keypair")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let short_path = store.wallet_path(&short_alias);
|
||||
std::fs::write(&short_path, b"[1,2,3]")
|
||||
.unwrap_or_else(|error| panic!("short fixture must be writable: {error}"));
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import
|
||||
std::fs::set_permissions(&short_path, std::fs::Permissions::from_mode(0o600))
|
||||
.unwrap_or_else(|error| panic!("fixture permissions must be set: {error}"));
|
||||
}
|
||||
let short_error = store
|
||||
.load(short_alias)
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("short keypair must fail"));
|
||||
assert_eq!(short_error.code(), "wallet_keypair_length_invalid");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_create_refuses_existing_wallet_and_preserves_first_pubkey() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let alias = ks_wallet::WalletAlias::parse("collision")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let first = store
|
||||
.create(alias.clone())
|
||||
.await
|
||||
.unwrap_or_else(|error| panic!("first legacy wallet must be created: {error}"));
|
||||
let second_error = store
|
||||
.create(alias.clone())
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("second legacy create must fail"));
|
||||
assert_eq!(second_error.code(), "wallet_file_already_exists");
|
||||
let loaded = store
|
||||
.load(alias)
|
||||
.await
|
||||
.unwrap_or_else(|error| panic!("first legacy wallet must remain readable: {error}"));
|
||||
assert_eq!(loaded.public_key(), first.public_key());
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn legacy_file_with_open_permissions_is_rejected() {
|
||||
use std::os::unix::fs::PermissionsExt; // rust-rules: trait-import
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let alias = ks_wallet::WalletAlias::parse("open-permissions")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let keypair = solana_keypair::Keypair::new();
|
||||
let path = store.wallet_path(&alias);
|
||||
write_legacy_fixture(&path, &keypair);
|
||||
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o644))
|
||||
.unwrap_or_else(|error| panic!("fixture permissions must be changed: {error}"));
|
||||
let error = store
|
||||
.load(alias)
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("open permissions must fail"));
|
||||
assert_eq!(error.code(), "wallet_file_permissions_too_open");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[tokio::test]
|
||||
async fn legacy_symlink_is_rejected() {
|
||||
let directory = tempfile::tempdir()
|
||||
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
|
||||
let store = ks_wallet::TemporaryWalletStore::new(directory.path())
|
||||
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
|
||||
let target_alias = ks_wallet::WalletAlias::parse("target")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let link_alias = ks_wallet::WalletAlias::parse("linked")
|
||||
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
|
||||
let keypair = solana_keypair::Keypair::new();
|
||||
let target_path = store.wallet_path(&target_alias);
|
||||
write_legacy_fixture(&target_path, &keypair);
|
||||
std::os::unix::fs::symlink(&target_path, store.wallet_path(&link_alias))
|
||||
.unwrap_or_else(|error| panic!("legacy symlink fixture must be created: {error}"));
|
||||
let error = store
|
||||
.load(link_alias)
|
||||
.await
|
||||
.err()
|
||||
.unwrap_or_else(|| panic!("legacy symlink must fail"));
|
||||
assert_eq!(error.code(), "wallet_file_type_invalid");
|
||||
}
|
||||
Reference in New Issue
Block a user