blob: 124341128373c374036918f43de403c1636a577f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package resultstore
import (
"context"
"crypto/x509"
"fmt"
"go.chromium.org/luci/auth"
api "google.golang.org/genproto/googleapis/devtools/resultstore/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/oauth"
)
// Connect returns a new Service connected to the ResultStore backend at the given host.
func Connect(ctx context.Context, host string) (Service, error) {
conn, err := connectToGRPCHost(ctx, host)
if err != nil {
return nil, err
}
return NewService(api.NewResultStoreUploadClient(conn)), nil
}
// AuthMode specifies how to authenticate with ResultStore.
type AuthMode string
// AuthMode constants.
const (
// LUCIAuth uses LUCI auth with SilentLogin. See the docs at
// go.chromium.org/luci/common/auth#SilentLogin for more details. This mode should
// always be used in production.
LUCIAuth AuthMode = "luci"
// GAEDefaultAuth uses the Google application default credentials, which are read from
// the environment variable GOOGLE_APPLICATION_CREDENTIALS. This is useful for local
// debugging and testing.
GAEDefaultAuth AuthMode = "gae_default"
)
const (
// Google Cloud API scope required to use ResultStore Upload API.
scope = "https://www.googleapis.com/auth/cloud-platform"
)
func connectToGRPCHost(ctx context.Context, host string) (*grpc.ClientConn, error) {
// TODO(IN-699): AuthMode and Options should be initialized by command-line flags.
var authOpts auth.Options
perRPC, err := perRPCCredentials(ctx, GAEDefaultAuth, authOpts)
if err != nil {
return nil, err
}
pool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("failed to create cert pool: %v", err)
}
transportCreds := credentials.NewClientTLSFromCert(pool, "")
return grpc.Dial(host,
grpc.WithTransportCredentials(transportCreds),
grpc.WithPerRPCCredentials(perRPC),
)
}
func perRPCCredentials(ctx context.Context, authMode AuthMode, authOpts auth.Options) (credentials.PerRPCCredentials, error) {
switch authMode {
case LUCIAuth:
authenticator := auth.NewAuthenticator(ctx, auth.SilentLogin, authOpts)
return authenticator.PerRPCCredentials()
case GAEDefaultAuth:
return oauth.NewApplicationDefault(ctx, scope)
default:
return nil, fmt.Errorf("invalid authenticatation mode: %v", authMode)
}
}