From d3e0ee854717a9e1ebab3795d534e5cddf5da95f Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Sun, 23 Aug 2026 07:26:27 +0000 Subject: [PATCH] [proxy] Fail a mapping update whose chains would not install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Publishing the chain before the route only helps if the chain is there. rebuildMiddlewareChains logged its error and returned, so a failed rebuild still fell through to AddMapping and published a route over chains that were never installed — served with no policy enforcement and no metering, which is the outcome the ordering change exists to prevent. Report the error instead. The caller already unwinds a failed setup, so the service stays unpublished rather than reachable and uncounted. An unset middleware manager is still not an error: that is a deployment without middleware, not a failure to install it. --- proxy/server.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/proxy/server.go b/proxy/server.go index 2a62db421..aee748339 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -2080,7 +2080,9 @@ func (s *Server) updateMapping(ctx context.Context, mapping *proto.ProxyMapping) // window in which an inference could complete unrouted and unmetered. // Rebuilding first inverts that: the worst a request in the window meets is // the new chain in front of the previous target, which is still counted. - s.rebuildMiddlewareChains(svcID, m) + if err := s.rebuildMiddlewareChains(svcID, m); err != nil { + return err + } s.meter.AddMapping(m) s.proxy.AddMapping(m) return nil @@ -2120,15 +2122,21 @@ func (s *Server) initMiddlewareManager(ctx context.Context) error { } // rebuildMiddlewareChains converts m into per-path bindings and calls -// Manager.Rebuild. Short-circuits when the middleware manager is unset. -func (s *Server) rebuildMiddlewareChains(svcID types.ServiceID, m proxy.Mapping) { +// Manager.Rebuild. Short-circuits when the middleware manager is unset, which +// is a deployment without middleware rather than a failure to install it. +// +// A rebuild that fails is reported rather than logged: the caller publishes +// the route once this returns, and a route published over chains that were +// not installed serves requests with no policy enforcement and no metering. +func (s *Server) rebuildMiddlewareChains(svcID types.ServiceID, m proxy.Mapping) error { if s.middlewareManager == nil { - return + return nil } bindings := buildMiddlewareBindings(svcID, m) if err := s.middlewareManager.Rebuild(string(svcID), bindings); err != nil { - s.Logger.WithError(err).WithField("service_id", svcID).Error("failed to rebuild middleware chains") + return fmt.Errorf("rebuild middleware chains for service %s: %w", svcID, err) } + return nil } // isLiveService reports whether svcID is currently present in the live