From 0f839417654987a48cdffc6a832f666862ccaf67 Mon Sep 17 00:00:00 2001 From: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> Date: Mon, 6 May 2024 09:28:28 +0200 Subject: [PATCH] feat(events): add step to emit events to GCP (#4901) * feat(gcp): add step to send events to GCP (#4896) * add gcp token handling * add initial step * publish events * add test cases * fix test case --------- Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com> * feat(gcp): Generate and validate the GCP OIDC token (#4899) * test setup for generation of jwt token * oidc token generator * push new step files * formatted code * removed toolchain and jose * removed toolchain:go 1.22.2 --------- Co-authored-by: jliempt <> Co-authored-by: D071696 Co-authored-by: d071696 <153099976+d071696@users.noreply.github.com> * feat(events): add pipeline start and end event (#4900) * add gcp token handling * add initial step * publish events * add test cases * fix test case * move files * add possible values * handle start and end event * add sap events * dependencies --------- Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com> * log successful event publish * remove dummy step * prevent step from failing * improve event creation * improve event creation * simplify eventing * remove detailed events * update parameter scope * update go.sum * fix test case * add missing method * refactor OIDC part * add oidc.go to vault pkg * mock OIDC token retrieval * mock GCP functions * update OIDC function name in Vault mocks * get event data from CPE * don't encode data payload in b64 * remove vault related changes * remove vault changes from step code * remove commented out code * documentation/steps/gcpPublishEvent.md * documentation/steps/gcpPublishEvent.md * remove hardcoded eventData * update roleID * go generate * add ordering key for pubsub event --------- Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com> Co-authored-by: D071696 Co-authored-by: d071696 <153099976+d071696@users.noreply.github.com> Co-authored-by: jliempt <> --- cmd/gcpPublishEvent.go | 90 +++++++ cmd/gcpPublishEvent_generated.go | 255 ++++++++++++++++++++ cmd/gcpPublishEvent_generated_test.go | 20 ++ cmd/gcpPublishEvent_test.go | 71 ++++++ cmd/metadata_generated.go | 1 + cmd/piper.go | 1 + documentation/docs/steps/gcpPublishEvent.md | 7 + go.mod | 50 ++-- go.sum | 118 +++++---- pkg/events/events.go | 59 +++++ pkg/events/events_test.go | 19 ++ pkg/events/options.go | 17 ++ pkg/events/options_test.go | 23 ++ pkg/gcp/pubsub.go | 64 +++++ pkg/gcp/pubsub_test.go | 45 ++++ pkg/gcp/token.go | 64 +++++ pkg/gcp/token_test.go | 50 ++++ resources/metadata/gcpPublishEvent.yaml | 83 +++++++ 18 files changed, 961 insertions(+), 76 deletions(-) create mode 100644 cmd/gcpPublishEvent.go create mode 100644 cmd/gcpPublishEvent_generated.go create mode 100644 cmd/gcpPublishEvent_generated_test.go create mode 100644 cmd/gcpPublishEvent_test.go create mode 100644 documentation/docs/steps/gcpPublishEvent.md create mode 100644 pkg/events/events.go create mode 100644 pkg/events/events_test.go create mode 100644 pkg/events/options.go create mode 100644 pkg/events/options_test.go create mode 100644 pkg/gcp/pubsub.go create mode 100644 pkg/gcp/pubsub_test.go create mode 100644 pkg/gcp/token.go create mode 100644 pkg/gcp/token_test.go create mode 100644 resources/metadata/gcpPublishEvent.yaml diff --git a/cmd/gcpPublishEvent.go b/cmd/gcpPublishEvent.go new file mode 100644 index 0000000000..1f8a52e78c --- /dev/null +++ b/cmd/gcpPublishEvent.go @@ -0,0 +1,90 @@ +package cmd + +import ( + "github.com/SAP/jenkins-library/pkg/events" + "github.com/SAP/jenkins-library/pkg/gcp" + "github.com/SAP/jenkins-library/pkg/log" + "github.com/SAP/jenkins-library/pkg/orchestrator" + "github.com/SAP/jenkins-library/pkg/telemetry" + + "github.com/pkg/errors" +) + +type gcpPublishEventUtils interface { + GetConfig() *gcpPublishEventOptions + GetOIDCTokenByValidation(roleID string) (string, error) + GetFederatedToken(projectNumber, pool, provider, token string) (string, error) + Publish(projectNumber string, topic string, token string, key string, data []byte) error +} + +type gcpPublishEventUtilsBundle struct { + config *gcpPublishEventOptions +} + +func (g gcpPublishEventUtilsBundle) GetConfig() *gcpPublishEventOptions { + return g.config +} + +func (g gcpPublishEventUtilsBundle) GetFederatedToken(projectNumber, pool, provider, token string) (string, error) { + return gcp.GetFederatedToken(projectNumber, pool, provider, token) +} + +func (g gcpPublishEventUtilsBundle) Publish(projectNumber string, topic string, token string, key string, data []byte) error { + return gcp.Publish(projectNumber, topic, token, key, data) +} + +// to be implemented through another PR! +func (g gcpPublishEventUtilsBundle) GetOIDCTokenByValidation(roleID string) (string, error) { + return "testToken", nil +} + +func gcpPublishEvent(config gcpPublishEventOptions, telemetryData *telemetry.CustomData) { + utils := gcpPublishEventUtilsBundle{ + config: &config, + } + + err := runGcpPublishEvent(utils) + if err != nil { + // do not fail the step + log.Entry().WithError(err).Warnf("step execution failed") + } +} + +func runGcpPublishEvent(utils gcpPublishEventUtils) error { + config := utils.GetConfig() + + var data []byte + var err error + + provider, err := orchestrator.GetOrchestratorConfigProvider(nil) + if err != nil { + log.Entry().WithError(err).Warning("Cannot infer config from CI environment") + } + + data, err = events.NewEvent(config.EventType, config.EventSource).CreateWithJSONData(config.EventData).ToBytes() + if err != nil { + return errors.Wrap(err, "failed to create event data") + } + + // this is currently returning a mock token. function will be implemented through another PR! + // roleID will come from GeneralConfig.HookConfig.OIDCConfig.RoleID + roleID := "test" + oidcToken, err := utils.GetOIDCTokenByValidation(roleID) + if err != nil { + return errors.Wrap(err, "failed to get OIDC token") + } + + token, err := utils.GetFederatedToken(config.GcpProjectNumber, config.GcpWorkloadIDentityPool, config.GcpWorkloadIDentityPoolProvider, oidcToken) + if err != nil { + return errors.Wrap(err, "failed to get federated token") + } + + err = utils.Publish(config.GcpProjectNumber, config.Topic, token, provider.BuildURL(), data) + if err != nil { + return errors.Wrap(err, "failed to publish event") + } + + log.Entry().Info("event published successfully!") + + return nil +} diff --git a/cmd/gcpPublishEvent_generated.go b/cmd/gcpPublishEvent_generated.go new file mode 100644 index 0000000000..47fcea9b21 --- /dev/null +++ b/cmd/gcpPublishEvent_generated.go @@ -0,0 +1,255 @@ +// Code generated by piper's step-generator. DO NOT EDIT. + +package cmd + +import ( + "fmt" + "os" + "time" + + "github.com/SAP/jenkins-library/pkg/config" + "github.com/SAP/jenkins-library/pkg/log" + "github.com/SAP/jenkins-library/pkg/splunk" + "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/SAP/jenkins-library/pkg/validation" + "github.com/spf13/cobra" +) + +type gcpPublishEventOptions struct { + VaultNamespace string `json:"vaultNamespace,omitempty"` + VaultServerURL string `json:"vaultServerUrl,omitempty"` + OIDCToken string `json:"OIDCToken,omitempty"` + GcpProjectNumber string `json:"gcpProjectNumber,omitempty"` + GcpWorkloadIDentityPool string `json:"gcpWorkloadIdentityPool,omitempty"` + GcpWorkloadIDentityPoolProvider string `json:"gcpWorkloadIdentityPoolProvider,omitempty"` + Topic string `json:"topic,omitempty"` + EventSource string `json:"eventSource,omitempty"` + EventType string `json:"eventType,omitempty"` + EventData string `json:"eventData,omitempty"` +} + +// GcpPublishEventCommand Publishes an event to GCP using OIDC authentication (beta) +func GcpPublishEventCommand() *cobra.Command { + const STEP_NAME = "gcpPublishEvent" + + metadata := gcpPublishEventMetadata() + var stepConfig gcpPublishEventOptions + var startTime time.Time + var logCollector *log.CollectorHook + var splunkClient *splunk.Splunk + telemetryClient := &telemetry.Telemetry{} + + var createGcpPublishEventCmd = &cobra.Command{ + Use: STEP_NAME, + Short: "Publishes an event to GCP using OIDC authentication (beta)", + Long: `This step is in beta. +Authentication to GCP is handled by an OIDC token received from, for example, Vault.`, + PreRunE: func(cmd *cobra.Command, _ []string) error { + startTime = time.Now() + log.SetStepName(STEP_NAME) + log.SetVerbose(GeneralConfig.Verbose) + + GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens) + + path, _ := os.Getwd() + fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path} + log.RegisterHook(fatalHook) + + err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile) + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return err + } + + if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { + sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) + log.RegisterHook(&sentryHook) + } + + if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 || len(GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint) > 0 { + splunkClient = &splunk.Splunk{} + logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID} + log.RegisterHook(logCollector) + } + + if err = log.RegisterANSHookIfConfigured(GeneralConfig.CorrelationID); err != nil { + log.Entry().WithError(err).Warn("failed to set up SAP Alert Notification Service log hook") + } + + validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages()) + if err != nil { + return err + } + if err = validation.ValidateStruct(stepConfig); err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return err + } + + return nil + }, + Run: func(_ *cobra.Command, _ []string) { + stepTelemetryData := telemetry.CustomData{} + stepTelemetryData.ErrorCode = "1" + handler := func() { + config.RemoveVaultSecretFiles() + stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) + stepTelemetryData.ErrorCategory = log.GetErrorCategory().String() + stepTelemetryData.PiperCommitHash = GitCommit + telemetryClient.SetData(&stepTelemetryData) + telemetryClient.Send() + if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { + splunkClient.Initialize(GeneralConfig.CorrelationID, + GeneralConfig.HookConfig.SplunkConfig.Dsn, + GeneralConfig.HookConfig.SplunkConfig.Token, + GeneralConfig.HookConfig.SplunkConfig.Index, + GeneralConfig.HookConfig.SplunkConfig.SendLogs) + splunkClient.Send(telemetryClient.GetData(), logCollector) + } + if len(GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint) > 0 { + splunkClient.Initialize(GeneralConfig.CorrelationID, + GeneralConfig.HookConfig.SplunkConfig.ProdCriblEndpoint, + GeneralConfig.HookConfig.SplunkConfig.ProdCriblToken, + GeneralConfig.HookConfig.SplunkConfig.ProdCriblIndex, + GeneralConfig.HookConfig.SplunkConfig.SendLogs) + splunkClient.Send(telemetryClient.GetData(), logCollector) + } + } + log.DeferExitHandler(handler) + defer handler() + telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME, GeneralConfig.HookConfig.PendoConfig.Token) + gcpPublishEvent(stepConfig, &stepTelemetryData) + stepTelemetryData.ErrorCode = "0" + log.Entry().Info("SUCCESS") + }, + } + + addGcpPublishEventFlags(createGcpPublishEventCmd, &stepConfig) + return createGcpPublishEventCmd +} + +func addGcpPublishEventFlags(cmd *cobra.Command, stepConfig *gcpPublishEventOptions) { + cmd.Flags().StringVar(&stepConfig.VaultNamespace, "vaultNamespace", os.Getenv("PIPER_vaultNamespace"), "") + cmd.Flags().StringVar(&stepConfig.VaultServerURL, "vaultServerUrl", os.Getenv("PIPER_vaultServerUrl"), "") + cmd.Flags().StringVar(&stepConfig.OIDCToken, "OIDCToken", os.Getenv("PIPER_OIDCToken"), "") + cmd.Flags().StringVar(&stepConfig.GcpProjectNumber, "gcpProjectNumber", os.Getenv("PIPER_gcpProjectNumber"), "") + cmd.Flags().StringVar(&stepConfig.GcpWorkloadIDentityPool, "gcpWorkloadIdentityPool", os.Getenv("PIPER_gcpWorkloadIdentityPool"), "A workload identity pool is an entity that lets you manage external identities.") + cmd.Flags().StringVar(&stepConfig.GcpWorkloadIDentityPoolProvider, "gcpWorkloadIdentityPoolProvider", os.Getenv("PIPER_gcpWorkloadIdentityPoolProvider"), "A workload identity pool provider is an entity that describes a relationship between Google Cloud and your IdP.") + cmd.Flags().StringVar(&stepConfig.Topic, "topic", os.Getenv("PIPER_topic"), "The pubsub topic to which the message is published.") + cmd.Flags().StringVar(&stepConfig.EventSource, "eventSource", os.Getenv("PIPER_eventSource"), "The events source as defined by CDEvents.") + cmd.Flags().StringVar(&stepConfig.EventType, "eventType", os.Getenv("PIPER_eventType"), "") + cmd.Flags().StringVar(&stepConfig.EventData, "eventData", os.Getenv("PIPER_eventData"), "Data to be merged with the generated data for the cloud event data field (JSON)") + +} + +// retrieve step metadata +func gcpPublishEventMetadata() config.StepData { + var theMetaData = config.StepData{ + Metadata: config.StepMetadata{ + Name: "gcpPublishEvent", + Aliases: []config.Alias{}, + Description: "Publishes an event to GCP using OIDC authentication (beta)", + }, + Spec: config.StepSpec{ + Inputs: config.StepInputs{ + Parameters: []config.StepParameters{ + { + Name: "vaultNamespace", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_vaultNamespace"), + }, + { + Name: "vaultServerUrl", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_vaultServerUrl"), + }, + { + Name: "OIDCToken", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_OIDCToken"), + }, + { + Name: "gcpProjectNumber", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_gcpProjectNumber"), + }, + { + Name: "gcpWorkloadIdentityPool", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_gcpWorkloadIdentityPool"), + }, + { + Name: "gcpWorkloadIdentityPoolProvider", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_gcpWorkloadIdentityPoolProvider"), + }, + { + Name: "topic", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_topic"), + }, + { + Name: "eventSource", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_eventSource"), + }, + { + Name: "eventType", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS"}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_eventType"), + }, + { + Name: "eventData", + ResourceRef: []config.ResourceReference{ + { + Name: "commonPipelineEnvironment", + Param: "custom/eventData", + }, + }, + Scope: []string{}, + Type: "string", + Mandatory: false, + Aliases: []config.Alias{}, + Default: os.Getenv("PIPER_eventData"), + }, + }, + }, + }, + } + return theMetaData +} diff --git a/cmd/gcpPublishEvent_generated_test.go b/cmd/gcpPublishEvent_generated_test.go new file mode 100644 index 0000000000..e5116f69f9 --- /dev/null +++ b/cmd/gcpPublishEvent_generated_test.go @@ -0,0 +1,20 @@ +//go:build unit +// +build unit + +package cmd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGcpPublishEventCommand(t *testing.T) { + t.Parallel() + + testCmd := GcpPublishEventCommand() + + // only high level testing performed - details are tested in step generation procedure + assert.Equal(t, "gcpPublishEvent", testCmd.Use, "command name incorrect") + +} diff --git a/cmd/gcpPublishEvent_test.go b/cmd/gcpPublishEvent_test.go new file mode 100644 index 0000000000..9dc5933172 --- /dev/null +++ b/cmd/gcpPublishEvent_test.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" +) + +type mockGcpPublishEventUtilsBundle struct { + config *gcpPublishEventOptions +} + +func (g *mockGcpPublishEventUtilsBundle) GetConfig() *gcpPublishEventOptions { + return g.config +} + +func (g *mockGcpPublishEventUtilsBundle) GetOIDCTokenByValidation(roleID string) (string, error) { + return "testOIDCtoken123", nil +} + +func (g *mockGcpPublishEventUtilsBundle) GetFederatedToken(projectNumber, pool, provider, token string) (string, error) { + return "testFederatedToken123", nil +} + +func (g *mockGcpPublishEventUtilsBundle) Publish(projectNumber string, topic string, token string, key string, data []byte) error { + if topic == "goodTestCase" { + return nil + } else if topic == "badTestCase" { + return errors.New("failed to send request") + } + return nil +} + +func TestRunGcpPublishEvent(t *testing.T) { + t.Parallel() + + t.Run("happy path", func(t *testing.T) { + t.Parallel() + // init + mock := &mockGcpPublishEventUtilsBundle{ + config: &gcpPublishEventOptions{ + EventType: "PipelineRunStarted", + EventSource: "unittest", + Topic: "goodTestCase", + }} + + // test + err := runGcpPublishEvent(mock) + + // assert + assert.NoError(t, err) + }) + + t.Run("error path", func(t *testing.T) { + t.Parallel() + // init + mock := &mockGcpPublishEventUtilsBundle{ + config: &gcpPublishEventOptions{ + EventType: "PipelineRunStarted", + EventSource: "unittest", + Topic: "badTestCase", + }} + + // test + err := runGcpPublishEvent(mock) + + // assert + assert.EqualError(t, err, "failed to publish event: failed to send request") + }) +} diff --git a/cmd/metadata_generated.go b/cmd/metadata_generated.go index d39526eb13..56cebc07d4 100644 --- a/cmd/metadata_generated.go +++ b/cmd/metadata_generated.go @@ -58,6 +58,7 @@ func GetAllStepMetadata() map[string]config.StepData { "detectExecuteScan": detectExecuteScanMetadata(), "fortifyExecuteScan": fortifyExecuteScanMetadata(), "gaugeExecuteTests": gaugeExecuteTestsMetadata(), + "gcpPublishEvent": gcpPublishEventMetadata(), "gctsCloneRepository": gctsCloneRepositoryMetadata(), "gctsCreateRepository": gctsCreateRepositoryMetadata(), "gctsDeploy": gctsDeployMetadata(), diff --git a/cmd/piper.go b/cmd/piper.go index 8377f61a41..1ce4f5089f 100644 --- a/cmd/piper.go +++ b/cmd/piper.go @@ -92,6 +92,7 @@ var GeneralConfig GeneralConfigOptions func Execute() { log.Entry().Infof("Version %s", GitCommit) + rootCmd.AddCommand(GcpPublishEventCommand()) rootCmd.AddCommand(ArtifactPrepareVersionCommand()) rootCmd.AddCommand(ConfigCommand()) rootCmd.AddCommand(DefaultsCommand()) diff --git a/documentation/docs/steps/gcpPublishEvent.md b/documentation/docs/steps/gcpPublishEvent.md new file mode 100644 index 0000000000..63991c1344 --- /dev/null +++ b/documentation/docs/steps/gcpPublishEvent.md @@ -0,0 +1,7 @@ +# ${docGenStepName} + +## ${docGenDescription} + +## ${docGenParameters} + +## ${docGenConfiguration} diff --git a/go.mod b/go.mod index cb0317a718..b2c2299b60 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ toolchain go1.21.9 replace github.com/moby/buildkit => github.com/moby/buildkit v0.11.6 require ( - cloud.google.com/go/storage v1.30.1 + cloud.google.com/go/storage v1.38.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 github.com/BurntSushi/toml v1.3.2 github.com/Jeffail/gabs/v2 v2.6.1 @@ -20,6 +20,7 @@ require ( github.com/bmatcuk/doublestar v1.3.4 github.com/bndr/gojenkins v1.1.1-0.20240109173050-c316119c46d5 github.com/buildpacks/lifecycle v0.18.4 + github.com/cloudevents/sdk-go/v2 v2.10.1 github.com/docker/cli v24.0.6+incompatible github.com/elliotchance/orderedmap v1.4.0 github.com/evanphx/json-patch v5.7.0+incompatible @@ -35,7 +36,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.16.1 github.com/google/go-github/v45 v45.2.0 - github.com/google/uuid v1.5.0 + github.com/google/uuid v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/vault/api v1.9.2 github.com/iancoleman/orderedmap v0.2.0 @@ -47,7 +48,7 @@ require ( github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 github.com/mitchellh/mapstructure v1.5.0 github.com/motemen/go-nuts v0.0.0-20220604134737-2658d0104f31 - github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 + github.com/package-url/packageurl-go v0.1.1 github.com/piper-validation/fortify-client-go v0.0.0-20220126145513-7b3e9a72af01 github.com/pkg/errors v0.9.1 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 @@ -58,9 +59,9 @@ require ( github.com/testcontainers/testcontainers-go v0.10.0 github.com/xuri/excelize/v2 v2.4.1 golang.org/x/mod v0.14.0 - golang.org/x/oauth2 v0.16.0 + golang.org/x/oauth2 v0.17.0 golang.org/x/text v0.14.0 - google.golang.org/api v0.157.0 + google.golang.org/api v0.167.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v2 v2.4.0 helm.sh/helm/v3 v3.14.0 @@ -97,21 +98,24 @@ require ( github.com/oapi-codegen/runtime v1.0.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/skeema/knownhosts v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/metric v1.23.0 // indirect + go.opentelemetry.io/otel/trace v1.23.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.17.0 // indirect golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect golang.org/x/tools v0.17.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect ) require ( - cloud.google.com/go v0.111.0 // indirect - cloud.google.com/go/compute v1.23.3 // indirect - cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.24.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect @@ -156,7 +160,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/analysis v0.21.2 // indirect github.com/go-openapi/errors v0.20.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect @@ -175,7 +179,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -239,16 +243,16 @@ require ( go.mongodb.org/mongo-driver v1.11.6 // indirect go.opencensus.io v0.24.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/crypto v0.18.0 + golang.org/x/crypto v0.19.0 golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 - golang.org/x/net v0.20.0 // indirect + golang.org/x/net v0.21.0 // indirect golang.org/x/sync v0.6.0 - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/grpc v1.60.1 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/grpc v1.62.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 7da2a071ce..7c3f129471 100644 --- a/go.sum +++ b/go.sum @@ -14,22 +14,22 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= 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= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 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= @@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo 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.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= -cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= +cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -258,11 +258,13 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go/v2 v2.10.1 h1:qNFovJ18fWOd8Q9ydWJPk1oiFudXyv1GxJIP7MwPjuM= +github.com/cloudevents/sdk-go/v2 v2.10.1/go.mod h1:GpCBmUj7DIRiDhVvsK5d6WCbgTWs8DxAWTRtAwQmIXs= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= @@ -409,8 +411,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -464,8 +466,9 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= @@ -698,14 +701,14 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -989,8 +992,8 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= -github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o= -github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +github.com/package-url/packageurl-go v0.1.1 h1:KTRE0bK3sKbFKAk3yy63DpeskU7Cvs/x/Da5l+RtzyU= +github.com/package-url/packageurl-go v0.1.1/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c h1:Gcce/r5tSQeprxswXXOwQ/RBU1bjQWVd9dB7QKoPXBE= github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c/go.mod h1:1iCZ0433JJMecYqCa+TdWA9Pax8MGl4ByuNDZ7eSnQY= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= @@ -1150,6 +1153,8 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= @@ -1207,24 +1212,30 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1248,8 +1259,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1341,16 +1352,16 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= 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= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1451,8 +1462,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1460,8 +1471,8 @@ golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 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= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1482,6 +1493,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb 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-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1546,8 +1558,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1565,8 +1577,8 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.157.0 h1:ORAeqmbrrozeyw5NjnMxh7peHO0UzV4wWYSwZeCUb20= -google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g= +google.golang.org/api v0.167.0 h1:CKHrQD1BLRii6xdkatBDXyKzM0mkawt2QP+H3LtPmSE= +google.golang.org/api v0.167.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= 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= @@ -1609,12 +1621,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= -google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78 h1:SzXBGiWM1LNVYLCRP3e0/Gsze804l4jGoJ5lYysEO5I= +google.golang.org/genproto/googleapis/api v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 h1:DKU1r6Tj5s1vlU/moGhuGz7E3xRfwjdAfDzbsaQJtEY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1632,8 +1644,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= diff --git a/pkg/events/events.go b/pkg/events/events.go new file mode 100644 index 0000000000..cd8d78e03b --- /dev/null +++ b/pkg/events/events.go @@ -0,0 +1,59 @@ +package events + +import ( + "encoding/json" + "time" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/google/uuid" + "github.com/pkg/errors" +) + +// type EventType string + +type EventData struct { + URL string `json:"url"` + CommitId string `json:"commitId"` + RepositoryURL string `json:"repositoryUrl"` +} + +type Event struct { + cloudEvent cloudevents.Event + eventType string + eventSource string +} + +func NewEvent(eventType, eventSource string) Event { + return Event{ + eventType: eventType, + eventSource: eventSource, + } +} + +func (e Event) CreateWithJSONData(data string, opts ...Option) Event { + return e.Create(data, opts...) +} + +func (e Event) Create(data any, opts ...Option) Event { + e.cloudEvent = cloudevents.NewEvent("1.0") + // set default values + e.cloudEvent.SetID(uuid.New().String()) + e.cloudEvent.SetType(e.eventType) + e.cloudEvent.SetTime(time.Now()) + e.cloudEvent.SetSource(e.eventSource) + e.cloudEvent.SetData("application/json", data) + + for _, applyOpt := range opts { + applyOpt(e.cloudEvent.Context.AsV1()) + } + + return e +} + +func (e Event) ToBytes() ([]byte, error) { + data, err := json.Marshal(e.cloudEvent) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal event data") + } + return data, nil +} diff --git a/pkg/events/events_test.go b/pkg/events/events_test.go new file mode 100644 index 0000000000..2ef1a0a00f --- /dev/null +++ b/pkg/events/events_test.go @@ -0,0 +1,19 @@ +package events + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestEventCreation(t *testing.T) { + t.Run("success", func(t *testing.T) { + // init + // test + event := NewEvent(mock.Anything, mock.Anything).Create(nil) + // asserts + assert.Equal(t, mock.Anything, event.cloudEvent.Type()) + assert.Equal(t, mock.Anything, event.cloudEvent.Source()) + }) +} diff --git a/pkg/events/options.go b/pkg/events/options.go new file mode 100644 index 0000000000..924068df1b --- /dev/null +++ b/pkg/events/options.go @@ -0,0 +1,17 @@ +package events + +import cloudevents "github.com/cloudevents/sdk-go/v2" + +type Option func(o *cloudevents.EventContextV1) + +func WithID(id string) Option { + return func(o *cloudevents.EventContextV1) { + o.SetID(id) + } +} + +func WithType(etype string) Option { + return func(o *cloudevents.EventContextV1) { + o.SetType(etype) + } +} diff --git a/pkg/events/options_test.go b/pkg/events/options_test.go new file mode 100644 index 0000000000..657a8bc173 --- /dev/null +++ b/pkg/events/options_test.go @@ -0,0 +1,23 @@ +package events + +import ( + "testing" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func Test(t *testing.T) { + t.Run("success", func(t *testing.T) { + // init + ec := cloudevents.EventContextV1{} + opts := []Option{WithID(mock.Anything)} + // test + for _, applyOpt := range opts { + applyOpt(&ec) + } + // asserts + assert.Equal(t, mock.Anything, ec.GetID()) + }) +} diff --git a/pkg/gcp/pubsub.go b/pkg/gcp/pubsub.go new file mode 100644 index 0000000000..3dd604ade3 --- /dev/null +++ b/pkg/gcp/pubsub.go @@ -0,0 +1,64 @@ +package gcp + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/pkg/errors" +) + +const api_url = "https://pubsub.googleapis.com/v1/projects/%s/topics/%s:publish" + +// https://pkg.go.dev/cloud.google.com/go/pubsub#Message +type EventMessage struct { + Data []byte `json:"data"` + OrderingKey string `json:"orderingKey"` +} + +type Event struct { + Messages []EventMessage `json:"messages"` +} + +func Publish(projectNumber string, topic string, token string, key string, data []byte) error { + ctx := context.Background() + + // build event + event := Event{ + Messages: []EventMessage{{ + Data: data, + OrderingKey: key, + }}, + } + + // marshal event + eventBytes, err := json.Marshal(event) + if err != nil { + return errors.Wrap(err, "failed to marshal event") + } + + // create request + request, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf(api_url, projectNumber, topic), bytes.NewReader(eventBytes)) + if err != nil { + return errors.Wrap(err, "failed to create request") + } + + // add headers + request.Header.Set("Content-Type", "application/json") + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + + // send request + response, err := http.DefaultClient.Do(request) + if err != nil { + return errors.Wrap(err, "failed to send request") + } + if response.StatusCode != http.StatusOK { + return fmt.Errorf("invalid status code: %v", response.StatusCode) + } + + //TODO: read response & messageIds + + return nil +} diff --git a/pkg/gcp/pubsub_test.go b/pkg/gcp/pubsub_test.go new file mode 100644 index 0000000000..a25e0a3b38 --- /dev/null +++ b/pkg/gcp/pubsub_test.go @@ -0,0 +1,45 @@ +package gcp + +import ( + "fmt" + "net/http" + "testing" + + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestPublish(t *testing.T) { + t.Run("success", func(t *testing.T) { + // init + projectNumber := "PROJECT_NUMBER" + topic := "TOPIC" + token := "TOKEN" + data := []byte(mock.Anything) + + apiurl := fmt.Sprintf(api_url, projectNumber, topic) + + mockResponse := map[string]interface{}{ + "messageIds": []string{"10721501285371497"}, + } + + // mock + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(http.MethodPost, apiurl, + func(req *http.Request) (*http.Response, error) { + assert.Contains(t, req.Header, "Authorization") + assert.Equal(t, req.Header.Get("Authorization"), "Bearer TOKEN") + assert.Contains(t, req.Header, "Content-Type") + assert.Equal(t, req.Header.Get("Content-Type"), "application/json") + return httpmock.NewJsonResponse(http.StatusOK, mockResponse) + }, + ) + + // test + err := Publish(projectNumber, topic, token, mock.Anything, data) + // asserts + assert.NoError(t, err) + }) +} diff --git a/pkg/gcp/token.go b/pkg/gcp/token.go new file mode 100644 index 0000000000..fe7a59346a --- /dev/null +++ b/pkg/gcp/token.go @@ -0,0 +1,64 @@ +package gcp + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/pkg/errors" + "google.golang.org/api/sts/v1" +) + +// https://cloud.google.com/iam/docs/reference/sts/rest +const exchangeTokenAPIURL = "https://sts.googleapis.com/v1/token" + +func GetFederatedToken(projectNumber, pool, provider, token string) (string, error) { + ctx := context.Background() + requestData := getExchangeTokenRequestData(projectNumber, pool, provider, token) + + // data to byte + jsonData, err := json.Marshal(requestData) + if err != nil { + return "", errors.Wrapf(err, "failed to marshal the request data") + } + + // build request + request, err := http.NewRequestWithContext(ctx, http.MethodPost, exchangeTokenAPIURL, bytes.NewReader(jsonData)) + if err != nil { + return "", errors.Wrap(err, "failed to build request") + } + + // send request + response, err := http.DefaultClient.Do(request) + if err != nil { + return "", errors.Wrap(err, "failed to send request") + } + if response.StatusCode != http.StatusOK { + return "", fmt.Errorf("invalid status code: %v", response.StatusCode) + } + + // response to data + defer response.Body.Close() + responseData := sts.GoogleIdentityStsV1ExchangeTokenResponse{} + err = json.NewDecoder(response.Body).Decode(&responseData) + if err != nil { + return "", errors.Wrap(err, "failed to decode response") + } + + return responseData.AccessToken, nil +} + +func getExchangeTokenRequestData(projectNumber string, pool string, provider string, token string) sts.GoogleIdentityStsV1ExchangeTokenRequest { + return sts.GoogleIdentityStsV1ExchangeTokenRequest{ + Audience: fmt.Sprintf( + "//iam.googleapis.com/projects/%s/locations/global/workloadIdentityPools/%s/providers/%s", + projectNumber, pool, provider), + Scope: "https://www.googleapis.com/auth/cloud-platform", + SubjectToken: token, + SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt", + GrantType: "urn:ietf:params:oauth:grant-type:token-exchange", + RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token", + } +} diff --git a/pkg/gcp/token_test.go b/pkg/gcp/token_test.go new file mode 100644 index 0000000000..00d5a6131a --- /dev/null +++ b/pkg/gcp/token_test.go @@ -0,0 +1,50 @@ +package gcp + +import ( + "net/http" + "testing" + + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "google.golang.org/api/sts/v1" +) + +func TestGetExchangeTokenRequestData(t *testing.T) { + // ctx := context.Background() + t.Run("success", func(t *testing.T) { + // init + projectNumber := "PROJECT_NUMBER" + pool := "POOL" + provider := "PROVIDER" + // test + data := getExchangeTokenRequestData(projectNumber, pool, provider, mock.Anything) + // asserts + assert.Equal(t, data.Audience, "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL/providers/PROVIDER") + assert.Equal(t, data.SubjectToken, mock.Anything) + }) +} + +func TestGetFederatedToken(t *testing.T) { + t.Run("success", func(t *testing.T) { + // init + projectNumber := "PROJECT_NUMBER" + pool := "POOL" + provider := "PROVIDER" + + // mock + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(http.MethodPost, exchangeTokenAPIURL, + func(req *http.Request) (*http.Response, error) { + return httpmock.NewJsonResponse(http.StatusOK, sts.GoogleIdentityStsV1ExchangeTokenResponse{AccessToken: mock.Anything}) + }, + ) + + // test + federatedToken, err := GetFederatedToken(projectNumber, pool, provider, mock.Anything) + // asserts + assert.NoError(t, err) + assert.Equal(t, mock.Anything, federatedToken) + }) +} diff --git a/resources/metadata/gcpPublishEvent.yaml b/resources/metadata/gcpPublishEvent.yaml new file mode 100644 index 0000000000..fb7abd048f --- /dev/null +++ b/resources/metadata/gcpPublishEvent.yaml @@ -0,0 +1,83 @@ +metadata: + name: gcpPublishEvent + description: Publishes an event to GCP using OIDC authentication (beta) + longDescription: | + This step is in beta. + Authentication to GCP is handled by an OIDC token received from, for example, Vault. +spec: + inputs: + params: + - name: vaultNamespace + type: "string" + description: + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: vaultServerUrl + type: "string" + description: + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: OIDCToken + description: + type: "string" + scope: + - PARAMETERS + - STAGES + - STEPS + - name: gcpProjectNumber + description: + type: "string" + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: gcpWorkloadIdentityPool + description: A workload identity pool is an entity that lets you manage external identities. + type: "string" + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: gcpWorkloadIdentityPoolProvider + description: A workload identity pool provider is an entity that describes a relationship between Google Cloud and your IdP. + type: "string" + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: topic + description: The pubsub topic to which the message is published. + type: "string" + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: eventSource + description: The events source as defined by CDEvents. + type: "string" + scope: + - GENERAL + - PARAMETERS + - STAGES + - STEPS + - name: eventType + description: + type: "string" + scope: + - PARAMETERS + - name: eventData + type: string + description: Data to be merged with the generated data for the cloud event data field (JSON) + resourceRef: + - name: commonPipelineEnvironment + param: custom/eventData