This commit is contained in:
Mateusz Gruszczyński committed 2026-10-31 23:42:58 +01:00
1 parent 2c03fcf248
commit d3b492874b
95 files changed
+1628 -743

No files matched your search

+2 -2
View File
@@ -194,7 +194,7 @@ async fn certificate_deploy(
)
.await
.map_err(auth::internal)?;
return Ok(Json(json!({
Ok(Json(json!({
"deployed": true,
"operation": "metadata-updated",
"created": false,
@@ -207,7 +207,7 @@ async fn certificate_deploy(
"public_tls": true,
"http3_new_handshakes": state.config.load().quic_tls.is_some(),
"administration_restart_required": false
})));
})))
}
crate::tls::ExternalPairDeployment::Staged {
cert_file,
+6 -4
View File
@@ -62,10 +62,12 @@ async fn dashboard_presets(
tracing::warn!("skipped invalid saved Overview preset");
continue;
};
let mut prefs = AdminPreferences::default();
prefs.dashboard_widgets = layout.dashboard_widgets;
prefs.dashboard_hidden_widgets = layout.dashboard_hidden_widgets;
prefs.dashboard_widget_sizes = layout.dashboard_widget_sizes;
let mut prefs = AdminPreferences {
dashboard_widgets: layout.dashboard_widgets,
dashboard_hidden_widgets: layout.dashboard_hidden_widgets,
dashboard_widget_sizes: layout.dashboard_widget_sizes,
..Default::default()
};
reconcile_dashboard_widgets(&mut prefs);
layout.dashboard_widgets = prefs.dashboard_widgets;
layout.dashboard_hidden_widgets = prefs.dashboard_hidden_widgets;
+2 -2
View File
@@ -182,7 +182,7 @@ fn validate_file_log_query(query: &FileLogQuery) -> Result<(), ApiError> {
.is_some_and(|value| value == 0 || value > FILE_LOG_MAX_AGGREGATE_RESULTS)
|| query
.aggregate_min_count
.is_some_and(|value| value < 2 || value > FILE_LOG_SCAN_LINES)
.is_some_and(|value| !(2..=FILE_LOG_SCAN_LINES).contains(&value))
|| query.offset.unwrap_or(0) > FILE_LOG_MAX_OFFSET
|| query
.limit
@@ -233,7 +233,7 @@ async fn file_logs_query(
));
}
} else {
sources.sort_by(|a, b| b.modified_ms.cmp(&a.modified_ms));
sources.sort_by_key(|source| std::cmp::Reverse(source.modified_ms));
if sources.len() > FILE_LOG_MAX_SOURCES {
truncated = true;
sources.truncate(FILE_LOG_MAX_SOURCES);
+1 -1
View File
@@ -2,7 +2,7 @@
"openapi": "3.0.3",
"info": {
"title": "RustProxy Administration API",
"version": "0.34.16",
"version": "0.35.0",
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust. The API also permits explicitly scoped GeneralApiBearer tokens on a narrow route allowlist, with RO/RW and source CIDR checks; API-token management and Prometheus-token management are browser-session-only."
},
"servers": [
+23 -17
View File
@@ -86,18 +86,20 @@ fn corner_style_defaults_and_rejects_unknown_presets() {
#[test]
fn old_widget_preferences_preserve_order_opt_in_and_survive_unknown_ids() {
let mut prefs = AdminPreferences::default();
prefs.dashboard_widgets = vec![
"errors".into(),
"from_future_release".into(),
"requests".into(),
"errors".into(),
];
prefs.dashboard_hidden_widgets = vec![
"errors".into(),
"from_future_release".into(),
"errors".into(),
];
let mut prefs = AdminPreferences {
dashboard_widgets: vec![
"errors".into(),
"from_future_release".into(),
"requests".into(),
"errors".into(),
],
dashboard_hidden_widgets: vec![
"errors".into(),
"from_future_release".into(),
"errors".into(),
],
..Default::default()
};
reconcile_dashboard_widgets(&mut prefs);
assert_eq!(prefs.dashboard_widgets[0], "errors");
assert_eq!(prefs.dashboard_widgets[1], "requests");
@@ -210,9 +212,11 @@ fn saved_dashboard_order_and_visibility_survive_new_factory_preset() {
#[test]
fn explicit_visible_stream_opt_in_is_not_reset_when_normalizing_saved_order() {
let mut prefs = AdminPreferences::default();
prefs.dashboard_widgets = default_admin_dashboard_widgets();
prefs.dashboard_hidden_widgets.clear();
let mut prefs = AdminPreferences {
dashboard_widgets: default_admin_dashboard_widgets(),
dashboard_hidden_widgets: Vec::new(),
..Default::default()
};
reconcile_dashboard_widgets(&mut prefs);
assert!(prefs.dashboard_hidden_widgets.is_empty());
assert!(prefs.dashboard_widgets.contains(&"cache_outcomes".into()));
@@ -224,8 +228,10 @@ fn explicit_visible_stream_opt_in_is_not_reset_when_normalizing_saved_order() {
fn dashboard_width_preferences_preserve_legacy_and_allow_custom_grids() {
let old: AdminPreferences = serde_json::from_str(r#"{"theme":"dark"}"#).unwrap();
assert!(old.dashboard_widget_sizes.is_none());
let mut prefs = AdminPreferences::default();
prefs.dashboard_widget_sizes = Some(std::collections::BTreeMap::new());
let mut prefs = AdminPreferences {
dashboard_widget_sizes: Some(std::collections::BTreeMap::new()),
..Default::default()
};
assert!(validate_admin_preferences(&prefs).is_ok());
for (id, span) in [
("http_protocol", 4),
+18 -4
View File
@@ -461,6 +461,7 @@ mod tests {
let (router, store, _dir, secret, _) = fixture().await;
let old = request("/api/status")
.header("authorization", format!("Bearer {}", "a".repeat(64)))
.extension(PeerAddr("127.0.0.1:45000".parse().unwrap()))
.body(Body::empty())
.unwrap();
assert_eq!(
@@ -1645,6 +1646,7 @@ mod tests {
.method("POST")
.header("authorization", format!("Bearer {token}"))
.header("content-type", "application/json")
.extension(PeerAddr("127.0.0.1:45000".parse().unwrap()))
.body(Body::from("{}"))
.unwrap(),
)
@@ -1663,7 +1665,11 @@ mod tests {
)
.await
.unwrap();
assert_eq!(forbidden_scope.status(), StatusCode::UNAUTHORIZED);
assert_eq!(forbidden_scope.status(), StatusCode::FORBIDDEN);
assert_eq!(
json_body(forbidden_scope).await,
json!({"error":"certificate_api.invalid_route"})
);
let revoked = router
.clone()
@@ -1804,7 +1810,11 @@ mod tests {
)
.await
.unwrap();
assert_eq!(denied.status(), StatusCode::UNAUTHORIZED);
assert_eq!(denied.status(), StatusCode::FORBIDDEN);
assert_eq!(
json_body(denied).await,
json!({"error":"certificate_api.invalid_route"})
);
let no_csrf = router
.clone()
.oneshot(
@@ -2774,6 +2784,7 @@ mod tests {
request(&path)
.header("cookie", cookie)
.header("authorization", format!("Bearer {secret}"))
.extension(PeerAddr("127.0.0.1:45000".parse().unwrap()))
.body(Body::empty())
.unwrap(),
)
@@ -3953,7 +3964,7 @@ mod tests {
)
.await
.unwrap();
assert_eq!(old_route.status(), StatusCode::METHOD_NOT_ALLOWED);
assert_eq!(old_route.status(), StatusCode::NOT_FOUND);
store.close().await;
}
@@ -4103,7 +4114,10 @@ mod tests {
.await
.unwrap();
assert_eq!(summary.status(), StatusCode::OK);
assert_eq!(summary.headers()["cache-control"], "no-store");
assert_eq!(
summary.headers()["cache-control"],
"private, no-store, no-cache, no-transform"
);
let summary = json_body(summary).await;
assert!(summary.get("prometheus").is_none());
assert_eq!(