diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index d34d969e6..6528aa74a 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -4766,3 +4766,10 @@ - 处理:generation progress、保存队列、生成/提交回包和延迟 `loadDraft` 统一用当前 scope、触发最低 revision 与回包当下草稿的单调门禁;同 revision 只允许完整相等回包。Tauri 指针和键盘选择复用 `resolveLayerPointerSelection`。pointerdown 只冻结快照,首次真实 move/resize/pan 才 capture 一次;零位移、未变选择和锁定图层不增加 undo、documentVersion 或草稿保存。 - 失败边界:`canvas.failed` 必须携带 `generation / draft-save / asset-commit / recovery / cancellation`,只有 `generation` 失败显示“返回修改/重新确认”。保存/CAS 只重试或重载,提交/恢复只安全恢复或对账,取消故障只保留草稿继续编辑;初始恢复失败也不得进入生成重试。 - 验证:用 deferred Promise 覆盖 r5/r6 逆序、保存与 progress 交错和 scope 切换;同时覆盖 Shift 单选自身、多选拖动、指针完整序列、零位移、首次有效移动只一条 history,以及五类失败的可访问名称与按钮集。 + +## Windows MSVC 测试不要依赖系统 OpenSSL(2026-08-17) + +- 现象:Windows 上执行 Rust 测试时,`openssl-sys` 构建脚本因找不到 OpenSSL 开发目录或 vcpkg 而失败;机器即使带有 Strawberry Perl 的 `openssl.exe` 和 `libssl.a`,也不能直接供 `x86_64-pc-windows-msvc` 链接。 +- 原因:测试代码仅为动态生成 RSA fixture 引入 `openssl` dev-dependency,从而把原本使用纯 Rust 加密实现的 crate 额外绑定到本机原生 OpenSSL 工具链;Strawberry 附带的库面向 MinGW,不等于可用的 MSVC OpenSSL SDK。 +- 处理:测试优先使用明确标记、只供测试的固定 PEM fixture,并继续通过项目自身的密钥解析与签名验证路径覆盖真实行为;不要仅为生成 fixture 引入系统原生库,也不要把 MinGW OpenSSL 路径写入 `OPENSSL_DIR` 冒充 MSVC 依赖。 +- 验证:运行目标 crate 的 `cargo tree -i openssl-sys --target all` 确认依赖已退出,再执行包含测试目标的 `cargo test --tests`,不能只用不会编译 dev-dependency 的 `cargo check --lib` 代替。 diff --git a/server-rs/Cargo.lock b/server-rs/Cargo.lock index 3c82d1717..fae607bfa 100644 --- a/server-rs/Cargo.lock +++ b/server-rs/Cargo.lock @@ -4222,7 +4222,6 @@ dependencies = [ "csv", "flate2", "hex", - "openssl", "reqwest", "ring", "serde", diff --git a/server-rs/crates/platform-wechat/Cargo.toml b/server-rs/crates/platform-wechat/Cargo.toml index 872319740..734f08116 100644 --- a/server-rs/crates/platform-wechat/Cargo.toml +++ b/server-rs/crates/platform-wechat/Cargo.toml @@ -26,5 +26,4 @@ urlencoding = { workspace = true } x509-parser = { workspace = true } [dev-dependencies] -openssl = "0.10" tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/server-rs/crates/platform-wechat/src/pay.rs b/server-rs/crates/platform-wechat/src/pay.rs index bcd582d83..ac8db5f1f 100644 --- a/server-rs/crates/platform-wechat/src/pay.rs +++ b/server-rs/crates/platform-wechat/src/pay.rs @@ -3526,7 +3526,6 @@ impl std::error::Error for WechatPayError {} mod tests { use super::*; use cbc::cipher::{BlockEncryptMut, block_padding::NoPadding}; - use openssl::{pkey::PKey, rsa::Rsa}; use reqwest::header::HeaderValue; use serde_json::json; @@ -3544,6 +3543,43 @@ KwIDAQAB const TEST_REFUND_API_V3_KEY: &str = "0123456789abcdef0123456789abcdef"; const TEST_REFUND_MCH_ID: &str = "1900000100"; const TEST_REFUND_PLATFORM_SERIAL: &str = "PUB_KEY_ID_REFUND_TEST"; + const TEST_REFUND_PRIVATE_KEY_PEM: &str = r#"-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDIcJQj53zLpqWa +d03vLxZjn4zUKi7aSiGTH5K9zcVsksySnsBt4RrkFqXSQligYT50o44Az04cc+cl +vjpzt1andBQz3jefv5S4Pc2hbVsjTkv3nJtei2niuFpvRc3MYFxS4fK2Nh1t2BqV +aUeXz0uJ3juyTNsgWEbN4zkw8bKDZKxLFqOxisv3vNopCkKKNRiqlaeN++MT/4xP +l6vD8+KHNMC7X4vMUiVK7g1yDi3cQcn+JhjhtPvzCOXsBzibBdhzhfIcmFg0zd5f +WJxMSOWWnrXlRaxCTykkk4dMGZfFuwmyfhgEEw0Ctm/Y3d/sRbYa1RHfmTk4md5S +bzshwJ8vAgMBAAECggEAHSw5e3JNOQzDrJQxrR7C2PQXWKfdEttYQKQHRQXGdrN0 +/+AILNXnBox/TPdoE8ujffFyEQ8bFMwPt/AUbNQh0hR0fkoY+XC2Ugx4ucaDTcOv +DdZmzJ9o5V0kmG5l8hmSRmPpYfjFVr/tupJMn71FhsboFF7YQ8BlacDpCYUcEMBb +2zuk2v9Vt9TUSjx6SzGtuF+u7LeenytH1Mxkx7B6RsyrSFQ2ro0RMV7vOy208/XF +3w8C5G8LQjegukCzxBq3DaHXFTYG1+l3KLUW5yherZPoLhY7NRbqje1LelCLWH7N +Ed3seElOV4DFoqX/abBOwaj+r6yqZRvTRaryIN7dDQKBgQDltM4QGIGH/x8ATv7l +rloByPfTanqktUodj6xURkf4R6HHJEWtbp3Fqc6QbTqrKgSj0OpEnUEslYt035m5 +p8C3Faf9yQYb65iGQFQ/KW6Co5EPhrv0tJUL862GpgQtj6QH7W7CkrtKT1kGqXJY +sKbwP0DfNXk3CdbRpXb8QqIu7QKBgQDfYim1tLOhlGnVouW1FgrrBo/8QGwZYOzv +UWDkifhaL0jYM/x3dbENbKZuG2K+n1MzmbteFcghudFeDM4rBIqLTX+SGIX7cg/V +2vl6UQWFQ5SMFL9i5WRY8B02S9Mo1NYVJInUW1rGxZXSaHmvGLzOhwfSnjnhCwU5 +KSxDp1ynCwKBgEZHSiBsjvzf1klO4fe9nzYamZAqbLmF6dYfhfcGxbA1ok5+T38f +b8/xAwz3DlMd+Otx2KsDfdQ5MMCiRLMjmveo/YvM/DyAmVrBxcTJVVFM3+3jKBBX +S56rgDTJCFA0OVhfkVqgcALtQeyi3SQ7b+fjQmLIRnzLWtkribrmXB6FAoGAQ8A9 +EExnMvmVg+MtMlgmJZRO9V4Aq03XbtpKveYOuiOfP1u9FepPMdgjPj/2GgSusnbM ++kM2+Oun0ZOmsCtnbcqqh4ACmvnETcNlaTDLsNiHZFkilvcmEUd6RK6Is9ihubXk +S9ENXj4tK6zeQzoIgcc4myu8OEIkamrPbxGCq3MCgYAqrW1pZHK5bNP9WUO3X+K1 +PIaVC2CNiH5uI2Ot6RYO2jkrKHZ7RQvu4uOwDqN9zP39eWr1NJ+bGlXgsmYSmhxg +Rylk83d6D6ErDxVXHpXOU7YNRaI3N5fKIoSRn3t2XafQ+cF5BQzq/VckAC8rJtCV +7zCsCmQI/oIjX7q6GGKCRg== +-----END PRIVATE KEY-----"#; + const TEST_REFUND_PUBLIC_KEY_PEM: &str = r#"-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHCUI+d8y6almndN7y8W +Y5+M1Cou2kohkx+Svc3FbJLMkp7AbeEa5Bal0kJYoGE+dKOOAM9OHHPnJb46c7dW +p3QUM943n7+UuD3NoW1bI05L95ybXotp4rhab0XNzGBcUuHytjYdbdgalWlHl89L +id47skzbIFhGzeM5MPGyg2SsSxajsYrL97zaKQpCijUYqpWnjfvjE/+MT5erw/Pi +hzTAu1+LzFIlSu4Ncg4t3EHJ/iYY4bT78wjl7Ac4mwXYc4XyHJhYNM3eX1icTEjl +lp615UWsQk8pJJOHTBmXxbsJsn4YBBMNArZv2N3f7EW2GtUR35k5OJneUm87IcCf +LwIDAQAB +-----END PUBLIC KEY-----"#; #[test] fn mock_pay_params_use_request_payment_shape() { @@ -4465,30 +4501,16 @@ KwIDAQAB } fn build_refund_notify_test_client() -> RealWechatPayClient { - let rsa = Rsa::generate(2_048).expect("refund test RSA key should generate"); - let key_pair = PKey::from_rsa(rsa).expect("refund test key pair should build"); - let private_key_pem = String::from_utf8( - key_pair - .private_key_to_pem_pkcs8() - .expect("refund test private key should encode"), - ) - .expect("refund test private key PEM should be UTF-8"); - let public_key_pem = String::from_utf8( - key_pair - .public_key_to_pem() - .expect("refund test public key should encode"), - ) - .expect("refund test public key PEM should be UTF-8"); RealWechatPayClient { client: reqwest::Client::new(), app_id: "wx-refund-test".to_string(), mch_id: TEST_REFUND_MCH_ID.to_string(), merchant_serial_no: "merchant-refund-test".to_string(), private_key: Arc::new( - parse_rsa_private_key(&private_key_pem) + parse_rsa_private_key(TEST_REFUND_PRIVATE_KEY_PEM) .expect("refund test private key should parse"), ), - platform_public_key_der: parse_public_key_pem(&public_key_pem) + platform_public_key_der: parse_public_key_pem(TEST_REFUND_PUBLIC_KEY_PEM) .expect("refund test public key should parse"), platform_serial_no: TEST_REFUND_PLATFORM_SERIAL.to_string(), api_v3_key: TEST_REFUND_API_V3_KEY.to_string(),