From ee0efe5e22192aa99872a6f3de9028fc75a27efc Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar <30073382+mighty840@users.noreply.github.com> Date: Thu, 16 Jul 2026 19:57:10 +0200 Subject: [PATCH] fix(upload): raise body-size limit to 512 MiB + surface upload errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Artifact uploads (PLC .projectarchive, firmware images, mobile packages) larger than axum's 2 MiB default request-body limit were rejected, and the wizard swallowed the error (`let _ = upload_target_artifact`), so the target was created with no artifact — every scan then showed "blocked, no artifact provided". - agent: DefaultBodyLimit::max(512 MiB) on the API router (multipart upload route). - dashboard: DefaultBodyLimit::max(512 MiB) on the axum app serving the upload server function (the browser→dashboard hop). - wizard: surface upload failures in the error banner instead of ignoring them. Found live: a 9.9 MB CODESYS .projectarchive failed to attach (a 1.7 KB .st worked). Co-Authored-By: Claude Opus 4.8 --- compliance-agent/src/api/server.rs | 5 ++++- compliance-dashboard/src/infrastructure/server.rs | 4 ++++ compliance-dashboard/src/pages/onboarding.rs | 10 ++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/compliance-agent/src/api/server.rs b/compliance-agent/src/api/server.rs index b56cef8..c60cf71 100644 --- a/compliance-agent/src/api/server.rs +++ b/compliance-agent/src/api/server.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use axum::extract::Request; +use axum::extract::{DefaultBodyLimit, Request}; use axum::http::HeaderValue; use axum::middleware::Next; use axum::response::Response; @@ -74,6 +74,9 @@ pub async fn start_api_server(agent: ComplianceAgent, port: u16) -> Result<(), A let mut app = routes::build_router() .merge(admin_router) + // Allow large artifact uploads (PLC .projectarchive, firmware images, + // mobile packages) — axum's default request-body limit is only 2 MiB. + .layer(DefaultBodyLimit::max(512 * 1024 * 1024)) .layer(Extension(Arc::new(agent.clone()))) .layer(CorsLayer::permissive()) .layer(TraceLayer::new_for_http()) diff --git a/compliance-dashboard/src/infrastructure/server.rs b/compliance-dashboard/src/infrastructure/server.rs index 20cb6fb..42b6f18 100644 --- a/compliance-dashboard/src/infrastructure/server.rs +++ b/compliance-dashboard/src/infrastructure/server.rs @@ -1,3 +1,4 @@ +use axum::extract::DefaultBodyLimit; use axum::routing::{get, post}; use axum::{middleware, Extension}; use dioxus::prelude::*; @@ -66,6 +67,9 @@ pub fn server_start(app: fn() -> Element) -> Result<(), DashboardError> { // Webhook proxy: forward to agent (no auth required) .route("/webhook/{platform}/{repo_id}", post(webhook_proxy)) .serve_dioxus_application(ServeConfig::new(), app) + // Allow large artifact uploads through the upload server function + // (PLC .projectarchive, firmware, mobile) — default is 2 MiB. + .layer(DefaultBodyLimit::max(512 * 1024 * 1024)) .layer(Extension(PendingOAuthStore::default())) .layer(middleware::from_fn(require_auth)) .layer(Extension(server_state)) diff --git a/compliance-dashboard/src/pages/onboarding.rs b/compliance-dashboard/src/pages/onboarding.rs index f67c9bb..2ffdc96 100644 --- a/compliance-dashboard/src/pages/onboarding.rs +++ b/compliance-dashboard/src/pages/onboarding.rs @@ -520,14 +520,20 @@ pub fn OnboardingPage() -> Element { created_id.set(Some(id.clone())); // Upload staged file artifacts now that the target exists. for pf in files { - let _ = upload_target_artifact( + let fname = pf.filename.clone(); + if let Err(e) = upload_target_artifact( id.clone(), pf.kind, pf.plc_format, pf.filename, pf.bytes, ) - .await; + .await + { + error.set(Some(format!( + "Upload failed for {fname}: {e}" + ))); + } } if let Ok(sc) = fetch_applicable_scans(id.clone()).await { scans.set(sc.data.scans);