Skip to content

Commit

Permalink
feat: add audit logging for rollout actions
Browse files Browse the repository at this point in the history
  • Loading branch information
yquansah committed Jul 6, 2023
1 parent 239a2fb commit d5310e6
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
1 change: 1 addition & 0 deletions internal/server/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
DistributionType Type = "distribution"
FlagType Type = "flag"
NamespaceType Type = "namespace"
RolloutType Type = "rollout"
RuleType Type = "rule"
SegmentType Type = "segment"
TokenType Type = "token"
Expand Down
43 changes: 43 additions & 0 deletions internal/server/audit/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,46 @@ func NewRule(r *flipt.Rule) *Rule {
NamespaceKey: r.NamespaceKey,
}
}

type Rollout struct {
NamespaceKey string `json:"namespace_key"`
FlagKey string `json:"flag_key"`
Rank int32 `json:"rank"`
Description string `json:"description"`
Threshold *RolloutThreshold `json:"threshold,omitempty"`
Segment *RolloutSegment `json:"segment,omitempty"`
}

type RolloutThreshold struct {
Percentage float32 `json:"percentage"`
Value bool `json:"value"`
}

type RolloutSegment struct {
Key string `json:"Key"`
Value bool `json:"value"`
}

func NewRollout(r *flipt.Rollout) *Rollout {
rollout := &Rollout{
NamespaceKey: r.NamespaceKey,
FlagKey: r.FlagKey,
Rank: r.Rank,
Description: r.Description,
}

switch rout := r.Rule.(type) {
case *flipt.Rollout_Segment:
rollout.Segment = &RolloutSegment{
Key: rout.Segment.SegmentKey,
Value: rout.Segment.Value,
}
case *flipt.Rollout_Threshold:
rollout.Threshold = &RolloutThreshold{
Percentage: rout.Threshold.Percentage,
Value: rout.Threshold.Value,
}

Check warning on line 191 in internal/server/audit/types.go

View check run for this annotation

Codecov / codecov/patch

internal/server/audit/types.go#L173-L191

Added lines #L173 - L191 were not covered by tests
}

return rollout

Check warning on line 194 in internal/server/audit/types.go

View check run for this annotation

Codecov / codecov/patch

internal/server/audit/types.go#L194

Added line #L194 was not covered by tests
}
6 changes: 6 additions & 0 deletions internal/server/middleware/grpc/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ func AuditUnaryInterceptor(logger *zap.Logger) grpc.UnaryServerInterceptor {
event = audit.NewEvent(audit.NamespaceType, audit.Delete, actor, r)
case *flipt.DeleteRuleRequest:
event = audit.NewEvent(audit.RuleType, audit.Delete, actor, r)
case *flipt.DeleteRolloutRequest:
event = audit.NewEvent(audit.RolloutType, audit.Delete, actor, r)

Check warning on line 273 in internal/server/middleware/grpc/middleware.go

View check run for this annotation

Codecov / codecov/patch

internal/server/middleware/grpc/middleware.go#L272-L273

Added lines #L272 - L273 were not covered by tests
}

// Short circuiting the middleware here since we have a non-nil event from
Expand Down Expand Up @@ -304,6 +306,10 @@ func AuditUnaryInterceptor(logger *zap.Logger) grpc.UnaryServerInterceptor {
if action != "" {
event = audit.NewEvent(audit.NamespaceType, action, actor, audit.NewNamespace(r))
}
case *flipt.Rollout:
if action != "" {
event = audit.NewEvent(audit.RolloutType, action, actor, audit.NewRollout(r))
}
case *flipt.Rule:
if action != "" {
event = audit.NewEvent(audit.RuleType, action, actor, audit.NewRule(r))
Expand Down
91 changes: 91 additions & 0 deletions internal/server/middleware/grpc/middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,97 @@ func TestAuditUnaryInterceptor_DeleteConstraint(t *testing.T) {
assert.Equal(t, 1, exporterSpy.GetSendAuditsCalled())
}

func TestAuditUnaryInterceptor_CreateRollout(t *testing.T) {
var (
store = &storeMock{}
logger = zaptest.NewLogger(t)
exporterSpy = newAuditExporterSpy(logger)
s = server.New(logger, store)
req = &flipt.CreateRolloutRequest{
FlagKey: "flagkey",
Rank: 1,
Rule: &flipt.CreateRolloutRequest_Threshold{
Threshold: &flipt.RolloutThreshold{
Percentage: 50.0,
Value: true,
},
},
}
)

store.On("CreateRollout", mock.Anything, req).Return(&flipt.Rollout{
Id: "1",
NamespaceKey: "default",
Rank: 1,
FlagKey: req.FlagKey,
}, nil)

unaryInterceptor := AuditUnaryInterceptor(logger)

handler := func(ctx context.Context, r interface{}) (interface{}, error) {
return s.CreateRollout(ctx, r.(*flipt.CreateRolloutRequest))
}

info := &grpc.UnaryServerInfo{
FullMethod: "CreateRollout",
}

tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
tp.RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporterSpy))

tr := tp.Tracer("SpanProcessor")
ctx, span := tr.Start(context.Background(), "OnStart")

got, err := unaryInterceptor(ctx, req, info, handler)
require.NoError(t, err)
assert.NotNil(t, got)

span.End()
assert.Equal(t, 1, exporterSpy.GetSendAuditsCalled())
}

func TestAuditUnaryInterceptor_UpdateRollout(t *testing.T) {
var (
store = &storeMock{}
logger = zaptest.NewLogger(t)
exporterSpy = newAuditExporterSpy(logger)
s = server.New(logger, store)
req = &flipt.UpdateRolloutRequest{
Description: "desc",
}
)

store.On("UpdateRollout", mock.Anything, req).Return(&flipt.Rollout{
Description: "desc",
FlagKey: "flagkey",
NamespaceKey: "default",
Rank: 1,
}, nil)

unaryInterceptor := AuditUnaryInterceptor(logger)

handler := func(ctx context.Context, r interface{}) (interface{}, error) {
return s.UpdateRollout(ctx, r.(*flipt.UpdateRolloutRequest))
}

info := &grpc.UnaryServerInfo{
FullMethod: "UpdateRollout",
}

tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sdktrace.AlwaysSample()))
tp.RegisterSpanProcessor(sdktrace.NewSimpleSpanProcessor(exporterSpy))

tr := tp.Tracer("SpanProcessor")
ctx, span := tr.Start(context.Background(), "OnStart")

got, err := unaryInterceptor(ctx, req, info, handler)
require.NoError(t, err)
assert.NotNil(t, got)

span.End()
assert.Equal(t, 1, exporterSpy.GetSendAuditsCalled())
}

func TestAuditUnaryInterceptor_CreateRule(t *testing.T) {
var (
store = &storeMock{}
Expand Down

0 comments on commit d5310e6

Please sign in to comment.