From da0ab29b2abd0c5fe7e862d17cc6790d82c17049 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 07:26:37 +0000 Subject: [PATCH 01/14] feat: Update dependencies and add frontend distribution path --- Cargo.lock | 76 ++++++++++++++++++++++++++++++++ apps/nxmesh-master/Cargo.toml | 5 +++ apps/nxmesh-master/frontend-dist | 1 + 3 files changed, 82 insertions(+) create mode 120000 apps/nxmesh-master/frontend-dist diff --git a/Cargo.lock b/Cargo.lock index 6a0439e..f321436 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -538,6 +538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", + "axum-macros", "base64", "bytes", "form_urlencoded", @@ -586,6 +587,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "base64" version = "0.22.1" @@ -2477,12 +2489,14 @@ dependencies = [ "handlebars", "hex", "jsonwebtoken", + "mime_guess", "mockall", "nxmesh-core", "nxmesh-migration", "nxmesh-proto", "rand 0.10.0", "rcgen", + "rust-embed", "sea-orm", "sea-orm-migration", "serde", @@ -3338,6 +3352,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-embed" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.117", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust-ini" version = "0.21.3" @@ -3454,6 +3502,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.28" @@ -4876,6 +4933,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -5046,6 +5113,15 @@ dependencies = [ "wasite", ] +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "windows-core" version = "0.62.2" diff --git a/apps/nxmesh-master/Cargo.toml b/apps/nxmesh-master/Cargo.toml index a851768..341f563 100644 --- a/apps/nxmesh-master/Cargo.toml +++ b/apps/nxmesh-master/Cargo.toml @@ -84,7 +84,12 @@ time = "0.3" # Cert handling zip = { workspace = true } +rust-embed = { version = "8.11.0", features = [] } +mime_guess = "2.0.5" [dev-dependencies] tokio-test.workspace = true mockall.workspace = true + +[features] +dev-tools = ["axum/macros"] diff --git a/apps/nxmesh-master/frontend-dist b/apps/nxmesh-master/frontend-dist new file mode 120000 index 0000000..3d33621 --- /dev/null +++ b/apps/nxmesh-master/frontend-dist @@ -0,0 +1 @@ +../nxmesh-frontend/dist/ \ No newline at end of file From e2d364722b00f6b47f72c32c16f9afe8e463b989 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 07:30:37 +0000 Subject: [PATCH 02/14] feat: Add frontend routing and asset handling with Axum --- apps/nxmesh-master/src/main.rs | 1 + apps/nxmesh-master/src/routes/frontend/mod.rs | 71 +++++++++++++++++++ apps/nxmesh-master/src/routes/mod.rs | 9 +++ 3 files changed, 81 insertions(+) create mode 100644 apps/nxmesh-master/src/routes/frontend/mod.rs create mode 100644 apps/nxmesh-master/src/routes/mod.rs diff --git a/apps/nxmesh-master/src/main.rs b/apps/nxmesh-master/src/main.rs index 5aad5d4..d4a7896 100644 --- a/apps/nxmesh-master/src/main.rs +++ b/apps/nxmesh-master/src/main.rs @@ -14,6 +14,7 @@ mod cli; mod config; mod connector; mod db; +mod routes; mod service; #[tokio::main] diff --git a/apps/nxmesh-master/src/routes/frontend/mod.rs b/apps/nxmesh-master/src/routes/frontend/mod.rs new file mode 100644 index 0000000..84baf96 --- /dev/null +++ b/apps/nxmesh-master/src/routes/frontend/mod.rs @@ -0,0 +1,71 @@ +use axum::{Router, response::IntoResponse}; +use tracing::error; + +// In development, build the frontend from the source directory, the soft link will handle the path resolution +// In deployment, pre-build the frontend and replace the frontend-dist folder with the built assets, the rust-embed will handle the embedding and path resolution +#[derive(rust_embed::Embed)] +#[folder = "./frontend-dist/"] +struct FrontendAssets; + +const INDEX_HTML: &str = "index.html"; + +pub async fn get_router() -> Router { + Router::new() + .route( + "/", + axum::routing::get(get_fallback_handler) + .head(get_fallback_handler) + .options(get_fallback_handler), + ) + .route( + "/{*path}", + axum::routing::get(get_file_handler) + .head(get_file_handler) + .options(get_file_handler), + ) + // + .fallback(get_fallback_handler().await) +} + +#[cfg_attr(debug_assertions, axum::debug_handler)] +pub async fn get_fallback_handler() -> Result>, axum::http::StatusCode> +{ + let index_html = get_index_html(); + match index_html { + Some(html) => Ok(axum::response::Html(html)), + None => Err(axum::http::StatusCode::NOT_FOUND), + } +} + +fn get_index_html() -> Option> { + FrontendAssets::get(INDEX_HTML).map(|asset| asset.data.as_ref().to_owned()) +} + +#[cfg_attr(debug_assertions, axum::debug_handler)] +async fn get_file_handler( + axum::extract::Path(path): axum::extract::Path, +) -> Result { + let file_path = if path.is_empty() { + INDEX_HTML.to_string() + } else { + path + }; + + match FrontendAssets::get(&file_path) { + Some(asset) => { + let content_type = mime_guess::from_path(&file_path).first_or_octet_stream(); + let response = axum::response::Response::builder() + .header(axum::http::header::CONTENT_TYPE, content_type.as_ref()) + .body(asset.data.into_owned().into()) + .map_err(|e| { + error!("Failed to build response for {}: {}", file_path, e); + axum::http::StatusCode::INTERNAL_SERVER_ERROR + })?; + Ok(response) + } + // return index.html for any file not found to support client-side routing in the frontend + None => get_fallback_handler() + .await + .map(|html| html.into_response()), + } +} diff --git a/apps/nxmesh-master/src/routes/mod.rs b/apps/nxmesh-master/src/routes/mod.rs new file mode 100644 index 0000000..80164a8 --- /dev/null +++ b/apps/nxmesh-master/src/routes/mod.rs @@ -0,0 +1,9 @@ +use axum::Router; + +mod frontend; + +pub async fn get_root_router() -> Router { + Router::new() + .merge(frontend::get_router().await) + .fallback(frontend::get_fallback_handler().await) +} From bbde3c1b6075af77bc511397b3ea9f1e8cfebdf8 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 07:31:29 +0000 Subject: [PATCH 03/14] feat: Refactor agent server initialization to support parallel api server --- apps/nxmesh-master/src/service/mod.rs | 43 +++++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/apps/nxmesh-master/src/service/mod.rs b/apps/nxmesh-master/src/service/mod.rs index a3ade80..1599a17 100644 --- a/apps/nxmesh-master/src/service/mod.rs +++ b/apps/nxmesh-master/src/service/mod.rs @@ -1,4 +1,6 @@ -use std::sync::Arc; +use std::{net::ToSocketAddrs, sync::Arc}; + +use tracing::info; use crate::{connector::agent::AgentConnectorTrait, service::certificate::CertificateService}; @@ -26,15 +28,38 @@ pub async fn start_master_server( println!("Certificate generated and stored successfully."); } - // Initialize agent connector - let mut agent_connector = crate::connector::agent::AgentConnector::new(Box::new( - crate::connector::agent::ssh::SshAgentConnector::new(settings.clone())?, - )); + let ssh_connector = crate::connector::agent::ssh::SshAgentConnector::new(settings.clone())?; + let cert_service_for_agent = cert_service.clone(); + let settings_for_agent = settings.clone(); + let connection_for_agent = db_connection.clone(); - // Start the agent server - agent_connector - .start_server(&settings, cert_service, db_connection) - .await?; + tokio::spawn(async move { + let mut connector = ssh_connector; + tracing::info!("Starting agent server..."); + if let Err(e) = connector + .start_server( + &settings_for_agent, + cert_service_for_agent, + connection_for_agent, + ) + .await + { + tracing::error!("Agent server failed: {}", e); + } else { + tracing::info!("Agent server stopped."); + } + }); + + let axum_router = crate::routes::get_root_router().await; + + // Start the HTTP server + let addr = format!("{}:{}", settings.server.bind_address, settings.server.port) + .to_socket_addrs()? + .next() + .ok_or("Invalid bind address")?; + let listener = tokio::net::TcpListener::bind(addr).await?; + info!("Web/API server is listening on {}", addr); + axum::serve(listener, axum_router).await?; Ok(()) } From a9a08d2ef8231994d1167ef86fe1337e1d75593e Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 07:31:45 +0000 Subject: [PATCH 04/14] feat: Enhance SSH Agent gRPC server logging for better monitoring --- apps/nxmesh-master/src/connector/agent/ssh.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/nxmesh-master/src/connector/agent/ssh.rs b/apps/nxmesh-master/src/connector/agent/ssh.rs index 5b02082..39d95e6 100644 --- a/apps/nxmesh-master/src/connector/agent/ssh.rs +++ b/apps/nxmesh-master/src/connector/agent/ssh.rs @@ -6,6 +6,7 @@ use nxmesh_proto::{ }; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; use tonic::transport::Server; +use tracing::info; use crate::{db::entities::public_key_revocations, service::agent::AgentServerService}; @@ -69,7 +70,14 @@ impl AgentConnectorTrait for SshAgentConnector { .layer(ssh_interceptor) .add_service(agent_server_service); - router.serve(addr).await?; + info!("SSH Agent gRPC server is listening on {}", addr); + router + .serve(addr) + .await + .inspect(|_| info!("SSH Agent gRPC server stopped gracefully.")) + .inspect_err(|e| { + tracing::error!("SSH Agent gRPC server failed: {}", e); + })?; Ok(()) } } From 6ce8850ddb7990ab702d03f0643d138ab70f5847 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 08:22:05 +0000 Subject: [PATCH 05/14] feat: Update frontend build cache path and add dummy artifact to prevent build failure --- .github/workflows/test.yaml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f704299..90200a3 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,11 +45,16 @@ jobs: - name: Restore frontend build cache uses: actions/cache@v4 with: - path: apps/nxmesh-frontend/build + path: apps/nxmesh-frontend/dist key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} restore-keys: | frontend-build-${{ runner.os }}- + - name: Add dummy fonrtend build artifact to prevent build failure + run: | + mkdir -p apps/nxmesh-frontend/dist + touch apps/nxmesh-frontend/dist/dummy + - name: Run tests run: cargo test --all-features @@ -74,11 +79,16 @@ jobs: - name: Restore frontend build cache uses: actions/cache@v4 with: - path: apps/nxmesh-frontend/build + path: apps/nxmesh-frontend/dist key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} restore-keys: | frontend-build-${{ runner.os }}- + - name: Add dummy fonrtend build artifact to prevent build failure + run: | + mkdir -p apps/nxmesh-frontend/dist + touch apps/nxmesh-frontend/dist/dummy + - name: Run clippy run: cargo clippy --all-features @@ -147,7 +157,7 @@ jobs: - name: Cache frontend build uses: actions/cache@v4 with: - path: apps/nxmesh-frontend/build + path: apps/nxmesh-frontend/dist key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} restore-keys: | frontend-build-${{ runner.os }}- From 1eeca606ec813f516e6a362d6b5f21374c384012 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 18 Apr 2026 08:37:08 +0000 Subject: [PATCH 06/14] feat: Remove debug handler attributes from fallback and file handler functions --- apps/nxmesh-master/src/routes/frontend/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/nxmesh-master/src/routes/frontend/mod.rs b/apps/nxmesh-master/src/routes/frontend/mod.rs index 84baf96..9f677c4 100644 --- a/apps/nxmesh-master/src/routes/frontend/mod.rs +++ b/apps/nxmesh-master/src/routes/frontend/mod.rs @@ -27,7 +27,6 @@ pub async fn get_router() -> Router { .fallback(get_fallback_handler().await) } -#[cfg_attr(debug_assertions, axum::debug_handler)] pub async fn get_fallback_handler() -> Result>, axum::http::StatusCode> { let index_html = get_index_html(); @@ -41,7 +40,6 @@ fn get_index_html() -> Option> { FrontendAssets::get(INDEX_HTML).map(|asset| asset.data.as_ref().to_owned()) } -#[cfg_attr(debug_assertions, axum::debug_handler)] async fn get_file_handler( axum::extract::Path(path): axum::extract::Path, ) -> Result { From d9fe053d417690cc323c472e2413d100f2e4134d Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:08:00 +0000 Subject: [PATCH 07/14] feat: Add new dependencies for axum-test and related packages in Cargo.lock --- Cargo.lock | 181 ++++++++++++++++++++++++++++++++++ apps/nxmesh-master/Cargo.toml | 1 + 2 files changed, 182 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f321436..a65fe00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -598,6 +598,34 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "axum-test" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a86bfe2ef15bee102ac34912f7f4542b0bb37dc464fa55461763999c4d625e7" +dependencies = [ + "anyhow", + "axum", + "bytes", + "bytesize", + "cookie", + "expect-json", + "http", + "http-body-util", + "hyper", + "hyper-util", + "mime", + "pretty_assertions", + "reserve-port", + "rust-multipart-rfc7578_2", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tower", + "url", +] + [[package]] name = "base64" version = "0.22.1" @@ -739,6 +767,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +[[package]] +name = "bytesize" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" + [[package]] name = "bzip2" version = "0.6.1" @@ -923,6 +957,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -1147,6 +1191,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -1200,6 +1250,15 @@ dependencies = [ "serde", ] +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" +dependencies = [ + "serde", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -1274,6 +1333,35 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "expect-json" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869f97f4abe8e78fc812a94ad6b721d72c4fb5532877c79610f2c238d7ccf6c4" +dependencies = [ + "chrono", + "email_address", + "expect-json-macros", + "num", + "regex", + "serde", + "serde_json", + "thiserror", + "typetag", + "uuid", +] + +[[package]] +name = "expect-json-macros" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6fdf550180a6c29a28cb9aac262dc0064c25735641d2317f670075e9a469d9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1976,6 +2064,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "inventory" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" +dependencies = [ + "rustversion", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -2346,6 +2443,20 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -2422,6 +2533,17 @@ dependencies = [ "num-modular", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2482,6 +2604,7 @@ dependencies = [ "async-stream", "async-trait", "axum", + "axum-test", "chrono", "clap", "config", @@ -2946,6 +3069,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -3275,6 +3408,15 @@ dependencies = [ "bytecheck", ] +[[package]] +name = "reserve-port" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94070964579245eb2f76e62a7668fe87bd9969ed6c41256f3bf614e3323dd3cc" +dependencies = [ + "thiserror", +] + [[package]] name = "ring" version = "0.17.14" @@ -3396,6 +3538,21 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rust-multipart-rfc7578_2" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bdaa068902270ca7fa8619775e1838e23a63620abac0947ce0f715819b8cec" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http", + "mime", + "rand 0.10.0", + "thiserror", +] + [[package]] name = "rust_decimal" version = "1.40.0" @@ -4756,6 +4913,30 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "typetag" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2212c8a9b9bcfca32024de14998494cf9a5dfa59ea1b829de98bac374b86bf" +dependencies = [ + "erased-serde", + "inventory", + "once_cell", + "serde", + "typetag-impl", +] + +[[package]] +name = "typetag-impl" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27a7a9b72ba121f6f1f6c3632b85604cac41aedb5ddc70accbebb6cac83de846" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "ucd-trie" version = "0.1.7" diff --git a/apps/nxmesh-master/Cargo.toml b/apps/nxmesh-master/Cargo.toml index 341f563..4fa030e 100644 --- a/apps/nxmesh-master/Cargo.toml +++ b/apps/nxmesh-master/Cargo.toml @@ -86,6 +86,7 @@ time = "0.3" zip = { workspace = true } rust-embed = { version = "8.11.0", features = [] } mime_guess = "2.0.5" +axum-test = "20.0.0" [dev-dependencies] tokio-test.workspace = true From 86e9fd42bb1e511828395d7a98e5a81611bcaee5 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:08:08 +0000 Subject: [PATCH 08/14] test: Add unit tests for frontend routing and file handling --- apps/nxmesh-master/src/routes/frontend/mod.rs | 80 +++++++++++++++++++ apps/nxmesh-master/src/routes/mod.rs | 27 +++++++ 2 files changed, 107 insertions(+) diff --git a/apps/nxmesh-master/src/routes/frontend/mod.rs b/apps/nxmesh-master/src/routes/frontend/mod.rs index 9f677c4..d510d1e 100644 --- a/apps/nxmesh-master/src/routes/frontend/mod.rs +++ b/apps/nxmesh-master/src/routes/frontend/mod.rs @@ -67,3 +67,83 @@ async fn get_file_handler( .map(|html| html.into_response()), } } + +#[cfg(test)] +#[allow(clippy::expect_used)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_get_index_html() { + let index_html = get_index_html(); + assert!( + index_html.is_some(), + "Expected to find index.html in embedded assets" + ); + } + + #[tokio::test] + async fn test_get_file_handler_existing_file() { + let response = get_file_handler(axum::extract::Path("index.html".to_string())).await; + assert!( + response.is_ok(), + "Expected to successfully retrieve index.html" + ); + let response = response.expect("Expected response to be Ok"); + assert_eq!(response.status(), axum::http::StatusCode::OK); + assert!( + response + .headers() + .get(axum::http::header::CONTENT_TYPE) + .map(|ct| ct.to_str().unwrap_or("")) + .expect("Content-Type header should be present") + .starts_with("text/html") + ); + } + + #[tokio::test] + async fn test_get_file_handler_nonexistent_file() { + let response = get_file_handler(axum::extract::Path("nonexistent.txt".to_string())).await; + assert!( + response.is_ok(), + "Expected to fallback to index.html for nonexistent file" + ); + let response = response.expect("Expected response to be Ok"); + assert_eq!(response.status(), axum::http::StatusCode::OK); + assert!( + response + .headers() + .get(axum::http::header::CONTENT_TYPE) + .map(|ct| ct.to_str().unwrap_or("")) + .expect("Content-Type header should be present") + .starts_with("text/html") + ) + } +} + +#[cfg(test)] +mod axum_tests { + use super::*; + use axum_test::TestServer; + + #[tokio::test] + async fn test_should_return_index_html_for_root_path() { + let router = get_router().await; + let server = TestServer::new(router); + let response = server.get("/").await; + assert_eq!(response.status_code(), 200); + } + + #[tokio::test] + async fn test_should_return_index_html_for_nonexistent_path() { + let router = get_router().await; + let server = TestServer::new(router); + let fallback_response = server.get("/nonexistent").await; + assert_eq!(fallback_response.status_code(), 200); + + let index_response = server.get("/").await; + assert_eq!(index_response.status_code(), 200); + + assert_eq!(fallback_response.text(), index_response.text()); + } +} diff --git a/apps/nxmesh-master/src/routes/mod.rs b/apps/nxmesh-master/src/routes/mod.rs index 80164a8..0583ef2 100644 --- a/apps/nxmesh-master/src/routes/mod.rs +++ b/apps/nxmesh-master/src/routes/mod.rs @@ -7,3 +7,30 @@ pub async fn get_root_router() -> Router { .merge(frontend::get_router().await) .fallback(frontend::get_fallback_handler().await) } + +#[cfg(test)] +mod tests { + use super::*; + use axum_test::TestServer; + + #[tokio::test] + async fn test_should_return_index_html_for_root_path() { + let router = get_root_router().await; + let server = TestServer::new(router); + let response = server.get("/").await; + assert_eq!(response.status_code(), 200); + } + + #[tokio::test] + async fn test_should_return_index_html_for_nonexistent_path() { + let router = get_root_router().await; + let server = TestServer::new(router); + let fallback_response = server.get("/nonexistent").await; + assert_eq!(fallback_response.status_code(), 200); + + let index_response = server.get("/").await; + assert_eq!(index_response.status_code(), 200); + + assert_eq!(fallback_response.text(), index_response.text()); + } +} From e74ddb96abb5b8b6ba850ceb3dfb02d2b0faa351 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 02:41:16 +0000 Subject: [PATCH 09/14] fix: embed frontend builds in test --- .github/workflows/test.yaml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 90200a3..a9ae96f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -50,13 +50,15 @@ jobs: restore-keys: | frontend-build-${{ runner.os }}- - - name: Add dummy fonrtend build artifact to prevent build failure + - name: Copy frontend build to expected location run: | - mkdir -p apps/nxmesh-frontend/dist - touch apps/nxmesh-frontend/dist/dummy + # unlink frontend-dist + rm -f apps/nxmesh-master/frontend-dist || true + rm -rf apps/nxmesh-master/frontend-dist || true + cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist - name: Run tests - run: cargo test --all-features + run: cargo test --all-features -- --show-output lint-crates: runs-on: ubuntu-latest @@ -84,10 +86,12 @@ jobs: restore-keys: | frontend-build-${{ runner.os }}- - - name: Add dummy fonrtend build artifact to prevent build failure + - name: Copy frontend build to expected location run: | - mkdir -p apps/nxmesh-frontend/dist - touch apps/nxmesh-frontend/dist/dummy + # unlink frontend-dist + rm -f apps/nxmesh-master/frontend-dist || true + rm -rf apps/nxmesh-master/frontend-dist || true + cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist - name: Run clippy run: cargo clippy --all-features @@ -159,5 +163,4 @@ jobs: with: path: apps/nxmesh-frontend/dist key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} - restore-keys: | - frontend-build-${{ runner.os }}- + # IGNORE restore-keys From 836617fa544da27f0406586e3bab2a98bfb8fb85 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 02:49:47 +0000 Subject: [PATCH 10/14] test: Add asset listing test for embedded frontend assets Co-authored-by: Copilot --- .github/workflows/test.yaml | 2 ++ apps/nxmesh-master/src/routes/frontend/mod.rs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index a9ae96f..318113c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -57,6 +57,8 @@ jobs: rm -rf apps/nxmesh-master/frontend-dist || true cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist + ls -la apps/nxmesh-master/frontend-dist + - name: Run tests run: cargo test --all-features -- --show-output diff --git a/apps/nxmesh-master/src/routes/frontend/mod.rs b/apps/nxmesh-master/src/routes/frontend/mod.rs index d510d1e..faaeb41 100644 --- a/apps/nxmesh-master/src/routes/frontend/mod.rs +++ b/apps/nxmesh-master/src/routes/frontend/mod.rs @@ -73,6 +73,16 @@ async fn get_file_handler( mod tests { use super::*; + #[tokio::test] + async fn test_asset() { + // list all embedded assets for debugging + let assets = FrontendAssets::iter().collect::>(); + assert!( + !assets.is_empty(), + "Expected to find embedded assets, but found none" + ); + } + #[tokio::test] async fn test_get_index_html() { let index_html = get_index_html(); From 4b80619c97f0861dc50a42905f738a39adefe5ed Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 03:21:36 +0000 Subject: [PATCH 11/14] fix: update frontend build process and add logging for embedded assets Co-authored-by: Copilot --- .github/workflows/test.yaml | 23 ++++++++----------- apps/nxmesh-master/src/routes/frontend/mod.rs | 1 + 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 318113c..86daf9f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -42,13 +42,11 @@ jobs: - name: Setup Rust, checkout and restore caches uses: ./.github/actions/setup-rust - - name: Restore frontend build cache - uses: actions/cache@v4 + - name: Download frontend build artifact + uses: actions/download-artifact@v3 with: + name: frontend-build path: apps/nxmesh-frontend/dist - key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} - restore-keys: | - frontend-build-${{ runner.os }}- - name: Copy frontend build to expected location run: | @@ -80,13 +78,11 @@ jobs: with: components: clippy, rustfmt - - name: Restore frontend build cache - uses: actions/cache@v4 + - name: Download frontend build artifact + uses: actions/download-artifact@v3 with: + name: frontend-build path: apps/nxmesh-frontend/dist - key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} - restore-keys: | - frontend-build-${{ runner.os }}- - name: Copy frontend build to expected location run: | @@ -160,9 +156,8 @@ jobs: cd apps/nxmesh-frontend bun run build - - name: Cache frontend build - uses: actions/cache@v4 + - name: Upload frontend build artifact + uses: actions/upload-artifact@v3 with: + name: frontend-build path: apps/nxmesh-frontend/dist - key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} - # IGNORE restore-keys diff --git a/apps/nxmesh-master/src/routes/frontend/mod.rs b/apps/nxmesh-master/src/routes/frontend/mod.rs index faaeb41..db345f6 100644 --- a/apps/nxmesh-master/src/routes/frontend/mod.rs +++ b/apps/nxmesh-master/src/routes/frontend/mod.rs @@ -77,6 +77,7 @@ mod tests { async fn test_asset() { // list all embedded assets for debugging let assets = FrontendAssets::iter().collect::>(); + println!("Embedded assets: {:?}", assets); assert!( !assets.is_empty(), "Expected to find embedded assets, but found none" From 1481e31182e9a6811212f423cad7a997e88f2ba1 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 04:26:29 +0000 Subject: [PATCH 12/14] Revert "fix: update frontend build process and add logging for embedded assets" This reverts commit 4b80619c97f0861dc50a42905f738a39adefe5ed. --- .github/workflows/test.yaml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 86daf9f..318113c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -42,11 +42,13 @@ jobs: - name: Setup Rust, checkout and restore caches uses: ./.github/actions/setup-rust - - name: Download frontend build artifact - uses: actions/download-artifact@v3 + - name: Restore frontend build cache + uses: actions/cache@v4 with: - name: frontend-build path: apps/nxmesh-frontend/dist + key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} + restore-keys: | + frontend-build-${{ runner.os }}- - name: Copy frontend build to expected location run: | @@ -78,11 +80,13 @@ jobs: with: components: clippy, rustfmt - - name: Download frontend build artifact - uses: actions/download-artifact@v3 + - name: Restore frontend build cache + uses: actions/cache@v4 with: - name: frontend-build path: apps/nxmesh-frontend/dist + key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} + restore-keys: | + frontend-build-${{ runner.os }}- - name: Copy frontend build to expected location run: | @@ -156,8 +160,9 @@ jobs: cd apps/nxmesh-frontend bun run build - - name: Upload frontend build artifact - uses: actions/upload-artifact@v3 + - name: Cache frontend build + uses: actions/cache@v4 with: - name: frontend-build path: apps/nxmesh-frontend/dist + key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} + # IGNORE restore-keys From dff828addfb287952dc78e12e04d6b169eee3da5 Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 06:04:55 +0000 Subject: [PATCH 13/14] fix: update frontend build process to create dummy artifacts and comment out artifact handling Co-authored-by: Copilot --- .github/workflows/test.yaml | 54 +++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 318113c..ae49d26 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -50,14 +50,27 @@ jobs: restore-keys: | frontend-build-${{ runner.os }}- - - name: Copy frontend build to expected location - run: | - # unlink frontend-dist - rm -f apps/nxmesh-master/frontend-dist || true - rm -rf apps/nxmesh-master/frontend-dist || true - cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist + # TODO: uncomment until artifact hanlding fixed in gitea + # - name: Download frontend build artifact + # uses: actions/download-artifact@v4 + # with: + # name: frontend-dist + # path: apps/nxmesh-frontend/dist - ls -la apps/nxmesh-master/frontend-dist + # - name: Copy frontend build to expected location + # run: | + # # unlink frontend-dist + # rm -f apps/nxmesh-master/frontend-dist || true + # rm -rf apps/nxmesh-master/frontend-dist || true + # cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist + + # ls -la apps/nxmesh-master/frontend-dist + + - name: Create dummy build artifacts + run: | + rm -f apps/nxmesh-master/frontend-dist || true + mkdir -p apps/nxmesh-master/frontend-dist + echo "

Dummy Build

" > apps/nxmesh-master/frontend-dist/index.html - name: Run tests run: cargo test --all-features -- --show-output @@ -88,12 +101,25 @@ jobs: restore-keys: | frontend-build-${{ runner.os }}- - - name: Copy frontend build to expected location + # TODO: uncomment until artifact hanlding fixed in gitea + # - name: Download frontend build artifact + # uses: actions/download-artifact@v4 + # with: + # name: frontend-dist + # path: apps/nxmesh-frontend/dist + + # - name: Copy frontend build to expected location + # run: | + # # unlink frontend-dist + # rm -f apps/nxmesh-master/frontend-dist || true + # rm -rf apps/nxmesh-master/frontend-dist || true + # cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist + + - name: Create dummy build artifacts run: | - # unlink frontend-dist rm -f apps/nxmesh-master/frontend-dist || true - rm -rf apps/nxmesh-master/frontend-dist || true - cp -r apps/nxmesh-frontend/dist apps/nxmesh-master/frontend-dist + mkdir -p apps/nxmesh-master/frontend-dist + echo "

Dummy Build

" > apps/nxmesh-master/frontend-dist/index.html - name: Run clippy run: cargo clippy --all-features @@ -166,3 +192,9 @@ jobs: path: apps/nxmesh-frontend/dist key: frontend-build-${{ runner.os }}-run-${{ github.run_id }} # IGNORE restore-keys + # TODO: uncomment until artifact hanlding fixed in gitea + # - name: Upload frontend build artifact + # uses: actions/upload-artifact@v4 + # with: + # name: frontend-dist + # path: apps/nxmesh-frontend/dist From 171e505f2250a4e6dc2b6f2912171edf77262d0f Mon Sep 17 00:00:00 2001 From: GW_MC <72297530+GWMCwing@users.noreply.github.com> Date: Sat, 25 Apr 2026 06:30:13 +0000 Subject: [PATCH 14/14] fix: update migration and entity generation commands in CI workflow --- .github/workflows/verify.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/verify.yaml b/.github/workflows/verify.yaml index 49bd73f..b06c201 100644 --- a/.github/workflows/verify.yaml +++ b/.github/workflows/verify.yaml @@ -109,14 +109,14 @@ jobs: - name: Apply migrations if: steps.check_changes.outputs.changed == 'true' run: | - cargo run -p nxmesh-migration -- up + cd crates && sea-orm-cli migrate up - name: Regenerate entities if: steps.check_changes.outputs.changed == 'true' run: | - sea-orm-cli generate entity \ + cd crates && sea-orm-cli generate entity \ --database-url "$DATABASE_URL" \ - --output-dir apps/nxmesh-master/src/db/entities \ + --output-dir ../apps/nxmesh-master/src/db/entities \ --with-serde both \ --with-copy-enums \ --date-time-crate chrono