public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 13/17] pdm-api-types: add staged_fingerprints field to NodeUrl
Date: Thu, 11 Jun 2026 14:03:23 +0200	[thread overview]
Message-ID: <20260611120327.257523-14-s.sterz@proxmox.com> (raw)
In-Reply-To: <20260611120327.257523-1-s.sterz@proxmox.com>

and fix up all use sides as well as the update endpoint.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 lib/pdm-api-types/src/remotes.rs   | 15 ++++++++++++++-
 server/src/api/pbs/mod.rs          |  2 ++
 server/src/api/pve/mod.rs          |  3 +++
 server/src/api/remotes/mod.rs      | 27 ++++++++++++++++++++++++++-
 ui/src/remotes/config.rs           |  1 +
 ui/src/remotes/node_url_list.rs    |  1 +
 ui/src/remotes/wizard_page_info.rs |  1 +
 7 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/lib/pdm-api-types/src/remotes.rs b/lib/pdm-api-types/src/remotes.rs
index 50c7892e..0a2e8651 100644
--- a/lib/pdm-api-types/src/remotes.rs
+++ b/lib/pdm-api-types/src/remotes.rs
@@ -8,7 +8,7 @@ use proxmox_schema::{ApiType, Schema, StringSchema, Updater, api};
 use proxmox_section_config::typed::ApiSectionDataEntry;
 use proxmox_section_config::{SectionConfig, SectionConfigPlugin};
 
-use crate::{Authid, HOST_OPTIONAL_PORT_FORMAT};
+use crate::{Authid, Fingerprint, HOST_OPTIONAL_PORT_FORMAT};
 
 pub const REMOTE_ID_SCHEMA: Schema = StringSchema::new("Remote ID.")
     .format(&crate::PROXMOX_SAFE_ID_FORMAT)
@@ -26,11 +26,19 @@ pub const REMOTE_ID_SCHEMA: Schema = StringSchema::new("Remote ID.")
             format: &crate::FINGERPRINT_SHA256_FORMAT,
             optional: true,
         },
+        "staged-fingerprints": {
+            type: Array,
+            optional: true,
+            items: {
+                type: Fingerprint,
+            }
+        }
     },
     default_key: "hostname",
 )]
 /// A node and its certificate information.
 #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
