From 384149ae38d7a9dd18bb5c6a199cb4897e95270a Mon Sep 17 00:00:00 2001 From: n08i40k Date: Fri, 4 Sep 2026 23:23:35 +0400 Subject: [PATCH] fix(tests): use local sqlite for tests and adapt test after jwt library update --- .github/workflows/build.yml | 3 - Cargo.lock | 221 ++---------------- Cargo.toml | 17 +- Dockerfile | 2 +- database/Cargo.toml | 3 + database/migration/Cargo.toml | 3 + .../migration/src/m20250904_024854_init.rs | 30 ++- .../provider-engels-polytechnic/Cargo.toml | 12 +- src/routes/auth/sign_in.rs | 11 +- src/state/mod.rs | 48 +++- src/utility/telegram.rs | 22 +- 11 files changed, 127 insertions(+), 245 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9ef7346..ed700c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,8 +13,6 @@ env: BINARY_NAME: schedule-parser-rusted - TEST_DB: ${{ secrets.TEST_DATABASE_URL }} - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ${{ secrets.SENTRY_ORG }} SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} @@ -43,7 +41,6 @@ jobs: run: | cargo test env: - DATABASE_URL: ${{ env.TEST_DB }} SCHEDULE_DISABLE_AUTO_UPDATE: 1 JWT_SECRET: "test-secret-at-least-256-bits-used" VK_ID_CLIENT_ID: 0 diff --git a/Cargo.lock b/Cargo.lock index c9000a9..d433f7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -692,6 +692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", + "untrusted 0.7.1", "zeroize", ] @@ -791,12 +792,6 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" -[[package]] -name = "base64ct" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - [[package]] name = "bcrypt" version = "0.19.3" @@ -1378,33 +1373,6 @@ dependencies = [ "cmov", ] -[[package]] -name = "curve25519-dalek" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.1", - "curve25519-dalek-derive", - "digest 0.11.3", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "darling" version = "0.20.11" @@ -1531,16 +1499,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "der" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" -dependencies = [ - "pem-rfc7468", - "zeroize", -] - [[package]] name = "deranged" version = "0.5.8" @@ -1645,28 +1603,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "ed25519" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" -dependencies = [ - "signature 3.0.0", -] - -[[package]] -name = "ed25519-dalek" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" -dependencies = [ - "curve25519-dalek", - "ed25519", - "sha2 0.11.0", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.18.0" @@ -1792,12 +1728,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" -[[package]] -name = "fiat-crypto" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" - [[package]] name = "find-msvc-tools" version = "0.1.12" @@ -1850,21 +1780,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -2346,22 +2261,6 @@ dependencies = [ "tower-service", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -2724,13 +2623,14 @@ version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881733cbc631fc9e472e24447ce32a64bedf2da498d6d8570b08edc87de71f65" dependencies = [ + "aws-lc-rs", "base64 0.22.1", "getrandom 0.2.17", "js-sys", "pem", "serde", "serde_json", - "signature 2.2.0", + "signature", "simple_asn1", "zeroize", ] @@ -2837,6 +2737,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ + "cc", "pkg-config", "vcpkg", ] @@ -2990,23 +2891,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "nix" version = "0.29.0" @@ -3281,49 +3165,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "openssl" -version = "0.10.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" -dependencies = [ - "bitflags 2.13.1", - "cfg-if", - "foreign-types", - "libc", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-sys" -version = "0.9.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "ordered-float" version = "4.6.0" @@ -3418,15 +3265,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "pem-rfc7468" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.2" @@ -3956,12 +3794,10 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", "mime", - "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -3973,7 +3809,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", "tokio-rustls", "tower", "tower-http", @@ -3994,7 +3829,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -4142,7 +3977,7 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4182,6 +4017,7 @@ dependencies = [ "actix-macros 0.1.0", "actix-test", "actix-web", + "aws-lc-rs", "base64 0.23.1", "bcrypt", "chrono", @@ -4189,7 +4025,6 @@ dependencies = [ "database", "derive_more", "dotenvy", - "ed25519-dalek", "env_logger", "futures-util", "hex-literal", @@ -4458,8 +4293,8 @@ checksum = "76a88b65feb368d9dde5d531a2b59b25016e36fd6e4978432371a3ee77746ca2" dependencies = [ "cfg_aliases", "httpdate", - "native-tls", "reqwest", + "rustls", "sentry-actix", "sentry-backtrace", "sentry-contexts", @@ -4759,12 +4594,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "signature" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" - [[package]] name = "simd-adler32" version = "0.3.10" @@ -5133,19 +4962,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.3", - "once_cell", - "rustix", - "windows-sys 0.61.2", -] - [[package]] name = "thiserror" version = "2.0.20" @@ -5279,16 +5095,6 @@ dependencies = [ "syn 3.0.4", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.5" @@ -5601,6 +5407,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -5634,14 +5446,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d" dependencies = [ "base64 0.23.1", - "der", "log", - "native-tls", "percent-encoding", + "rustls", "rustls-pki-types", "ureq-proto", "utf8-zero", - "webpki-root-certs", + "webpki-roots 1.0.9", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b14935e..9d7ab69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ futures-util = "0" # authorization bcrypt = "0" -jsonwebtoken = { version = "11", features = ["use_pem"] } +jsonwebtoken = { version = "11", features = ["use_pem", "aws_lc_rs"] } # creating users objectid = "0" @@ -48,7 +48,17 @@ reqwest = { version = "0", features = ["json", "form"] } mime = "0" # error handling -sentry = "0" +sentry = { version = "0", default-features = false, features = [ + "backtrace", + "contexts", + "debug-images", + "logs", + "metrics", + "panic", + "release-health", + "reqwest", + "rustls", +] } sentry-actix = "0" # [de]serializing @@ -70,7 +80,7 @@ log = "0" # telegram webdata deciding and verify base64 = "0" percent-encoding = "2" -ed25519-dalek = "3.0.0-pre.1" +aws-lc-rs = "1" # development tracing console-subscriber = { version = "0", optional = true } @@ -78,4 +88,5 @@ tracing = { version = "0", optional = true } [dev-dependencies] providers = { path = "providers", features = ["test"] } +database = { path = "database", features = ["sqlite"] } actix-test = { path = "actix-test" } diff --git a/Dockerfile b/Dockerfile index 4a04c2a..160cd52 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ ARG BINARY_NAME WORKDIR /app/ RUN apt update && \ - apt install -y libpq5 ca-certificates openssl + apt install -y ca-certificates COPY ./${BINARY_NAME} /bin/main RUN chmod +x /bin/main diff --git a/database/Cargo.toml b/database/Cargo.toml index c78d7f0..7cfcd59 100644 --- a/database/Cargo.toml +++ b/database/Cargo.toml @@ -3,6 +3,9 @@ name = "database" version = "0.1.0" edition = "2024" +[features] +sqlite = ["sea-orm/sqlx-sqlite", "migration/sqlite"] + [dependencies] migration = { path = "migration" } entity = { path = "entity" } diff --git a/database/migration/Cargo.toml b/database/migration/Cargo.toml index 75bf2f5..a6077cd 100644 --- a/database/migration/Cargo.toml +++ b/database/migration/Cargo.toml @@ -8,6 +8,9 @@ publish = false name = "migration" path = "src/lib.rs" +[features] +sqlite = ["sea-orm-migration/sqlx-sqlite"] + [dependencies] async-std = { version = "1", features = ["attributes", "tokio1"] } diff --git a/database/migration/src/m20250904_024854_init.rs b/database/migration/src/m20250904_024854_init.rs index 8a643e6..779a314 100644 --- a/database/migration/src/m20250904_024854_init.rs +++ b/database/migration/src/m20250904_024854_init.rs @@ -1,5 +1,5 @@ use sea_orm_migration::prelude::extension::postgres::Type; -use sea_orm_migration::sea_orm::{EnumIter, Iterable}; +use sea_orm_migration::sea_orm::{DatabaseBackend, EnumIter, Iterable}; use sea_orm_migration::{prelude::*, schema::*}; #[derive(DeriveMigrationName)] @@ -8,14 +8,16 @@ pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_type( - Type::create() - .as_enum(UserRole) - .values(UserRoleVariants::iter()) - .to_owned(), - ) - .await?; + if manager.get_database_backend() == DatabaseBackend::Postgres { + manager + .create_type( + Type::create() + .as_enum(UserRole) + .values(UserRoleVariants::iter()) + .to_owned(), + ) + .await?; + } manager .create_table( @@ -40,9 +42,13 @@ impl MigrationTrait for Migration { .drop_table(Table::drop().table(User::Table).to_owned()) .await?; - manager - .drop_type(Type::drop().name(UserRole).to_owned()) - .await + if manager.get_database_backend() == DatabaseBackend::Postgres { + manager + .drop_type(Type::drop().name(UserRole).to_owned()) + .await?; + } + + Ok(()) } } diff --git a/providers/provider-engels-polytechnic/Cargo.toml b/providers/provider-engels-polytechnic/Cargo.toml index df5720b..fd8f22a 100644 --- a/providers/provider-engels-polytechnic/Cargo.toml +++ b/providers/provider-engels-polytechnic/Cargo.toml @@ -28,6 +28,16 @@ ua_generator = "0" regex = "1" strsim = "0" log = "0" -sentry = "0" +sentry = { version = "0", default-features = false, features = [ + "backtrace", + "contexts", + "debug-images", + "logs", + "metrics", + "panic", + "release-health", + "reqwest", + "rustls", +] } fancy-regex = "0" diff --git a/src/routes/auth/sign_in.rs b/src/routes/auth/sign_in.rs index 79f0fc4..bb38c64 100644 --- a/src/routes/auth/sign_in.rs +++ b/src/routes/auth/sign_in.rs @@ -146,8 +146,8 @@ mod tests { use actix_web::http::StatusCode; use actix_web::test; use database::entity::sea_orm_active_enums::UserRole; - use database::entity::ActiveUser; - use database::sea_orm::{ActiveModelTrait, Set}; + use database::entity::{ActiveUser, UserEntity}; + use database::sea_orm::{ActiveModelTrait, EntityTrait, Set}; use sha1::{Digest, Sha1}; use std::fmt::Write; @@ -193,8 +193,13 @@ mod tests { android_version: Set(None), }; + UserEntity::delete_by_id(&id) + .exec(app_state.get_database()) + .await + .expect("Failed to delete user"); + active_user - .save(app_state.get_database()) + .insert(app_state.get_database()) .await .expect("Failed to save user"); } diff --git a/src/state/mod.rs b/src/state/mod.rs index a23fd9e..a3d4c28 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -51,15 +51,8 @@ impl AppState { database: if let Some(database) = database { database } else { - let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - - let mut opt = ConnectOptions::new(database_url.clone()); - - opt.max_connections(4) - .min_connections(2) - .connect_timeout(Duration::from_secs(10)) - .idle_timeout(Duration::from_secs(8)) - .sqlx_logging(true); + let opt = database_connect_options(); + let database_url = opt.get_url().to_string(); let database = Database::connect(opt) .await @@ -104,6 +97,43 @@ impl AppState { } } +/// Параметры подключения к базе данных. +#[cfg(not(test))] +fn database_connect_options() -> ConnectOptions { + let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + + let mut opt = ConnectOptions::new(database_url); + + opt.max_connections(4) + .min_connections(2) + .connect_timeout(Duration::from_secs(10)) + .idle_timeout(Duration::from_secs(8)) + .sqlx_logging(true); + + opt +} + +/// SQLite во временном файле: база в памяти умрёт вместе с соединением. +#[cfg(test)] +fn database_connect_options() -> ConnectOptions { + let path = std::env::temp_dir().join(format!( + "{}-test-{}.sqlite", + env!("CARGO_PKG_NAME"), + std::process::id() + )); + + let _ = std::fs::remove_file(&path); + + let mut opt = ConnectOptions::new(format!("sqlite://{}?mode=rwc", path.display())); + + opt.max_connections(1) + .min_connections(1) + .connect_timeout(Duration::from_secs(10)) + .sqlx_logging(true); + + opt +} + /// Create a new object web::Data. pub async fn new_app_state( database: Option, diff --git a/src/utility/telegram.rs b/src/utility/telegram.rs index a4a421a..e8bf369 100644 --- a/src/utility/telegram.rs +++ b/src/utility/telegram.rs @@ -1,10 +1,13 @@ +use aws_lc_rs::signature::{ED25519, UnparsedPublicKey}; use base64::Engine; use derive_more::{Display, Error}; -use ed25519_dalek::Verifier; use hex_literal::hex; use serde::Deserialize; use std::collections::HashMap; +/// Длина подписи Ed25519 в байтах. +const ED25519_SIGNATURE_LENGTH: usize = 64; + pub struct WebAppInitDataMap { pub data_map: HashMap, } @@ -54,10 +57,10 @@ impl WebAppInitDataMap { hex!("40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec"), ]; - let verifying_key = ed25519_dalek::VerifyingKey::from_bytes( - &TELEGRAM_PUBLIC_KEY[if test_dc { 1 } else { 0 }], - ) - .unwrap(); + let verifying_key = UnparsedPublicKey::new( + &ED25519, + TELEGRAM_PUBLIC_KEY[if test_dc { 1 } else { 0 }], + ); let signature = { let raw = self @@ -69,8 +72,11 @@ impl WebAppInitDataMap { .decode(raw) .map_err(|_| VerifyError::BadSignature)?; - ed25519_dalek::Signature::from_slice(bytes.as_slice()) - .map_err(|_| VerifyError::BadSignature)? + if bytes.len() != ED25519_SIGNATURE_LENGTH { + return Err(VerifyError::BadSignature); + } + + bytes }; let data_check_string = format!("{}:WebAppData\n{}", bot_id, { @@ -85,7 +91,7 @@ impl WebAppInitDataMap { }); verifying_key - .verify(data_check_string.as_bytes(), &signature) + .verify(data_check_string.as_bytes(), signature.as_slice()) .map_err(|_| VerifyError::IntegrityCheckFailed) } }