From dbc7bbd90579b0cc802b954e0d58b9770e00b49a Mon Sep 17 00:00:00 2001 From: d-g-town <66391417+d-g-town@users.noreply.github.com> Date: Mon, 18 Sep 2023 13:27:48 -0400 Subject: [PATCH] change exported env group methods to return secret variables as dummy value (#3587) Co-authored-by: David Townley --- .../update_app_environment_group.go | 11 +++--- dashboard/package.json | 2 +- go.mod | 2 +- go.sum | 13 ------- go.work.sum | 2 ++ .../kubernetes/environment_groups/create.go | 18 +++++++++- internal/kubernetes/environment_groups/get.go | 34 ++++++++++++++++++- .../kubernetes/environment_groups/list.go | 32 +++++++++++++++-- .../kubernetes/environment_groups/sync.go | 2 +- 9 files changed, 90 insertions(+), 26 deletions(-) diff --git a/api/server/handlers/porter_app/update_app_environment_group.go b/api/server/handlers/porter_app/update_app_environment_group.go index 46f5d272b9..9166b53aed 100644 --- a/api/server/handlers/porter_app/update_app_environment_group.go +++ b/api/server/handlers/porter_app/update_app_environment_group.go @@ -161,18 +161,19 @@ func (c *UpdateAppEnvironmentHandler) ServeHTTP(w http.ResponseWriter, r *http.R } } for key, newValue := range request.Secrets { - if existingValue, ok := latestEnvironmentGroup.SecretVariables[key]; !ok || string(existingValue) != newValue { + // We cannot check if the values are the same because the existing secrets are substituted with dummy values. However, if the new value is a dummy value, then it is unchanged. + if _, ok := latestEnvironmentGroup.SecretVariables[key]; !ok || newValue != environment_groups.EnvGroupSecretDummyValue { sameEnvGroup = false } } if request.HardUpdate { - for key, existingValue := range latestEnvironmentGroup.Variables { - if newValue, ok := request.Variables[key]; !ok || existingValue != newValue { + for key := range latestEnvironmentGroup.Variables { + if _, ok := request.Variables[key]; !ok { sameEnvGroup = false } } - for key, existingValue := range latestEnvironmentGroup.SecretVariables { - if newValue, ok := request.Secrets[key]; !ok || string(existingValue) != newValue { + for key := range latestEnvironmentGroup.SecretVariables { + if _, ok := request.Secrets[key]; !ok { sameEnvGroup = false } } diff --git a/dashboard/package.json b/dashboard/package.json index 008fa1ccd7..a88763dd81 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -147,4 +147,4 @@ "webpack-cli": "^3.3.12", "webpack-dev-server": "^3.11.0" } -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 2caa68f96a..b24c1502b0 100644 --- a/go.mod +++ b/go.mod @@ -73,6 +73,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v0.23.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v0.5.0 github.com/briandowns/spinner v1.18.1 + github.com/cloudflare/cloudflare-go v0.76.0 github.com/glebarez/sqlite v1.6.0 github.com/go-chi/chi/v5 v5.0.8 github.com/honeycombio/otel-config-go v1.11.0 @@ -123,7 +124,6 @@ require ( github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220517224237-e6f29200ae04 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect - github.com/cloudflare/cloudflare-go v0.76.0 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect diff --git a/go.sum b/go.sum index e022bf9bcc..2406e2826e 100644 --- a/go.sum +++ b/go.sum @@ -960,7 +960,6 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -968,8 +967,6 @@ github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1: github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -1993,8 +1990,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2105,8 +2100,6 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2273,8 +2266,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2285,8 +2276,6 @@ golang.org/x/term v0.0.0-20210422114643-f5beecf764ed/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2299,8 +2288,6 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/go.work.sum b/go.work.sum index b66cdd54a2..bfa0c46473 100644 --- a/go.work.sum +++ b/go.work.sum @@ -982,6 +982,7 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= @@ -991,6 +992,7 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= diff --git a/internal/kubernetes/environment_groups/create.go b/internal/kubernetes/environment_groups/create.go index b8b61e96d9..706a3a8fd8 100644 --- a/internal/kubernetes/environment_groups/create.go +++ b/internal/kubernetes/environment_groups/create.go @@ -1,6 +1,7 @@ package environment_groups import ( + "bytes" "context" "fmt" "strconv" @@ -38,11 +39,26 @@ func CreateOrUpdateBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent } telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-namespace", Value: Namespace_EnvironmentGroups}) - latestEnvironmentGroup, err := LatestBaseEnvironmentGroup(ctx, a, environmentGroup.Name) + latestEnvironmentGroup, err := latestBaseEnvironmentGroup(ctx, a, environmentGroup.Name) if err != nil { return telemetry.Error(ctx, span, err, "unable to get latest base environment group by name") } + // If any of the secret variables are set to the dummy value (i.e. are unchanged), replace them with the existing value. + for k, v := range environmentGroup.SecretVariables { + if bytes.Equal(v, []byte(EnvGroupSecretDummyValue)) { + existingValue, ok := latestEnvironmentGroup.SecretVariables[k] + if !ok { + return telemetry.Error(ctx, span, nil, "secret variable does not exist in latest environment group") + } + if string(existingValue) == "" { + return telemetry.Error(ctx, span, nil, "secret variable value is empty") + } + + environmentGroup.SecretVariables[k] = existingValue + } + } + newEnvironmentGroup := EnvironmentGroup{ Name: environmentGroup.Name, Variables: environmentGroup.Variables, diff --git a/internal/kubernetes/environment_groups/get.go b/internal/kubernetes/environment_groups/get.go index 618a7aec9b..71a1ec500b 100644 --- a/internal/kubernetes/environment_groups/get.go +++ b/internal/kubernetes/environment_groups/get.go @@ -7,7 +7,9 @@ import ( "github.com/porter-dev/porter/internal/telemetry" ) -// LatestBaseEnvironmentGroup returns the most recent version of an environment group stored in the porter-env-group namespace +// LatestBaseEnvironmentGroup returns the most recent version of an environment group stored in the porter-env-group namespace. +// It replaces all secret values with a dummy variable and can be used to return values to the user. If you need access to the true secret values, +// use the private latestBaseEnvironmentGroup function instead. func LatestBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent, environmentGroupName string) (EnvironmentGroup, error) { ctx, span := telemetry.NewSpan(ctx, "latest-base-env-group") defer span.End() @@ -35,6 +37,36 @@ func LatestBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent, enviro return highestVersionEnvironmentGroup, nil } +// latestBaseEnvironmentGroup returns the most recent version of an environment group stored in the porter-env-group namespace. +// This is a private function because it returns all secret values. If you are trying to retrieve the latest base environment group to return to the user, +// use the exported LatestBaseEnvironmentGroup instead. +func latestBaseEnvironmentGroup(ctx context.Context, a *kubernetes.Agent, environmentGroupName string) (EnvironmentGroup, error) { + ctx, span := telemetry.NewSpan(ctx, "latest-base-env-group-private") + defer span.End() + telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "environment-group-name", Value: environmentGroupName}) + + var eg EnvironmentGroup + + baseEnvironmentGroupVersions, err := listEnvironmentGroups(ctx, a, WithEnvironmentGroupName(environmentGroupName), WithNamespace(Namespace_EnvironmentGroups)) + if err != nil { + return eg, telemetry.Error(ctx, span, err, "unable to list base environment groups") + } + + var highestVersionEnvironmentGroup EnvironmentGroup + for _, baseEnvironmentGroup := range baseEnvironmentGroupVersions { + if baseEnvironmentGroup.Version > highestVersionEnvironmentGroup.Version { + highestVersionEnvironmentGroup = baseEnvironmentGroup + } + } + + telemetry.WithAttributes(span, + telemetry.AttributeKV{Key: "highest-version", Value: highestVersionEnvironmentGroup.Version}, + telemetry.AttributeKV{Key: "highest-version-name", Value: highestVersionEnvironmentGroup.Name}, + ) + + return highestVersionEnvironmentGroup, nil +} + // EnvironmentGroupInTargetNamespaceInput contains all information required to check if an environment group exists in a target namespace. // If you are looking for envrionment groups in the base namespace, consider using LatestBaseEnvironmentGroup or ListBaseEnvironmentGroups instead type EnvironmentGroupInTargetNamespaceInput struct { diff --git a/internal/kubernetes/environment_groups/list.go b/internal/kubernetes/environment_groups/list.go index 40728e0d4b..47415343bd 100644 --- a/internal/kubernetes/environment_groups/list.go +++ b/internal/kubernetes/environment_groups/list.go @@ -66,9 +66,11 @@ func WithEnvironmentGroupVersion(version int) EnvironmentGroupOption { } } -// ListEnvironmentGroups returns all environment groups stored in the provided namespace. If none is set, it will use the namespace "porter-env-group" -func ListEnvironmentGroups(ctx context.Context, a *kubernetes.Agent, listOpts ...EnvironmentGroupOption) ([]EnvironmentGroup, error) { - ctx, span := telemetry.NewSpan(ctx, "list-environment-groups") +// listEnvironmentGroups returns all environment groups stored in the provided namespace. If none is set, it will use the namespace "porter-env-group". +// This method returns all secret values, which should never be returned out of this package. If you are trying to get the environment group values to return to the user, +// use the exported ListEnvironmentGroups instead. +func listEnvironmentGroups(ctx context.Context, a *kubernetes.Agent, listOpts ...EnvironmentGroupOption) ([]EnvironmentGroup, error) { + ctx, span := telemetry.NewSpan(ctx, "list-environment-groups-private") defer span.End() var opts environmentGroupOptions @@ -166,6 +168,30 @@ func ListEnvironmentGroups(ctx context.Context, a *kubernetes.Agent, listOpts .. return envGroups, nil } +// EnvGroupSecretDummyValue is the value that will be returned for secret variables in environment groups +const EnvGroupSecretDummyValue = "********" + +// ListEnvironmentGroups returns all environment groups stored in the provided namespace. If none is set, it will use the namespace "porter-env-group". +// This method replaces all secret values with a dummy value so that they are not exposed to the user. If you need access to the true secret values, +// use the unexported listEnvironmentGroups instead. +func ListEnvironmentGroups(ctx context.Context, a *kubernetes.Agent, listOpts ...EnvironmentGroupOption) ([]EnvironmentGroup, error) { + ctx, span := telemetry.NewSpan(ctx, "list-environment-groups") + defer span.End() + + envGroups, err := listEnvironmentGroups(ctx, a, listOpts...) + if err != nil { + return nil, telemetry.Error(ctx, span, err, "unable to list environment groups") + } + + for _, envGroup := range envGroups { + for k := range envGroup.SecretVariables { + envGroup.SecretVariables[k] = []byte(EnvGroupSecretDummyValue) + } + } + + return envGroups, nil +} + // LinkedPorterApplication represents an application which was linked to an environment group type LinkedPorterApplication struct { Name string diff --git a/internal/kubernetes/environment_groups/sync.go b/internal/kubernetes/environment_groups/sync.go index da106672fd..9a6e72ae13 100644 --- a/internal/kubernetes/environment_groups/sync.go +++ b/internal/kubernetes/environment_groups/sync.go @@ -44,7 +44,7 @@ func SyncLatestVersionToNamespace(ctx context.Context, a *kubernetes.Agent, inp telemetry.AttributeKV{Key: "target-environment-namespace", Value: inp.TargetNamespace}, ) - baseEnvironmentGroup, err := LatestBaseEnvironmentGroup(ctx, a, inp.BaseEnvironmentGroupName) + baseEnvironmentGroup, err := latestBaseEnvironmentGroup(ctx, a, inp.BaseEnvironmentGroupName) if err != nil { return output, telemetry.Error(ctx, span, err, "unable to find latest environment group version") }