Procházet zdrojové kódy

Add telemetry to policy middleware (#3573)

Feroze Mohideen před 2 roky
rodič
revize
75e2b8e337

+ 11 - 5
api/server/authz/policy.go

@@ -2,7 +2,6 @@ package authz
 
 import (
 	"context"
-	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/authz/policy"
@@ -11,6 +10,7 @@ import (
 	"github.com/porter-dev/porter/api/server/shared/requestutils"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/telemetry"
 )
 
 type PolicyMiddleware struct {
@@ -39,11 +39,15 @@ type PolicyHandler struct {
 }
 
 func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-policy-handler")
+	defer span.End()
+
 	// get the full map of scopes to resource actions
 	reqScopes, reqErr := getRequestActionForEndpoint(r, h.endpointMeta)
 
 	if reqErr != nil {
-		apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, reqErr, true)
+		err := telemetry.Error(ctx, span, reqErr, "unable to get request action for endpoint")
+		apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest), true)
 		return
 	}
 
@@ -70,7 +74,8 @@ func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	policyDocs, reqErr := h.loader.LoadPolicyDocuments(policyLoaderOpts)
 
 	if reqErr != nil {
-		apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, reqErr, true)
+		err := telemetry.Error(ctx, span, reqErr, "unable to load policy documents")
+		apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError), true)
 		return
 	}
 
@@ -78,12 +83,13 @@ func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	hasAccess := policy.HasScopeAccess(policyDocs, reqScopes)
 
 	if !hasAccess {
+		err := telemetry.Error(ctx, span, nil, "insufficient permissions to perform action")
 		apierrors.HandleAPIError(
 			h.config.Logger,
 			h.config.Alerter,
 			w,
 			r,
-			apierrors.NewErrForbidden(fmt.Errorf("policy forbids action in project %d", policyLoaderOpts.ProjectID)),
+			apierrors.NewErrPassThroughToClient(err, http.StatusForbidden),
 			true,
 		)
 
@@ -91,7 +97,7 @@ func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 
 	// add the set of resource ids to the request context
-	ctx := NewRequestScopeCtx(r.Context(), reqScopes)
+	ctx = NewRequestScopeCtx(ctx, reqScopes)
 	r = r.Clone(ctx)
 	h.next.ServeHTTP(w, r)
 }

+ 2 - 2
api/server/authz/policy_test.go

@@ -158,7 +158,7 @@ func TestPolicyMiddlewareInvalidPermissions(t *testing.T) {
 	handler.ServeHTTP(rr, req)
 
 	assert.False(t, next.WasCalled, "next handler should not have been called")
-	apitest.AssertResponseForbidden(t, rr)
+	apitest.AssertForbiddenError(t, rr)
 }
 
 func TestPolicyMiddlewareFailInvalidLoader(t *testing.T) {
@@ -296,5 +296,5 @@ func assertInternalError(t *testing.T, next *testHandler, rr *httptest.ResponseR
 	// first assert that that the next middleware was not called
 	assert.False(next.WasCalled, "next handler should not have been called")
 
-	apitest.AssertResponseInternalServerError(t, rr)
+	apitest.AssertInternalServerError(t, rr)
 }

+ 22 - 0
api/server/shared/apitest/response.go

@@ -42,6 +42,17 @@ func AssertResponseForbidden(t *testing.T, rr *httptest.ResponseRecorder) {
 	assert.Equal(t, expReqErr, reqErr, "body should be forbidden error")
 }
 
+// AssertForbiddenError asserts that the response has status code of a forbidden error
+func AssertForbiddenError(t *testing.T, rr *httptest.ResponseRecorder) {
+	reqErr := &types.ExternalError{}
+	err := json.NewDecoder(rr.Result().Body).Decode(reqErr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, http.StatusForbidden, rr.Result().StatusCode, "status code should be forbidden")
+}
+
 func AssertResponseInternalServerError(t *testing.T, rr *httptest.ResponseRecorder) {
 	reqErr := &types.ExternalError{}
 	err := json.NewDecoder(rr.Result().Body).Decode(reqErr)
@@ -57,6 +68,17 @@ func AssertResponseInternalServerError(t *testing.T, rr *httptest.ResponseRecord
 	assert.Equal(t, expReqErr, reqErr, "body should be internal server error")
 }
 
+// AssertInternalServerError asserts that the response has status code of an internal server error
+func AssertInternalServerError(t *testing.T, rr *httptest.ResponseRecorder) {
+	reqErr := &types.ExternalError{}
+	err := json.NewDecoder(rr.Result().Body).Decode(reqErr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, http.StatusInternalServerError, rr.Result().StatusCode, "status code should be internal server error")
+}
+
 func AssertResponseError(t *testing.T, rr *httptest.ResponseRecorder, statusCode int, expReqErr *types.ExternalError) {
 	reqErr := &types.ExternalError{}
 	err := json.NewDecoder(rr.Result().Body).Decode(reqErr)