Import changes for goma server

  - 1a6bbe3274588ca7e97c865042c12d12edbc6690 update goma's base image to ubuntu 18.04
  - 80208c196d4287f40ce7c2ff962dbe5c04a0c9e6 remoteexec: add cross tag for RBE latency
  - d603b5908de4c5f0fd382c0c9785544a24f3367f fix -imsvc for windows cross
  - a99662ca8b8019c9ca27d53ece4a17bf4566082e fix -resource-dir for windows cross
  - f7d5df8c574fb2f4daa3478ef15585003bbaa4fa remoteexec: log cross compile type
  - 9ece49a555e96722fe1589b2e166ae4beb186759 fix for pnacl-clang.bat
  - 187521df7447d2978abab600af2f3c6af119781e fix pnacl-clang target
  - 3252da722b78a9a7dc94268ec337f09dd34ca76e use go 1.16.3
  - 61c5b528a3eddcee80a972c3b466934c46cb905d remoteexec: add test for windows ats & windows cross
  - 80736a74ae59d5ea4a6d114909dffee8a16f3ee2 remoteexec: fix windows dedup
  - 48d4fb1f2baead1f57e8bea8a3431514d6a5375e remoteexec: make --rtlib= relocatable
  - 453728e7c0fbd3a84a021e0eabd8870a7d9b25b1 remoteexec: support windows cross
  - 2fd0eca64142f7e1b271a0e8ddeec2777c254e01 descriptor: fix for pnacl windows cross compile
  - dd545a524f1edb2ccc2d85182e24a2875354049a dedup input filenames with ignoring case for Windows
  - d3ecbd19f4a697d56e9cc83315461d5814b09ca4 setup support windows cross
  - 032d4948194a2fb6734fbc9a8099fd1c27a07ff8 winpath: add ToPosix
  - ba840171d45a273ef2d47adcc667c4fbf81ed726 add windows_cross option
  - 8c280f1b00721ced84ef82dcfdf6a9061f40ce94 remoteexec: handle -Xclang -plugin-args-*
  - f25daa29f4146c25178503db9a46579e419cfe3d remoteexec: don't log error details if codes is OK
  - 816c57e5a65d57f469bc0a984761cecc24d528db remoteexec: record error details if exists
  - f7fe660d334f7cadc3a67e104a8cba8c29ad74bc roll google.golang.org/api v0.42.0 -> v0.43.0
  - 8a39e9b4750f25d2b5efec88463545a057247769 roll cloud.google.com/go v0.79.0 -> v0.80.0
  - 588653e059d80edca6534a367b6f2e822b9a88b3 add acl_lookup command
  - 56b296201042f5ce257650fffaa79d1d782e7dcc roll github.com/golang/protobuf v1.4.3 -> v1.5.1
  - 171c59e1266ab669895bae065fa1cf432e023506 roll google.golang.org/api v0.41.0 -> v0.42.0
  - 74d35147dc0608bdcf658b9cc6804005454a9cce roll protobuf to 3.15.6
  - bb7919124a39de18c0152914e73cb135b916aa2b use go 1.16.2
  - 99b0870036c05a650e5d5d5cf532cd0160bc57f1 [gcc_flags] Fix -ffile-compilation-dir relocatable bug
  - c3b4ff315dc9af90977250198442e33fd8ba0290 roll cloud.google.com/go v0.78.0 -> v0.79.0
  - 90550ace421f2a7585ae2d63e630963b2dcde7f4 roll google.golang.org/api v0.40.0 -> v0.41.0
  - 4aeba81435ec0a7347a2495f4fc5993834d81f79 remoteexec: ignore env var if /winsysroot or -imsvc is gi...
  - 637b12a53f0908dcf3d27a350836552a74be0b55 roll protobuf to 3.15.5
  - 97677d7bd10bccbd5564859c81c720d85262e995 remoteexec: use cas error for output file.
  - afadec5d6cf1303e214701c7b596f5273f9b93cc roll github.com/google/go-cmp v0.5.4 -> v0.5.5
  - 2a3dc2d1ddb24577aba5a7456be143668b2fe207 roll cloud.google.com/go/pubsub v1.10.0 -> v1.10.1
  - 8804ca5754ea18071c184d2d9c9e521ddb9ffcd1 migrate ptypes
  - 5ef81ec10990b583d15e9054870c9c1b1b6b56ca migrate protobuf library
  - 9eef9a1cd7b12ab6e2ca78a93131055935bb4ef5 remoteexec: handle -Xclang -target-feature
  - 126b0e2724fc11fc3dedee3a80952bc42e13fdce roll cloud.google.com/go/storage v1.13.0 -> v1.14.0
  - 14545dfae258ad5126d8c67bb3f7aeee149f756c [flags] Add support for '-fprofile-list=' flag
  - b2b7344397758cd264672d181cda56e35e1f1787 [flags] Support jointed form "-fdebug-compilation-dir" fl...
  - 94b1d90241a31ead35899302139e10b67f7443dc [flags] Add support for code coverage related flags
  - be882f5c2322393265d15395f1adadcdf687c7e7 remoteexec: relocatable feature flag for -Xclang
  - 9906e83ef1f369a8e22ab546ab094bdc6cca8c3d migrate github.com/golang/protobuf to google.golang.org/p...

GitOrigin-RevId: ec0138e0a575ad2ce4ae851dec6502ccc32921b1
Change-Id: I203208e108c52bf7d4a32ffc61c8370a0952888f
diff --git a/README.md b/README.md
index 9a016e7..7256fca 100644
--- a/README.md
+++ b/README.md
@@ -40,23 +40,14 @@
    --remote-instance-name $REMOTE_INSTANCE_NAME
 ```
 
-for chromium, platform container image should be created with
-[install-build-dep.sh](https://chromium.googlesource.com/chromium/src/+/master/build/install-build-deps.sh).
-
-Example Dockerfile
+for chromium, platform container image would be something like
 ```
-FROM ubuntu:16.04
+FROM marketing.gcr.io/google/ubuntu1804:latest
 ENV DEBIAN_FRONTEND noninteractive
 
-ADD https://chromium.googlesource.com/chromium/src/+/master/build/install-build-deps.sh?format=TEXT /tmp/install-build-deps.sh.base64
-RUN base64 -d /tmp/install-build-deps.sh.base64 > /tmp/install-build-deps.sh \
+RUN apt-get -y update \
   && \
