Skip to content

Commit b87e911

Browse files
committed
feat: add deadline and trace context to iamv1.Caller
As a workaround for CEL-Go currently not supporting threading the user context through expression and function evaluation, this patch adds support for the caller to thread request deadline and trace context through to the CEL functions, so that downstream gRPC calls can inherit the request deadline and trace context. This might all be removable if/when CEL attains built-in support for "async functions", as per google/cel-go#368
1 parent d807e57 commit b87e911

File tree

7 files changed

+181
-43
lines changed

7 files changed

+181
-43
lines changed

cmd/iamctl/go.sum

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+
3838
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
3939
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
4040
cloud.google.com/go/spanner v1.17.0/go.mod h1:+17t2ixFwRG4lWRwE+5kipDR9Ef07Jkmc8z0IbMDKUs=
41-
cloud.google.com/go/spanner v1.20.0/go.mod h1:ajR/W06cMHQu7nqQ4irRGplPNoWgejGJlEhlB8xBTKk=
4241
cloud.google.com/go/spanner v1.21.0 h1:NWLJnTTPwKu5OB/3SwL/VkJ9rIpvNPjalWz0p6vywnk=
4342
cloud.google.com/go/spanner v1.21.0/go.mod h1:P1Pl0zyIIdhovaFueBrOjSQ6jKQDfl5bVemE+gdEJog=
4443
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=

cmd/iamctl/internal/examplecmd/exampleservercmd/server.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"google.golang.org/grpc"
2424
"google.golang.org/grpc/codes"
2525
"google.golang.org/grpc/status"
26+
"google.golang.org/protobuf/types/known/timestamppb"
2627
)
2728

2829
func newServer(spannerClient *spanner.Client) (*iamexample.Authorization, error) {
@@ -126,6 +127,11 @@ type googleIdentityTokenCallerResolver struct{}
126127
func (googleIdentityTokenCallerResolver) ResolveCaller(ctx context.Context) (*iamv1.Caller, error) {
127128
const authorizationKey = "authorization"
128129
var result iamv1.Caller
130+
if deadline, ok := ctx.Deadline(); ok {
131+
result.Context = &iamv1.Caller_Context{
132+
Deadline: timestamppb.New(deadline),
133+
}
134+
}
129135
token, ok := iamtoken.FromIncomingContext(ctx, authorizationKey)
130136
if !ok {
131137
return &result, nil

iamcaller/chain.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ func (c chainResolver) ResolveCaller(ctx context.Context) (*iamv1.Caller, error)
3636
for key, value := range nextCaller.Metadata {
3737
Add(&result, key, value)
3838
}
39+
// TODO: Remove this when CEL-Go supports async functions with context arguments.
40+
if result.Context == nil && nextCaller.Context != nil {
41+
result.Context = nextCaller.Context
42+
}
3943
}
4044
return &result, nil
4145
}

iamcaller/chain_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"context"
55
"errors"
66
"testing"
7+
"time"
78

89
iamv1 "go.einride.tech/iam/proto/gen/einride/iam/v1"
910
"google.golang.org/protobuf/testing/protocmp"
11+
"google.golang.org/protobuf/types/known/timestamppb"
1012
"gotest.tools/v3/assert"
1113
)
1214

@@ -83,6 +85,23 @@ func TestChainResolvers(t *testing.T) {
8385
assert.DeepEqual(t, expected, actual, protocmp.Transform())
8486
})
8587

88+
t.Run("context", func(t *testing.T) {
89+
expected := &iamv1.Caller{
90+
Context: &iamv1.Caller_Context{
91+
Deadline: timestamppb.New(time.Unix(1234, 0).UTC()),
92+
Trace: "mock-trace-context",
93+
},
94+
Members: []string{"test:bar", "test:foo"},
95+
Metadata: map[string]*iamv1.Caller_Metadata{
96+
"key1": {Members: []string{"test:foo"}},
97+
"key2": {Members: []string{"test:bar"}},
98+
},
99+
}
100+
actual, err := ChainResolvers(constant(expected)).ResolveCaller(context.Background())
101+
assert.NilError(t, err)
102+
assert.DeepEqual(t, expected, actual, protocmp.Transform())
103+
})
104+
86105
t.Run("error", func(t *testing.T) {
87106
actual, err := ChainResolvers(
88107
constant(&iamv1.Caller{

iamexample/caller.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"go.einride.tech/iam/iamcaller"
77
iamv1 "go.einride.tech/iam/proto/gen/einride/iam/v1"
88
"google.golang.org/grpc/metadata"
9+
"google.golang.org/protobuf/types/known/timestamppb"
910
)
1011

1112
// MemberHeader is the gRPC header used by the example server to determine IAM members of the caller.
@@ -23,13 +24,16 @@ type memberHeaderResolver struct{}
2324
// ResolveCaller implements iamcaller.Resolver.
2425
func (m *memberHeaderResolver) ResolveCaller(ctx context.Context) (*iamv1.Caller, error) {
2526
var result iamv1.Caller
26-
md, ok := metadata.FromIncomingContext(ctx)
27-
if !ok {
28-
return &result, nil
27+
if md, ok := metadata.FromIncomingContext(ctx); ok {
28+
iamcaller.Add(&result, MemberHeader, &iamv1.Caller_Metadata{
29+
Members: md.Get(MemberHeader),
30+
})
31+
}
32+
if deadline, ok := ctx.Deadline(); ok {
33+
result.Context = &iamv1.Caller_Context{
34+
Deadline: timestamppb.New(deadline),
35+
}
2936
}
30-
iamcaller.Add(&result, MemberHeader, &iamv1.Caller_Metadata{
31-
Members: md.Get(MemberHeader),
32-
})
3337
return &result, nil
3438
}
3539

proto/gen/einride/iam/v1/caller.pb.go

Lines changed: 131 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

proto/src/einride/iam/v1/caller.proto

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,22 @@ message Caller {
1919
repeated string members = 1;
2020
// Caller identity from gRPC metadata key/value pairs.
2121
map<string, Metadata> metadata = 2;
22+
// Caller context.
23+
// TODO: Remove this when cel-go supports async functions with context threading.
24+
Context context = 3;
2225
// Caller identity for a gRPC metadata key/value pair.
2326
message Metadata {
2427
// The IAM members from the metadata value.
2528
repeated string members = 1;
2629
// The identity token from the metadata value.
2730
IdentityToken identity_token = 2;
2831
}
32+
// Caller context for downstream network calls.
33+
// TODO: Remove this when cel-go supports async functions with context threading.
34+
message Context {
35+
// Deadline for the caller's request.
36+
google.protobuf.Timestamp deadline = 1;
37+
// Trace context for the caller's request.
38+
string trace = 2;
39+
}
2940
}

0 commit comments

Comments
 (0)