From ffe61fa4ec61a55b40f21cd2b9540393ff2c106f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Tue, 25 Nov 2025 21:51:38 -0500 Subject: [PATCH] incus-osd/providers/operations_center: Handle server switching away from self-signed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber --- .../providers/provider_operations_center.go | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/incus-osd/internal/providers/provider_operations_center.go b/incus-osd/internal/providers/provider_operations_center.go index 4711bc6..2df222d 100644 --- a/incus-osd/internal/providers/provider_operations_center.go +++ b/incus-osd/internal/providers/provider_operations_center.go @@ -283,6 +283,10 @@ func (p *operationsCenter) load(ctx context.Context) error { return errors.New("no operations center token provided") } + return p.loadTLS(ctx) +} + +func (p *operationsCenter) loadTLS(ctx context.Context) error { // Prepare the TLS config. tlsConfig := &tls.Config{ MinVersion: tls.VersionTLS13, @@ -358,6 +362,50 @@ func (p *operationsCenter) apiRequest(ctx context.Context, method string, path s // Make the REST call. resp, err := tryRequest(p.client, req) if err != nil { + isCertError := func(err error) bool { + var urlErr *url.Error + + if !errors.As(err, &urlErr) { + return false + } + + { + var errCase0 *tls.CertificateVerificationError + switch { + case errors.As(urlErr.Unwrap(), &errCase0): + return true + default: + return false + } + } + } + + // Check if we got a potential transition to a globally valid certificate. + if p.serverCertificate != "" && isCertError(err) { + // Retry with the system CA. + p.serverCertificate = "" + + // Re-load the TLS client. + err = p.loadTLS(ctx) + if err != nil { + // Attempt to reset the client from config. + _ = p.load(ctx) + + return nil, err + } + + // Re-try the request. + resp, err := p.apiRequest(ctx, method, path, data) + if err != nil { + return nil, err + } + + // If successful, commit the change of config. + delete(p.state.System.Provider.Config.Config, "server_certificate") + + return resp, nil + } + return nil, err }