diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27e432e --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# IDE folders +/.idea +/.vscode + +# Environment variables +/**/*.env + +# Executable files +/**/*.exe + +# Private and public keys +/**/*.ed +/**/*.pub +/**/*.pem + +# Commands +/**/*.cmd +/**/*.sh +/**/*.bat \ No newline at end of file diff --git a/cloud/gcloud/constants.go b/cloud/gcloud/constants.go new file mode 100644 index 0000000..9b20c5a --- /dev/null +++ b/cloud/gcloud/constants.go @@ -0,0 +1,17 @@ +package gcloud + +type AuthorizationIdx int + +const ( + TokenIdx AuthorizationIdx = iota +) + +// Int returns the integer value of the index +func (i AuthorizationIdx) Int() int { + return int(i) +} + +const ( + // AuthorizationMetadataKey is the key of the authorization metadata + AuthorizationMetadataKey = "x-serverless-authorization" +) diff --git a/cloud/gcloud/errors.go b/cloud/gcloud/errors.go new file mode 100644 index 0000000..732981a --- /dev/null +++ b/cloud/gcloud/errors.go @@ -0,0 +1,10 @@ +package gcloud + +import "errors" + +var ( + NilGoogleCredentialsError = errors.New("google credentials cannot be nil") + NilTokenSourceError = errors.New("token source cannot be nil") + FailedToLoadGoogleCredentialsError = errors.New("failed to load google credentials") + FailedToCreateTokenSourceError = errors.New("failed to create token source") +) diff --git a/cloud/gcloud/loader.go b/cloud/gcloud/loader.go new file mode 100644 index 0000000..69c10ca --- /dev/null +++ b/cloud/gcloud/loader.go @@ -0,0 +1,40 @@ +package gcloud + +import ( + "context" + "golang.org/x/oauth2/google" + "google.golang.org/api/idtoken" + "google.golang.org/api/option" + "google.golang.org/grpc/credentials/oauth" +) + +// LoadGoogleCredentials loads the Google credentials +func LoadGoogleCredentials(ctx context.Context) (*google.Credentials, error) { + credentials, err := google.FindDefaultCredentials(ctx) + if err != nil { + return nil, FailedToLoadGoogleCredentialsError + } + return credentials, nil +} + +// LoadServiceAccountCredentials loads the service account credentials +func LoadServiceAccountCredentials( + ctx context.Context, url string, credentials *google.Credentials, +) (*oauth.TokenSource, error) { + // Check if the credentials are nil + if credentials == nil { + return nil, NilGoogleCredentialsError + } + + // Create a new token source + tokenSource, err := idtoken.NewTokenSource( + ctx, + url, + option.WithCredentials(credentials), + ) + if err != nil { + return nil, FailedToCreateTokenSourceError + } + + return &oauth.TokenSource{TokenSource: tokenSource}, nil +} diff --git a/cloud/gcloud/logger.go b/cloud/gcloud/logger.go new file mode 100644 index 0000000..7d8ca8c --- /dev/null +++ b/cloud/gcloud/logger.go @@ -0,0 +1,47 @@ +package gcloud + +import ( + gologger "github.com/ralvarezdev/go-logger" + gologgerstatus "github.com/ralvarezdev/go-logger/status" + "google.golang.org/grpc/credentials/oauth" +) + +// Logger is the logger for Google Cloud +type Logger struct { + logger gologger.Logger +} + +// NewLogger is the logger for Google Cloud +func NewLogger(logger gologger.Logger) (*Logger, error) { + // Check if the logger is nil + if logger == nil { + return nil, gologger.NilLoggerError + } + + return &Logger{logger: logger}, nil +} + +// LoadedTokenSource logs the loaded token source +func (l *Logger) LoadedTokenSource(tokenSource *oauth.TokenSource) { + // Check if the token source is nil + if tokenSource == nil { + l.logger.LogError(gologger.NewLogError("failed to load token source", nil, NilTokenSourceError)) + return + } + + // Get the access token from the token source + token, err := tokenSource.Token() + if err != nil { + l.logger.LogError(gologger.NewLogError("failed to load token source", nil, err)) + return + } + + l.logger.LogMessage( + gologger.NewLogMessage( + "loaded token source", + gologgerstatus.StatusDebug, + nil, + token.AccessToken, + ), + ) +} diff --git a/env/errors.go b/env/errors.go new file mode 100644 index 0000000..cce8730 --- /dev/null +++ b/env/errors.go @@ -0,0 +1,8 @@ +package env + +import "errors" + +var ( + EnvironmentVariableNotFoundError = "environment variable not found: %v" + FailedToLoadEnvironmentVariablesError = errors.New("failed to load environment variables") +) diff --git a/env/loader.go b/env/loader.go new file mode 100644 index 0000000..eef3928 --- /dev/null +++ b/env/loader.go @@ -0,0 +1,16 @@ +package env + +import ( + "fmt" + "os" +) + +// LoadVariable load variable from environment variables +func LoadVariable(key string) (uri string, err error) { + // Get environment variable + variable, exists := os.LookupEnv(key) + if !exists { + return "", fmt.Errorf(EnvironmentVariableNotFoundError, key) + } + return variable, nil +} diff --git a/env/logger.go b/env/logger.go new file mode 100644 index 0000000..34b8704 --- /dev/null +++ b/env/logger.go @@ -0,0 +1,33 @@ +package env + +import ( + gologger "github.com/ralvarezdev/go-logger" + gologgerstatus "github.com/ralvarezdev/go-logger/status" +) + +// Logger is the environment logger +type Logger struct { + logger gologger.Logger +} + +// NewLogger creates a new environment logger +func NewLogger(logger gologger.Logger) (*Logger, error) { + // Check if the logger is nil + if logger == nil { + return nil, gologger.NilLoggerError + } + + return &Logger{logger: logger}, nil +} + +// EnvironmentVariableLoaded logs a message when an environment variable is loaded +func (l *Logger) EnvironmentVariableLoaded(variablesName ...string) { + l.logger.LogMessage( + gologger.NewLogMessage( + "environment variable loaded", + gologgerstatus.StatusDebug, + nil, + variablesName..., + ), + ) +} diff --git a/filesystem/errors.go b/filesystem/errors.go new file mode 100644 index 0000000..4c2ebf7 --- /dev/null +++ b/filesystem/errors.go @@ -0,0 +1,5 @@ +package filesystem + +var ( + UnableToReadFileError = "unable to read file: %v" +) diff --git a/filesystem/read_files.go b/filesystem/read_files.go new file mode 100644 index 0000000..f2ea42c --- /dev/null +++ b/filesystem/read_files.go @@ -0,0 +1,14 @@ +package filesystem + +import ( + "os" +) + +// ReadFile reads the file from the given path +func ReadFile(path string) ([]byte, error) { + file, err := os.ReadFile(path) + if err != nil { + return nil, UnableToReadFileError + } + return file, nil +} diff --git a/filesystem/working_directory.go b/filesystem/working_directory.go new file mode 100644 index 0000000..90c5f41 --- /dev/null +++ b/filesystem/working_directory.go @@ -0,0 +1,16 @@ +package filesystem + +import ( + "os" + "path/filepath" +) + +// GetCurrentDirectory gets the current directory of the executable +func GetCurrentDirectory() (string, error) { + execPath, err := os.Executable() + if err != nil { + return "", err + } + + return filepath.Dir(execPath), nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d30ea78 --- /dev/null +++ b/go.mod @@ -0,0 +1,32 @@ +module github.com/ralvarezdev/go-loader + +go 1.23.4 + +require ( + github.com/ralvarezdev/go-logger v0.1.0 + golang.org/x/oauth2 v0.24.0 + google.golang.org/api v0.213.0 + google.golang.org/grpc v1.69.0 +) + +require ( + cloud.google.com/go/auth v0.13.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/s2a-go v0.1.8 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.14.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.32.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect + google.golang.org/protobuf v1.35.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9c01c9f --- /dev/null +++ b/go.sum @@ -0,0 +1,71 @@ +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= +cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ralvarezdev/go-logger v0.1.0 h1:i2AI1nlxU6Hizvk75Vc8wtFydiVrqIeeRbJwiuO/69A= +github.com/ralvarezdev/go-logger v0.1.0/go.mod h1:v5OvFrkS+wsYNTCVegXWiRhBtcYrQJr4LDMDntvpAos= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +google.golang.org/api v0.213.0 h1:KmF6KaDyFqB417T68tMPbVmmwtIXs2VB60OJKIHB0xQ= +google.golang.org/api v0.213.0/go.mod h1:V0T5ZhNUUNpYAlL306gFZPFt5F5D/IeyLoktduYYnvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI= +google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/http/listener/errors.go b/http/listener/errors.go new file mode 100644 index 0000000..b9f047d --- /dev/null +++ b/http/listener/errors.go @@ -0,0 +1,9 @@ +package listener + +import "errors" + +var ( + FailedToCloseError = errors.New("failed to close listener") + FailedToListenError = errors.New("failed to listen") + FailedToServeError = errors.New("failed to serve") +) diff --git a/http/listener/loader.go b/http/listener/loader.go new file mode 100644 index 0000000..53f88cd --- /dev/null +++ b/http/listener/loader.go @@ -0,0 +1,34 @@ +package listener + +import ( + goloaderenv "github.com/ralvarezdev/go-loader/env" + "strings" +) + +// Port is the port of the server +type Port struct { + Port string + Host string +} + +// LoadPort load port from environment variables +func LoadPort(host string, key string) ( + *Port, error, +) { + // Get environment variable + port, err := goloaderenv.LoadVariable(key) + if err != nil { + return nil, err + } + + // Build host string + var hostBuilder strings.Builder + hostBuilder.WriteString(host) + hostBuilder.WriteString(":") + hostBuilder.WriteString(port) + + return &Port{ + Port: port, + Host: hostBuilder.String(), + }, nil +} diff --git a/http/listener/logger.go b/http/listener/logger.go new file mode 100644 index 0000000..303bffc --- /dev/null +++ b/http/listener/logger.go @@ -0,0 +1,26 @@ +package listener + +import ( + gologger "github.com/ralvarezdev/go-logger" + gologgerstatus "github.com/ralvarezdev/go-logger/status" +) + +// Logger is the logger for the listener +type Logger struct { + logger gologger.Logger +} + +// NewLogger creates a new listener logger +func NewLogger(logger gologger.Logger) (*Logger, error) { + // Check if the logger is nil + if logger == nil { + return nil, gologger.NilLoggerError + } + + return &Logger{logger: logger}, nil +} + +// ServerStarted logs a success message when the server starts +func (l *Logger) ServerStarted(port string) { + l.logger.LogMessage(gologger.NewLogMessage("server started", gologgerstatus.StatusDebug, nil, port)) +} diff --git a/http/tls/errors.go b/http/tls/errors.go new file mode 100644 index 0000000..edd8f5a --- /dev/null +++ b/http/tls/errors.go @@ -0,0 +1,8 @@ +package tls + +import "errors" + +var ( + FailedToAddCAPemError = errors.New("failed to add server ca's certificate") + FailedToLoadSystemCredentialsError = errors.New("failed to load system credentials") +) diff --git a/http/tls/loader.go b/http/tls/loader.go new file mode 100644 index 0000000..b07736e --- /dev/null +++ b/http/tls/loader.go @@ -0,0 +1,48 @@ +package tls + +import ( + "crypto/tls" + "crypto/x509" + goloaderfs "github.com/ralvarezdev/go-loader/filesystem" + "google.golang.org/grpc/credentials" +) + +// LoadTLSCredentials loads the TLS credentials +func LoadTLSCredentials(pemServerCAPath string) ( + credentials.TransportCredentials, error, +) { + // Load certificate of the CA who signed server's certificate + pemServerCA, err := goloaderfs.ReadFile(pemServerCAPath) + if err != nil { + return nil, err + } + + // Create a certificate pool from the certificate + certPool := x509.NewCertPool() + + // Append the certificates from the PEM file + if !certPool.AppendCertsFromPEM(pemServerCA) { + return nil, FailedToAddCAPemError + } + + // Create the credentials and return it + config := &tls.Config{ + RootCAs: certPool, + } + return credentials.NewTLS(config), nil +} + +// LoadSystemCredentials loads the system credentials +func LoadSystemCredentials() (credentials.TransportCredentials, error) { + // Load the system cert pool + systemRoots, err := x509.SystemCertPool() + if err != nil { + return nil, FailedToLoadSystemCredentialsError + } + + return credentials.NewTLS( + &tls.Config{ + RootCAs: systemRoots, + }, + ), nil +}