Skip to content

Commit

Permalink
enhancement: Ability to set request ID
Browse files Browse the repository at this point in the history
Adds `RequestIDGenerator` option that allows the user to configure a
function to be called for each request to generate the request ID.

Signed-off-by: Charith Ellawala <charith@cerbos.dev>
  • Loading branch information
charithe committed Jun 20, 2024
1 parent 939e23d commit 9a7ce2e
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 21 deletions.
12 changes: 6 additions & 6 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
---
run:
timeout: 300s
skip-dirs:
- "^genpb/"
- "^hack/"
- "^tools/"
build-tags:
- tests

Expand Down Expand Up @@ -40,7 +36,6 @@ linters-settings:

nolintlint:
allow-unused: false
allow-leading-space: false
require-specific: true

tagliatelle:
Expand Down Expand Up @@ -69,13 +64,13 @@ linters:
- gofumpt
- goimports
- goheader
- gomnd
- gomoddirectives
- gosec
- govet
- importas
- makezero
- misspell
- mnd
- nakedret
- nestif
- nilerr
Expand All @@ -99,6 +94,11 @@ linters:
issues:
max-same-issues: 30

exclude-dirs:
- "^genpb/"
- "^hack/"
- "^tools/"

exclude-rules:
- path: _test\.go
linters:
Expand Down
16 changes: 6 additions & 10 deletions cerbos/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"time"

grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
"github.com/rs/xid"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
Expand Down Expand Up @@ -156,9 +155,9 @@ func New(address string, opts ...Opt) (*GRPCClient, error) {
func mkConn(address string, opts ...Opt) (*grpc.ClientConn, *config, error) {
conf := &config{
address: address,
connectTimeout: 30 * time.Second, //nolint:gomnd
maxRetries: 3, //nolint:gomnd
retryTimeout: 2 * time.Second, //nolint:gomnd
connectTimeout: 30 * time.Second, //nolint:mnd
maxRetries: 3, //nolint:mnd
retryTimeout: 2 * time.Second, //nolint:mnd
userAgent: internal.UserAgent("grpc"),
}

Expand Down Expand Up @@ -298,9 +297,8 @@ func (c *GRPCClient) PlanResources(ctx context.Context, principal *Principal, re
return nil, fmt.Errorf("invalid resource: %w", err)
}

reqID := xid.New()
req := &requestv1.PlanResourcesRequest{
RequestId: reqID.String(),
RequestId: c.opts.RequestID(ctx),
Action: action,
Principal: principal.Obj,
Resource: &enginev1.PlanResourcesInput_Resource{
Expand Down Expand Up @@ -333,9 +331,8 @@ func (c *GRPCClient) CheckResources(ctx context.Context, principal *Principal, r
return nil, fmt.Errorf("invalid resource batch; %w", err)
}

reqID := xid.New()
req := &requestv1.CheckResourcesRequest{
RequestId: reqID.String(),
RequestId: c.opts.RequestID(ctx),
Principal: principal.Obj,
Resources: resourceBatch.Batch,
}
Expand All @@ -362,9 +359,8 @@ func (c *GRPCClient) IsAllowed(ctx context.Context, principal *Principal, resour
return false, fmt.Errorf("invalid resource: %w", err)
}

reqID := xid.New()
req := &requestv1.CheckResourcesRequest{
RequestId: reqID.String(),
RequestId: c.opts.RequestID(ctx),
Principal: principal.Obj,
Resources: []*requestv1.CheckResourcesRequest_ResourceEntry{
{Actions: []string{action}, Resource: resource.Obj},
Expand Down
10 changes: 10 additions & 0 deletions cerbos/request_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package cerbos

import (
"context"

"google.golang.org/grpc/metadata"

"github.com/cerbos/cerbos-sdk-go/internal"
Expand Down Expand Up @@ -43,3 +45,11 @@ func Headers(keyValues ...string) RequestOpt {
opt.Metadata = metadata.Pairs(keyValues...)
}
}

// RequestIDGenerator is invoked on every request to generate a request ID.
// If not defined, a random request ID is generated by the SDK client.
func RequestIDGenerator(generator func(context.Context) string) RequestOpt {
return func(opt *internal.ReqOpt) {
opt.RequestIDGenerator = generator
}
}
24 changes: 23 additions & 1 deletion cerbos/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const timeout = 30 * time.Second
func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testing.T) {
//nolint:thelper
return func(t *testing.T) {
token := tests.GenerateToken(t, time.Now().Add(5*time.Minute)) //nolint:gomnd
token := tests.GenerateToken(t, time.Now().Add(5*time.Minute)) //nolint:mnd
c := c.With(
AuxDataJWT(token, ""),
IncludeMeta(true),
Expand Down Expand Up @@ -76,6 +76,7 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin
check := func(t *testing.T, have *CheckResourcesResponse, err error) {
t.Helper()
require.NoError(t, err)
require.NotEmpty(t, have.GetRequestId())

haveXX125 := have.GetResource("XX125", MatchResourceKind("leave_request"))
require.NoError(t, haveXX125.Err())
Expand Down Expand Up @@ -107,6 +108,15 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin

require.NotNil(t, have.Results[0].Meta, "no metadata found in the result")
})

t.Run("TestRequestIDGenerator", func(t *testing.T) {
ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
defer cancelFunc()

have, err := c.With(RequestIDGenerator(func(_ context.Context) string { return "foo" })).CheckResources(ctx, principal, resources)
check(t, have, err)
require.Equal(t, "foo", have.GetRequestId())
})
})

t.Run("CheckResourcesScoped", func(t *testing.T) {
Expand Down Expand Up @@ -145,6 +155,7 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin
check := func(t *testing.T, have *CheckResourcesResponse, err error) {
t.Helper()
require.NoError(t, err)
require.NotEmpty(t, have.GetRequestId())

haveXX125 := have.GetResource("XX125", MatchResourceKind("leave_request"))
require.NoError(t, haveXX125.Err())
Expand Down Expand Up @@ -202,6 +213,7 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin
check := func(t *testing.T, have *CheckResourcesResponse, err error) {
t.Helper()
require.NoError(t, err)
require.NotEmpty(t, have.GetRequestId())

haveXX125 := have.GetResource("XX125")
require.NoError(t, haveXX125.Err())
Expand Down Expand Up @@ -307,6 +319,7 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin
check := func(t *testing.T, have *PlanResourcesResponse, err error) {
t.Helper()
is := require.New(t)
require.NotEmpty(t, have.GetRequestId())

is.NoError(err)
is.Equal(enginev1.PlanResourcesFilter_KIND_CONDITIONAL, have.Filter.Kind, "Expected conditional filter")
Expand All @@ -333,6 +346,15 @@ func TestClient[P PrincipalContext, C Client[C, P]](c Client[C, P]) func(*testin
have, err := cc.WithPrincipal(principal).PlanResources(ctx, resource, "approve")
check(t, have, err)
})

t.Run("TestRequestIDGenerator", func(t *testing.T) {
ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
defer cancelFunc()

have, err := cc.With(RequestIDGenerator(func(_ context.Context) string { return "foo" })).PlanResources(ctx, principal, resource, "approve")
check(t, have, err)
require.Equal(t, "foo", have.GetRequestId())
})
})
}
}
17 changes: 14 additions & 3 deletions internal/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import (
"google.golang.org/grpc/metadata"

requestv1 "github.com/cerbos/cerbos/api/genpb/cerbos/request/v1"
"github.com/rs/xid"
)

type ReqOpt struct {
AuxData *requestv1.AuxData
Metadata metadata.MD
IncludeMeta bool
AuxData *requestv1.AuxData
Metadata metadata.MD
RequestIDGenerator func(context.Context) string
IncludeMeta bool
}

func (o *ReqOpt) Context(ctx context.Context) context.Context {
Expand All @@ -24,3 +26,12 @@ func (o *ReqOpt) Context(ctx context.Context) context.Context {

return metadata.NewOutgoingContext(ctx, o.Metadata)
}

func (o *ReqOpt) RequestID(ctx context.Context) string {
if o != nil && o.RequestIDGenerator != nil {
return o.RequestIDGenerator(ctx)
}

reqID := xid.New()
return reqID.String()
}
2 changes: 1 addition & 1 deletion internal/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func GenerateToken(t *testing.T, expiry time.Time) string {
require.NoError(t, token.Set(jwt.AudienceKey, "cerbos-jwt-tests"))
require.NoError(t, token.Set(jwt.ExpirationKey, expiry))
require.NoError(t, token.Set("customString", "foobar"))
require.NoError(t, token.Set("customInt", 42)) //nolint:gomnd
require.NoError(t, token.Set("customInt", 42)) //nolint:mnd
require.NoError(t, token.Set("customArray", []string{"A", "B", "C"}))
require.NoError(t, token.Set("customMap", map[string]any{"A": "AA", "B": "BB", "C": "CC"}))

Expand Down

0 comments on commit 9a7ce2e

Please sign in to comment.