-  apt-get -y update \
-  && \
-  apt-get install -f -y build-essential gcc-4.8 g++-4.8 docker.io \
-  && \
-  bash /tmp/install-build-deps.sh --lib32 --no-prompt \
-     --no-chromeos-fonts \
+  apt-get install -f -y build-essential lsb-release python \
   && \
   rm -rf /var/lib/apt/lists/*
 
diff --git a/auth/acl/checker.go b/auth/acl/checker.go
index dc48b20..4977436 100644
--- a/auth/acl/checker.go
+++ b/auth/acl/checker.go
@@ -10,11 +10,11 @@
 	"strings"
 	"sync"
 
-	"github.com/golang/protobuf/proto"
 	"golang.org/x/oauth2"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/auth"
 	"go.chromium.org/goma/server/auth/account"
@@ -85,48 +85,58 @@
 	return nil
 }
 
-// CheckToken checks token and returns group id and token used for backend API.
-func (c *Checker) CheckToken(ctx context.Context, token *oauth2.Token, tokenInfo *auth.TokenInfo) (string, *oauth2.Token, error) {
+// FindGroup finds a group for tokenInfo.
+func (c *Checker) FindGroup(ctx context.Context, tokenInfo *auth.TokenInfo) (*pb.Group, error) {
 	c.mu.RLock()
 	defer c.mu.RUnlock()
 
-	logger := log.FromContext(ctx)
-
 	for _, g := range c.config.GetGroups() {
 		if !checkGroup(ctx, tokenInfo, g, c.AuthDB) {
 			continue
 		}
-
-		logger.Debugf("in group:%s", g.Id)
-		if g.Reject {
-			logger.Errorf("group:%s rejected", g.Id)
-			return g.Id, nil, grpc.Errorf(codes.PermissionDenied, "access rejected")
-		}
-		if g.ServiceAccount == "" {
-			logger.Debugf("group:%s use EUC", g.Id)
-			return g.Id, token, nil
-		}
-
-		sa := c.accounts[g.ServiceAccount]
-		if sa == nil {
-			logger.Errorf("group:%s service account not found: %s", g.Id, g.ServiceAccount)
-			return g.Id, nil, grpc.Errorf(codes.Internal, "service account not found: %s", g.ServiceAccount)
-		}
-		saToken, err := sa.Token(ctx)
-		if err != nil {
-			logger.Errorf("group:%s service account:%s error:%v", g.Id, g.ServiceAccount, err)
-			return g.Id, nil, grpc.Errorf(codes.Internal, "service account:%s error:%v", g.ServiceAccount, err)
-		}
-		logger.Debugf("group:%s use service account:%s", g.Id, g.ServiceAccount)
-		return g.Id, saToken, nil
+		return g, nil
 	}
-	if ctx.Err() != nil {
-		err := status.FromContextError(ctx.Err()).Err()
-		logger.Errorf("acl check context error: %v", err)
-		return "", nil, err
+	return nil, fmt.Errorf("no group for %q %q", tokenInfo.Email, tokenInfo.Audience)
+}
+
+// CheckToken checks token and returns group id and token used for backend API.
+func (c *Checker) CheckToken(ctx context.Context, token *oauth2.Token, tokenInfo *auth.TokenInfo) (string, *oauth2.Token, error) {
+
+	logger := log.FromContext(ctx)
+
+	g, err := c.FindGroup(ctx, tokenInfo)
+	if err != nil {
+		if ctx.Err() != nil {
+			err := status.FromContextError(ctx.Err()).Err()
+			logger.Errorf("acl check context error: %v", err)
+			return "", nil, err
+		}
+		logger.Errorf("no acl match: %v", err)
+		return "", nil, grpc.Errorf(codes.PermissionDenied, "access rejected")
 	}
-	logger.Errorf("no acl match")
-	return "", nil, grpc.Errorf(codes.PermissionDenied, "access rejected")
+
+	logger.Debugf("in group:%s", g.Id)
+	if g.Reject {
+		logger.Errorf("group:%s rejected", g.Id)
+		return g.Id, nil, grpc.Errorf(codes.PermissionDenied, "access rejected")
+	}
+	if g.ServiceAccount == "" {
+		logger.Debugf("group:%s use EUC", g.Id)
+		return g.Id, token, nil
+	}
+
+	sa := c.accounts[g.ServiceAccount]
+	if sa == nil {
+		logger.Errorf("group:%s service account not found: %s", g.Id, g.ServiceAccount)
+		return g.Id, nil, grpc.Errorf(codes.Internal, "service account not found: %s", g.ServiceAccount)
+	}
+	saToken, err := sa.Token(ctx)
+	if err != nil {
+		logger.Errorf("group:%s service account:%s error:%v", g.Id, g.ServiceAccount, err)
+		return g.Id, nil, grpc.Errorf(codes.Internal, "service account:%s error:%v", g.ServiceAccount, err)
+	}
+	logger.Debugf("group:%s use service account:%s", g.Id, g.ServiceAccount)
+	return g.Id, saToken, nil
 }
 
 func checkGroup(ctx context.Context, tokenInfo *auth.TokenInfo, g *pb.Group, authDB AuthDB) bool {
diff --git a/auth/acl/loader.go b/auth/acl/loader.go
index db5b972..d16b57a 100644
--- a/auth/acl/loader.go
+++ b/auth/acl/loader.go
@@ -9,7 +9,7 @@
 	"fmt"
 	"io/ioutil"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/encoding/prototext"
 
 	pb "go.chromium.org/goma/server/proto/auth"
 )
@@ -40,7 +40,7 @@
 		return nil, err
 	}
 	a := &pb.ACL{}
-	err = proto.UnmarshalText(string(b), a)
+	err = prototext.Unmarshal(b, a)
 	if err != nil {
 		return nil, fmt.Errorf("load error %s: %v", l.Filename, err)
 	}
diff --git a/auth/authdb/client_test.go b/auth/authdb/client_test.go
index 8fc7e6d..6c4a92e 100644
--- a/auth/authdb/client_test.go
+++ b/auth/authdb/client_test.go
@@ -10,9 +10,9 @@
 	"net/http/httptest"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	authdbrpc "go.chromium.org/goma/server/httprpc/authdb"
@@ -20,6 +20,7 @@
 )
 
 type fakeAuthDBServer struct {
+	pb.UnimplementedAuthDBServiceServer
 	t        *testing.T
 	want     *pb.CheckMembershipReq
 	resp     *pb.CheckMembershipResp
diff --git a/auth/authdb/handler.go b/auth/authdb/handler.go
index 63cc74d..db6b933 100644
--- a/auth/authdb/handler.go
+++ b/auth/authdb/handler.go
@@ -17,6 +17,7 @@
 
 // Handler handles request to AuthDB.
 type Handler struct {
+	pb.UnimplementedAuthDBServiceServer
 	AuthDB AuthDB
 }
 
diff --git a/auth/client_test.go b/auth/client_test.go
index 264d124..366b7e2 100644
--- a/auth/client_test.go
+++ b/auth/client_test.go
@@ -15,10 +15,10 @@
 	"testing"
 	"time"
 
-	"github.com/golang/protobuf/ptypes"
 	"golang.org/x/oauth2"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
+	"google.golang.org/protobuf/types/known/timestamppb"
 
 	"go.chromium.org/goma/server/auth/enduser"
 	authpb "go.chromium.org/goma/server/proto/auth"
@@ -52,10 +52,7 @@
 
 	t.Log("should return the same with ExpiresAt.")
 	tm := time.Now().Add(time.Hour)
-	expires, err := ptypes.TimestampProto(tm)
-	if err != nil {
-		t.Fatalf("ptypes.TimestampProto(%v) error %v; want nil", tm, err)
-	}
+	expires := timestamppb.New(tm)
 	ai = authInfo{
 		resp: &authpb.AuthResp{
 			ExpiresAt: expires,
@@ -69,15 +66,9 @@
 
 func TestAuthInfoCheck(t *testing.T) {
 	hourAgo := time.Now().Add(-1 * time.Hour)
-	expiredHourAgo, err := ptypes.TimestampProto(hourAgo)
-	if err != nil {
-		t.Fatalf("ptypes.TimestampProto(%v) error %v; want nil", hourAgo, err)
-	}
+	expiredHourAgo := timestamppb.New(hourAgo)
 	hour := time.Now().Add(time.Hour)
-	willExpireInHour, err := ptypes.TimestampProto(hour)
-	if err != nil {
-		t.Fatalf("ptypes.TimestampProto(%v) error %v; want nil", willExpireInHour, err)
-	}
+	willExpireInHour := timestamppb.New(hour)
 
 	for _, tc := range []struct {
 		desc  string
@@ -175,10 +166,7 @@
 		return now.Add(1 * time.Hour)
 	}
 	expires := expiresAt()
-	expiresProto, err := ptypes.TimestampProto(expires)
-	if err != nil {
-		t.Fatalf("expires %s: %v", expires, err)
-	}
+	expiresProto := timestamppb.New(expires)
 	var deadline time.Time
 	var callCount int
 	a := &Auth{
@@ -266,10 +254,6 @@
 	if otime, ntime := expires, expires2; otime.Equal(ntime) {
 		t.Fatalf("expiresAt: %s == %s", otime, ntime)
 	}
-	expiresProto, err = ptypes.TimestampProto(expires2)
-	if err != nil {
-		t.Fatalf("timestamp %s: %v", expires2, err)
-	}
 	user, err = a.Check(ctx, req)
 	if err != nil {
 		t.Fatalf("Check failed: %v", err)
@@ -318,10 +302,7 @@
 
 	t.Log("1. access succeed (using cache)")
 	hour := time.Now().Add(time.Hour)
-	willExpireInHour, err := ptypes.TimestampProto(hour)
-	if err != nil {
-		t.Fatalf("ptypes.TimestampProto(%v) error %v; want nil", willExpireInHour, err)
-	}
+	willExpireInHour := timestamppb.New(hour)
 	email := "example@google.com"
 	a1 := &Auth{
 		cache: map[string]*authInfo{
@@ -419,7 +400,7 @@
 
 	t.Log("5. access fail due to expired token.")
 	hourAgo := time.Now().Add(-1 * time.Hour)
-	expiredHourAgo, err := ptypes.TimestampProto(hourAgo)
+	expiredHourAgo := timestamppb.New(hourAgo)
 	a5 := &Auth{
 		Client: dummyClient{
 			auth: func(ctx context.Context, req *authpb.AuthReq) (*authpb.AuthResp, error) {
diff --git a/auth/service.go b/auth/service.go
index c629fa2..55a1d07 100644
--- a/auth/service.go
+++ b/auth/service.go
@@ -9,13 +9,13 @@
 	"sync"
 	"time"
 
-	"github.com/golang/protobuf/ptypes"
 	"go.opencensus.io/trace"
 	"golang.org/x/oauth2"
 	"golang.org/x/sync/singleflight"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/types/known/timestamppb"
 
 	"go.chromium.org/goma/server/log"
 	authpb "go.chromium.org/goma/server/proto/auth"
@@ -40,6 +40,7 @@
 
 // Service implements goma auth service.
 type Service struct {
+	authpb.UnimplementedAuthServiceServer
 	// CheckToken optionally checks access token with token info.
 	// If it is not set, all access will be rejected.
 	// If it returns grpc's codes.PermissionDenied error,
@@ -157,11 +158,7 @@
 		return nil, grpc.Errorf(codes.Internal, "nil TokenInfo is given for %q", te.Group)
 	}
 
-	expires, err := ptypes.TimestampProto(te.TokenInfo.ExpiresAt)
-	if err != nil {
-		return nil, grpc.Errorf(codes.OutOfRange, "bad ExpiresAt %s for %q: %v", te.TokenInfo.ExpiresAt, te.Group, err)
-	}
-
+	expires := timestamppb.New(te.TokenInfo.ExpiresAt)
 	var errorDescription string
 	var quota int32
 	if te.TokenInfo.Err == nil {
diff --git a/auth/service_test.go b/auth/service_test.go
index f50717d..553c8c9 100644
--- a/auth/service_test.go
+++ b/auth/service_test.go
@@ -13,8 +13,8 @@
 	"testing"
 	"time"
 
-	"github.com/golang/protobuf/ptypes"
 	"golang.org/x/oauth2"
+	"google.golang.org/protobuf/types/known/timestamppb"
 
 	authpb "go.chromium.org/goma/server/proto/auth"
 )
@@ -62,10 +62,7 @@
 		t.Fatalf("Auth failed: %v", err)
 	}
 	expires := expiresAt()
-	expiresProto, err := ptypes.TimestampProto(expires)
-	if err != nil {
-		t.Fatalf("timestamp %s: %v", expires, err)
-	}
+	expiresProto := timestamppb.New(expires)
 	want := &authpb.AuthResp{
 		Email:     "foo@example.com",
 		ExpiresAt: expiresProto,
@@ -125,11 +122,7 @@
 	if otime, ntime := expires, expires2; otime.Equal(ntime) {
 		t.Fatalf("expiresAt: %s == %s", otime, ntime)
 	}
-	expiresProto, err = ptypes.TimestampProto(expires2)
-	if err != nil {
-		t.Fatalf("timestamp %s: %v", expires2, err)
-	}
-	want.ExpiresAt = expiresProto
+	want.ExpiresAt = timestamppb.New(expires2)
 	resp, err = s.Auth(ctx, &authpb.AuthReq{
 		Authorization: "Bearer token-value",
 	})
@@ -155,7 +148,7 @@
 	// 0. access succeeds by cache
 	email := "example@google.com"
 	expiresAt := time.Now().Add(10 * time.Second)
-	ptypeExpiresAt, err := ptypes.TimestampProto(expiresAt)
+	ptypeExpiresAt := timestamppb.New(expiresAt)
 	ti := &TokenInfo{
 		Email:     email,
 		Audience:  "test-audience.apps.googleusercontent.com",
@@ -177,9 +170,6 @@
 			TokenType:   "Bearer",
 		},
 	}
-	if err != nil {
-		t.Fatalf("ptypes.TimestampProto(%v) return error %v; want non error", expiresAt, err)
-	}
 	token := &oauth2.Token{
 		AccessToken: "test",
 		TokenType:   "Bearer",
diff --git a/backend/exec.go b/backend/exec.go
index 6af92f7..1058f2f 100644
--- a/backend/exec.go
+++ b/backend/exec.go
@@ -19,6 +19,7 @@
 
 // ExecServer handles /e.
 type ExecServer struct {
+	execpb.UnimplementedExecServiceServer
 	Client execpb.ExecServiceClient
 }
 
diff --git a/backend/execlog.go b/backend/execlog.go
index 175e7ca..174f28d 100644
--- a/backend/execlog.go
+++ b/backend/execlog.go
@@ -17,6 +17,7 @@
 
 // ExeclogServer handles /sl.
 type ExeclogServer struct {
+	execlogpb.UnimplementedLogServiceServer
 	Client execlogpb.LogServiceClient
 }
 
diff --git a/backend/file.go b/backend/file.go
index 43d4d48..79ae1d4 100644
--- a/backend/file.go
+++ b/backend/file.go
@@ -19,6 +19,7 @@
 
 // FileServer handles /s and /l.
 type FileServer struct {
+	filepb.UnimplementedFileServiceServer
 	Client filepb.FileServiceClient
 }
 
diff --git a/cache/cache.go b/cache/cache.go
index e490428..017ecce 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -170,6 +170,7 @@
 
 // Cache represents key-value cache.
 type Cache struct {
+	cachepb.UnimplementedCacheServiceServer
 	mem memcache
 	gcs *gcs.Cache
 
diff --git a/cache/cache_test.go b/cache/cache_test.go
index 725f3c7..5bb5038 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -8,9 +8,9 @@
 	"context"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
 
 	pb "go.chromium.org/goma/server/proto/cache"
 )
diff --git a/cache/gcs/cache.go b/cache/gcs/cache.go
index d29446f..fcf91e7 100644
--- a/cache/gcs/cache.go
+++ b/cache/gcs/cache.go
@@ -36,6 +36,8 @@
 
 // Cache represents key-value cache using google cloud storage.
 type Cache struct {
+	pb.UnimplementedCacheServiceServer
+
 	bkt                 *storage.BucketHandle
 	AdmissionController AdmissionController
 	// should be accessed via stomic pkg.
diff --git a/cipd_manifest.txt b/cipd_manifest.txt
index 681c246..b91651b 100644
--- a/cipd_manifest.txt
+++ b/cipd_manifest.txt
@@ -13,9 +13,9 @@
 # https://chrome-infra-packages.appspot.com/
 
 # go
-infra/3pp/tools/go/${platform} version:1.16
+infra/3pp/tools/go/${platform} version:2@1.16.3
 
 # protoc
 # If the version you want is missing, please follow the instruction in:
 # https://chromium.googlesource.com/infra/infra/+/refs/heads/master/bootstrap/cipd/doc/infra/tools/protoc/
-infra/tools/protoc/${platform} protobuf_version:v3.15.3
+infra/tools/protoc/${platform} protobuf_version:v3.15.6
diff --git a/cipd_manifest.versions b/cipd_manifest.versions
index 1900f25..89f8a85 100644
--- a/cipd_manifest.versions
+++ b/cipd_manifest.versions
@@ -2,9 +2,9 @@
 # Do not modify manually. All changes will be overwritten.
 
 infra/3pp/tools/go/linux-amd64
-	version:1.16
-	MxMgv8pi7utBtJGyURlZNC03jAiV-hUbo0Qk7u9MNOEC
+	version:2@1.16.3
+	0BIvdJH6lhOo4yG3OFKu5psrrEjmw0KmDlfXyR4N0GcC
 
 infra/tools/protoc/linux-amd64
-	protobuf_version:v3.15.3
-	iybrJKcHxYG5uY9dj6Or1-r4ifJIY270CTA5c6EJI34C
+	protobuf_version:v3.15.6
+	HW_LwR3sFW08qVchbm2kz3OaOdOFmblSmmpmly6pDewC
diff --git a/cmd/exec_server/main.go b/cmd/exec_server/main.go
index 3e6b08f..25da2b8 100644
--- a/cmd/exec_server/main.go
+++ b/cmd/exec_server/main.go
@@ -25,7 +25,6 @@
 
 	"cloud.google.com/go/pubsub"
 	"cloud.google.com/go/storage"
-	"github.com/golang/protobuf/proto"
 	"github.com/googleapis/google-cloud-go-testing/storage/stiface"
 	"go.opencensus.io/plugin/ocgrpc"
 	"go.opencensus.io/stats"
@@ -37,6 +36,7 @@
 	bspb "google.golang.org/genproto/googleapis/bytestream"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
+	"google.golang.org/protobuf/encoding/prototext"
 
 	"go.chromium.org/goma/server/cache/redis"
 	"go.chromium.org/goma/server/command"
@@ -472,7 +472,7 @@
 	case *configMap != "":
 		go func() {
 			cm := &cmdpb.ConfigMap{}
-			err := proto.UnmarshalText(*configMap, cm)
+			err := prototext.Unmarshal([]byte(*configMap), cm)
 			if err != nil {
 				ready <- fmt.Errorf("parse configmap %q: %v", *configMap, err)
 				return
@@ -491,7 +491,7 @@
 	case *toolchainConfigBucket != "":
 		cm := &cmdpb.ConfigMap{}
 		if *configMap != "" {
-			err := proto.UnmarshalText(*configMap, cm)
+			err := prototext.Unmarshal([]byte(*configMap), cm)
 			if err != nil {
 				ready <- fmt.Errorf("parse configmap %q: %v", *configMap, err)
 				return
diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go
index c02a5fb..f68d1d4 100644
--- a/cmd/frontend/main.go
+++ b/cmd/frontend/main.go
@@ -17,7 +17,6 @@
 	"net/http"
 	"path/filepath"
 
-	"github.com/golang/protobuf/proto"
 	"go.opencensus.io/stats/view"
 	"go.opencensus.io/trace"
 	"go.opencensus.io/zpages"
@@ -25,6 +24,7 @@
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/encoding/prototext"
 
 	"go.chromium.org/goma/server/auth"
 	"go.chromium.org/goma/server/backend"
@@ -149,7 +149,7 @@
 	defer authConn.Close()
 
 	beCfg := &bepb.BackendConfig{}
-	err = proto.UnmarshalText(*backendConfig, beCfg)
+	err = prototext.Unmarshal([]byte(*backendConfig), beCfg)
 	if err != nil {
 		logger.Fatal(err)
 	}
diff --git a/cmd/goma_grpc_client/main.go b/cmd/goma_grpc_client/main.go
index 738e220..a48fa3b 100644
--- a/cmd/goma_grpc_client/main.go
+++ b/cmd/goma_grpc_client/main.go
@@ -21,11 +21,12 @@
 	"path/filepath"
 	"strings"
 
-	"github.com/golang/protobuf/proto"
 	"go.uber.org/zap"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/metadata"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/auth/account"
 	"go.chromium.org/goma/server/auth/enduser"
@@ -204,7 +205,7 @@
 	if err != nil {
 		fatalf("desc: %v", err)
 	}
-	err = proto.UnmarshalText(requestMsg, desc.req)
+	err = prototext.Unmarshal([]byte(requestMsg), desc.req)
 	if err != nil {
 		fatalf("request: %v", err)
 	}
@@ -221,5 +222,5 @@
 	if err != nil {
 		fatalf("call: %v", err)
 	}
-	fmt.Println("response:\n", proto.MarshalTextString(resp))
+	fmt.Println("response:\n", prototext.Format(resp))
 }
diff --git a/cmd/goma_replay/main.go b/cmd/goma_replay/main.go
index 5bd6fd7..80b4925 100644
--- a/cmd/goma_replay/main.go
+++ b/cmd/goma_replay/main.go
@@ -32,11 +32,11 @@
 	"syscall"
 	"time"
 
-	"github.com/golang/protobuf/proto"
 	"go.uber.org/zap"
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2/google"
 	googleoauth2 "google.golang.org/api/oauth2/v2"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	"go.chromium.org/goma/server/log"
diff --git a/cmd/remoteexec_proxy/main.go b/cmd/remoteexec_proxy/main.go
index 97bd04a..f4a220c 100644
--- a/cmd/remoteexec_proxy/main.go
+++ b/cmd/remoteexec_proxy/main.go
@@ -26,12 +26,12 @@
 
 	"cloud.google.com/go/storage"
 	rpb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
-	"github.com/golang/protobuf/proto"
 	"go.opencensus.io/plugin/ocgrpc"
 	"go.opencensus.io/trace"
 	"google.golang.org/api/option"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
+	"google.golang.org/protobuf/encoding/prototext"
 
 	"go.chromium.org/goma/server/auth"
 	"go.chromium.org/goma/server/auth/account"
@@ -52,6 +52,7 @@
 	cachepb "go.chromium.org/goma/server/proto/cache"
 	cmdpb "go.chromium.org/goma/server/proto/command"
 	execpb "go.chromium.org/goma/server/proto/exec"
+	execlogpb "go.chromium.org/goma/server/proto/execlog"
 	filepb "go.chromium.org/goma/server/proto/file"
 	"go.chromium.org/goma/server/remoteexec"
 	"go.chromium.org/goma/server/remoteexec/digest"
@@ -123,7 +124,9 @@
 	return c.Service.LookupFile(ctx, req)
 }
 
-type execlogService struct{}
+type execlogService struct {
+	execlogpb.UnimplementedLogServiceServer
+}
 
 func (c execlogService) SaveLog(ctx context.Context, req *gomapb.SaveLogReq) (*gomapb.SaveLogResp, error) {
 	return &gomapb.SaveLogResp{}, nil
@@ -168,6 +171,7 @@
 }
 
 type reExecServer struct {
+	execpb.UnimplementedExecServiceServer
 	re *remoteexec.Adapter
 }
 
@@ -179,6 +183,7 @@
 }
 
 type reFileServer struct {
+	filepb.UnimplementedFileServiceServer
 	s filepb.FileServiceServer
 }
 
@@ -243,7 +248,7 @@
 		return nil, err
 	}
 	resp := &cmdpb.ConfigResp{}
-	err = proto.UnmarshalText(string(b), resp)
+	err = prototext.Unmarshal(b, resp)
 	if err != nil {
 		return nil, err
 	}
@@ -477,8 +482,8 @@
 	mux := http.DefaultServeMux
 	frontend.Register(mux, frontend.Frontend{
 		Backend: localBackend{
-			ExecService: reExecServer{re},
-			FileService: reFileServer{fileServiceClient.Service},
+			ExecService: reExecServer{re: re},
+			FileService: reFileServer{s: fileServiceClient.Service},
 			Auth: &auth.Auth{
 				Client: authClient{Service: authService},
 			},
diff --git a/command/configmap.go b/command/configmap.go
index 1288458..1769e42 100644
--- a/command/configmap.go
+++ b/command/configmap.go
@@ -19,13 +19,14 @@
 
 	"cloud.google.com/go/pubsub"
 	"cloud.google.com/go/storage"
-	"github.com/golang/protobuf/proto"
-	"github.com/golang/protobuf/ptypes"
 	"github.com/googleapis/google-cloud-go-testing/storage/stiface"
 	"go.opencensus.io/stats"
 	"go.opencensus.io/stats/view"
 	"golang.org/x/sync/errgroup"
 	"google.golang.org/api/iterator"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+	"google.golang.org/protobuf/types/known/timestamppb"
 
 	"go.chromium.org/goma/server/log"
 	cmdpb "go.chromium.org/goma/server/proto/command"
@@ -231,7 +232,7 @@
 	if err != nil {
 		return nil, err
 	}
-	err = proto.UnmarshalText(string(buf), c.ConfigMap)
+	err = prototext.Unmarshal(buf, c.ConfigMap)
 	if err != nil {
 		return nil, err
 	}
@@ -740,10 +741,7 @@
 			if err != nil {
 				return err
 			}
-			ts, err := ptypes.TimestampProto(attrs.Updated)
-			if err != nil {
-				return err
-			}
+			ts := timestamppb.New(attrs.Updated)
 			if err = checkSelector(rc, d.Selector); err != nil {
 				logger.Errorf("selector in %s/%s: %v", bucket, attrs.Name, err)
 				return nil
diff --git a/command/descriptor/descriptor.go b/command/descriptor/descriptor.go
index 2966802..f50a6db 100644
--- a/command/descriptor/descriptor.go
+++ b/command/descriptor/descriptor.go
@@ -63,6 +63,7 @@
 	// compiler specific
 	// https://clang.llvm.org/docs/CrossCompilation.html#target-triple
 	ClangNeedTarget bool // true if -target is needed.
+	WindowsCross    bool
 }
 
 // Runner runs command and get combined output.
@@ -113,6 +114,16 @@
 			return nil, fmt.Errorf("need_target=true for non clang: %s", sel.Name)
 		}
 	}
+	if c.WindowsCross {
+		switch sel.Name {
+		case "clang-cl", "clang", "clang++":
+			// clang, clang++ for pnacl-clang
+			cd.Cross.WindowsCross = true
+		default:
+			// gcc, g++ for nacl-gcc but we disable them in client side due to ELF-32
+			return nil, fmt.Errorf("windows_cross=true is not supported for %s", sel.Name)
+		}
+	}
 
 	// When filename starts with "/", it means the binary is specified with absolute path.
 	// It implies the binary is not relocatable.
diff --git a/command/descriptor/load.go b/command/descriptor/load.go
index 62c39bc..acfccd3 100644
--- a/command/descriptor/load.go
+++ b/command/descriptor/load.go
@@ -8,7 +8,7 @@
 	"io/ioutil"
 	"path/filepath"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	pb "go.chromium.org/goma/server/proto/command"
 )
diff --git a/command/descriptor/posixpath/posixpath.go b/command/descriptor/posixpath/posixpath.go
index a4b59be..ed835a3 100644
--- a/command/descriptor/posixpath/posixpath.go
+++ b/command/descriptor/posixpath/posixpath.go
@@ -13,6 +13,8 @@
 // FilePath provides posix filepath.
 type FilePath struct{}
 
+func (FilePath) String() string { return "posix.filepath" }
+
 func (FilePath) IsAbs(path string) bool     { return IsAbs(path) }
 func (FilePath) Base(path string) string    { return Base(path) }
 func (FilePath) Dir(path string) string     { return Dir(path) }
diff --git a/command/descriptor/relocate.go b/command/descriptor/relocate.go
index 78a0b00..6daa7de 100644
--- a/command/descriptor/relocate.go
+++ b/command/descriptor/relocate.go
@@ -7,7 +7,7 @@
 import (
 	"fmt"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/command/descriptor/posixpath"
 	"go.chromium.org/goma/server/command/descriptor/winpath"
diff --git a/command/descriptor/save.go b/command/descriptor/save.go
index 508aa7c..ff43fcb 100644
--- a/command/descriptor/save.go
+++ b/command/descriptor/save.go
@@ -8,7 +8,7 @@
 	"io/ioutil"
 	"path/filepath"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/hash"
 
diff --git a/command/descriptor/winpath/winpath.go b/command/descriptor/winpath/winpath.go
index 6e22f98..526eb2f 100644
--- a/command/descriptor/winpath/winpath.go
+++ b/command/descriptor/winpath/winpath.go
@@ -21,6 +21,8 @@
 // FilePath provides win filepath.
 type FilePath struct{}
 
+func (FilePath) String() string { return "win.filepath" }
+
 func (FilePath) IsAbs(path string) bool     { return IsAbs(path) }
 func (FilePath) Base(path string) string    { return Base(path) }
 func (FilePath) Dir(path string) string     { return Dir(path) }
@@ -136,6 +138,13 @@
 	return elems
 }
 
+// ToPosix converts fname into posix filepath.
+// It drops drive letters.
+func ToPosix(fname string) string {
+	_, path := splitDrive(fname)
+	return strings.ReplaceAll(path, "\\", "/")
+}
+
 func fixPathSep(path string, oldSep, newSep byte) string {
 	if !strings.ContainsRune(path, rune(oldSep)) {
 		return path
diff --git a/command/descriptor/winpath/winpath_test.go b/command/descriptor/winpath/winpath_test.go
index 13a9cd1..bd5f1f4 100644
--- a/command/descriptor/winpath/winpath_test.go
+++ b/command/descriptor/winpath/winpath_test.go
@@ -364,6 +364,28 @@
 
 }
 
+func TestToPosix(t *testing.T) {
+	for _, tc := range []struct {
+		path string
+		want string
+	}{
+		{"a", "a"},
+		{`a\b`, "a/b"},
+		{"a/b", "a/b"},
+		{`a\b\c`, "a/b/c"},
+		{`a/b\c`, "a/b/c"},
+		{`\a\b\c`, "/a/b/c"},
+		{`c:\a`, "/a"},
+		{`c:\a\b\c`, "/a/b/c"},
+		{`c:a\b\c`, "a/b/c"},
+	} {
+		got := ToPosix(tc.path)
+		if got != tc.want {
+			t.Errorf("ToPosix(%q)=%q; want=%q", tc.path, got, tc.want)
+		}
+	}
+}
+
 func BenchmarkCleanAlreadyClean(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		Clean("../abc/def/ghi")
diff --git a/command/normalizer/normalizer.go b/command/normalizer/normalizer.go
index eeeeef8..37ed333 100644
--- a/command/normalizer/normalizer.go
+++ b/command/normalizer/normalizer.go
@@ -6,9 +6,9 @@
 	"fmt"
 	"strings"
 
-	cmdpb "go.chromium.org/goma/server/proto/command"
+	"google.golang.org/protobuf/proto"
 
-	"github.com/golang/protobuf/proto"
+	cmdpb "go.chromium.org/goma/server/proto/command"
 )
 
 type target struct {
diff --git a/command/normalizer/normalizer_test.go b/command/normalizer/normalizer_test.go
index 0e639e5..08199e7 100644
--- a/command/normalizer/normalizer_test.go
+++ b/command/normalizer/normalizer_test.go
@@ -6,7 +6,7 @@
 	"reflect"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	cmdpb "go.chromium.org/goma/server/proto/command"
 )
@@ -432,6 +432,10 @@
 			want:  "x86_64-darwin",
 		},
 		{
+			input: "le32-unknown-nacl",
+			want:  "le32-nacl",
+		},
+		{
 			input:     "x86_64-unknown-linux-gnu-should-parse-error",
 			wantError: true,
 		},
diff --git a/exec/inventory.go b/exec/inventory.go
index fab04f4..ff5107b 100644
--- a/exec/inventory.go
+++ b/exec/inventory.go
@@ -13,15 +13,15 @@
 	"sync"
 	"time"
 
-	"github.com/golang/protobuf/proto"
-	"github.com/golang/protobuf/ptypes"
 	"go.opencensus.io/stats"
 	"go.opencensus.io/stats/view"
 	"go.opencensus.io/tag"
 	"go.opencensus.io/trace"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/auth/enduser"
 	"go.chromium.org/goma/server/command/descriptor"
+	"go.chromium.org/goma/server/command/descriptor/winpath"
 	"go.chromium.org/goma/server/command/normalizer"
 	"go.chromium.org/goma/server/log"
 	gomapb "go.chromium.org/goma/server/proto/api"
@@ -224,7 +224,7 @@
 			m = newConfigs[addr]
 		}
 		m[sel] = cfg
-		logger.Infof("configure %s: %s", sel, addr)
+		logger.Infof("configure %s: %s => %v", sel, addr, cfg)
 	}
 	in.mu.Lock()
 	defer in.mu.Unlock()
@@ -365,17 +365,23 @@
 		return nil, nil, fmt.Errorf("no matching backend found for %v", cmdSel)
 	}
 
+	for _, cfg := range ccfgs {
+		err := cfg.GetBuildInfo().GetTimestamp().CheckValid()
+		if err != nil {
+			logger.Warnf("invalid timestamp in %v: %v", cfg, err)
+		}
+	}
+
 	// 3. choose the latest compiler config.
 	sort.Slice(ccfgs, func(i, j int) bool {
-		ti, err := ptypes.Timestamp(ccfgs[i].GetBuildInfo().GetTimestamp())
-		if err != nil {
-			logger.Warnf("strange timestamp: %v", err)
-			ti = time.Unix(0, 0)
+		var ti, tj time.Time
+		tsi := ccfgs[i].GetBuildInfo().GetTimestamp()
+		if tsi.IsValid() {
+			ti = tsi.AsTime()
 		}
-		tj, err := ptypes.Timestamp(ccfgs[j].GetBuildInfo().GetTimestamp())
-		if err != nil {
-			logger.Warnf("strange timestamp: %v", err)
-			tj = time.Unix(0, 0)
+		tsj := ccfgs[j].GetBuildInfo().GetTimestamp()
+		if tsj.IsValid() {
+			tj = tsj.AsTime()
 		}
 		return ti.Before(tj)
 	})
@@ -440,6 +446,9 @@
 	}
 	setPicked(resp.Result, cfg, path2sel)
 
+	if cfg.CmdDescriptor.GetCross().GetWindowsCross() {
+		cmdPath = winpath.ToPosix(cmdPath)
+	}
 	cmdFiles, err := descriptor.RelocateCmd(cmdPath, cfg.CmdDescriptor.Setup, subprogSetups)
 	if err != nil {
 		resp.Error = gomapb.ExecResp_BAD_REQUEST.Enum()
diff --git a/execlog/service.go b/execlog/service.go
index e333f80..0b73115 100644
--- a/execlog/service.go
+++ b/execlog/service.go
@@ -14,6 +14,7 @@
 
 	"go.chromium.org/goma/server/log"
 	gomapb "go.chromium.org/goma/server/proto/api"
+	execlogpb "go.chromium.org/goma/server/proto/execlog"
 )
 
 // DefaultMaxReqMsgSize is max request message size for execlog service.
@@ -200,6 +201,7 @@
 
 // Service represents goma execlog service.
 type Service struct {
+	execlogpb.UnimplementedLogServiceServer
 }
 
 func osFamily(e *gomapb.ExecLog) string {
diff --git a/file/cache.go b/file/cache.go
index e8a98c1..05a9b2d 100644
--- a/file/cache.go
+++ b/file/cache.go
@@ -10,8 +10,8 @@
 	"io/ioutil"
 	"path/filepath"
 
-	"github.com/golang/protobuf/proto"
 	"google.golang.org/grpc"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/hash"
 	"go.chromium.org/goma/server/log"
diff --git a/file/disk.go b/file/disk.go
index 877dd98..a3037f6 100644
--- a/file/disk.go
+++ b/file/disk.go
@@ -11,7 +11,7 @@
 	"io"
 	"os"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/hash"
 	gomapb "go.chromium.org/goma/server/proto/api"
diff --git a/file/service.go b/file/service.go
index 8f4f484..5ec85f8 100644
--- a/file/service.go
+++ b/file/service.go
@@ -9,17 +9,18 @@
 	"sync"
 	"time"
 
-	"github.com/golang/protobuf/proto"
 	"go.opencensus.io/trace"
 	"golang.org/x/sync/errgroup"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/hash"
 	"go.chromium.org/goma/server/log"
 
 	gomapb "go.chromium.org/goma/server/proto/api"
 	cachepb "go.chromium.org/goma/server/proto/cache"
+	filepb "go.chromium.org/goma/server/proto/file"
 )
 
 const (
@@ -31,6 +32,7 @@
 
 // Service represents goma file service.
 type Service struct {
+	filepb.UnimplementedFileServiceServer
 	// Cache is a fileblob storage.
 	Cache cachepb.CacheServiceClient
 }
diff --git a/go.mod b/go.mod
index 68ce81e..93f6fa3 100644
--- a/go.mod
+++ b/go.mod
@@ -3,17 +3,17 @@
 go 1.12
 
 require (
-	cloud.google.com/go v0.78.0
-	cloud.google.com/go/pubsub v1.10.0
-	cloud.google.com/go/storage v1.13.0
+	cloud.google.com/go v0.80.0
+	cloud.google.com/go/pubsub v1.10.1
+	cloud.google.com/go/storage v1.14.0
 	contrib.go.opencensus.io/exporter/stackdriver v0.13.5
 	github.com/bazelbuild/remote-apis v0.0.0-20200904140912-1aeb39973178
 	github.com/bazelbuild/remote-apis-sdks v0.0.0-20201118210229-b732553f9d45
 	github.com/fsnotify/fsnotify v1.4.9
 	github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
-	github.com/golang/protobuf v1.4.3
+	github.com/golang/protobuf v1.5.1
 	github.com/gomodule/redigo v1.8.4
-	github.com/google/go-cmp v0.5.4
+	github.com/google/go-cmp v0.5.5
 	github.com/google/uuid v1.2.0
 	github.com/googleapis/gax-go/v2 v2.0.5
 	github.com/googleapis/google-cloud-go-testing v0.0.0-20190904031503-2d24dde44ba5
@@ -21,11 +21,12 @@
 	go.opencensus.io v0.23.0
 	go.uber.org/zap v1.16.0
 	golang.org/x/build v0.0.0-20191031202223-0706ea4fce0c
-	golang.org/x/net v0.0.0-20210119194325-5f4716e94777
-	golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99
-	golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
-	google.golang.org/api v0.40.0
-	google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c
+	golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4
+	golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84
+	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
+	google.golang.org/api v0.43.0
+	google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a
 	google.golang.org/grpc v1.36.0
-	google.golang.org/protobuf v1.25.0
+	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect
+	google.golang.org/protobuf v1.26.0
 )
diff --git a/go.sum b/go.sum
index c40eb21..db7c6b4 100644
--- a/go.sum
+++ b/go.sum
@@ -17,8 +17,10 @@
 cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
 cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
 cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
-cloud.google.com/go v0.78.0 h1:oKpsiyKMfVpwR3zSAkQixGzlVE5ovitBuO0qSmCf0bI=
 cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.80.0 h1:kAdyAMrj9CjqOSGiluseVjIgAyQ3uxADYtUYR6MwYeY=
+cloud.google.com/go v0.80.0/go.mod h1:fqpb6QRi1CFGAMXDoE72G+b+Ybv7dMB/T1tbExDHktI=
 cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
 cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
 cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -31,15 +33,15 @@
 cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
 cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
 cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
-cloud.google.com/go/pubsub v1.10.0 h1:JK22g5uNpscGPthjJE/D0siWtA6UlU4Cb6pLcyJkzyQ=
-cloud.google.com/go/pubsub v1.10.0/go.mod h1:eNpTrkOy7dCpkNyaSNetMa6udbgecJMd0ZsTJS/cuNo=
+cloud.google.com/go/pubsub v1.10.1 h1:ysSVlI7vw1doId/jatBqfbbMUjFVe29oiHHc2fpSzf4=
+cloud.google.com/go/pubsub v1.10.1/go.mod h1:P5XeG4KyW/T3e/DqxdTTLZGMNAW42PzRs7haJ5gdhcc=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.13.0 h1:amPvhCOI+Hltp6rPu+62YdwhIrjf+34PKVAL4HwgYwk=
-cloud.google.com/go/storage v1.13.0/go.mod h1:pqFyBUK3zZqMIIU5+8NaZq6/Ma3ClgUg9Hv5jfuJnvo=
+cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU=
+cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 contrib.go.opencensus.io/exporter/stackdriver v0.13.5 h1:TNaexHK16gPUoc7uzELKOU7JULqccn1NDuqUxmxSqfo=
 contrib.go.opencensus.io/exporter/stackdriver v0.13.5/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
@@ -122,8 +124,9 @@
 github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
 github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -137,8 +140,10 @@
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1 h1:jAbXjIeW2ZSW2AwFxlGTDoc2CjI2XujLkV3ArsZFCvc=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg=
 github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
@@ -159,8 +164,9 @@
 github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
 github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
@@ -178,8 +184,9 @@
 github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210122040257-d980be63207e h1:41CTEDOoUXp+FxbPYuEhth5dE/s+NT1cRuhSoqhBQ1E=
 github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5 h1:zIaiqGYDQwa4HVx5wGRTXbx38Pqxjemn4BP98wpzpXo=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -359,8 +366,10 @@
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 h1:b0LrWgu8+q7z4J+0Y3Umo5q1dL7NXBkKBWkaVkAq17E=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -370,9 +379,10 @@
 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os=
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84 h1:duBc5zuJsmJXYOVVE/6PxejI+N3AaCqKjtsoLn1Je5Q=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -383,8 +393,9 @@
 golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -421,9 +432,13 @@
 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43 h1:SgQ6LNaYJU0JIuEHv9+s6EbhSCwYeAf5Yvj6lpYlqAE=
 golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210314195730-07df6a141424/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -436,7 +451,7 @@
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -514,10 +529,11 @@
 google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
 google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.38.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.39.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
-google.golang.org/api v0.40.0 h1:uWrpz12dpVPn7cojP82mk02XDgTJLDPc2KbVTxrWb4A=
 google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.42.0/go.mod h1:+Oj4s6ch2SEGtPjGqfUfZonBH0GjQH89gTeKKAEGZKI=
+google.golang.org/api v0.43.0 h1:4sAyIHT6ZohtAQDoxws+ez7bROYmUlOVvsUscYCDTqA=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -563,10 +579,15 @@
 google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c h1:7A9LQhrZmuCPI79/sYSbscFqBp4XFYf6oaIQuV1xji4=
 google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210302174412-5ede27ff9881/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210312152112-fc591d9ea70f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a h1:XVaQ1+BDKvrRcgppHhtAaniHCKyV5xJAvymwsPHHFaE=
+google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a/go.mod h1:f2Bd7+2PlaVKmvKQ52aspJZXIDaRQBVdOOBfJ5i8OEs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -586,6 +607,8 @@
 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.36.0 h1:o1bcQ6imQMIOpdrO3SWf2z5RV72WbDwdXuK0MDlc8As=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -595,8 +618,10 @@
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/hash/hash.go b/hash/hash.go
index 708c85a..4aee98c 100644
--- a/hash/hash.go
+++ b/hash/hash.go
@@ -9,10 +9,12 @@
 	"crypto/hmac"
 	"crypto/sha256"
 	"encoding/hex"
+	"fmt"
 	"io"
 	"os"
+	"reflect"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 )
 
 // SHA256HMAC returns a hexdecimal representation of the SHA256 hmac of the given two content.
@@ -30,6 +32,12 @@
 
 // SHA256Proto returns a hexdecimal representation of the SHA256 hash of the given protocol buffer.
 func SHA256Proto(m proto.Message) (string, error) {
+	// github.com/golang/protobuf/proto's Marshal returned error for nil
+	// message, but google.golang.org/protobuf/proto returns nil err.
+	// To preserve behavior of SHA256Proto, check m is nil-pointer or not.
+	if !reflect.ValueOf(m).IsValid() {
+		return "", fmt.Errorf("nil %T", m)
+	}
 	b, err := proto.Marshal(m)
 	if err != nil {
 		return "", err
diff --git a/httprpc/authdb/authdb.go b/httprpc/authdb/authdb.go
index bff95cb..05eea6e 100644
--- a/httprpc/authdb/authdb.go
+++ b/httprpc/authdb/authdb.go
@@ -9,7 +9,7 @@
 	"context"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	pb "go.chromium.org/goma/server/proto/auth"
diff --git a/httprpc/client.go b/httprpc/client.go
index 543df86..fb18ed9 100644
--- a/httprpc/client.go
+++ b/httprpc/client.go
@@ -13,10 +13,10 @@
 	"io/ioutil"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
 	"go.opencensus.io/trace"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
 )
 
 // Client is httprpc client.
diff --git a/httprpc/e2e_test.go b/httprpc/e2e_test.go
index a6f51a8..af739d4 100644
--- a/httprpc/e2e_test.go
+++ b/httprpc/e2e_test.go
@@ -11,7 +11,7 @@
 	"net/http/httptest"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 
diff --git a/httprpc/exec/exec.go b/httprpc/exec/exec.go
index 44b308e..38a529c 100644
--- a/httprpc/exec/exec.go
+++ b/httprpc/exec/exec.go
@@ -11,7 +11,7 @@
 	"context"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	pb "go.chromium.org/goma/server/proto/api"
diff --git a/httprpc/execlog/execlog.go b/httprpc/execlog/execlog.go
index 7f6b7a2..c380fc8 100644
--- a/httprpc/execlog/execlog.go
+++ b/httprpc/execlog/execlog.go
@@ -11,7 +11,7 @@
 	"context"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	pb "go.chromium.org/goma/server/proto/api"
diff --git a/httprpc/file/file.go b/httprpc/file/file.go
index 7437c92..76c845f 100644
--- a/httprpc/file/file.go
+++ b/httprpc/file/file.go
@@ -11,7 +11,7 @@
 	"context"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	pb "go.chromium.org/goma/server/proto/api"
diff --git a/httprpc/server.go b/httprpc/server.go
index 87f22cd..c8a4a6b 100644
--- a/httprpc/server.go
+++ b/httprpc/server.go
@@ -15,12 +15,12 @@
 	"strings"
 	"time"
 
-	"github.com/golang/protobuf/proto"
 	"go.opencensus.io/trace"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/status"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/log"
 	"go.chromium.org/goma/server/rpc"
diff --git a/httprpc/server_test.go b/httprpc/server_test.go
index cfdcf57..6989ad3 100644
--- a/httprpc/server_test.go
+++ b/httprpc/server_test.go
@@ -13,8 +13,8 @@
 	"net/http/httptest"
 	"testing"
 
-	"github.com/golang/protobuf/proto"
 	healthpb "google.golang.org/grpc/health/grpc_health_v1"
+	"google.golang.org/protobuf/proto"
 
 	pb "go.chromium.org/goma/server/proto/auth"
 )
diff --git a/httprpc/settings/settings.go b/httprpc/settings/settings.go
index bb98258..b79457b 100644
--- a/httprpc/settings/settings.go
+++ b/httprpc/settings/settings.go
@@ -9,7 +9,7 @@
 	"context"
 	"net/http"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/httprpc"
 	pb "go.chromium.org/goma/server/proto/settings"
diff --git a/proto/api/goma_data.pb.go b/proto/api/goma_data.pb.go
index f7e857c..a3dff34 100644
--- a/proto/api/goma_data.pb.go
+++ b/proto/api/goma_data.pb.go
@@ -6,14 +6,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: api/goma_data.proto
 
 package api
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
@@ -28,10 +27,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type FileBlob_BlobType int32
 
 const (
diff --git a/proto/api/goma_log.pb.go b/proto/api/goma_log.pb.go
index 8a4e5cd..b3aac8c 100644
--- a/proto/api/goma_log.pb.go
+++ b/proto/api/goma_log.pb.go
@@ -7,14 +7,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: api/goma_log.proto
 
 package api
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -28,10 +27,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type ExecLog_AuthenticationType int32
 
 const (
diff --git a/proto/auth/acl.pb.go b/proto/auth/acl.pb.go
index 1d1f0e1..c2840ae 100644
--- a/proto/auth/acl.pb.go
+++ b/proto/auth/acl.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: auth/acl.proto
 
 package auth
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 // Group defines a group of users that shares the same service account.
 // Different groups may share a service account.
 type Group struct {
diff --git a/proto/auth/auth.pb.go b/proto/auth/auth.pb.go
index 6e8804b..0b53a69 100644
--- a/proto/auth/auth.pb.go
+++ b/proto/auth/auth.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: auth/auth.proto
 
 package auth
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
@@ -26,10 +25,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type AuthReq struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
diff --git a/proto/auth/auth_service.pb.go b/proto/auth/auth_service.pb.go
index cb5dd05..dadb150 100644
--- a/proto/auth/auth_service.pb.go
+++ b/proto/auth/auth_service.pb.go
@@ -4,18 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: auth/auth_service.proto
 
 package auth
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -28,10 +23,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_auth_auth_service_proto protoreflect.FileDescriptor
 
 var file_auth_auth_service_proto_rawDesc = []byte{
@@ -85,83 +76,3 @@
 	file_auth_auth_service_proto_goTypes = nil
 	file_auth_auth_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// AuthServiceClient is the client API for AuthService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type AuthServiceClient interface {
-	Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*AuthResp, error)
-}
-
-type authServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
-	return &authServiceClient{cc}
-}
-
-func (c *authServiceClient) Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*AuthResp, error) {
-	out := new(AuthResp)
-	err := c.cc.Invoke(ctx, "/auth.AuthService/Auth", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// AuthServiceServer is the server API for AuthService service.
-type AuthServiceServer interface {
-	Auth(context.Context, *AuthReq) (*AuthResp, error)
-}
-
-// UnimplementedAuthServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedAuthServiceServer struct {
-}
-
-func (*UnimplementedAuthServiceServer) Auth(context.Context, *AuthReq) (*AuthResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Auth not implemented")
-}
-
-func RegisterAuthServiceServer(s *grpc.Server, srv AuthServiceServer) {
-	s.RegisterService(&_AuthService_serviceDesc, srv)
-}
-
-func _AuthService_Auth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(AuthReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(AuthServiceServer).Auth(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/auth.AuthService/Auth",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(AuthServiceServer).Auth(ctx, req.(*AuthReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _AuthService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "auth.AuthService",
-	HandlerType: (*AuthServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "Auth",
-			Handler:    _AuthService_Auth_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "auth/auth_service.proto",
-}
diff --git a/proto/auth/auth_service_grpc.pb.go b/proto/auth/auth_service_grpc.pb.go
new file mode 100644
index 0000000..cf4324a
--- /dev/null
+++ b/proto/auth/auth_service_grpc.pb.go
@@ -0,0 +1,101 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package auth
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// AuthServiceClient is the client API for AuthService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type AuthServiceClient interface {
+	Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*AuthResp, error)
+}
+
+type authServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
+	return &authServiceClient{cc}
+}
+
+func (c *authServiceClient) Auth(ctx context.Context, in *AuthReq, opts ...grpc.CallOption) (*AuthResp, error) {
+	out := new(AuthResp)
+	err := c.cc.Invoke(ctx, "/auth.AuthService/Auth", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// AuthServiceServer is the server API for AuthService service.
+// All implementations must embed UnimplementedAuthServiceServer
+// for forward compatibility
+type AuthServiceServer interface {
+	Auth(context.Context, *AuthReq) (*AuthResp, error)
+	mustEmbedUnimplementedAuthServiceServer()
+}
+
+// UnimplementedAuthServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedAuthServiceServer struct {
+}
+
+func (UnimplementedAuthServiceServer) Auth(context.Context, *AuthReq) (*AuthResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Auth not implemented")
+}
+func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
+
+// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AuthServiceServer will
+// result in compilation errors.
+type UnsafeAuthServiceServer interface {
+	mustEmbedUnimplementedAuthServiceServer()
+}
+
+func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
+	s.RegisterService(&AuthService_ServiceDesc, srv)
+}
+
+func _AuthService_Auth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(AuthReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(AuthServiceServer).Auth(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/auth.AuthService/Auth",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(AuthServiceServer).Auth(ctx, req.(*AuthReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AuthService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "auth.AuthService",
+	HandlerType: (*AuthServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Auth",
+			Handler:    _AuthService_Auth_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "auth/auth_service.proto",
+}
diff --git a/proto/auth/authdb.pb.go b/proto/auth/authdb.pb.go
index dde45e8..1d8f824 100644
--- a/proto/auth/authdb.pb.go
+++ b/proto/auth/authdb.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: auth/authdb.proto
 
 package auth
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type CheckMembershipReq struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
diff --git a/proto/auth/authdb_service.pb.go b/proto/auth/authdb_service.pb.go
index 48ac168..93e635d 100644
--- a/proto/auth/authdb_service.pb.go
+++ b/proto/auth/authdb_service.pb.go
@@ -4,18 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: auth/authdb_service.proto
 
 package auth
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -28,10 +23,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_auth_authdb_service_proto protoreflect.FileDescriptor
 
 var file_auth_authdb_service_proto_rawDesc = []byte{
@@ -88,83 +79,3 @@
 	file_auth_authdb_service_proto_goTypes = nil
 	file_auth_authdb_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// AuthDBServiceClient is the client API for AuthDBService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type AuthDBServiceClient interface {
-	CheckMembership(ctx context.Context, in *CheckMembershipReq, opts ...grpc.CallOption) (*CheckMembershipResp, error)
-}
-
-type authDBServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewAuthDBServiceClient(cc grpc.ClientConnInterface) AuthDBServiceClient {
-	return &authDBServiceClient{cc}
-}
-
-func (c *authDBServiceClient) CheckMembership(ctx context.Context, in *CheckMembershipReq, opts ...grpc.CallOption) (*CheckMembershipResp, error) {
-	out := new(CheckMembershipResp)
-	err := c.cc.Invoke(ctx, "/auth.AuthDBService/CheckMembership", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// AuthDBServiceServer is the server API for AuthDBService service.
-type AuthDBServiceServer interface {
-	CheckMembership(context.Context, *CheckMembershipReq) (*CheckMembershipResp, error)
-}
-
-// UnimplementedAuthDBServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedAuthDBServiceServer struct {
-}
-
-func (*UnimplementedAuthDBServiceServer) CheckMembership(context.Context, *CheckMembershipReq) (*CheckMembershipResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method CheckMembership not implemented")
-}
-
-func RegisterAuthDBServiceServer(s *grpc.Server, srv AuthDBServiceServer) {
-	s.RegisterService(&_AuthDBService_serviceDesc, srv)
-}
-
-func _AuthDBService_CheckMembership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(CheckMembershipReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(AuthDBServiceServer).CheckMembership(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/auth.AuthDBService/CheckMembership",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(AuthDBServiceServer).CheckMembership(ctx, req.(*CheckMembershipReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _AuthDBService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "auth.AuthDBService",
-	HandlerType: (*AuthDBServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "CheckMembership",
-			Handler:    _AuthDBService_CheckMembership_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "auth/authdb_service.proto",
-}
diff --git a/proto/auth/authdb_service_grpc.pb.go b/proto/auth/authdb_service_grpc.pb.go
new file mode 100644
index 0000000..03f3929
--- /dev/null
+++ b/proto/auth/authdb_service_grpc.pb.go
@@ -0,0 +1,101 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package auth
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// AuthDBServiceClient is the client API for AuthDBService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type AuthDBServiceClient interface {
+	CheckMembership(ctx context.Context, in *CheckMembershipReq, opts ...grpc.CallOption) (*CheckMembershipResp, error)
+}
+
+type authDBServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewAuthDBServiceClient(cc grpc.ClientConnInterface) AuthDBServiceClient {
+	return &authDBServiceClient{cc}
+}
+
+func (c *authDBServiceClient) CheckMembership(ctx context.Context, in *CheckMembershipReq, opts ...grpc.CallOption) (*CheckMembershipResp, error) {
+	out := new(CheckMembershipResp)
+	err := c.cc.Invoke(ctx, "/auth.AuthDBService/CheckMembership", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// AuthDBServiceServer is the server API for AuthDBService service.
+// All implementations must embed UnimplementedAuthDBServiceServer
+// for forward compatibility
+type AuthDBServiceServer interface {
+	CheckMembership(context.Context, *CheckMembershipReq) (*CheckMembershipResp, error)
+	mustEmbedUnimplementedAuthDBServiceServer()
+}
+
+// UnimplementedAuthDBServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedAuthDBServiceServer struct {
+}
+
+func (UnimplementedAuthDBServiceServer) CheckMembership(context.Context, *CheckMembershipReq) (*CheckMembershipResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method CheckMembership not implemented")
+}
+func (UnimplementedAuthDBServiceServer) mustEmbedUnimplementedAuthDBServiceServer() {}
+
+// UnsafeAuthDBServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AuthDBServiceServer will
+// result in compilation errors.
+type UnsafeAuthDBServiceServer interface {
+	mustEmbedUnimplementedAuthDBServiceServer()
+}
+
+func RegisterAuthDBServiceServer(s grpc.ServiceRegistrar, srv AuthDBServiceServer) {
+	s.RegisterService(&AuthDBService_ServiceDesc, srv)
+}
+
+func _AuthDBService_CheckMembership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(CheckMembershipReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(AuthDBServiceServer).CheckMembership(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/auth.AuthDBService/CheckMembership",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(AuthDBServiceServer).CheckMembership(ctx, req.(*CheckMembershipReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// AuthDBService_ServiceDesc is the grpc.ServiceDesc for AuthDBService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AuthDBService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "auth.AuthDBService",
+	HandlerType: (*AuthDBServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "CheckMembership",
+			Handler:    _AuthDBService_CheckMembership_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "auth/authdb_service.proto",
+}
diff --git a/proto/backend/backend.pb.go b/proto/backend/backend.pb.go
index 25d6f4a..907f33a 100644
--- a/proto/backend/backend.pb.go
+++ b/proto/backend/backend.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: backend/backend.proto
 
 package backend
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type LocalBackend struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
diff --git a/proto/cache/cache.pb.go b/proto/cache/cache.pb.go
index 8f48176..d241d6e 100644
--- a/proto/cache/cache.pb.go
+++ b/proto/cache/cache.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: cache/cache.proto
 
 package cache
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type KV struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
diff --git a/proto/cache/cache_service.pb.go b/proto/cache/cache_service.pb.go
index dc188dc..16d0eda 100644
--- a/proto/cache/cache_service.pb.go
+++ b/proto/cache/cache_service.pb.go
@@ -4,18 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: cache/cache_service.proto
 
 package cache
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -28,10 +23,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_cache_cache_service_proto protoreflect.FileDescriptor
 
 var file_cache_cache_service_proto_rawDesc = []byte{
@@ -92,119 +83,3 @@
 	file_cache_cache_service_proto_goTypes = nil
 	file_cache_cache_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// CacheServiceClient is the client API for CacheService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type CacheServiceClient interface {
-	Get(ctx context.Context, in *GetReq, opts ...grpc.CallOption) (*GetResp, error)
-	Put(ctx context.Context, in *PutReq, opts ...grpc.CallOption) (*PutResp, error)
-}
-
-type cacheServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewCacheServiceClient(cc grpc.ClientConnInterface) CacheServiceClient {
-	return &cacheServiceClient{cc}
-}
-
-func (c *cacheServiceClient) Get(ctx context.Context, in *GetReq, opts ...grpc.CallOption) (*GetResp, error) {
-	out := new(GetResp)
-	err := c.cc.Invoke(ctx, "/cache.CacheService/Get", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *cacheServiceClient) Put(ctx context.Context, in *PutReq, opts ...grpc.CallOption) (*PutResp, error) {
-	out := new(PutResp)
-	err := c.cc.Invoke(ctx, "/cache.CacheService/Put", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// CacheServiceServer is the server API for CacheService service.
-type CacheServiceServer interface {
-	Get(context.Context, *GetReq) (*GetResp, error)
-	Put(context.Context, *PutReq) (*PutResp, error)
-}
-
-// UnimplementedCacheServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedCacheServiceServer struct {
-}
-
-func (*UnimplementedCacheServiceServer) Get(context.Context, *GetReq) (*GetResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
-}
-func (*UnimplementedCacheServiceServer) Put(context.Context, *PutReq) (*PutResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Put not implemented")
-}
-
-func RegisterCacheServiceServer(s *grpc.Server, srv CacheServiceServer) {
-	s.RegisterService(&_CacheService_serviceDesc, srv)
-}
-
-func _CacheService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(GetReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(CacheServiceServer).Get(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/cache.CacheService/Get",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(CacheServiceServer).Get(ctx, req.(*GetReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _CacheService_Put_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(PutReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(CacheServiceServer).Put(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/cache.CacheService/Put",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(CacheServiceServer).Put(ctx, req.(*PutReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _CacheService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "cache.CacheService",
-	HandlerType: (*CacheServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "Get",
-			Handler:    _CacheService_Get_Handler,
-		},
-		{
-			MethodName: "Put",
-			Handler:    _CacheService_Put_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "cache/cache_service.proto",
-}
diff --git a/proto/cache/cache_service_grpc.pb.go b/proto/cache/cache_service_grpc.pb.go
new file mode 100644
index 0000000..3b8d73d
--- /dev/null
+++ b/proto/cache/cache_service_grpc.pb.go
@@ -0,0 +1,137 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package cache
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// CacheServiceClient is the client API for CacheService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type CacheServiceClient interface {
+	Get(ctx context.Context, in *GetReq, opts ...grpc.CallOption) (*GetResp, error)
+	Put(ctx context.Context, in *PutReq, opts ...grpc.CallOption) (*PutResp, error)
+}
+
+type cacheServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewCacheServiceClient(cc grpc.ClientConnInterface) CacheServiceClient {
+	return &cacheServiceClient{cc}
+}
+
+func (c *cacheServiceClient) Get(ctx context.Context, in *GetReq, opts ...grpc.CallOption) (*GetResp, error) {
+	out := new(GetResp)
+	err := c.cc.Invoke(ctx, "/cache.CacheService/Get", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *cacheServiceClient) Put(ctx context.Context, in *PutReq, opts ...grpc.CallOption) (*PutResp, error) {
+	out := new(PutResp)
+	err := c.cc.Invoke(ctx, "/cache.CacheService/Put", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// CacheServiceServer is the server API for CacheService service.
+// All implementations must embed UnimplementedCacheServiceServer
+// for forward compatibility
+type CacheServiceServer interface {
+	Get(context.Context, *GetReq) (*GetResp, error)
+	Put(context.Context, *PutReq) (*PutResp, error)
+	mustEmbedUnimplementedCacheServiceServer()
+}
+
+// UnimplementedCacheServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedCacheServiceServer struct {
+}
+
+func (UnimplementedCacheServiceServer) Get(context.Context, *GetReq) (*GetResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+func (UnimplementedCacheServiceServer) Put(context.Context, *PutReq) (*PutResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Put not implemented")
+}
+func (UnimplementedCacheServiceServer) mustEmbedUnimplementedCacheServiceServer() {}
+
+// UnsafeCacheServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to CacheServiceServer will
+// result in compilation errors.
+type UnsafeCacheServiceServer interface {
+	mustEmbedUnimplementedCacheServiceServer()
+}
+
+func RegisterCacheServiceServer(s grpc.ServiceRegistrar, srv CacheServiceServer) {
+	s.RegisterService(&CacheService_ServiceDesc, srv)
+}
+
+func _CacheService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(GetReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CacheServiceServer).Get(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/cache.CacheService/Get",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CacheServiceServer).Get(ctx, req.(*GetReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _CacheService_Put_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(PutReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(CacheServiceServer).Put(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/cache.CacheService/Put",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(CacheServiceServer).Put(ctx, req.(*PutReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// CacheService_ServiceDesc is the grpc.ServiceDesc for CacheService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var CacheService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "cache.CacheService",
+	HandlerType: (*CacheServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Get",
+			Handler:    _CacheService_Get_Handler,
+		},
+		{
+			MethodName: "Put",
+			Handler:    _CacheService_Put_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "cache/cache_service.proto",
+}
diff --git a/proto/command/command.pb.go b/proto/command/command.pb.go
index dd7555d..2af8661 100644
--- a/proto/command/command.pb.go
+++ b/proto/command/command.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: command/command.proto
 
 package command
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	api "go.chromium.org/goma/server/proto/api"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
@@ -27,10 +26,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type CmdDescriptor_PathType int32
 
 const (
@@ -1147,6 +1142,9 @@
 	// in args if args does not have -target option.
 	// note: it is clang/clang++ specific.
 	ClangNeedTarget bool `protobuf:"varint,1,opt,name=clang_need_target,json=clangNeedTarget,proto3" json:"clang_need_target,omitempty"`
+	// If windows_cross is true, it accepts compile request from windows,
+	// but run it on linux workers.
+	WindowsCross bool `protobuf:"varint,2,opt,name=windows_cross,json=windowsCross,proto3" json:"windows_cross,omitempty"`
 }
 
 func (x *CmdDescriptor_Cross) Reset() {
@@ -1188,6 +1186,13 @@
 	return false
 }
 
+func (x *CmdDescriptor_Cross) GetWindowsCross() bool {
+	if x != nil {
+		return x.WindowsCross
+	}
+	return false
+}
+
 // EmulationOpts is used when goma backend cannot fully emulate client environment.
 type CmdDescriptor_EmulationOpts struct {
 	state         protoimpl.MessageState
@@ -1398,7 +1403,7 @@
 	0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x6f,
 	0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x06,
 	0x10, 0x07, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x09, 0x75, 0x70, 0x73, 0x74,
-	0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0x90, 0x05, 0x0a, 0x0d, 0x43, 0x6d, 0x64, 0x44, 0x65, 0x73,
+	0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, 0xb5, 0x05, 0x0a, 0x0d, 0x43, 0x6d, 0x64, 0x44, 0x65, 0x73,
 	0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x08, 0x73, 0x65, 0x6c, 0x65, 0x63,
 	0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
 	0x61, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x08, 0x73, 0x65,
@@ -1425,114 +1430,117 @@
 	0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
 	0x6e, 0x64, 0x2e, 0x43, 0x6d, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72,
 	0x2e, 0x50, 0x61, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x70, 0x61, 0x74, 0x68, 0x54,
-	0x79, 0x70, 0x65, 0x1a, 0x33, 0x0a, 0x05, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11,
+	0x79, 0x70, 0x65, 0x1a, 0x58, 0x0a, 0x05, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x11,
 	0x63, 0x6c, 0x61, 0x6e, 0x67, 0x5f, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65,
 	0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x4e, 0x65,
-	0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x1a, 0x50, 0x0a, 0x0d, 0x45, 0x6d, 0x75, 0x6c,
-	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x72, 0x65, 0x73,
-	0x70, 0x65, 0x63, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x63, 0x6c,
-	0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
-	0x19, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e,
-	0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, 0x39, 0x0a, 0x08, 0x50, 0x61,
-	0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
-	0x4e, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a,
-	0x05, 0x50, 0x4f, 0x53, 0x49, 0x58, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49, 0x4e, 0x44,
-	0x4f, 0x57, 0x53, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10,
-	0x06, 0x52, 0x08, 0x63, 0x6d, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x73, 0x52, 0x0b, 0x70, 0x61, 0x63,
-	0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x22, 0xe3, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x6d,
-	0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12,
-	0x44, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65,
-	0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
-	0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65,
-	0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x73,
-	0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x62, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
-	0x65, 0x42, 0x61, 0x73, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x61, 0x73,
-	0x5f, 0x6e, 0x73, 0x6a, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68,
-	0x61, 0x73, 0x4e, 0x73, 0x6a, 0x61, 0x69, 0x6c, 0x1a, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70,
-	0x65, 0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
-	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xbe,
-	0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27, 0x0a, 0x06, 0x74, 0x61, 0x72,
-	0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
-	0x61, 0x6e, 0x64, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67,
-	0x65, 0x74, 0x12, 0x31, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
-	0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x6d, 0x64, 0x5f, 0x64, 0x65, 0x73,
-	0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e,
-	0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x43, 0x6d, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x63, 0x6d, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69,
-	0x70, 0x74, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x13, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78,
-	0x65, 0x63, 0x5f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f,
-	0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x12,
-	0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f,
-	0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
-	0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x63, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x43, 0x4c, 0x52, 0x03, 0x61,
-	0x63, 0x6c, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22,
-	0x59, 0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65,
-	0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d,
-	0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x12, 0x2b, 0x0a,
-	0x11, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75,
-	0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c,
-	0x6f, 0x77, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x7c, 0x0a, 0x08, 0x50, 0x6c,
-	0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72,
-	0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x6d,
-	0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x50, 0x72,
-	0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69,
-	0x65, 0x73, 0x1a, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x12,
-	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xae, 0x03, 0x0a, 0x0d, 0x52, 0x75, 0x6e,
-	0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x21,
-	0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x64, 0x64,
-	0x72, 0x12, 0x56, 0x0a, 0x17, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x72, 0x75,
-	0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01,
-	0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x6c, 0x61,
-	0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x52, 0x15, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x75, 0x6e, 0x74,
-	0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d, 0x0a, 0x08, 0x70, 0x6c, 0x61,
-	0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f,
-	0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08,
-	0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2b, 0x0a, 0x11, 0x61, 0x6c, 0x6c, 0x6f,
-	0x77, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x50, 0x72, 0x65, 0x62,
-	0x75, 0x69, 0x6c, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f,
-	0x77, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x73, 0x18, 0x04, 0x20,
-	0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x50,
-	0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x73, 0x12, 0x42, 0x0a, 0x13, 0x64, 0x69, 0x73, 0x61,
-	0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18,
-	0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
-	0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x12, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c,
-	0x6f, 0x77, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x1e, 0x0a, 0x03,
-	0x61, 0x63, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
-	0x61, 0x6e, 0x64, 0x2e, 0x41, 0x43, 0x4c, 0x52, 0x03, 0x61, 0x63, 0x6c, 0x4a, 0x04, 0x08, 0x07,
-	0x10, 0x08, 0x52, 0x15, 0x72, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
-	0x5f, 0x62, 0x61, 0x73, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x56, 0x0a, 0x15, 0x50, 0x6c, 0x61,
-	0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f,
-	0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x5f, 0x6e, 0x73, 0x6a, 0x61, 0x69, 0x6c,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x4e, 0x73, 0x6a, 0x61, 0x69,
-	0x6c, 0x22, 0x3f, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x12, 0x32,
-	0x0a, 0x08, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x75, 0x6e, 0x74, 0x69,
-	0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d,
-	0x65, 0x73, 0x22, 0x56, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70,
-	0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12,
-	0x29, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x6f,
-	0x2e, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x6f,
-	0x6d, 0x61, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
-	0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x69, 0x6e, 0x64,
+	0x6f, 0x77, 0x73, 0x5f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x1a, 0x50, 0x0a,
+	0x0d, 0x45, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x3f,
+	0x0a, 0x1c, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x5f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
+	0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x49, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22,
+	0x39, 0x0a, 0x08, 0x50, 0x61, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x55,
+	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x54, 0x59, 0x50, 0x45,
+	0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x4f, 0x53, 0x49, 0x58, 0x10, 0x01, 0x12, 0x0b, 0x0a,
+	0x07, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05,
+	0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x52, 0x08, 0x63, 0x6d, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x73,
+	0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x22, 0xe3, 0x01,
+	0x0a, 0x12, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74,
+	0x66, 0x6f, 0x72, 0x6d, 0x12, 0x44, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69,
+	0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
+	0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61,
+	0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a,
+	0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x72, 0x62,
+	0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x62, 0x65, 0x49, 0x6e,
+	0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x42, 0x61, 0x73, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d,
+	0x0a, 0x0a, 0x68, 0x61, 0x73, 0x5f, 0x6e, 0x73, 0x6a, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73, 0x4e, 0x73, 0x6a, 0x61, 0x69, 0x6c, 0x1a, 0x34, 0x0a,
+	0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a,
+	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x22, 0xbe, 0x02, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x27,
+	0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f,
+	0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52,
+	0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x31, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6f,
+	0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52,
+	0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x0e, 0x63, 0x6d,
+	0x64, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x43, 0x6d, 0x64,
+	0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x0d, 0x63, 0x6d, 0x64, 0x44,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x13, 0x72, 0x65, 0x6d,
+	0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+	0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50, 0x6c, 0x61, 0x74, 0x66,
+	0x6f, 0x72, 0x6d, 0x52, 0x12, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x65, 0x78, 0x65, 0x63, 0x50,
+	0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x69, 0x6d,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x63, 0x6c, 0x18, 0x07,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41,
+	0x43, 0x4c, 0x52, 0x03, 0x61, 0x63, 0x6c, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x05, 0x69,
+	0x6d, 0x61, 0x67, 0x65, 0x22, 0x59, 0x0a, 0x03, 0x41, 0x43, 0x4c, 0x12, 0x25, 0x0a, 0x0e, 0x61,
+	0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75,
+	0x70, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64,
+	0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64,
+	0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22,
+	0x7c, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3a, 0x0a, 0x0a, 0x70,
+	0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x1a, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f,
+	0x72, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f,
+	0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x1a, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65,
+	0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xae, 0x03,
+	0x0a, 0x0d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
+	0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x61,
+	0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x12, 0x56, 0x0a, 0x17, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f,
+	0x72, 0x6d, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
+	0x64, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+	0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x15, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72,
+	0x6d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2d,
+	0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66,
+	0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x2b, 0x0a,
+	0x11, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c,
+	0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65,
+	0x64, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x64, 0x69,
+	0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c,
+	0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c,
+	0x6f, 0x77, 0x65, 0x64, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x73, 0x12, 0x42, 0x0a,
+	0x13, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d,
+	0x61, 0x6e, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6f, 0x6d,
+	0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x12, 0x64,
+	0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
+	0x73, 0x12, 0x1e, 0x0a, 0x03, 0x61, 0x63, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c,
+	0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x43, 0x4c, 0x52, 0x03, 0x61, 0x63,
+	0x6c, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x52, 0x15, 0x72, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x73,
+	0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x56,
+	0x0a, 0x15, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d,
+	0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x6d, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x69, 0x6d,
+	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x68, 0x61, 0x73, 0x5f, 0x6e,
+	0x73, 0x6a, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x68, 0x61, 0x73,
+	0x4e, 0x73, 0x6a, 0x61, 0x69, 0x6c, 0x22, 0x3f, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x4d, 0x61, 0x70, 0x12, 0x32, 0x0a, 0x08, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
+	0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x72,
+	0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x72, 0x73, 0x69,
+	0x6f, 0x6e, 0x49, 0x64, 0x12, 0x29, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x42,
+	0x2b, 0x5a, 0x29, 0x67, 0x6f, 0x2e, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d, 0x2e, 0x6f,
+	0x72, 0x67, 0x2f, 0x67, 0x6f, 0x6d, 0x61, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/proto/command/command.proto b/proto/command/command.proto
index 20caf55..c1e1c33 100644
--- a/proto/command/command.proto
+++ b/proto/command/command.proto
@@ -129,6 +129,10 @@
     // note: it is clang/clang++ specific.
     bool clang_need_target = 1;
 
+    // If windows_cross is true, it accepts compile request from windows,
+    // but run it on linux workers.
+    bool windows_cross = 2;
+
     // TODO: implement followings.
     // - needs path conversion
     //   - nacl/win->linux
diff --git a/proto/command/command_service.pb.go b/proto/command/command_service.pb.go
index 57d6967..127e455 100644
--- a/proto/command/command_service.pb.go
+++ b/proto/command/command_service.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: command/command_service.proto
 
 package command
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -24,10 +23,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_command_command_service_proto protoreflect.FileDescriptor
 
 var file_command_command_service_proto_rawDesc = []byte{
diff --git a/proto/command/package_opts.pb.go b/proto/command/package_opts.pb.go
index 0e851e7..c401ff5 100644
--- a/proto/command/package_opts.pb.go
+++ b/proto/command/package_opts.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: command/package_opts.proto
 
 package command
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 // PackageOpts is a package option.
 // NEXT_ID_TO_USE: 8
 type PackageOpts struct {
diff --git a/proto/command/setup.pb.go b/proto/command/setup.pb.go
index 107ba2c..1b62b0e 100644
--- a/proto/command/setup.pb.go
+++ b/proto/command/setup.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: command/setup.proto
 
 package command
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 // PrefixStyle represents a style of prefix.
 // if it is ASIS, prefix parameter is read as-is.
 // if it is REGEXP, prefix parameter is read as a regular expression.
@@ -93,7 +88,7 @@
 // path is represented as server path (posix style),
 // and converted to client path in CmdDescriptor.Setup.
 //
-// NEXT ID TO USE: 8
+// NEXT ID TO USE: 9
 type Install struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -131,6 +126,8 @@
 	// e.g. set --target x86_64-apple-darwin-10.8.0 sent by client.
 	// note: this is clang/clang++ only.
 	ClangNeedTarget bool `protobuf:"varint,6,opt,name=clang_need_target,json=clangNeedTarget,proto3" json:"clang_need_target,omitempty"`
+	// windows_cross is true for windows cross compile on linux.
+	WindowsCross bool `protobuf:"varint,8,opt,name=windows_cross,json=windowsCross,proto3" json:"windows_cross,omitempty"`
 }
 
 func (x *Install) Reset() {
@@ -214,6 +211,13 @@
 	return false
 }
 
+func (x *Install) GetWindowsCross() bool {
+	if x != nil {
+		return x.WindowsCross
+	}
+	return false
+}
+
 type Setup struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -348,7 +352,7 @@
 
 var file_command_setup_proto_rawDesc = []byte{
 	0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x2e,
-	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xaa,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xcf,
 	0x03, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
 	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06,
 	0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72,
@@ -365,25 +369,27 @@
 	0x74, 0x6f, 0x72, 0x52, 0x0b, 0x66, 0x6f, 0x72, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
 	0x12, 0x2a, 0x0a, 0x11, 0x63, 0x6c, 0x61, 0x6e, 0x67, 0x5f, 0x6e, 0x65, 0x65, 0x64, 0x5f, 0x74,
 	0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x6c, 0x61,
-	0x6e, 0x67, 0x4e, 0x65, 0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x1a, 0x4f, 0x0a, 0x0b,
-	0x46, 0x6f, 0x72, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x74,
-	0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72,
-	0x67, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x68, 0x61,
-	0x73, 0x68, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x62,
-	0x69, 0x6e, 0x61, 0x72, 0x79, 0x48, 0x61, 0x73, 0x68, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x4c, 0x0a,
-	0x0b, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x12, 0x08, 0x0a, 0x04,
-	0x41, 0x53, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x47, 0x45, 0x58, 0x50,
-	0x10, 0x01, 0x12, 0x27, 0x0a, 0x23, 0x52, 0x45, 0x47, 0x45, 0x58, 0x50, 0x5f, 0x4d, 0x41, 0x59,
-	0x5f, 0x53, 0x4b, 0x49, 0x50, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x5f, 0x48, 0x41, 0x53,
-	0x48, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x48, 0x0a, 0x05, 0x53,
-	0x65, 0x74, 0x75, 0x70, 0x12, 0x2c, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73,
-	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
-	0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c,
-	0x6c, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
-	0x65, 0x5f, 0x6f, 0x70, 0x74, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x6f, 0x2e, 0x63, 0x68, 0x72, 0x6f,
-	0x6d, 0x69, 0x75, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x6f, 0x6d, 0x61, 0x2f, 0x73, 0x65,
-	0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
-	0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6e, 0x67, 0x4e, 0x65, 0x65, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0d,
+	0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x18, 0x08, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x0c, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x43, 0x72, 0x6f, 0x73,
+	0x73, 0x1a, 0x4f, 0x0a, 0x0b, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72,
+	0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x62, 0x69, 0x6e, 0x61,
+	0x72, 0x79, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x0e, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x48, 0x61, 0x73, 0x68, 0x46, 0x72,
+	0x6f, 0x6d, 0x22, 0x4c, 0x0a, 0x0b, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x53, 0x74, 0x79, 0x6c,
+	0x65, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x53, 0x49, 0x53, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x52,
+	0x45, 0x47, 0x45, 0x58, 0x50, 0x10, 0x01, 0x12, 0x27, 0x0a, 0x23, 0x52, 0x45, 0x47, 0x45, 0x58,
+	0x50, 0x5f, 0x4d, 0x41, 0x59, 0x5f, 0x53, 0x4b, 0x49, 0x50, 0x5f, 0x42, 0x49, 0x4e, 0x41, 0x52,
+	0x59, 0x5f, 0x48, 0x41, 0x53, 0x48, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x02,
+	0x22, 0x48, 0x0a, 0x05, 0x53, 0x65, 0x74, 0x75, 0x70, 0x12, 0x2c, 0x0a, 0x08, 0x69, 0x6e, 0x73,
+	0x74, 0x61, 0x6c, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f,
+	0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x52, 0x08, 0x69,
+	0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x0b, 0x70,
+	0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x70, 0x74, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x6f,
+	0x2e, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x6f,
+	0x6d, 0x61, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
+	0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/proto/command/setup.proto b/proto/command/setup.proto
index 756ab34..23d904b 100644
--- a/proto/command/setup.proto
+++ b/proto/command/setup.proto
@@ -12,7 +12,7 @@
 // path is represented as server path (posix style),
 // and converted to client path in CmdDescriptor.Setup.
 //
-// NEXT ID TO USE: 8
+// NEXT ID TO USE: 9
 message Install {
   // PrefixStyle represents a style of prefix.
   // if it is ASIS, prefix parameter is read as-is.
@@ -102,6 +102,9 @@
   // e.g. set --target x86_64-apple-darwin-10.8.0 sent by client.
   // note: this is clang/clang++ only.
   bool clang_need_target = 6;
+
+  // windows_cross is true for windows cross compile on linux.
+  bool windows_cross = 8;
 }
 
 message Setup {
diff --git a/proto/doc.go b/proto/doc.go
index d6964ae..89ef377 100644
--- a/proto/doc.go
+++ b/proto/doc.go
@@ -23,19 +23,19 @@
 
 //go:generate ./gen_protoc-gen-go
 //go:generate ./copy_google_protobuf.sh
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative api/goma_data.proto api/goma_log.proto
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative exec/exec_service.proto
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative file/file_service.proto
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative execlog/log_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative api/goma_data.proto api/goma_log.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative exec/exec_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative file/file_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative execlog/log_service.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative cache/cache.proto cache/cache_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative cache/cache.proto cache/cache_service.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative command/command.proto command/command_service.proto command/setup.proto command/package_opts.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative command/command.proto command/command_service.proto command/setup.proto command/package_opts.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative auth/auth.proto auth/acl.proto auth/auth_service.proto auth/authdb.proto auth/authdb_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative auth/auth.proto auth/acl.proto auth/auth_service.proto auth/authdb.proto auth/authdb_service.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative backend/backend.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative backend/backend.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative settings/settings.proto settings/settings_service.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative settings/settings.proto settings/settings_service.proto
 
-//go:generate protoc -I. --go_out=plugins=grpc:. --go_opt=paths=source_relative nsjail/config.proto
+//go:generate protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative nsjail/config.proto
diff --git a/proto/exec/exec_service.pb.go b/proto/exec/exec_service.pb.go
index 4655cb4..0bceb55 100644
--- a/proto/exec/exec_service.pb.go
+++ b/proto/exec/exec_service.pb.go
@@ -4,19 +4,14 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: exec/exec_service.proto
 
 package exec
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
 	api "go.chromium.org/goma/server/proto/api"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -30,10 +25,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 // TODO: reconsider good error codes.
 type ExecServiceApplicationError int32
 
@@ -187,83 +178,3 @@
 	file_exec_exec_service_proto_goTypes = nil
 	file_exec_exec_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// ExecServiceClient is the client API for ExecService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type ExecServiceClient interface {
-	Exec(ctx context.Context, in *api.ExecReq, opts ...grpc.CallOption) (*api.ExecResp, error)
-}
-
-type execServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewExecServiceClient(cc grpc.ClientConnInterface) ExecServiceClient {
-	return &execServiceClient{cc}
-}
-
-func (c *execServiceClient) Exec(ctx context.Context, in *api.ExecReq, opts ...grpc.CallOption) (*api.ExecResp, error) {
-	out := new(api.ExecResp)
-	err := c.cc.Invoke(ctx, "/devtools_goma.ExecService/Exec", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// ExecServiceServer is the server API for ExecService service.
-type ExecServiceServer interface {
-	Exec(context.Context, *api.ExecReq) (*api.ExecResp, error)
-}
-
-// UnimplementedExecServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedExecServiceServer struct {
-}
-
-func (*UnimplementedExecServiceServer) Exec(context.Context, *api.ExecReq) (*api.ExecResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Exec not implemented")
-}
-
-func RegisterExecServiceServer(s *grpc.Server, srv ExecServiceServer) {
-	s.RegisterService(&_ExecService_serviceDesc, srv)
-}
-
-func _ExecService_Exec_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(api.ExecReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(ExecServiceServer).Exec(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/devtools_goma.ExecService/Exec",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(ExecServiceServer).Exec(ctx, req.(*api.ExecReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _ExecService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "devtools_goma.ExecService",
-	HandlerType: (*ExecServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "Exec",
-			Handler:    _ExecService_Exec_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "exec/exec_service.proto",
-}
diff --git a/proto/exec/exec_service_grpc.pb.go b/proto/exec/exec_service_grpc.pb.go
new file mode 100644
index 0000000..c7062e5
--- /dev/null
+++ b/proto/exec/exec_service_grpc.pb.go
@@ -0,0 +1,102 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package exec
+
+import (
+	context "context"
+	api "go.chromium.org/goma/server/proto/api"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// ExecServiceClient is the client API for ExecService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type ExecServiceClient interface {
+	Exec(ctx context.Context, in *api.ExecReq, opts ...grpc.CallOption) (*api.ExecResp, error)
+}
+
+type execServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewExecServiceClient(cc grpc.ClientConnInterface) ExecServiceClient {
+	return &execServiceClient{cc}
+}
+
+func (c *execServiceClient) Exec(ctx context.Context, in *api.ExecReq, opts ...grpc.CallOption) (*api.ExecResp, error) {
+	out := new(api.ExecResp)
+	err := c.cc.Invoke(ctx, "/devtools_goma.ExecService/Exec", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// ExecServiceServer is the server API for ExecService service.
+// All implementations must embed UnimplementedExecServiceServer
+// for forward compatibility
+type ExecServiceServer interface {
+	Exec(context.Context, *api.ExecReq) (*api.ExecResp, error)
+	mustEmbedUnimplementedExecServiceServer()
+}
+
+// UnimplementedExecServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedExecServiceServer struct {
+}
+
+func (UnimplementedExecServiceServer) Exec(context.Context, *api.ExecReq) (*api.ExecResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Exec not implemented")
+}
+func (UnimplementedExecServiceServer) mustEmbedUnimplementedExecServiceServer() {}
+
+// UnsafeExecServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to ExecServiceServer will
+// result in compilation errors.
+type UnsafeExecServiceServer interface {
+	mustEmbedUnimplementedExecServiceServer()
+}
+
+func RegisterExecServiceServer(s grpc.ServiceRegistrar, srv ExecServiceServer) {
+	s.RegisterService(&ExecService_ServiceDesc, srv)
+}
+
+func _ExecService_Exec_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(api.ExecReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ExecServiceServer).Exec(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/devtools_goma.ExecService/Exec",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ExecServiceServer).Exec(ctx, req.(*api.ExecReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// ExecService_ServiceDesc is the grpc.ServiceDesc for ExecService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var ExecService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "devtools_goma.ExecService",
+	HandlerType: (*ExecServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Exec",
+			Handler:    _ExecService_Exec_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "exec/exec_service.proto",
+}
diff --git a/proto/execlog/log_service.pb.go b/proto/execlog/log_service.pb.go
index 1edd51c..029b081 100644
--- a/proto/execlog/log_service.pb.go
+++ b/proto/execlog/log_service.pb.go
@@ -4,19 +4,14 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: execlog/log_service.proto
 
 package execlog
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
 	api "go.chromium.org/goma/server/proto/api"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -29,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_execlog_log_service_proto protoreflect.FileDescriptor
 
 var file_execlog_log_service_proto_rawDesc = []byte{
@@ -88,83 +79,3 @@
 	file_execlog_log_service_proto_goTypes = nil
 	file_execlog_log_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// LogServiceClient is the client API for LogService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type LogServiceClient interface {
-	SaveLog(ctx context.Context, in *api.SaveLogReq, opts ...grpc.CallOption) (*api.SaveLogResp, error)
-}
-
-type logServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewLogServiceClient(cc grpc.ClientConnInterface) LogServiceClient {
-	return &logServiceClient{cc}
-}
-
-func (c *logServiceClient) SaveLog(ctx context.Context, in *api.SaveLogReq, opts ...grpc.CallOption) (*api.SaveLogResp, error) {
-	out := new(api.SaveLogResp)
-	err := c.cc.Invoke(ctx, "/devtools_goma.LogService/SaveLog", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// LogServiceServer is the server API for LogService service.
-type LogServiceServer interface {
-	SaveLog(context.Context, *api.SaveLogReq) (*api.SaveLogResp, error)
-}
-
-// UnimplementedLogServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedLogServiceServer struct {
-}
-
-func (*UnimplementedLogServiceServer) SaveLog(context.Context, *api.SaveLogReq) (*api.SaveLogResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method SaveLog not implemented")
-}
-
-func RegisterLogServiceServer(s *grpc.Server, srv LogServiceServer) {
-	s.RegisterService(&_LogService_serviceDesc, srv)
-}
-
-func _LogService_SaveLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(api.SaveLogReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(LogServiceServer).SaveLog(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/devtools_goma.LogService/SaveLog",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(LogServiceServer).SaveLog(ctx, req.(*api.SaveLogReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _LogService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "devtools_goma.LogService",
-	HandlerType: (*LogServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "SaveLog",
-			Handler:    _LogService_SaveLog_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "execlog/log_service.proto",
-}
diff --git a/proto/execlog/log_service_grpc.pb.go b/proto/execlog/log_service_grpc.pb.go
new file mode 100644
index 0000000..6447b8d
--- /dev/null
+++ b/proto/execlog/log_service_grpc.pb.go
@@ -0,0 +1,102 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package execlog
+
+import (
+	context "context"
+	api "go.chromium.org/goma/server/proto/api"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// LogServiceClient is the client API for LogService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type LogServiceClient interface {
+	SaveLog(ctx context.Context, in *api.SaveLogReq, opts ...grpc.CallOption) (*api.SaveLogResp, error)
+}
+
+type logServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewLogServiceClient(cc grpc.ClientConnInterface) LogServiceClient {
+	return &logServiceClient{cc}
+}
+
+func (c *logServiceClient) SaveLog(ctx context.Context, in *api.SaveLogReq, opts ...grpc.CallOption) (*api.SaveLogResp, error) {
+	out := new(api.SaveLogResp)
+	err := c.cc.Invoke(ctx, "/devtools_goma.LogService/SaveLog", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// LogServiceServer is the server API for LogService service.
+// All implementations must embed UnimplementedLogServiceServer
+// for forward compatibility
+type LogServiceServer interface {
+	SaveLog(context.Context, *api.SaveLogReq) (*api.SaveLogResp, error)
+	mustEmbedUnimplementedLogServiceServer()
+}
+
+// UnimplementedLogServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedLogServiceServer struct {
+}
+
+func (UnimplementedLogServiceServer) SaveLog(context.Context, *api.SaveLogReq) (*api.SaveLogResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method SaveLog not implemented")
+}
+func (UnimplementedLogServiceServer) mustEmbedUnimplementedLogServiceServer() {}
+
+// UnsafeLogServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to LogServiceServer will
+// result in compilation errors.
+type UnsafeLogServiceServer interface {
+	mustEmbedUnimplementedLogServiceServer()
+}
+
+func RegisterLogServiceServer(s grpc.ServiceRegistrar, srv LogServiceServer) {
+	s.RegisterService(&LogService_ServiceDesc, srv)
+}
+
+func _LogService_SaveLog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(api.SaveLogReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(LogServiceServer).SaveLog(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/devtools_goma.LogService/SaveLog",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(LogServiceServer).SaveLog(ctx, req.(*api.SaveLogReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// LogService_ServiceDesc is the grpc.ServiceDesc for LogService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var LogService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "devtools_goma.LogService",
+	HandlerType: (*LogServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "SaveLog",
+			Handler:    _LogService_SaveLog_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "execlog/log_service.proto",
+}
diff --git a/proto/file/file_service.pb.go b/proto/file/file_service.pb.go
index ebaab39..f032ef4 100644
--- a/proto/file/file_service.pb.go
+++ b/proto/file/file_service.pb.go
@@ -7,19 +7,14 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: file/file_service.proto
 
 package file
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
 	api "go.chromium.org/goma/server/proto/api"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -32,10 +27,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_file_file_service_proto protoreflect.FileDescriptor
 
 var file_file_file_service_proto_rawDesc = []byte{
@@ -100,119 +91,3 @@
 	file_file_file_service_proto_goTypes = nil
 	file_file_file_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// FileServiceClient is the client API for FileService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type FileServiceClient interface {
-	StoreFile(ctx context.Context, in *api.StoreFileReq, opts ...grpc.CallOption) (*api.StoreFileResp, error)
-	LookupFile(ctx context.Context, in *api.LookupFileReq, opts ...grpc.CallOption) (*api.LookupFileResp, error)
-}
-
-type fileServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewFileServiceClient(cc grpc.ClientConnInterface) FileServiceClient {
-	return &fileServiceClient{cc}
-}
-
-func (c *fileServiceClient) StoreFile(ctx context.Context, in *api.StoreFileReq, opts ...grpc.CallOption) (*api.StoreFileResp, error) {
-	out := new(api.StoreFileResp)
-	err := c.cc.Invoke(ctx, "/devtools_goma.FileService/StoreFile", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-func (c *fileServiceClient) LookupFile(ctx context.Context, in *api.LookupFileReq, opts ...grpc.CallOption) (*api.LookupFileResp, error) {
-	out := new(api.LookupFileResp)
-	err := c.cc.Invoke(ctx, "/devtools_goma.FileService/LookupFile", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// FileServiceServer is the server API for FileService service.
-type FileServiceServer interface {
-	StoreFile(context.Context, *api.StoreFileReq) (*api.StoreFileResp, error)
-	LookupFile(context.Context, *api.LookupFileReq) (*api.LookupFileResp, error)
-}
-
-// UnimplementedFileServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedFileServiceServer struct {
-}
-
-func (*UnimplementedFileServiceServer) StoreFile(context.Context, *api.StoreFileReq) (*api.StoreFileResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method StoreFile not implemented")
-}
-func (*UnimplementedFileServiceServer) LookupFile(context.Context, *api.LookupFileReq) (*api.LookupFileResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method LookupFile not implemented")
-}
-
-func RegisterFileServiceServer(s *grpc.Server, srv FileServiceServer) {
-	s.RegisterService(&_FileService_serviceDesc, srv)
-}
-
-func _FileService_StoreFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(api.StoreFileReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(FileServiceServer).StoreFile(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/devtools_goma.FileService/StoreFile",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(FileServiceServer).StoreFile(ctx, req.(*api.StoreFileReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-func _FileService_LookupFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(api.LookupFileReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(FileServiceServer).LookupFile(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/devtools_goma.FileService/LookupFile",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(FileServiceServer).LookupFile(ctx, req.(*api.LookupFileReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _FileService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "devtools_goma.FileService",
-	HandlerType: (*FileServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "StoreFile",
-			Handler:    _FileService_StoreFile_Handler,
-		},
-		{
-			MethodName: "LookupFile",
-			Handler:    _FileService_LookupFile_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "file/file_service.proto",
-}
diff --git a/proto/file/file_service_grpc.pb.go b/proto/file/file_service_grpc.pb.go
new file mode 100644
index 0000000..3afad5a
--- /dev/null
+++ b/proto/file/file_service_grpc.pb.go
@@ -0,0 +1,138 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package file
+
+import (
+	context "context"
+	api "go.chromium.org/goma/server/proto/api"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// FileServiceClient is the client API for FileService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type FileServiceClient interface {
+	StoreFile(ctx context.Context, in *api.StoreFileReq, opts ...grpc.CallOption) (*api.StoreFileResp, error)
+	LookupFile(ctx context.Context, in *api.LookupFileReq, opts ...grpc.CallOption) (*api.LookupFileResp, error)
+}
+
+type fileServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewFileServiceClient(cc grpc.ClientConnInterface) FileServiceClient {
+	return &fileServiceClient{cc}
+}
+
+func (c *fileServiceClient) StoreFile(ctx context.Context, in *api.StoreFileReq, opts ...grpc.CallOption) (*api.StoreFileResp, error) {
+	out := new(api.StoreFileResp)
+	err := c.cc.Invoke(ctx, "/devtools_goma.FileService/StoreFile", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *fileServiceClient) LookupFile(ctx context.Context, in *api.LookupFileReq, opts ...grpc.CallOption) (*api.LookupFileResp, error) {
+	out := new(api.LookupFileResp)
+	err := c.cc.Invoke(ctx, "/devtools_goma.FileService/LookupFile", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// FileServiceServer is the server API for FileService service.
+// All implementations must embed UnimplementedFileServiceServer
+// for forward compatibility
+type FileServiceServer interface {
+	StoreFile(context.Context, *api.StoreFileReq) (*api.StoreFileResp, error)
+	LookupFile(context.Context, *api.LookupFileReq) (*api.LookupFileResp, error)
+	mustEmbedUnimplementedFileServiceServer()
+}
+
+// UnimplementedFileServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedFileServiceServer struct {
+}
+
+func (UnimplementedFileServiceServer) StoreFile(context.Context, *api.StoreFileReq) (*api.StoreFileResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method StoreFile not implemented")
+}
+func (UnimplementedFileServiceServer) LookupFile(context.Context, *api.LookupFileReq) (*api.LookupFileResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method LookupFile not implemented")
+}
+func (UnimplementedFileServiceServer) mustEmbedUnimplementedFileServiceServer() {}
+
+// UnsafeFileServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to FileServiceServer will
+// result in compilation errors.
+type UnsafeFileServiceServer interface {
+	mustEmbedUnimplementedFileServiceServer()
+}
+
+func RegisterFileServiceServer(s grpc.ServiceRegistrar, srv FileServiceServer) {
+	s.RegisterService(&FileService_ServiceDesc, srv)
+}
+
+func _FileService_StoreFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(api.StoreFileReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(FileServiceServer).StoreFile(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/devtools_goma.FileService/StoreFile",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(FileServiceServer).StoreFile(ctx, req.(*api.StoreFileReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _FileService_LookupFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(api.LookupFileReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(FileServiceServer).LookupFile(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/devtools_goma.FileService/LookupFile",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(FileServiceServer).LookupFile(ctx, req.(*api.LookupFileReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// FileService_ServiceDesc is the grpc.ServiceDesc for FileService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var FileService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "devtools_goma.FileService",
+	HandlerType: (*FileServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "StoreFile",
+			Handler:    _FileService_StoreFile_Handler,
+		},
+		{
+			MethodName: "LookupFile",
+			Handler:    _FileService_LookupFile_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "file/file_service.proto",
+}
diff --git a/proto/gen_protoc-gen-go b/proto/gen_protoc-gen-go
index 3ec15cf..f3c28e3 100755
--- a/proto/gen_protoc-gen-go
+++ b/proto/gen_protoc-gen-go
@@ -1,4 +1,10 @@
 #!/bin/sh
 # Copyright 2018 Google Inc. All Rights Reserved.
-version="$(go list -m -f '{{.Version}}' github.com/golang/protobuf)"
-go get "github.com/golang/protobuf/protoc-gen-go@${version}"
+version="$(go list -m -f '{{.Version}}' google.golang.org/protobuf)"
+go get "google.golang.org/protobuf/cmd/protoc-gen-go@${version}"
+version="$(go list -m -f '{{.Version}}' google.golang.org/grpc/cmd/protoc-gen-go-grpc)"
+if [ -z "${version}" ]; then
+  go get "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
+else
+  go get "google.golang.org/grpc/cmd/protoc-gen-go-grpc@${version}"
+fi
diff --git a/proto/nsjail/config.pb.go b/proto/nsjail/config.pb.go
index c64e860..c534062 100644
--- a/proto/nsjail/config.pb.go
+++ b/proto/nsjail/config.pb.go
@@ -1,13 +1,12 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: nsjail/config.proto
 
 package nsjail
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -21,10 +20,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type Mode int32
 
 const (
diff --git a/proto/settings/settings.pb.go b/proto/settings/settings.pb.go
index 40ec4f5..f84bf94 100644
--- a/proto/settings/settings.pb.go
+++ b/proto/settings/settings.pb.go
@@ -4,14 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: settings/settings.proto
 
 package settings
 
 import (
-	proto "github.com/golang/protobuf/proto"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -25,10 +24,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 type Settings struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
diff --git a/proto/settings/settings_service.pb.go b/proto/settings/settings_service.pb.go
index e6c727e..fbd2a86 100644
--- a/proto/settings/settings_service.pb.go
+++ b/proto/settings/settings_service.pb.go
@@ -4,18 +4,13 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.25.0
-// 	protoc        v3.15.3
+// 	protoc-gen-go v1.26.0
+// 	protoc        v3.15.6
 // source: settings/settings_service.proto
 
 package settings
 
 import (
-	context "context"
-	proto "github.com/golang/protobuf/proto"
-	grpc "google.golang.org/grpc"
-	codes "google.golang.org/grpc/codes"
-	status "google.golang.org/grpc/status"
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
@@ -28,10 +23,6 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
-// This is a compile-time assertion that a sufficiently up-to-date version
-// of the legacy proto package is being used.
-const _ = proto.ProtoPackageIsVersion4
-
 var File_settings_settings_service_proto protoreflect.FileDescriptor
 
 var file_settings_settings_service_proto_rawDesc = []byte{
@@ -88,83 +79,3 @@
 	file_settings_settings_service_proto_goTypes = nil
 	file_settings_settings_service_proto_depIdxs = nil
 }
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ context.Context
-var _ grpc.ClientConnInterface
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the grpc package it is being compiled against.
-const _ = grpc.SupportPackageIsVersion6
-
-// SettingsServiceClient is the client API for SettingsService service.
-//
-// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
-type SettingsServiceClient interface {
-	Get(ctx context.Context, in *SettingsReq, opts ...grpc.CallOption) (*SettingsResp, error)
-}
-
-type settingsServiceClient struct {
-	cc grpc.ClientConnInterface
-}
-
-func NewSettingsServiceClient(cc grpc.ClientConnInterface) SettingsServiceClient {
-	return &settingsServiceClient{cc}
-}
-
-func (c *settingsServiceClient) Get(ctx context.Context, in *SettingsReq, opts ...grpc.CallOption) (*SettingsResp, error) {
-	out := new(SettingsResp)
-	err := c.cc.Invoke(ctx, "/settings.SettingsService/Get", in, out, opts...)
-	if err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
-// SettingsServiceServer is the server API for SettingsService service.
-type SettingsServiceServer interface {
-	Get(context.Context, *SettingsReq) (*SettingsResp, error)
-}
-
-// UnimplementedSettingsServiceServer can be embedded to have forward compatible implementations.
-type UnimplementedSettingsServiceServer struct {
-}
-
-func (*UnimplementedSettingsServiceServer) Get(context.Context, *SettingsReq) (*SettingsResp, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
-}
-
-func RegisterSettingsServiceServer(s *grpc.Server, srv SettingsServiceServer) {
-	s.RegisterService(&_SettingsService_serviceDesc, srv)
-}
-
-func _SettingsService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(SettingsReq)
-	if err := dec(in); err != nil {
-		return nil, err
-	}
-	if interceptor == nil {
-		return srv.(SettingsServiceServer).Get(ctx, in)
-	}
-	info := &grpc.UnaryServerInfo{
-		Server:     srv,
-		FullMethod: "/settings.SettingsService/Get",
-	}
-	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(SettingsServiceServer).Get(ctx, req.(*SettingsReq))
-	}
-	return interceptor(ctx, in, info, handler)
-}
-
-var _SettingsService_serviceDesc = grpc.ServiceDesc{
-	ServiceName: "settings.SettingsService",
-	HandlerType: (*SettingsServiceServer)(nil),
-	Methods: []grpc.MethodDesc{
-		{
-			MethodName: "Get",
-			Handler:    _SettingsService_Get_Handler,
-		},
-	},
-	Streams:  []grpc.StreamDesc{},
-	Metadata: "settings/settings_service.proto",
-}
diff --git a/proto/settings/settings_service_grpc.pb.go b/proto/settings/settings_service_grpc.pb.go
new file mode 100644
index 0000000..6740817
--- /dev/null
+++ b/proto/settings/settings_service_grpc.pb.go
@@ -0,0 +1,101 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package settings
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// SettingsServiceClient is the client API for SettingsService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type SettingsServiceClient interface {
+	Get(ctx context.Context, in *SettingsReq, opts ...grpc.CallOption) (*SettingsResp, error)
+}
+
+type settingsServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewSettingsServiceClient(cc grpc.ClientConnInterface) SettingsServiceClient {
+	return &settingsServiceClient{cc}
+}
+
+func (c *settingsServiceClient) Get(ctx context.Context, in *SettingsReq, opts ...grpc.CallOption) (*SettingsResp, error) {
+	out := new(SettingsResp)
+	err := c.cc.Invoke(ctx, "/settings.SettingsService/Get", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// SettingsServiceServer is the server API for SettingsService service.
+// All implementations must embed UnimplementedSettingsServiceServer
+// for forward compatibility
+type SettingsServiceServer interface {
+	Get(context.Context, *SettingsReq) (*SettingsResp, error)
+	mustEmbedUnimplementedSettingsServiceServer()
+}
+
+// UnimplementedSettingsServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedSettingsServiceServer struct {
+}
+
+func (UnimplementedSettingsServiceServer) Get(context.Context, *SettingsReq) (*SettingsResp, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
+}
+func (UnimplementedSettingsServiceServer) mustEmbedUnimplementedSettingsServiceServer() {}
+
+// UnsafeSettingsServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to SettingsServiceServer will
+// result in compilation errors.
+type UnsafeSettingsServiceServer interface {
+	mustEmbedUnimplementedSettingsServiceServer()
+}
+
+func RegisterSettingsServiceServer(s grpc.ServiceRegistrar, srv SettingsServiceServer) {
+	s.RegisterService(&SettingsService_ServiceDesc, srv)
+}
+
+func _SettingsService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(SettingsReq)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(SettingsServiceServer).Get(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/settings.SettingsService/Get",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(SettingsServiceServer).Get(ctx, req.(*SettingsReq))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// SettingsService_ServiceDesc is the grpc.ServiceDesc for SettingsService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var SettingsService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "settings.SettingsService",
+	HandlerType: (*SettingsServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "Get",
+			Handler:    _SettingsService_Get_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "settings/settings_service.proto",
+}
diff --git a/remoteexec/adapter.go b/remoteexec/adapter.go
index c75d62e..5ec9442 100644
--- a/remoteexec/adapter.go
+++ b/remoteexec/adapter.go
@@ -19,17 +19,18 @@
 	rpb "github.com/bazelbuild/remote-apis/build/bazel/remote/execution/v2"
 
 	"github.com/golang/protobuf/proto"
-	"github.com/golang/protobuf/ptypes"
 	"go.opencensus.io/stats"
 	"go.opencensus.io/trace"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/oauth"
 	"google.golang.org/grpc/metadata"
+	"google.golang.org/protobuf/types/known/durationpb"
 
 	"go.chromium.org/goma/server/auth/enduser"
 	"go.chromium.org/goma/server/exec"
 	"go.chromium.org/goma/server/log"
 	gomapb "go.chromium.org/goma/server/proto/api"
+	execpb "go.chromium.org/goma/server/proto/exec"
 	fpb "go.chromium.org/goma/server/proto/file"
 	"go.chromium.org/goma/server/remoteexec/cas"
 	"go.chromium.org/goma/server/remoteexec/digest"
@@ -68,6 +69,7 @@
 
 // Adapter is an adapter from goma API to remoteexec API.
 type Adapter struct {
+	execpb.UnimplementedExecServiceServer
 	// InstancePrefix is the prefix (dirname) of the full RBE instance name.
 	// e.g. If instance name == "projects/$PROJECT/instances/default_instance",
 	// then InstancePrefix is "projects/$PROJECT/instances"
@@ -274,7 +276,7 @@
 			digestCache: f.DigestCache,
 		},
 		action: &rpb.Action{
-			Timeout:    ptypes.DurationProto(timeout),
+			Timeout:    durationpb.New(timeout),
 			DoNotCache: doNotCache(gomaReq),
 		},
 	}
diff --git a/remoteexec/clang-cl.go b/remoteexec/clang-cl.go
index c695bb7..649c0be 100644
--- a/remoteexec/clang-cl.go
+++ b/remoteexec/clang-cl.go
@@ -15,10 +15,14 @@
 
 // longest first
 var clangClPathFlags = []string{
+	"-fcoverage-compilation-dir=",
 	"-fcrash-diagnostics-dir=",
+	"-fdebug-compilation-dir=",
+	"-ffile-compilation-dir=",
 	"-fprofile-sample-use=",
 	"-fsanitize-blacklist=",
 	"-fprofile-instr-use=",
+	"-fprofile-list=",
 	"-resource-dir=",
 	"/vctoolsdir",
 	"/winsysroot",
@@ -122,6 +126,7 @@
 	subArgs := map[string][]string{}
 	var subCmd string
 	pathFlag := false
+	winsysrootFlag := false
 Loop:
 	for _, arg := range args {
 		if pathFlag {
@@ -131,6 +136,9 @@
 			pathFlag = false
 			continue
 		}
+		if strings.HasPrefix(arg, "/winsysroot") || strings.HasPrefix(arg, "-imsvc") {
+			winsysrootFlag = true
+		}
 		for _, fp := range clangClPathFlags {
 			if arg != fp && strings.HasPrefix(arg, fp) {
 				if filepath.IsAbs(arg[len(fp):]) {
@@ -261,12 +269,31 @@
 		}
 	}
 
-	// Don't check environment variables.
+	// Don't check environment variables, if -imsvc or /winsysroot is set.
 	// Typically user sets `INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\ATLMFC\include;...`
 	// so it makes always non-relocatble.
-	// in chromium build, cang-cl uses -imsvc instead of relying on
-	// %INCLUDE%, so it would be ok to ignore environment variables.
+	// in chromium build, clang-cl uses /winsysroot (or -imsvc in past)
+	// instead of relying on %INCLUDE%, so it would be ok to ignore
+	// environment variables.
 	// http://b/173755650
+	if winsysrootFlag {
+		return nil
+	}
+	// otherwise, check environment variables.
+	for _, env := range envs {
+		e := strings.SplitN(env, "=", 2)
+		if len(e) != 2 {
+			return fmt.Errorf("bad environment variable: %s", env)
+		}
+		if e[0] == "PWD" {
+			continue
+		}
+		// TODO: need to split by list separator
+		// for %INCLUDE% or so?
+		if filepath.IsAbs(e[1]) {
+			return fmt.Errorf("abs path in env %s=%s", e[0], e[1])
+		}
+	}
 	return nil
 }
 
@@ -287,10 +314,14 @@
 			pathFlag = true
 		case strings.HasPrefix(arg, "-debug-info-kind"):
 			continue
-		case arg == "-add-plugin", arg == "-mllvm", arg == "-plugin-arg-blink-gc-plugin":
+		case arg == "-add-plugin", arg == "-mllvm":
 			// TODO: pass llvmArgRelocatable for -mllvm?
 			skipFlag = true
 			continue
+		case strings.HasPrefix(arg, "-plugin-arg-"):
+			skipFlag = true
+			continue
+		case strings.HasPrefix(arg, "-f"): // feature
 		default:
 			return unknownFlagError{arg: fmt.Sprintf("clang-cl: %s", arg)}
 		}
diff --git a/remoteexec/clang-cl_test.go b/remoteexec/clang-cl_test.go
index 9e409ca..e52775f 100644
--- a/remoteexec/clang-cl_test.go
+++ b/remoteexec/clang-cl_test.go
@@ -189,6 +189,62 @@
 			relocatable: false,
 		},
 		{
+			desc: "-fdebug-compilation-dir= unrelocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fdebug-compilation-dir=C:\\chromium\\src\\out\\Release\\debug_compilation_dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-fdebug-compilation-dir= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fdebug-compilation-dir=.\\debug_compilation_dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-fcoverage-compilation-dir= unrelocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fcoverage-compilation-dir=C:\\chromium\\src\\out\\Release\\coverage_compilation_dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-fcoverage-compilation-dir= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fcoverage-compilation-dir=.\\out\\Release\\coverage_compilation_dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-ffile-compilation-dir= unrelocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-ffile-compilation-dir=C:\\chromium\\src\\out\\Release\\file-compilation-dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-ffile-compilation-dir= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-ffile-compilation-dir=.\\out\\Release\\file-compilation-dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-fprofile-list= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fprofile-list=C:\\chromium\\src\\out\\Release\\profile-list"),
+			relocatable: false,
+		},
+		{
+			desc: "-fprofile-list= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fprofile-list=.\\out\\Release\\profile-list"),
+			relocatable: true,
+		},
+		{
 			desc:        "invalid msvc flag",
 			args:        modifyArgs(baseReleaseArgs, "", "/invalid"),
 			relocatable: false,
@@ -222,6 +278,21 @@
 			relocatable: false,
 		},
 		{
+			desc: "-Xclang -fno-experimental-new-pass-manager",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-Xclang", "-fno-experimental-new-pass-manager"),
+			relocatable: true,
+		},
+		{
+			desc: "-Xclang plugin-args",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-Xclang", "-add-plugin",
+				"-Xclang", "find-bad-constructs",
+				"-Xclang", "-plugin-arg-find-bad-constructs",
+				"-Xclang", "checked-ptr-as-trivial-member"),
+			relocatable: true,
+		},
+		{
 			desc: "-mllvm -instcombine-lower-dbg-declare=0",
 			args: append(append([]string{}, baseReleaseArgs...),
 				"-mllvm", "-instcombine-lower-dbg-declare=0"),
diff --git a/remoteexec/client.go b/remoteexec/client.go
index ef91ba3..65a44e8 100644
--- a/remoteexec/client.go
+++ b/remoteexec/client.go
@@ -184,6 +184,14 @@
 					recordRemoteExecFinish(ctx)
 					return status.Errorf(codes.Unavailable, "operation stream lost: %v", err)
 				}
+				// record error details if any
+				// https://github.com/bazelbuild/remote-apis/blob/1aeb399731780e61dece542dc656da1775a20840/build/bazel/remote/execution/v2/remote_execution.proto#L102
+				st, ok := status.FromError(err)
+				if ok {
+					for _, dt := range st.Details() {
+						logger.Warnf("error details for %v: %v", err, dt)
+					}
+				}
 				return err
 			}
 			if opName == "" {
@@ -220,6 +228,13 @@
 func erespErr(ctx context.Context, eresp *rpb.ExecuteResponse) error {
 	logger := log.FromContext(ctx)
 	st := eresp.GetStatus()
+	// record details if any
+	// when OK, it has empty google.devtools.remotebuildbot.ComamndStatus
+	// {code=0, message=""}.
+	if codes.Code(st.GetCode()) != codes.OK && len(st.GetDetails()) > 0 {
+		logger.Warnf("error details for %v: %v", codes.Code(st.GetCode()), st.GetDetails())
+	}
+
 	// https://github.com/bazelbuild/remote-apis/blob/e7282cf0f0e16e7ba84209be5417279e6815bee7/build/bazel/remote/execution/v2/remote_execution.proto#L83
 	// FAILED_PRECONDITION:
 	//   one or more errors occured in setting up the action
diff --git a/remoteexec/exec.go b/remoteexec/exec.go
index f8bb143..b63c6e3 100644
--- a/remoteexec/exec.go
+++ b/remoteexec/exec.go
@@ -30,6 +30,8 @@
 	"google.golang.org/grpc/status"
 
 	"go.chromium.org/goma/server/command/descriptor"
+	"go.chromium.org/goma/server/command/descriptor/posixpath"
+	"go.chromium.org/goma/server/command/descriptor/winpath"
 	"go.chromium.org/goma/server/exec"
 	"go.chromium.org/goma/server/log"
 	gomapb "go.chromium.org/goma/server/proto/api"
@@ -69,6 +71,8 @@
 	allowChroot bool
 	needChroot  bool
 
+	crossTarget string
+
 	err error
 }
 
@@ -203,6 +207,12 @@
 		r.gomaResp.ErrorMessage = append(r.gomaResp.ErrorMessage, fmt.Sprintf("bad compiler config: %v", err))
 		return r.gomaResp
 	}
+	if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+		r.filepath = winpath.FilePath{}
+		// drop .bat suffix
+		// http://b/185210502#comment12
+		cmdFiles[0].Path = strings.TrimSuffix(cmdFiles[0].Path, ".bat")
+	}
 
 	r.cmdConfig = cmdConfig
 	r.cmdFiles = cmdFiles
@@ -227,7 +237,7 @@
 		}
 	}
 	r.allowChroot = cmdConfig.GetRemoteexecPlatform().GetHasNsjail()
-	logger.Infof("platform: %s, allowChroot=%t", r.platform, r.allowChroot)
+	logger.Infof("platform: %s, allowChroot=%t path_tpye=%s windows_cross=%t", r.platform, r.allowChroot, cmdConfig.GetCmdDescriptor().GetSetup().GetPathType(), cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross())
 	return nil
 }
 
@@ -376,6 +386,35 @@
 	return eg.Wait()
 }
 
+func dedupInputs(filepath clientFilePath, cwd string, inputs []*gomapb.ExecReq_Input) []*gomapb.ExecReq_Input {
+	var deduped []*gomapb.ExecReq_Input
+	m := make(map[string]int) // key name -> index in deduped
+
+	for _, input := range inputs {
+		fname := input.GetFilename()
+		if !filepath.IsAbs(fname) {
+			fname = filepath.Join(cwd, fname)
+		}
+		k := strings.ToLower(fname)
+		i, found := m[k]
+		if !found {
+			m[k] = len(deduped)
+			deduped = append(deduped, input)
+			continue
+		}
+		// If there is already registered filename, compare and take shorter one.
+		if len(input.GetFilename()) < len(deduped[i].GetFilename()) {
+			deduped[i] = input
+			continue
+		}
+		// If length is same, take lexicographically smaller one.
+		if len(input.GetFilename()) == len(deduped[i].GetFilename()) && input.GetFilename() < deduped[i].GetFilename() {
+			deduped[i] = input
+		}
+	}
+	return deduped
+}
+
 type inputFileResult struct {
 	missingInput  string
 	missingReason string
@@ -462,7 +501,7 @@
 	r.tree = merkletree.New(r.filepath, rootDir, r.digestStore)
 	r.needChroot = needChroot
 
-	logger.Infof("new input tree cwd:%s root:%s execRoot:%s %s", r.gomaReq.GetCwd(), r.tree.RootDir(), execRootDir, r.cmdConfig.GetCmdDescriptor().GetSetup().GetPathType())
+	logger.Infof("new input tree cwd:%s root:%s execRoot:%s %s", r.gomaReq.GetCwd(), r.tree.RootDir(), execRootDir, r.filepath)
 	// If toolchain_included is true, r.gomaReq.Input and cmdFiles will contain the same files.
 	// To avoid dup, if it's added in r.gomaReq.Input, we don't add it as cmdFiles.
 	// While processing r.gomaReq.Input, we handle missing input, so the main routine is in
@@ -492,11 +531,20 @@
 	cleanRootDir := r.filepath.Clean(r.tree.RootDir())
 
 	start := time.Now()
-	results := inputFiles(ctx, r.gomaReq.Input, r.input, func(filename string) (string, error) {
+	reqInputs := r.gomaReq.Input
+	if _, ok := r.filepath.(winpath.FilePath); ok && !r.cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+		// need to dedup filename for windows,
+		// except windows cross case.
+		reqInputs = dedupInputs(r.filepath, cleanCWD, r.gomaReq.Input)
+		if len(reqInputs) != len(r.gomaReq.Input) {
+			logger.Infof("input dedup %d -> %d", len(r.gomaReq.Input), len(reqInputs))
+		}
+	}
+	results := inputFiles(ctx, reqInputs, r.input, func(filename string) (string, error) {
 		return rootRel(r.filepath, filename, cleanCWD, cleanRootDir)
 	}, executableInputs)
-	uploads := make([]*gomapb.ExecReq_Input, 0, len(r.gomaReq.Input))
-	for i, input := range r.gomaReq.Input {
+	uploads := make([]*gomapb.ExecReq_Input, 0, len(reqInputs))
+	for i, input := range reqInputs {
 		result := &results[i]
 		if r.err == nil && result.err != nil {
 			r.err = result.err
@@ -506,10 +554,10 @@
 		}
 	}
 	if r.err != nil {
-		logger.Warnf("inputFiles=%d uploads=%d in %s err:%v", len(r.gomaReq.Input), len(uploads), time.Since(start), r.err)
+		logger.Warnf("inputFiles=%d uploads=%d in %s err:%v", len(reqInputs), len(uploads), time.Since(start), r.err)
 		return nil
 	}
-	logger.Infof("inputFiles=%d uploads=%d in %s", len(r.gomaReq.Input), len(uploads), time.Since(start))
+	logger.Infof("inputFiles=%d uploads=%d in %s", len(reqInputs), len(uploads), time.Since(start))
 
 	var files []merkletree.Entry
 	var missingInputs []string
@@ -527,7 +575,7 @@
 		files = append(files, in.file)
 	}
 	if len(missingInputs) > 0 {
-		logger.Infof("missing %d inputs out of %d. need to uploads=%d", len(missingInputs), len(r.gomaReq.Input), len(uploads))
+		logger.Infof("missing %d inputs out of %d. need to uploads=%d", len(missingInputs), len(reqInputs), len(uploads))
 
 		r.gomaResp.MissingInput = missingInputs
 		r.gomaResp.MissingReason = missingReason
@@ -575,6 +623,7 @@
 		fname, err := rootRel(r.filepath, e.Name, cleanCWD, cleanRootDir)
 		if err != nil {
 			if err == errOutOfRoot {
+				logger.Warnf("cmd files: out of root: %s", e.Name)
 				continue
 			}
 			r.err = fmt.Errorf("command file: %v", err)
@@ -713,6 +762,9 @@
 	if wd == "" {
 		wd = "."
 	}
+	if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+		wd = winpath.ToPosix(wd)
+	}
 	envs := []string{fmt.Sprintf("WORK_DIR=%s", wd)}
 
 	// The developer of this program can make multiple wrapper scripts
@@ -724,12 +776,12 @@
 
 	args := buildArgs(ctx, cmdConfig, argv0, r.gomaReq)
 	// TODO: only allow specific envs.
+	r.crossTarget = targetFromArgs(args)
 
 	var relocatableErr error
 	wt := wrapperRelocatable
-	pathType := cmdConfig.GetCmdDescriptor().GetSetup().GetPathType()
-	switch pathType {
-	case cmdpb.CmdDescriptor_POSIX:
+	switch r.filepath.(type) {
+	case posixpath.FilePath:
 		if r.needChroot {
 			wt = wrapperNsjailChroot
 		} else {
@@ -739,7 +791,7 @@
 				logger.Infof("non relocatable: %v", relocatableErr)
 			}
 		}
-	case cmdpb.CmdDescriptor_WINDOWS:
+	case winpath.FilePath:
 		relocatableErr = relocatableReq(ctx, cmdConfig, r.filepath, r.gomaReq.Arg, r.gomaReq.Env)
 		if relocatableErr != nil {
 			wt = wrapperWinInputRootAbsolutePath
@@ -747,9 +799,22 @@
 		} else {
 			wt = wrapperWin
 		}
+		if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+			switch wt {
+			case wrapperWinInputRootAbsolutePath:
+				// we expect most case is relocatable
+				// with -fdebug-compilation-dir=.
+				// but it would break if user uses unknown
+				// flags, which makes request unrelocatable.
+				// See rootDir fix in wrapperInputRootAbsolutePath below.
+				wt = wrapperInputRootAbsolutePath
+			case wrapperWin:
+				wt = wrapperRelocatable
+			}
+		}
 	default:
 		// internal error? maybe toolchain config is broken.
-		return fmt.Errorf("bad path type: %v", pathType)
+		return fmt.Errorf("bad path type: %T", r.filepath)
 	}
 
 	const posixWrapperName = "run.sh"
@@ -776,7 +841,17 @@
 		wrapperData := digest.Bytes("wrapper-script", []byte(wrapperScript))
 		files, wrapperData = r.maybeApplyHardening(ctx, "InputRootAbsolutePath", files, wrapperData)
 		// https://cloud.google.com/remote-build-execution/docs/remote-execution-properties#container_properties
-		r.addPlatformProperty(ctx, "InputRootAbsolutePath", r.tree.RootDir())
+		rootDir := r.tree.RootDir()
+		if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+			// we can't use windows path as absolute path.
+			// drop first two letters (i.e. `C:`), and
+			// convert \ to /.
+			// instead of making relocatable check loose,
+			// better to omit drive letter and make the
+			// effective for the same drive letter.
+			rootDir = winpath.ToPosix(rootDir)
+		}
+		r.addPlatformProperty(ctx, "InputRootAbsolutePath", rootDir)
 		for _, e := range r.gomaReq.Env {
 			envs = append(envs, e)
 		}
@@ -882,6 +957,9 @@
 	if wrapperPath == posixWrapperName {
 		wrapperPath = "./" + posixWrapperName
 	}
+	if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+		wrapperPath = winpath.ToPosix(wrapperPath)
+	}
 	r.args = append([]string{wrapperPath}, args...)
 
 	err = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(wrapperTypeKey, wt.String())}, wrapperCount.M(1))
@@ -938,6 +1016,19 @@
 func buildArgs(ctx context.Context, cmdConfig *cmdpb.Config, arg0 string, req *gomapb.ExecReq) []string {
 	// TODO: need compiler specific handling?
 	args := append([]string{arg0}, req.Arg[1:]...)
+	if cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+		args[0] = winpath.ToPosix(args[0])
+	argLoop:
+		for i := 1; i < len(args); i++ {
+			for _, f := range []string{"/winsysroot", "-resource-dir=", "-imsvc"} {
+				if strings.HasPrefix(args[i], f) {
+					args[i] = f + winpath.ToPosix(strings.TrimPrefix(args[i], f))
+					continue argLoop
+				}
+			}
+			// TODO: need to handle other args?
+		}
+	}
 	if cmdConfig.GetCmdDescriptor().GetCross().GetClangNeedTarget() {
 		args = addTargetIfNotExist(args, req.GetCommandSpec().GetTarget())
 	}
@@ -958,6 +1049,21 @@
 	return append(args, fmt.Sprintf("--target=%s", target))
 }
 
+func targetFromArgs(args []string) string {
+	for i, arg := range args {
+		if arg == "-target" {
+			if i < len(args)-1 {
+				return args[i+1]
+			}
+			return ""
+		}
+		if strings.HasPrefix(arg, "--target=") {
+			return strings.TrimPrefix(arg, "--target=")
+		}
+	}
+	return ""
+}
+
 type unknownFlagError struct {
 	arg string
 }
@@ -1091,6 +1197,9 @@
 		if err != nil {
 			return nil, fmt.Errorf("output %s: %v", output, err)
 		}
+		if r.cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+			rel = winpath.ToPosix(rel)
+		}
 		command.OutputFiles = append(command.OutputFiles, rel)
 	}
 	sort.Strings(command.OutputFiles)
@@ -1102,6 +1211,9 @@
 		if err != nil {
 			return nil, fmt.Errorf("output dir %s: %v", output, err)
 		}
+		if r.cmdConfig.GetCmdDescriptor().GetCross().GetWindowsCross() {
+			rel = winpath.ToPosix(rel)
+		}
 		command.OutputDirectories = append(command.OutputDirectories, rel)
 	}
 	sort.Strings(command.OutputDirectories)
@@ -1341,12 +1453,15 @@
 	outputTime := timestampSub(ctx, md.GetOutputUploadCompletedTimestamp(), md.GetOutputUploadStartTimestamp())
 	osFamily := platformOSFamily(r.platform)
 	dockerRuntime := platformDockerRuntime(r.platform)
-	logger.Infof("exit=%d cache=%s : exec on %q[%s, %s] queue=%s worker=%s input=%s exec=%s output=%s",
+	crossCompileType := crossCompileType(r.cmdConfig.GetCmdDescriptor().GetCross())
+	logger.Infof("exit=%d cache=%s : exec on %q[%s, %s, cross:%s, target=%s] queue=%s worker=%s input=%s exec=%s output=%s",
 		eresp.Result.GetExitCode(),
 		r.gomaResp.GetCacheHit(),
 		md.GetWorker(),
 		osFamily,
 		dockerRuntime,
+		crossCompileType,
+		r.crossTarget,
 		queueTime,
 		workerTime,
 		inputTime,
@@ -1358,6 +1473,7 @@
 		tag.Upsert(rbeCacheKey, r.gomaResp.GetCacheHit().String()),
 		tag.Upsert(rbePlatformOSFamilyKey, osFamily),
 		tag.Upsert(rbePlatformDockerRuntimeKey, dockerRuntime),
+		tag.Upsert(rbeCrossKey, crossCompileType),
 	}
 	stats.RecordWithTags(ctx, tags, rbeQueueTime.M(float64(queueTime.Nanoseconds())/1e6))
 	stats.RecordWithTags(ctx, tags, rbeWorkerTime.M(float64(workerTime.Nanoseconds())/1e6))
@@ -1496,6 +1612,16 @@
 	return "default"
 }
 
+func crossCompileType(cross *cmdpb.CmdDescriptor_Cross) string {
+	switch {
+	case cross.GetWindowsCross():
+		return "win"
+	case cross.GetClangNeedTarget():
+		return "need-target"
+	}
+	return "no"
+}
+
 func shortLogMsg(msg []byte) string {
 	if len(msg) <= 1024 {
 		return string(msg)
diff --git a/remoteexec/exec_test.go b/remoteexec/exec_test.go
index 8f563d2..79fbdd7 100644
--- a/remoteexec/exec_test.go
+++ b/remoteexec/exec_test.go
@@ -16,6 +16,7 @@
 	"github.com/golang/protobuf/proto"
 	"github.com/google/go-cmp/cmp"
 
+	"go.chromium.org/goma/server/command/descriptor/winpath"
 	"go.chromium.org/goma/server/hash"
 	"go.chromium.org/goma/server/log"
 	gomapb "go.chromium.org/goma/server/proto/api"
@@ -23,6 +24,85 @@
 	"go.chromium.org/goma/server/remoteexec/merkletree"
 )
 
+func TestDedupInputs(t *testing.T) {
+	toExecReq_Input := func(filenames []string) []*gomapb.ExecReq_Input {
+		var r []*gomapb.ExecReq_Input
+		for _, fname := range filenames {
+			r = append(r, &gomapb.ExecReq_Input{
+				Filename: proto.String(fname),
+			})
+		}
+		return r
+	}
+	fromExecReq_Input := func(inputs []*gomapb.ExecReq_Input) []string {
+		var r []string
+		for _, input := range inputs {
+			r = append(r, input.GetFilename())
+		}
+		return r
+	}
+
+	for _, tc := range []struct {
+		desc   string
+		cwd    string
+		inputs []string
+		want   []string
+	}{
+		{
+			desc: "no-dup",
+			cwd:  `c:\b\w`,
+			inputs: []string{
+				"foo",
+				"bar",
+			},
+			want: []string{
+				"foo",
+				"bar",
+			},
+		},
+		{
+			desc: "dup",
+			cwd:  `c:\b\w`,
+			inputs: []string{
+				"Foo",
+				"foo",
+			},
+			want: []string{
+				"Foo",
+			},
+		},
+		{
+			desc: "dup-pref",
+			cwd:  `c:\b\w`,
+			inputs: []string{
+				"foo",
+				"Foo",
+			},
+			want: []string{
+				"Foo",
+			},
+		},
+		{
+			desc: "short-path",
+			cwd:  `c:\b\w`,
+			inputs: []string{
+				"foo",
+				`c:\b\w\Foo`,
+			},
+			want: []string{
+				"foo",
+			},
+		},
+	} {
+		t.Run(tc.desc, func(t *testing.T) {
+			got := dedupInputs(winpath.FilePath{}, tc.cwd, toExecReq_Input(tc.inputs))
+			if diff := cmp.Diff(tc.want, fromExecReq_Input(got)); diff != "" {
+				t.Errorf("dedupInputs: diff -want +got:\n%s", diff)
+			}
+		})
+	}
+}
+
 func TestSortMissing(t *testing.T) {
 	inputs := []*gomapb.ExecReq_Input{
 		{
diff --git a/remoteexec/fake_cluster_for_test.go b/remoteexec/fake_cluster_for_test.go
index 9d403e9..81b28c2 100644
--- a/remoteexec/fake_cluster_for_test.go
+++ b/remoteexec/fake_cluster_for_test.go
@@ -231,6 +231,38 @@
 	}
 }
 
+// newFakeClangCL creates new fake toolchain for clang-cl.
+func newFakeClangCL(f *fakeCmdStorage, version string) *fakeToolchain {
+	clangCLFile := f.newFileSpec("bin/clang-cl", true)
+	return &fakeToolchain{
+		descs: []*cpb.CmdDescriptor{
+			{
+				Selector: &cpb.Selector{
+					Name:       "clang-cl",
+					Version:    version,
+					Target:     "x86_64-windows-msvc",
+					BinaryHash: clangCLFile.Hash,
+				},
+				Setup: &cpb.CmdDescriptor_Setup{
+					CmdFile:  clangCLFile,
+					PathType: cpb.CmdDescriptor_POSIX,
+				},
+				Cross: &cpb.CmdDescriptor_Cross{
+					WindowsCross: true,
+				},
+			},
+		},
+		RemoteexecPlatform: &cpb.RemoteexecPlatform{
+			Properties: []*cpb.RemoteexecPlatform_Property{
+				{
+					Name:  "container-image",
+					Value: "docker://grpc.io/goma-dev/container-image@sha256:yyy",
+				},
+			},
+		},
+	}
+}
+
 // pushToolchains push fake toolchain in fake cluster.
 func (f *fakeCluster) pushToolchains(ctx context.Context, tc *fakeToolchain) error {
 	config := &cpb.ConfigResp{
diff --git a/remoteexec/gcc.go b/remoteexec/gcc.go
index 10e34bd..9770c5e 100644
--- a/remoteexec/gcc.go
+++ b/remoteexec/gcc.go
@@ -12,10 +12,14 @@
 
 // longest first
 var pathFlags = []string{
+	"-fcoverage-compilation-dir=",
 	"-fcrash-diagnostics-dir=",
+	"-fdebug-compilation-dir=",
+	"-ffile-compilation-dir=",
 	"-fprofile-sample-use=",
 	"-fsanitize-blacklist=",
 	"-fprofile-instr-use=",
+	"-fprofile-list=",
 	"-resource-dir=",
 	"--include=",
 	"--sysroot=",
@@ -88,10 +92,20 @@
 		}
 		for _, fp := range pathFlags {
 			if arg != fp && strings.HasPrefix(arg, fp) {
-
 				if filepath.IsAbs(arg[len(fp):]) {
 					return fmt.Errorf("abs path: %s", arg)
 				}
+				if fp == "-fdebug-compilation-dir=" || fp == "-ffile-compilation-dir=" {
+					switch subCmd {
+					case "clang":
+						subArgs[subCmd] = append(subArgs[subCmd], arg)
+						fallthrough
+					case "":
+						debugCompilationDir = true
+						continue Loop
+					}
+					return errors.New("-fdebug-compilation-dir= and -ffile-compilation-dir= not supported for " + subCmd)
+				}
 				continue Loop
 			}
 		}
@@ -171,6 +185,7 @@
 		case arg == "-MMD" || arg == "-MD" || arg == "-M":
 		case arg == "-Qunused-arguments":
 		case arg == "-static-libgcc":
+		case strings.HasPrefix(arg, "--rtlib="):
 			continue
 
 		case arg == "-o":
@@ -251,13 +266,14 @@
 		case skipFlag:
 			skipFlag = false
 
-		case arg == "-mllvm", arg == "-add-plugin", arg == "-fdebug-compilation-dir":
+		case arg == "-mllvm", arg == "-add-plugin", arg == "-fdebug-compilation-dir", arg == "-target-feature":
 			// TODO: pass llvmArgRelocatable for -mllvm?
 			skipFlag = true
 		case strings.HasPrefix(arg, "-plugin-arg-"):
 			skipFlag = true
 		case arg == "-load":
 			pathFlag = true
+		case strings.HasPrefix(arg, "-f"): // feature
 		case strings.HasPrefix(arg, "-debug-info-kind="):
 		default:
 			return unknownFlagError{arg: fmt.Sprintf("clang: %s", arg)}
diff --git a/remoteexec/gcc_test.go b/remoteexec/gcc_test.go
index 01e51cc..2971322 100644
--- a/remoteexec/gcc_test.go
+++ b/remoteexec/gcc_test.go
@@ -67,6 +67,50 @@
 		"obj/base/base/time.o",
 	}
 
+	baseDebugArgs := []string{
+		"../../third_party/llvm-build/Release+Asserts/bin/clang++",
+		"-MMD",
+		"-MF",
+		"obj/base/base/time.o.d",
+		"-DUSE_SYMBOLIZE",
+		"-I../..",
+		"-fno-strict-aliasing",
+		"--param=ssp-buffer-size=4",
+		"-fPIC",
+		"-pipe",
+		"-B../../third_party/binutils/Linux_x64/Release/bin",
+		"-pthread",
+		"-Xclang",
+		"-mllvm",
+		"-Xclang",
+		"-instcombine-lower-dbg-declare=0",
+		"-no-canonical-prefixes",
+		"-m64",
+		"-march=x86-64",
+		"-Wall",
+		"-g2",
+		"-gsplit-dwarf",
+		"-Xclang",
+		"-load",
+		"-Xclang",
+		"../../third_party/llvm-build/Release+Asserts/lib/libFindBadCustructs.so",
+		"-Xclang",
+		"-add-plugin",
+		"-Xclang",
+		"find-bad-constructs",
+		"-Xclang",
+		"-plugin-arg-find-bad-constructs",
+		"-Xclang",
+		"check-enum-max-value",
+		"-isystem../../build/linux/debian_sid_amd64-sysroot/usr/include/glib-2.0",
+		"-O2",
+		"--sysroot=../../build/linux/debian_sid_amd64-sysroot",
+		"-c",
+		"../../base/time/time.cc",
+		"-o",
+		"obj/base/base/time.o",
+	}
+
 	modifyArgs := func(args []string, prefix, replace string) []string {
 		var ret []string
 		found := false
@@ -100,49 +144,7 @@
 		},
 		{
 			desc: "chromium base debug",
-			args: []string{
-				"../../third_party/llvm-build/Release+Asserts/bin/clang++",
-				"-MMD",
-				"-MF",
-				"obj/base/base/time.o.d",
-				"-DUSE_SYMBOLIZE",
-				"-I../..",
-				"-fno-strict-aliasing",
-				"--param=ssp-buffer-size=4",
-				"-fPIC",
-				"-pipe",
-				"-B../../third_party/binutils/Linux_x64/Release/bin",
-				"-pthread",
-				"-Xclang",
-				"-mllvm",
-				"-Xclang",
-				"-instcombine-lower-dbg-declare=0",
-				"-no-canonical-prefixes",
-				"-m64",
-				"-march=x86-64",
-				"-Wall",
-				"-g2",
-				"-gsplit-dwarf",
-				"-Xclang",
-				"-load",
-				"-Xclang",
-				"../../third_party/llvm-build/Release+Asserts/lib/libFindBadCustructs.so",
-				"-Xclang",
-				"-add-plugin",
-				"-Xclang",
-				"find-bad-constructs",
-				"-Xclang",
-				"-plugin-arg-find-bad-constructs",
-				"-Xclang",
-				"check-enum-max-value",
-				"-isystem../../build/linux/debian_sid_amd64-sysroot/usr/include/glib-2.0",
-				"-O2",
-				"--sysroot=../../build/linux/debian_sid_amd64-sysroot",
-				"-c",
-				"../../base/time/time.cc",
-				"-o",
-				"obj/base/base/time.o",
-			},
+			args: baseDebugArgs,
 			envs: []string{
 				"PWD=/b/c/b/linux/src/out/Debug",
 			},
@@ -380,6 +382,12 @@
 			relocatable: true,
 		},
 		{
+			desc: "-Xclang -fno-experimental-new-pass-manager",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-Xclang", "-fno-experimental-new-pass-manager"),
+			relocatable: true,
+		},
+		{
 			desc: "-mllvm -sanitizer-coverage-prune-blocks=1",
 			args: append(append([]string{}, baseReleaseArgs...),
 				"-mllvm", "-sanitizer-coverage-prune-blocks=1"),
@@ -421,6 +429,69 @@
 				"-Wa,--fatal-warnings"),
 			relocatable: true,
 		},
+		{
+			desc: "-fcoverage-compilation-dir= unrelocatable",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-fcoverage-compilation-dir=/b/c/b/linux/src/out/data/coverage-compilation-dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-fcoverage-compilation-dir= relocatable",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-fcoverage-compilation-dir=./out/data/coverage-compilation-dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-ffile-compilation-dir= unrelocatable with debug build",
+			args: append(append([]string{}, baseDebugArgs...),
+				"-ffile-compilation-dir=/b/c/b/linux/src/out/data/file-compilation-dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-ffile-compilation-dir= relocatable with debug build",
+			args: append(append([]string{}, baseDebugArgs...),
+				"-ffile-compilation-dir=./out/data/file-compilation-dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-ffile-compilation-dir= unrelocatable with release build",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-ffile-compilation-dir=/b/c/b/linux/src/out/data/file-compilation-dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-ffile-compilation-dir= relocatable with release build",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-ffile-compilation-dir=./out/data/file-compilation-dir"),
+			relocatable: true,
+		},
+		{
+			desc: "-fprofile-list= unrelocatable",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-fprofile-list=/b/c/b/linux/src/out/data/profile-list"),
+			relocatable: false,
+		},
+		{
+			desc: "-fprofile-list= relocatable",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-fprofile-list=./out/data/profile-list"),
+			relocatable: true,
+		},
+		{
+			desc: "clang -target-feature",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"-Xclang", "-target-feature",
+				"-Xclang", "+crc",
+				"-Xclang", "-target-feature",
+				"-Xclang", "+crypto"),
+			relocatable: true,
+		},
+		{
+			desc: "clang --rtlib=",
+			args: append(append([]string{}, baseReleaseArgs...),
+				"--rtlib=libgcc"),
+			relocatable: true,
+		},
 	} {
 		t.Run(tc.desc, func(t *testing.T) {
 			err := gccRelocatableReq(posixpath.FilePath{}, tc.args, tc.envs)
@@ -513,6 +584,20 @@
 				"-isystem/b/c/b/linux/src/build/linux/debian_sid_amd64-sysroot/usr/include/glib-2.0"),
 			relocatable: false,
 		},
+		{
+			desc: "-fdebug-compilation-dir= unrelocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fdebug-compilation-dir=/b/c/b/linux/src/out/data/debug_compilation_dir"),
+			relocatable: false,
+		},
+		{
+			desc: "-fdebug-compilation-dir= relocatable",
+			args: append(append([]string{},
+				baseReleaseArgs...),
+				"-fdebug-compilation-dir=./debug_compilation_dir"),
+			relocatable: true,
+		},
 	} {
 		t.Run(tc.desc, func(t *testing.T) {
 			err := gccRelocatableReq(posixpath.FilePath{}, tc.args, tc.envs)
diff --git a/remoteexec/gomaoutput.go b/remoteexec/gomaoutput.go
index dd51b8a..b160562 100644
--- a/remoteexec/gomaoutput.go
+++ b/remoteexec/gomaoutput.go
@@ -288,12 +288,14 @@
 	}()
 
 	blob, err := toChunkedFileBlob(ctx, rd, output.Digest.SizeBytes, g.gomaFile)
+	// prefer cas err for Unauthenticated error.
+	// http://b/181914314
+	if casErr := <-casErrCh; casErr != nil {
+		return nil, casErr
+	}
 	if err != nil {
 		return nil, status.Errorf(status.Code(err), "failed to convert output:{%v} to chunked FileBlob: %v", output, err)
 	}
-	if err = <-casErrCh; err != nil {
-		return nil, err
-	}
 	return blob, nil
 }
 
diff --git a/remoteexec/nsjail.go b/remoteexec/nsjail.go
index 537c9cd..7a75e67 100644
--- a/remoteexec/nsjail.go
+++ b/remoteexec/nsjail.go
@@ -8,7 +8,8 @@
 	"sort"
 	"strings"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
 
 	gomapb "go.chromium.org/goma/server/proto/api"
 	nsjailpb "go.chromium.org/goma/server/proto/nsjail"
@@ -253,5 +254,5 @@
 		// Default size might be too strict, and not suitable for
 		// compiling.
 	}
-	return []byte(proto.MarshalTextString(cfg))
+	return []byte(prototext.Format(cfg))
 }
diff --git a/remoteexec/nsjail_test.go b/remoteexec/nsjail_test.go
index 018d87b..5caa88a 100644
--- a/remoteexec/nsjail_test.go
+++ b/remoteexec/nsjail_test.go
@@ -7,7 +7,8 @@
 import (
 	"testing"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
 
 	"go.chromium.org/goma/server/command/descriptor/posixpath"
 	gomapb "go.chromium.org/goma/server/proto/api"
@@ -135,7 +136,7 @@
 
 func TestNsjailHardeningConfig(t *testing.T) {
 	cfg := &nsjailpb.NsJailConfig{}
-	err := proto.UnmarshalText(nsjailHardeningConfig, cfg)
+	err := prototext.Unmarshal([]byte(nsjailHardeningConfig), cfg)
 	if err != nil {
 		t.Errorf("unmarshal\n%s\n => %v", nsjailHardeningConfig, err)
 	}
diff --git a/remoteexec/stats.go b/remoteexec/stats.go
index 9703a45..8666c4a 100644
--- a/remoteexec/stats.go
+++ b/remoteexec/stats.go
@@ -96,6 +96,7 @@
 	rbeCacheKey                 = tag.MustNewKey("cache")
 	rbePlatformOSFamilyKey      = tag.MustNewKey("os-family")
 	rbePlatformDockerRuntimeKey = tag.MustNewKey("docker-runtime")
+	rbeCrossKey                 = tag.MustNewKey("cross")
 	// wrapper?
 
 	rbeTagKeys = []tag.Key{
@@ -103,6 +104,7 @@
 		rbeCacheKey,
 		rbePlatformOSFamilyKey,
 		rbePlatformDockerRuntimeKey,
+		rbeCrossKey,
 	}
 
 	defaultLatencyDistribution = view.Distribution(1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000)
diff --git a/rpc/grpctest/grpctest_test.go b/rpc/grpctest/grpctest_test.go
index eabb90b..eeab798 100644
--- a/rpc/grpctest/grpctest_test.go
+++ b/rpc/grpctest/grpctest_test.go
@@ -18,6 +18,7 @@
 
 // MyServer is fake execlog server.
 type MyServer struct {
+	pb.UnimplementedLogServiceServer
 	Req  *gomapb.SaveLogReq
 	Resp *gomapb.SaveLogResp
 	Err  error
diff --git a/rpc/retry.go b/rpc/retry.go
index cbec300..f1128e7 100644
--- a/rpc/retry.go
+++ b/rpc/retry.go
@@ -13,7 +13,6 @@
 	"strings"
 	"time"
 
-	"github.com/golang/protobuf/ptypes"
 	"go.opencensus.io/trace"
 	epb "google.golang.org/genproto/googleapis/rpc/errdetails"
 	"google.golang.org/grpc"
@@ -181,7 +180,11 @@
 	for _, d := range st.Details() {
 		if ri, ok := d.(*epb.RetryInfo); ok {
 			dur := ri.GetRetryDelay()
-			d, err := ptypes.Duration(dur)
+			var d time.Duration
+			err := dur.CheckValid()
+			if err == nil {
+				d = dur.AsDuration()
+			}
 			return RetriableError{
 				Err:    err,
 				Max:    retryMax,