From: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
To: Lukas Wagner <l.wagner@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [PATCH proxmox 3/5] notify: Update Endpoint trait and Bus to use State
Date: Thu, 12 Feb 2026 09:26:56 +0100 [thread overview]
Message-ID: <2ht7zyrnl6w2ufveidy7wzdxlaqj6jgei3ao2m7rhrxioqavfk@yvochtl365lg> (raw)
In-Reply-To: <DGBEHSEEHUGO.3MSZ0R7IE6P54@proxmox.com>
On Tue, Feb 10, 2026 at 04:52:14PM +0100, Lukas Wagner wrote:
> Hey Arthur,
>
> some comments inline.
>
> On Wed Feb 4, 2026 at 5:13 PM CET, Arthur Bied-Charreton wrote:
> > This lays the groundwork for handling OAuth2 state in proxmox-notify by
> > updating the crate's internal API to pass around a mutable State struct.
> >
> > The state can be updated by its consumers and will be persisted
> > afterwards, much like the Config struct, with the difference that it is
> > fully internal to the crate. External consumers of the API do not need
> > to know/care about it.
> >
> > Signed-off-by: Arthur Bied-Charreton <a.bied-charreton@proxmox.com>
> > ---
> > proxmox-notify/src/api/common.rs | 70 +++++++++++++++++++++---
> > proxmox-notify/src/endpoints/gotify.rs | 4 +-
> > proxmox-notify/src/endpoints/sendmail.rs | 4 +-
> > proxmox-notify/src/endpoints/smtp.rs | 17 +++++-
> > proxmox-notify/src/endpoints/webhook.rs | 4 +-
> > proxmox-notify/src/lib.rs | 42 +++++++++-----
> > 6 files changed, 113 insertions(+), 28 deletions(-)
> >
> > diff --git a/proxmox-notify/src/api/common.rs b/proxmox-notify/src/api/common.rs
> > index fa2356e2..3483be9a 100644
> > --- a/proxmox-notify/src/api/common.rs
> > +++ b/proxmox-notify/src/api/common.rs
> > @@ -1,7 +1,52 @@
> > use proxmox_http_error::HttpError;
> >
> > use super::http_err;
> > -use crate::{Bus, Config, Notification};
> > +use crate::{context::context, Bus, Config, Notification, State};
> > +
> > +use tracing::error;
> > +
> > +fn get_state() -> State {
> > + let path_str = context().state_file_path();
> > + let path = std::path::Path::new(path_str);
> > +
> > + match path.exists() {
> > + true => match State::from_path(path) {
> > + Ok(s) => s,
> > + Err(e) => {
> > + // We don't want to block notifications on all endpoints only
> > + // because the stateful ones are broken.
> > + error!("could not instantiate state from {path_str}: {e}",);
> > + State::default()
> > + }
> > + },
> > + false => State::default(),
> > + }
> > +}
>
> This is a good example of TOCTOU (time of check, time of use). First you
> check if something exists in the filesystem, and if it does, you read
> the file. In theory, it could happen that the file is removed in between
> these two lines, leading to an error when reading the file. Now, in
> this concrete case here this is not a huge issue, but nevertheless its
> better to avoid it if you can. In this case here you can just read the
> file and then in case of an error check for ENOENT. See [1]
> for a very similar example.
>
> [1] https://git.proxmox.com/?p=proxmox-datacenter-manager.git;a=blob;f=server/src/remote_updates.rs;h=e772eef510218d8da41fe4a88ee47847b2598045;hb=HEAD#l159
>
> In proxmox-sys there are also the file_read_optional_string or
> file_get_optional_contents helpers which should do just that.
>
Makes sense, thanks!
> > +
> > +fn persist_state(state: &State) {
> > + let path_str = context().state_file_path();
> > +
> > + if let Err(e) = state.persist(path_str) {
> > + error!("could not persist state at '{path_str}': {e}");
> > + }
> > +}
> > +
>
> `refresh_targets` sounds very generic. How about
> `periodic_maintenance_task` or something alike?
>
See
https://lore.proxmox.com/pve-devel/3kqo4fxy4y3lrkhv7exd57ap6llkds2sxrn7gqj6wfxbo5zrvc@pvacwvkdp3zi/
> > +pub fn refresh_targets(config: &Config) -> Result<(), HttpError> {
> > + let bus = Bus::from_config(config).map_err(|err| {
> > + http_err!(
> > + INTERNAL_SERVER_ERROR,
> > + "Could not instantiate notification bus: {err}"
> > + )
> > + })?;
> > +
> > + let mut state = get_state();
> > +
> > + bus.refresh_targets(&mut state);
> > +
> > + persist_state(&state);
> > +
> > + Ok(())
> > +}
>
> I wonder, should we attempt to persist the state in case of an error
> here?
Yes we should, I overlooked that, thanks for catching it
> > +#[derive(Serialize, Deserialize, Clone, Debug, Default)]
> > +#[serde(rename_all = "kebab-case")]
> > +pub struct SmtpState {
> > + #[serde(skip_serializing_if = "Option::is_none")]
> > + pub oauth2_refresh_token: Option<String>,
> > + pub last_refreshed: u64,
> > +}
> > +
> > +impl EndpointState for SmtpState {}
> > +
> > #[api]
> > #[derive(Serialize, Deserialize, Clone, Updater, Debug)]
> > #[serde(rename_all = "kebab-case")]
> > @@ -158,7 +169,9 @@ pub struct SmtpEndpoint {
> > }
> >
> > impl Endpoint for SmtpEndpoint {
> > - fn send(&self, notification: &Notification) -> Result<(), Error> {
> > + fn send(&self, notification: &Notification, state: &mut State) -> Result<(), Error> {
> > + let mut endpoint_state = state.get_or_default::<SmtpState>(self.name())?;
>
> We talked about this off-list already, but it think would be cool if an
> endpoint would not get the entire state container, but only it's *own*
> state. I quickly tried this using an associated type in the trait for
> the state type and making `send` generic, but unfortunately this did not
> really work out - we store all endpoints in a HashMap<String, Box<dyn
> Endpoint>.
>
> This could probably be solved with some internal architectural changes,
> removing the Box<dyn ...> and replace it with 'manual' dispatching
> using an enum wrapper and `match`.
>
>
I am working on that, using an enum seems like the right choice here, it
feels a lot better (modulo the extra dispatching/variant unwrapping
boilerplate, but each concrete endpoint having to get its own state from
a generic pool is not much better).
next prev parent reply other threads:[~2026-02-12 8:26 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-04 16:13 [RFC cluster/docs/manager/proxmox{,-perl-rs,-widget-toolkit} 00/15] fix #7238: Add XOAUTH2 authentication support for SMTP notification targets Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 1/5] notify: Introduce xoauth2 module Arthur Bied-Charreton
2026-02-06 15:00 ` Lukas Wagner
2026-02-09 8:34 ` Arthur Bied-Charreton
2026-02-10 8:24 ` Lukas Wagner
2026-02-10 10:23 ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 2/5] notify: Add state file handling Arthur Bied-Charreton
2026-02-10 15:51 ` Lukas Wagner
2026-02-04 16:13 ` [PATCH proxmox 3/5] notify: Update Endpoint trait and Bus to use State Arthur Bied-Charreton
2026-02-10 15:52 ` Lukas Wagner
2026-02-12 8:26 ` Arthur Bied-Charreton [this message]
2026-02-04 16:13 ` [PATCH proxmox 4/5] notify: smtp: add OAuth2/XOAUTH2 authentication support Arthur Bied-Charreton
2026-02-10 15:52 ` Lukas Wagner
2026-02-11 13:00 ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox 5/5] notify: Add test for State Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-perl-rs 1/1] notify: update bindings with new OAuth2 parameters Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-widget-toolkit 1/2] utils: Add OAuth2 flow handlers Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH proxmox-widget-toolkit 2/2] notifications: Add opt-in OAuth2 support for SMTP targets Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 1/5] notifications: Add OAuth2 parameters to schema and add/update endpoints Arthur Bied-Charreton
2026-02-11 8:55 ` Lukas Wagner
2026-02-11 12:47 ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 2/5] notifications: Add refresh-targets endpoint Arthur Bied-Charreton
2026-02-11 9:49 ` Lukas Wagner
2026-02-11 12:44 ` Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 3/5] notifications: Trigger notification target refresh in pveupdate Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-manager 4/5] notifications: Handle OAuth2 callback in login handler Arthur Bied-Charreton
2026-02-11 9:00 ` Lukas Wagner
2026-02-04 16:13 ` [PATCH pve-manager 5/5] notifications: Opt into OAuth2 authentication Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-cluster 1/1] notifications: Add refresh_targets subroutine to PVE::Notify Arthur Bied-Charreton
2026-02-04 16:13 ` [PATCH pve-docs 1/1] notifications: Add section about OAuth2 to SMTP targets docs Arthur Bied-Charreton
2026-02-11 10:06 ` Lukas Wagner
2026-02-11 13:15 ` Arthur Bied-Charreton
2026-02-13 16:06 ` superseded: [RFC cluster/docs/manager/proxmox{,-perl-rs,-widget-toolkit} 00/15] fix #7238: Add XOAUTH2 authentication support for SMTP notification targets Arthur Bied-Charreton
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=2ht7zyrnl6w2ufveidy7wzdxlaqj6jgei3ao2m7rhrxioqavfk@yvochtl365lg \
--to=a.bied-charreton@proxmox.com \
--cc=l.wagner@proxmox.com \
--cc=pve-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