Skip to content

Commit c16c1f3

Browse files
committed
feat: simplify user agent version constraint handling in interceptors
Signed-off-by: Matthieu MOREL <[email protected]>
1 parent bfd72b4 commit c16c1f3

File tree

2 files changed

+24
-32
lines changed

2 files changed

+24
-32
lines changed

util/grpc/useragent.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,21 @@ import (
1212
"google.golang.org/grpc/status"
1313
)
1414

15-
// UserAgentUnaryServerInterceptor returns a UnaryServerInterceptor which enforces a minimum client
16-
// version in the user agent
17-
func UserAgentUnaryServerInterceptor(clientName, constraintStr string) grpc.UnaryServerInterceptor {
15+
// parseSemVerConstraint returns a semVer Constraint instance or panic if there is a parsing error with the provided constraint.
16+
func parseSemVerConstraint(constraintStr string) *semver.Constraints {
1817
semVerConstraint, err := semver.NewConstraint(constraintStr)
1918
if err != nil {
2019
panic(err)
2120
}
21+
return semVerConstraint
22+
}
23+
24+
// UserAgentUnaryServerInterceptor returns a UnaryServerInterceptor which enforces a minimum client
25+
// version in the user agent
26+
func UserAgentUnaryServerInterceptor(clientName, constraintStr string) grpc.UnaryServerInterceptor {
27+
semVerConstraint := parseSemVerConstraint(constraintStr)
2228
return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
23-
if err := userAgentEnforcer(ctx, clientName, constraintStr, semVerConstraint); err != nil {
29+
if err := userAgentEnforcer(ctx, clientName, semVerConstraint); err != nil {
2430
return nil, err
2531
}
2632
return handler(ctx, req)
@@ -30,19 +36,16 @@ func UserAgentUnaryServerInterceptor(clientName, constraintStr string) grpc.Unar
3036
// UserAgentStreamServerInterceptor returns a StreamServerInterceptor which enforces a minimum client
3137
// version in the user agent
3238
func UserAgentStreamServerInterceptor(clientName, constraintStr string) grpc.StreamServerInterceptor {
33-
semVerConstraint, err := semver.NewConstraint(constraintStr)
34-
if err != nil {
35-
panic(err)
36-
}
39+
semVerConstraint := parseSemVerConstraint(constraintStr)
3740
return func(srv any, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
38-
if err := userAgentEnforcer(stream.Context(), clientName, constraintStr, semVerConstraint); err != nil {
41+
if err := userAgentEnforcer(stream.Context(), clientName, semVerConstraint); err != nil {
3942
return err
4043
}
4144
return handler(srv, stream)
4245
}
4346
}
4447

45-
func userAgentEnforcer(ctx context.Context, clientName, constraintStr string, semVerConstraint *semver.Constraints) error {
48+
func userAgentEnforcer(ctx context.Context, clientName string, semVerConstraint *semver.Constraints) error {
4649
var userAgents []string
4750
if md, ok := metadata.FromIncomingContext(ctx); ok {
4851
for _, ua := range md["user-agent"] {
@@ -52,7 +55,7 @@ func userAgentEnforcer(ctx context.Context, clientName, constraintStr string, se
5255
}
5356
}
5457
if isLegacyClient(userAgents) {
55-
return status.Errorf(codes.FailedPrecondition, "unsatisfied client version constraint: %s", constraintStr)
58+
return status.Errorf(codes.FailedPrecondition, "unsatisfied client version constraint: %s", semVerConstraint)
5659
}
5760

5861
for _, userAgent := range userAgents {

util/grpc/useragent_test.go

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,49 +9,38 @@ import (
99
)
1010

1111
func Test_UserAgentEnforcer(t *testing.T) {
12+
clientName := "argo-cd"
13+
constraintStr := "^1"
14+
semverConstraint, _ := semver.NewConstraint(constraintStr)
15+
1216
t.Run("Test enforcing valid user-agent", func(t *testing.T) {
13-
clientName := "argo-cd"
14-
constraintStr := "^1"
15-
semverConstraint, _ := semver.NewConstraint(constraintStr)
1617
md := metadata.New(map[string]string{"user-agent": "argo-cd/1.0"})
1718
ctx := metadata.NewIncomingContext(t.Context(), md)
18-
err := userAgentEnforcer(ctx, clientName, constraintStr, semverConstraint)
19+
err := userAgentEnforcer(ctx, clientName, semverConstraint)
1920
require.NoError(t, err)
2021
})
2122
t.Run("Test enforcing ignored user-agent", func(t *testing.T) {
22-
clientName := "argo-cd"
23-
constraintStr := "^1"
24-
semverConstraint, _ := semver.NewConstraint(constraintStr)
2523
md := metadata.New(map[string]string{"user-agent": "flux/3.0"})
2624
ctx := metadata.NewIncomingContext(t.Context(), md)
27-
err := userAgentEnforcer(ctx, clientName, constraintStr, semverConstraint)
25+
err := userAgentEnforcer(ctx, clientName, semverConstraint)
2826
require.NoError(t, err)
2927
})
3028
t.Run("Test enforcing user-agent with version not matching constraint", func(t *testing.T) {
31-
clientName := "argo-cd"
32-
constraintStr := "^1"
33-
semverConstraint, _ := semver.NewConstraint(constraintStr)
3429
md := metadata.New(map[string]string{"user-agent": "argo-cd/3.0"})
3530
ctx := metadata.NewIncomingContext(t.Context(), md)
36-
err := userAgentEnforcer(ctx, clientName, constraintStr, semverConstraint)
31+
err := userAgentEnforcer(ctx, clientName, semverConstraint)
3732
require.ErrorContains(t, err, "unsatisfied client version constraint")
3833
})
3934
t.Run("Test legacy user-agent", func(t *testing.T) {
40-
clientName := "argo-cd"
41-
constraintStr := "^1"
42-
semverConstraint, _ := semver.NewConstraint(constraintStr)
4335
md := metadata.New(map[string]string{"user-agent": "grpc-go/1.15.0"})
4436
ctx := metadata.NewIncomingContext(t.Context(), md)
45-
err := userAgentEnforcer(ctx, clientName, constraintStr, semverConstraint)
46-
require.ErrorContains(t, err, "unsatisfied client version constraint")
37+
err := userAgentEnforcer(ctx, clientName, semverConstraint)
38+
require.EqualError(t, err, "rpc error: code = FailedPrecondition desc = unsatisfied client version constraint: ^1")
4739
})
4840
t.Run("Test invalid version", func(t *testing.T) {
49-
clientName := "argo-cd"
50-
constraintStr := "^1"
51-
semverConstraint, _ := semver.NewConstraint(constraintStr)
5241
md := metadata.New(map[string]string{"user-agent": "argo-cd/super"})
5342
ctx := metadata.NewIncomingContext(t.Context(), md)
54-
err := userAgentEnforcer(ctx, clientName, constraintStr, semverConstraint)
43+
err := userAgentEnforcer(ctx, clientName, semverConstraint)
5544
require.ErrorContains(t, err, "could not parse version")
5645
})
5746
}

0 commit comments

Comments
 (0)