OpenFeature: Inject eval ctx into req ctx (#108017)
* OpenFeature: Inject eval ctx into req ctx * Remove stackId * add unit test Signed-off-by: Dave Henderson <dave.henderson@grafana.com> --------- Signed-off-by: Dave Henderson <dave.henderson@grafana.com> Co-authored-by: Dave Henderson <dave.henderson@grafana.com>
This commit is contained in:
@@ -6,10 +6,12 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/open-feature/go-sdk/openfeature"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
authnClients "github.com/grafana/grafana/pkg/services/authn/clients"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
|
||||
@@ -141,6 +143,16 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler {
|
||||
reqContext.Resp.Before(h.addIDHeaderEndOfRequestFunc(reqContext.SignedInUser))
|
||||
}
|
||||
|
||||
// Set open feature evaluation context with namespace
|
||||
ns := "default"
|
||||
if id != nil {
|
||||
ns = id.Namespace
|
||||
}
|
||||
evalCtx := openfeature.NewEvaluationContext(ns, map[string]any{
|
||||
"namespace": ns,
|
||||
})
|
||||
ctx = openfeature.MergeTransactionContext(ctx, evalCtx)
|
||||
|
||||
// End the span to make next handlers not wrapped within middleware span
|
||||
span.End()
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
@@ -5,10 +5,12 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/open-feature/go-sdk/openfeature"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
@@ -209,4 +211,50 @@ func TestContextHandler(t *testing.T) {
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("openfeature evaluation context defaults", func(t *testing.T) {
|
||||
handler := contexthandler.ProvideService(
|
||||
setting.NewCfg(),
|
||||
&authntest.FakeService{ExpectedErr: errors.New("some error")},
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
server := webtest.NewServer(t, routing.NewRouteRegister())
|
||||
server.Mux.Use(handler.Middleware)
|
||||
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
|
||||
evalCtx := openfeature.TransactionContext(c.Req.Context())
|
||||
require.NotNil(t, evalCtx)
|
||||
require.Equal(t, "default", evalCtx.Attribute("namespace"))
|
||||
})
|
||||
|
||||
res, err := server.Send(server.NewGetRequest("/api/handler"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("openfeature evaluation context with user namespace", func(t *testing.T) {
|
||||
handler := contexthandler.ProvideService(
|
||||
setting.NewCfg(),
|
||||
&authntest.FakeService{
|
||||
ExpectedIdentity: &authn.Identity{
|
||||
ID: "1",
|
||||
Type: claims.TypeUser,
|
||||
Namespace: "org-3",
|
||||
},
|
||||
},
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
server := webtest.NewServer(t, routing.NewRouteRegister())
|
||||
server.Mux.Use(handler.Middleware)
|
||||
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
|
||||
evalCtx := openfeature.TransactionContext(c.Req.Context())
|
||||
require.NotNil(t, evalCtx)
|
||||
require.Equal(t, "org-3", evalCtx.Attribute("namespace"))
|
||||
})
|
||||
|
||||
res, err := server.Send(server.NewGetRequest("/api/handler"))
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user