From 79a0ef2c62731d519481bee939d83477dc3a8489 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 22 Oct 2026 21:02:55 -0700 Subject: [PATCH 1/8] fix(guest-agent): saturate oversized log durations instead of overflowing Signed-off-by: Kevin Wang (cherry picked from commit 452679d86a3167b65059545ba4e1f09c07c35612) Signed-off-by: Kevin Wang --- guest-agent/src/http_routes.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/guest-agent/src/http_routes.rs b/guest-agent/src/http_routes.rs index 636ea809a..c56dbb22f 100644 --- a/guest-agent/src/http_routes.rs +++ b/guest-agent/src/http_routes.rs @@ -203,9 +203,9 @@ mod docker_logs { let seconds = match unit { "s" => value, - "m" => value * 60, - "h" => value * 3600, - "d" => value * 24 * 3600, + "m" => value.saturating_mul(60), + "h" => value.saturating_mul(3600), + "d" => value.saturating_mul(24 * 3600), _ => { anyhow::bail!("Invalid time unit. Use s, m, h, or d"); } @@ -358,6 +358,19 @@ mod docker_logs { ); } + #[test] + fn an_oversized_duration_reaches_back_to_the_epoch() { + let now = SystemTime::now(); + for unit in ["s", "m", "h", "d"] { + let duration = format!("{}{unit}", u64::MAX); + assert_eq!( + parse_duration_inner(&duration, now).unwrap(), + 0, + "{duration}" + ); + } + } + #[test] fn test_parse_duration_errors() { // Invalid unit From eb57dab3c0805773db4e782d127598fc2a7f79c3 Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Thu, 22 Oct 2026 20:46:07 -0700 Subject: [PATCH 2/8] fix(ra-rpc): pin swagger-ui with SRI on the api-docs page Signed-off-by: Kevin Wang (cherry picked from commit 36aa4958094c908d6854a70868965328b5b09685) Signed-off-by: Kevin Wang --- ra-rpc/src/openapi.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/ra-rpc/src/openapi.rs b/ra-rpc/src/openapi.rs index 7eb0a0e92..a33d402bd 100644 --- a/ra-rpc/src/openapi.rs +++ b/ra-rpc/src/openapi.rs @@ -211,15 +211,24 @@ pub(crate) struct RenderedDoc { pub struct SwaggerUiConfig { pub title: String, pub dark_mode: bool, - pub swagger_ui_dist: String, } +// Pinned with SRI so a CDN or upstream compromise cannot run script on the +// page, which shares an origin with the API it documents. Hashes are of the +// files in the npm tarball for this version. +const SWAGGER_UI_DIST: &str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.32.15"; +const SWAGGER_UI_CSS_SRI: &str = + "sha384-fgyWYkUAamzuI8mJFu/xpRP0JWCJRwkwUwsYDoOYVHUJ8NQE5cENn8ib3ppwFFSX"; +const SWAGGER_UI_BUNDLE_SRI: &str = + "sha384-m7zaGj7MPzU+G4lz2eyy73GxK9bbRDr9bB2CSdj8wodg2wu/Wnt6wsoLP3JD+RS9"; +const SWAGGER_UI_PRESET_SRI: &str = + "sha384-9rDX8vR4ir9/JIiV/XvxMpb5T9tVyFbssk49PV935hrdwmkVNJ7VZMM0RXAm184h"; + impl Default for SwaggerUiConfig { fn default() -> Self { Self { title: "pRPC Explorer".to_string(), dark_mode: true, - swagger_ui_dist: "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5".to_string(), } } } @@ -996,18 +1005,6 @@ fn field_type(field: &FieldDescriptorProto) -> FieldType { fn build_swagger_ui_html(spec_url: &str, cfg: &SwaggerUiConfig) -> String { let spec = spec_url.replace('\'', "\\'"); - let css = format!( - "{}/swagger-ui.css", - cfg.swagger_ui_dist.trim_end_matches('/') - ); - let bundle = format!( - "{}/swagger-ui-bundle.js", - cfg.swagger_ui_dist.trim_end_matches('/') - ); - let preset = format!( - "{}/swagger-ui-standalone-preset.js", - cfg.swagger_ui_dist.trim_end_matches('/') - ); let background = if cfg.dark_mode { "#0b0d10" } else { "#fafafa" }; format!( r#" @@ -1015,7 +1012,7 @@ fn build_swagger_ui_html(spec_url: &str, cfg: &SwaggerUiConfig) -> String { {title} - +