+#[serde(rename_all = "kebab-case")]
 pub struct NodeUrl {
     /// The node address.
     pub hostname: String,
@@ -38,6 +46,11 @@ pub struct NodeUrl {
     /// Certificate fingerprint.
     #[serde(skip_serializing_if = "Option::is_none")]
     pub fingerprint: Option<String>,
+
+    /// A list of staged fingerprints. If one of these is encountered while connecting to a node,
+    /// they'll replace the main certificate fingerprint. The connection will be deemed valid.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub staged_fingerprints: Option<Vec<Fingerprint>>,
 }
 
 #[api]
diff --git a/server/src/api/pbs/mod.rs b/server/src/api/pbs/mod.rs
index 1fc75c34..98a88a23 100644
--- a/server/src/api/pbs/mod.rs
+++ b/server/src/api/pbs/mod.rs
@@ -273,6 +273,7 @@ pub async fn scan_remote_pbs(
         nodes: vec![PropertyString::new(NodeUrl {
             hostname,
             fingerprint,
+            staged_fingerprints: None,
         })],
         authid: authid.clone(),
         token,
@@ -325,6 +326,7 @@ pub async fn list_realm_remote_pbs(
         nodes: vec![PropertyString::new(NodeUrl {
             hostname,
             fingerprint,
+            staged_fingerprints: None,
         })],
         authid: "root@pam".parse()?,
         token: String::new(),
diff --git a/server/src/api/pve/mod.rs b/server/src/api/pve/mod.rs
index 0970f2ff..64413a3e 100644
--- a/server/src/api/pve/mod.rs
+++ b/server/src/api/pve/mod.rs
@@ -483,6 +483,7 @@ pub async fn scan_remote_pve(
         nodes: vec![PropertyString::new(NodeUrl {
             hostname,
             fingerprint,
+            staged_fingerprints: None,
         })],
         authid: authid.clone(),
         token,
@@ -508,6 +509,7 @@ pub async fn scan_remote_pve(
         nodes.push(PropertyString::new(NodeUrl {
             hostname: node.node,
             fingerprint,
+            staged_fingerprints: None,
         }));
     }
 
@@ -574,6 +576,7 @@ pub async fn list_realm_remote_pve(
         nodes: vec![PropertyString::new(NodeUrl {
             hostname,
             fingerprint,
+            staged_fingerprints: None,
         })],
         authid: "root@pam".parse()?,
         token: String::new(),
diff --git a/server/src/api/remotes/mod.rs b/server/src/api/remotes/mod.rs
index e416f619..090a3b32 100644
--- a/server/src/api/remotes/mod.rs
+++ b/server/src/api/remotes/mod.rs
@@ -412,7 +412,32 @@ pub fn update_remote(
         }
     }
 
-    if let Some(v) = updater.nodes {
+    if let Some(mut v) = updater.nodes {
+        for node in &mut v {
+            // If the updater included staged fingerprints for the remote, update them.
+            if node.staged_fingerprints.is_some() {
+                continue;
+            }
+
+            // If not, keep the previous fingerprints intact.
+            let staged_fp = entry
+                .nodes
+                .iter()
+                .find_map(|n| {
+                    if n.hostname == node.hostname
+                        && n.fingerprint.as_ref().map(|f| f.to_lowercase())
+                            == node.fingerprint.as_ref().map(|f| f.to_lowercase())
+                    {
+                        return Some(n.staged_fingerprints.clone());
+                    }
+
+                    None
+                })
+                .flatten();
+
+            node.staged_fingerprints = staged_fp;
+        }
+
         entry.nodes = v;
     }
     if let Some(v) = updater.authid {
diff --git a/ui/src/remotes/config.rs b/ui/src/remotes/config.rs
index ea3c5bcd..0e272c2c 100644
--- a/ui/src/remotes/config.rs
+++ b/ui/src/remotes/config.rs
@@ -59,6 +59,7 @@ pub async fn create_remote(mut data: Value, remote_type: RemoteType) -> Result<(
         let nodes = vec![PropertyString::new(NodeUrl {
             hostname: data["hostname"].as_str().unwrap_or_default().to_string(),
             fingerprint: data["fingerprint"].as_str().map(|fp| fp.to_string()),
+            staged_fingerprints: None,
         })];
         data["nodes"] = serde_json::to_value(nodes)?;
     }
diff --git a/ui/src/remotes/node_url_list.rs b/ui/src/remotes/node_url_list.rs
index d18d8a23..4afc6482 100644
--- a/ui/src/remotes/node_url_list.rs
+++ b/ui/src/remotes/node_url_list.rs
@@ -220,6 +220,7 @@ impl ManagedField for PdmNodeUrlField {
                                 data: NodeUrl {
                                     hostname: String::new(),
                                     fingerprint: None,
+                                    staged_fingerprints: None,
                                 },
                             })
                         }
diff --git a/ui/src/remotes/wizard_page_info.rs b/ui/src/remotes/wizard_page_info.rs
index 1e56c4e1..4f8e3302 100644
--- a/ui/src/remotes/wizard_page_info.rs
+++ b/ui/src/remotes/wizard_page_info.rs
@@ -131,6 +131,7 @@ async fn scan(
             PropertyString::new(NodeUrl {
                 hostname,
                 fingerprint: fingerprint.map(|fp| fp.to_uppercase()),
+                staged_fingerprints: None,
             }),
         );
     }
-- 
2.47.3





  parent reply	other threads:[~2026-06-11 12:03 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-11 12:03 [RFC cluster/datacenter-manager/manager/proxmox 00/17] TLS Certificate Staging Shannon Sterz
2026-06-11 12:03 ` [PATCH cluster 01/17] setup: allow caller to provide the certificate filename Shannon Sterz
2026-06-11 12:03 ` [PATCH manager 02/17] bin/api: add a new staged certificate when renewing self-signed cert Shannon Sterz
2026-06-11 12:03 ` [PATCH manager 03/17] api: certificates: if node parameter is 'localhost' return local certs Shannon Sterz
2026-06-11 12:03 ` [PATCH proxmox 04/17] client: ignore certificate trust store validation result on fp option Shannon Sterz
2026-06-11 12:03 ` [PATCH proxmox 05/17] pve-api-types: expose certificates info endpoint Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 06/17] client: don't short-circuit on valid certificate when tls fp exists Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 07/17] client: allow users to update a changed fingerprint interactively Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 08/17] cli/api-types: move Fingerprint to common api type crate Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 09/17] server: connection: report mismatching fingerprint as untrusted on probe Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 10/17] ui: wizzard: add context if a provided fingerprint did not match remote Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 11/17] ui: wizzard: nodes page: always update fingerprints on user confirmation Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 12/17] pdm-api-types: implement ApiType for Fingerprint Shannon Sterz
2026-06-11 12:03 ` Shannon Sterz [this message]
2026-06-11 12:03 ` [PATCH datacenter-manager 14/17] server: remotes: lock remotes config when updating it Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 15/17] server: connection: rotate in staged fingerprints when encountering them Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 16/17] server: api: tasks: move `spawn_aborted_on_shutdown()` to super module Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 17/17] server: bin: api: tasks: add task to discover new staged certificates Shannon Sterz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260611120327.257523-14-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal