feat: middleware bypass overlay (#221)

* **New Features**
  * Routes can promote route-local bypass rules into matching entrypoint middleware, layering route-specific bypasses onto existing entrypoint rules and avoiding duplicate evaluation.

* **Behavior Changes**
  * Entrypoint middleware updates now refresh per-route overlays at runtime; overlay compilation failures result in HTTP 500 (errors are not exposed verbatim).
  * Route middleware accessors now return safe clones.

* **Documentation**
  * Clarified promotion, consumption, merging and qualification semantics with examples.

* **Tests**
  * Added tests covering promotion, cache invalidation, consumption semantics, and error handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Yuzerion
2026-04-15 18:35:06 +08:00
committed by GitHub
parent 31eea0a885
commit 44298d1933
18 changed files with 1000 additions and 7 deletions

View File

@@ -0,0 +1,82 @@
package middleware
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
"github.com/yusing/godoxy/internal/agentpool"
"github.com/yusing/godoxy/internal/homepage"
nettypes "github.com/yusing/godoxy/internal/net/types"
"github.com/yusing/godoxy/internal/route/routes"
"github.com/yusing/godoxy/internal/types"
"github.com/yusing/goutils/task"
)
func TestWithConsumedRouteOverlaysPreservesExistingRequestContext(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
req = routes.WithRouteContext(req, fakeMiddlewareHTTPRoute{name: "test-route"})
req = WithConsumedRouteOverlays(req, map[string]struct{}{
"redirecthttp": {},
}, map[string]struct{}{
"oidc": {},
})
require.Equal(t, "test-route", routes.TryGetUpstreamName(req))
require.True(t, isRouteBypassPromoted(req, "redirectHTTP"))
require.True(t, isRouteMiddlewareConsumed(req, "oidc"))
require.False(t, isRouteBypassPromoted(req, "forwardauth"))
require.False(t, isRouteMiddlewareConsumed(req, "forwardauth"))
}
func TestWithConsumedRouteOverlaysReturnsNewRequestWhenOverlayIsPresent(t *testing.T) {
req := httptest.NewRequest("GET", "http://example.com", nil)
updated := WithConsumedRouteOverlays(req, map[string]struct{}{"redirecthttp": {}}, nil)
require.NotEqual(t, req, updated)
require.True(t, isRouteBypassPromoted(updated, "redirectHTTP"))
require.False(t, isRouteBypassPromoted(req, "redirectHTTP"))
}
type fakeMiddlewareHTTPRoute struct {
name string
}
func (r fakeMiddlewareHTTPRoute) Key() string { return r.name }
func (r fakeMiddlewareHTTPRoute) Name() string { return r.name }
func (r fakeMiddlewareHTTPRoute) Start(task.Parent) error { return nil }
func (r fakeMiddlewareHTTPRoute) Task() *task.Task { return nil }
func (r fakeMiddlewareHTTPRoute) Finish(any) {}
func (r fakeMiddlewareHTTPRoute) MarshalZerologObject(*zerolog.Event) {}
func (r fakeMiddlewareHTTPRoute) ProviderName() string { return "" }
func (r fakeMiddlewareHTTPRoute) GetProvider() types.RouteProvider { return nil }
func (r fakeMiddlewareHTTPRoute) ListenURL() *nettypes.URL { return nil }
func (r fakeMiddlewareHTTPRoute) TargetURL() *nettypes.URL { return nil }
func (r fakeMiddlewareHTTPRoute) HealthMonitor() types.HealthMonitor { return nil }
func (r fakeMiddlewareHTTPRoute) SetHealthMonitor(types.HealthMonitor) {}
func (r fakeMiddlewareHTTPRoute) References() []string { return nil }
func (r fakeMiddlewareHTTPRoute) ShouldExclude() bool { return false }
func (r fakeMiddlewareHTTPRoute) Started() <-chan struct{} { return nil }
func (r fakeMiddlewareHTTPRoute) IdlewatcherConfig() *types.IdlewatcherConfig { return nil }
func (r fakeMiddlewareHTTPRoute) HealthCheckConfig() types.HealthCheckConfig {
return types.HealthCheckConfig{}
}
func (r fakeMiddlewareHTTPRoute) LoadBalanceConfig() *types.LoadBalancerConfig {
return nil
}
func (r fakeMiddlewareHTTPRoute) HomepageItem() homepage.Item { return homepage.Item{} }
func (r fakeMiddlewareHTTPRoute) DisplayName() string { return r.name }
func (r fakeMiddlewareHTTPRoute) ContainerInfo() *types.Container { return nil }
func (r fakeMiddlewareHTTPRoute) InboundMTLSProfileRef() string { return "" }
func (r fakeMiddlewareHTTPRoute) RouteMiddlewares() map[string]types.LabelMap { return nil }
func (r fakeMiddlewareHTTPRoute) GetAgent() *agentpool.Agent { return nil }
func (r fakeMiddlewareHTTPRoute) IsDocker() bool { return false }
func (r fakeMiddlewareHTTPRoute) IsAgent() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseLoadBalance() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseIdleWatcher() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseHealthCheck() bool { return false }
func (r fakeMiddlewareHTTPRoute) UseAccessLog() bool { return false }
func (r fakeMiddlewareHTTPRoute) ServeHTTP(http.ResponseWriter, *http.Request) {}