From f282e7c42abef0f2559c0dbcd5a004d92a1d6c4c Mon Sep 17 00:00:00 2001 From: Bharath B Date: Sat, 8 Aug 2026 11:27:48 +0530 Subject: [PATCH 1/3] ESO-566: Allow overriding operand container args outside the ExternalSecretsConfig API Signed-off-by: Bharath B --- pkg/controller/external_secrets/constants.go | 15 + .../external_secrets/deployments.go | 107 +++++ .../external_secrets/deployments_test.go | 413 ++++++++++++++++++ test/e2e/README.md | 8 + test/e2e/e2e_suite_test.go | 2 + test/e2e/helpers_test.go | 309 +++++++++++++ test/e2e/operand_args_test.go | 285 ++++++++++++ test/e2e/trusted_ca_bundle_test.go | 16 +- 8 files changed, 1143 insertions(+), 12 deletions(-) create mode 100644 test/e2e/operand_args_test.go diff --git a/pkg/controller/external_secrets/constants.go b/pkg/controller/external_secrets/constants.go index 10ad9742b..b82fa01dc 100644 --- a/pkg/controller/external_secrets/constants.go +++ b/pkg/controller/external_secrets/constants.go @@ -26,6 +26,8 @@ const ( OperandWebhookDeployment = externalsecretsCommonName + "-webhook" // OperandCertControllerDeployment is the in-tree cert-controller Deployment name. OperandCertControllerDeployment = externalsecretsCommonName + "-cert-controller" + // OperandBitwardenSDKServerDeployment is the bitwarden-sdk-server Deployment name. + OperandBitwardenSDKServerDeployment = "bitwarden-sdk-server" // OperandCoreControllerContainer is the core controller container name. OperandCoreControllerContainer = externalsecretsCommonName @@ -110,6 +112,19 @@ const ( // containing the image version of the bitwarden-sdk-server as value. bitwardenImageVersionEnvVarName = "BITWARDEN_SDK_SERVER_IMAGE_VERSION" + // TODO: Remove in v1.4.0. Backported to 1.1/1.2 as a temporary escape hatch; + // v1.3.0 adds ExternalSecretsConfig advancedOverrides for per-component Deployment + // overrides and is the migration window before these env vars are removed. + // + // OperandExternalSecretsArgsEnvVar is the operator env var for core controller container args overrides. + OperandExternalSecretsArgsEnvVar = "OPERAND_EXTERNAL_SECRETS_ARGS" + // OperandWebhookArgsEnvVar is the operator env var for webhook container args overrides. + OperandWebhookArgsEnvVar = "OPERAND_WEBHOOK_ARGS" + // OperandCertControllerArgsEnvVar is the operator env var for cert-controller container args overrides. + OperandCertControllerArgsEnvVar = "OPERAND_CERT_CONTROLLER_ARGS" + // OperandBitwardenSDKServerArgsEnvVar is the operator env var for bitwarden-sdk-server container args overrides. + OperandBitwardenSDKServerArgsEnvVar = "OPERAND_BITWARDEN_SDK_SERVER_ARGS" + // certmanagerTLSSecretWebhook is the TLS secret created by cert-manager for the webhook component. A different // name is used to avoiding clash with the secret created by the inbuilt cert-controller component. certmanagerTLSSecretWebhook = "external-secrets-webhook-cm" diff --git a/pkg/controller/external_secrets/deployments.go b/pkg/controller/external_secrets/deployments.go index 3f2ed58e7..be04f07ed 100644 --- a/pkg/controller/external_secrets/deployments.go +++ b/pkg/controller/external_secrets/deployments.go @@ -5,6 +5,7 @@ import ( "maps" "os" "slices" + "strings" "time" "unsafe" @@ -130,6 +131,9 @@ func (r *Reconciler) getDeploymentObject(assetName string, esc *operatorv1alpha1 switch assetName { case controllerDeploymentAssetName: r.updateContainerSpec(deployment, esc, image, logLevel) + if err := applyOperandArgsFromEnv(deployment, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err != nil { + return nil, fmt.Errorf("failed to apply operand args from env: %w", err) + } if err := r.applyUserCABundleConfig(deployment, esc); err != nil { wrapped := fmt.Errorf("failed to apply user CA bundle config: %w", err) // When the referenced ConfigMap is missing, the deployment spec is updated to remove @@ -146,12 +150,21 @@ func (r *Reconciler) getDeploymentObject(assetName string, esc *operatorv1alpha1 checkInterval = normalizeDurationArg(esc.Spec.ApplicationConfig.WebhookConfig.CertificateCheckInterval.Duration.String()) } updateWebhookContainerSpec(deployment, image, logLevel, checkInterval) + if err := applyOperandArgsFromEnv(deployment, OperandWebhookContainer, OperandWebhookArgsEnvVar); err != nil { + return nil, fmt.Errorf("failed to apply operand args from env: %w", err) + } updateWebhookVolumeConfig(deployment, esc) case certControllerDeploymentAssetName: updateCertControllerContainerSpec(deployment, image, logLevel) + if err := applyOperandArgsFromEnv(deployment, OperandCertControllerContainer, OperandCertControllerArgsEnvVar); err != nil { + return nil, fmt.Errorf("failed to apply operand args from env: %w", err) + } case bitwardenDeploymentAssetName: deployment.Labels["app.kubernetes.io/version"] = os.Getenv(bitwardenImageVersionEnvVarName) updateBitwardenServerContainerSpec(deployment, bitwardenImage) + if err := applyOperandArgsFromEnv(deployment, OperandBitwardenContainer, OperandBitwardenSDKServerArgsEnvVar); err != nil { + return nil, fmt.Errorf("failed to apply operand args from env: %w", err) + } updateBitwardenVolumeConfig(deployment, esc) } @@ -792,6 +805,100 @@ func (r *Reconciler) removeUserCABundleConfig(deployment *appsv1.Deployment) { } } +// argFlagKey returns the flag key for a container arg (everything before the first '='), +// or the whole token when there is no '='. Positional args without a leading "--" return "". +func argFlagKey(arg string) string { + if !strings.HasPrefix(arg, "--") { + return "" + } + if i := strings.IndexByte(arg, '='); i >= 0 { + return arg[:i] + } + return arg +} + +// parseOperandArgsEnv parses a comma-separated list of full CLI flags +// (e.g. "--concurrent=5,--loglevel=debug"). Empty segments (from trailing or +// repeated commas) are skipped. Callers should treat a fully empty/whitespace +// env value as a no-op before calling this helper. +func parseOperandArgsEnv(raw string) ([]string, error) { + parts := strings.Split(raw, ",") + args := make([]string, 0, len(parts)) + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "" { + continue + } + if !strings.HasPrefix(part, "--") { + return nil, common.NewUserConfigurationError( + fmt.Errorf("argument %q must start with --", part), + "invalid custom arg override", + ) + } + args = append(args, part) + } + return args, nil +} + +// mergeContainerArgs overrides matching --flag keys in base with overrides and appends +// unknown keys. Positional args (no leading "--") in base are preserved in place; +// non-flag overrides are skipped (parseOperandArgsEnv already rejects them for the env path). +func mergeContainerArgs(base []string, overrides []string) []string { + if len(overrides) == 0 { + return base + } + + keyIndex := make(map[string]int, len(base)) + for i, arg := range base { + if key := argFlagKey(arg); key != "" { + keyIndex[key] = i + } + } + + result := slices.Clone(base) + for _, override := range overrides { + key := argFlagKey(override) + if key == "" { + continue + } + if idx, ok := keyIndex[key]; ok { + result[idx] = override + continue + } + result = append(result, override) + keyIndex[key] = len(result) - 1 + } + return result +} + +// applyOperandArgsFromEnv reads envVarName and merges its comma-separated --key=value +// flags into the named container's Args. Unset or empty env is a no-op. +// +// TODO: Remove in v1.4.0. Backported to 1.1/1.2 as a temporary escape hatch; +// v1.3.0 adds ExternalSecretsConfig advancedOverrides for per-component Deployment +// overrides and is the migration window before this env-based path is removed. +func applyOperandArgsFromEnv(deployment *appsv1.Deployment, containerName, envVarName string) error { + raw := strings.TrimSpace(os.Getenv(envVarName)) + if raw == "" { + return nil + } + + overrides, err := parseOperandArgsEnv(raw) + if err != nil { + return fmt.Errorf("%s: %w", envVarName, err) + } + + for i := range deployment.Spec.Template.Spec.Containers { + if deployment.Spec.Template.Spec.Containers[i].Name != containerName { + continue + } + deployment.Spec.Template.Spec.Containers[i].Args = mergeContainerArgs( + deployment.Spec.Template.Spec.Containers[i].Args, overrides) + return nil + } + return fmt.Errorf("container %s not found in deployment %s", containerName, deployment.GetName()) +} + // applyUserDeploymentConfigs updates the deployment resource spec with user specified configurations. func (r *Reconciler) applyUserDeploymentConfigs(deployment *appsv1.Deployment, esc *operatorv1alpha1.ExternalSecretsConfig, assetName string) error { componentName, containerName, err := getComponentNameFromAsset(assetName) diff --git a/pkg/controller/external_secrets/deployments_test.go b/pkg/controller/external_secrets/deployments_test.go index 8c21569b9..6de6cfcf6 100644 --- a/pkg/controller/external_secrets/deployments_test.go +++ b/pkg/controller/external_secrets/deployments_test.go @@ -2473,3 +2473,416 @@ func TestCreateOrApplyDeploymentFromAssetReturnsTrustedCAError(t *testing.T) { } }) } + +func TestParseOperandArgsEnv(t *testing.T) { + tests := []struct { + name string + raw string + want []string + wantErr bool + }{ + {name: "empty", raw: "", want: []string{}}, + {name: "whitespace only", raw: " \t ", want: []string{}}, + { + name: "single flag", + raw: "--concurrent=5", + want: []string{"--concurrent=5"}, + }, + { + name: "multiple flags with spaces", + raw: "--concurrent=5, --loglevel=debug", + want: []string{"--concurrent=5", "--loglevel=debug"}, + }, + { + name: "boolean style without equals", + raw: "--enable-foo,--enable-bar=true", + want: []string{"--enable-foo", "--enable-bar=true"}, + }, + { + name: "empty segments skipped", + raw: "--concurrent=5,,--loglevel=debug,", + want: []string{"--concurrent=5", "--loglevel=debug"}, + }, + {name: "missing dashes", raw: "concurrent=5", wantErr: true}, + {name: "single dash rejected", raw: "-concurrent=5", wantErr: true}, + {name: "positional token rejected", raw: "webhook,--port=10250", wantErr: true}, + {name: "positional only rejected", raw: "certcontroller", wantErr: true}, + {name: "bare equals rejected", raw: "=value", wantErr: true}, + {name: "valid then positional rejected", raw: "--port=10250,webhook", wantErr: true}, + {name: "positional mid-list rejected", raw: "--concurrent=5,not-a-flag,--loglevel=debug", wantErr: true}, + {name: "single dash mid-list rejected", raw: "--concurrent=5,-v,--loglevel=debug", wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseOperandArgsEnv(tt.raw) + if tt.wantErr { + if err == nil { + t.Fatalf("parseOperandArgsEnv(%q) error = nil, want error", tt.raw) + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("parseOperandArgsEnv(%q) error = %v, want UserConfigurationError", tt.raw, err) + } + if !strings.Contains(err.Error(), "invalid custom arg override") { + t.Fatalf("parseOperandArgsEnv(%q) error = %v, want message %q", tt.raw, err, "invalid custom arg override") + } + if !strings.Contains(err.Error(), "must start with --") { + t.Fatalf("parseOperandArgsEnv(%q) error = %v, want cause mentioning must start with --", tt.raw, err) + } + return + } + if err != nil { + t.Fatalf("parseOperandArgsEnv(%q) unexpected error: %v", tt.raw, err) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("parseOperandArgsEnv(%q) = %#v, want %#v", tt.raw, got, tt.want) + } + }) + } +} + +func TestMergeContainerArgs(t *testing.T) { + tests := []struct { + name string + base []string + overrides []string + want []string + }{ + { + name: "nil overrides unchanged", + base: []string{"--concurrent=1"}, + overrides: nil, + want: []string{"--concurrent=1"}, + }, + { + name: "override existing key", + base: []string{"--concurrent=1", "--metrics-addr=:8080"}, + overrides: []string{"--concurrent=5"}, + want: []string{"--concurrent=5", "--metrics-addr=:8080"}, + }, + { + name: "append new key", + base: []string{"--concurrent=1"}, + overrides: []string{"--enable-foo=true"}, + want: []string{"--concurrent=1", "--enable-foo=true"}, + }, + { + name: "boolean token replaces valued flag with same key", + base: []string{"--enable-foo=true", "--loglevel=info"}, + overrides: []string{"--enable-foo"}, + want: []string{"--enable-foo", "--loglevel=info"}, + }, + { + name: "preserve leading positional token", + base: []string{"webhook", "--port=10250", "--loglevel=info"}, + overrides: []string{"--loglevel=debug", "--metrics-addr=:9090"}, + want: []string{"webhook", "--port=10250", "--loglevel=debug", "--metrics-addr=:9090"}, + }, + { + name: "preserve certcontroller positional token", + base: []string{"certcontroller", "--crd-requeue-interval=5m"}, + overrides: []string{"--crd-requeue-interval=10m"}, + want: []string{"certcontroller", "--crd-requeue-interval=10m"}, + }, + { + name: "skip non-flag overrides", + base: []string{"webhook", "--port=10250"}, + overrides: []string{"webhook", "--port=10251"}, + want: []string{"webhook", "--port=10251"}, + }, + { + name: "all non-flag overrides leave base unchanged", + base: []string{"webhook", "--port=10250"}, + overrides: []string{"webhook", "certcontroller", "-v"}, + want: []string{"webhook", "--port=10250"}, + }, + { + name: "empty override tokens skipped", + base: []string{"--concurrent=1"}, + overrides: []string{"", "--concurrent=2", ""}, + want: []string{"--concurrent=2"}, + }, + { + name: "single-dash override skipped", + base: []string{"--loglevel=info"}, + overrides: []string{"-loglevel=debug", "--metrics-addr=:9090"}, + want: []string{"--loglevel=info", "--metrics-addr=:9090"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := mergeContainerArgs(tt.base, tt.overrides) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("mergeContainerArgs() = %#v, want %#v", got, tt.want) + } + }) + } +} + +func TestApplyOperandArgsFromEnv(t *testing.T) { + deploymentWithContainer := func(name string, args []string) *appsv1.Deployment { + return &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{Name: "test"}, + Spec: appsv1.DeploymentSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{Name: name, Args: args}}, + }, + }, + }, + } + } + + t.Run("unset env is no-op", func(t *testing.T) { + dep := deploymentWithContainer(OperandCoreControllerContainer, []string{"--concurrent=1"}) + if err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := []string{"--concurrent=1"} + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, want) { + t.Errorf("Args = %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, want) + } + }) + + t.Run("empty env is no-op", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, " ") + dep := deploymentWithContainer(OperandCoreControllerContainer, []string{"--concurrent=1"}) + if err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := []string{"--concurrent=1"} + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, want) { + t.Errorf("Args = %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, want) + } + }) + + t.Run("overrides and appends", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--concurrent=5,--enable-foo=true") + dep := deploymentWithContainer(OperandCoreControllerContainer, []string{"--concurrent=1", "--metrics-addr=:8080"}) + if err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := []string{"--concurrent=5", "--metrics-addr=:8080", "--enable-foo=true"} + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, want) { + t.Errorf("Args = %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, want) + } + }) + + t.Run("invalid entry fails", func(t *testing.T) { + t.Setenv(OperandWebhookArgsEnvVar, "not-a-flag") + dep := deploymentWithContainer(OperandWebhookContainer, []string{"webhook", "--port=10250"}) + err := applyOperandArgsFromEnv(dep, OperandWebhookContainer, OperandWebhookArgsEnvVar) + if err == nil { + t.Fatal("expected error for invalid args env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + wantSubstrings := []string{ + OperandWebhookArgsEnvVar, + "invalid custom arg override", + `argument "not-a-flag" must start with --`, + } + for _, sub := range wantSubstrings { + if !strings.Contains(err.Error(), sub) { + t.Fatalf("error = %v, want substring %q", err, sub) + } + } + }) + + t.Run("positional env value fails without mutating args", func(t *testing.T) { + t.Setenv(OperandWebhookArgsEnvVar, "webhook,--port=10251") + original := []string{"webhook", "--port=10250"} + dep := deploymentWithContainer(OperandWebhookContainer, append([]string(nil), original...)) + err := applyOperandArgsFromEnv(dep, OperandWebhookContainer, OperandWebhookArgsEnvVar) + if err == nil { + t.Fatal("expected error for positional env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, original) { + t.Errorf("Args mutated on error: %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, original) + } + }) + + t.Run("single dash env value fails", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "-concurrent=5") + dep := deploymentWithContainer(OperandCoreControllerContainer, []string{"--concurrent=1"}) + err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar) + if err == nil { + t.Fatal("expected error for single-dash env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + }) + + t.Run("invalid entry after valid flags fails", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--concurrent=5,bad") + original := []string{"--concurrent=1"} + dep := deploymentWithContainer(OperandCoreControllerContainer, append([]string(nil), original...)) + err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar) + if err == nil { + t.Fatal("expected error for mixed valid/invalid env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, original) { + t.Errorf("Args mutated on error: %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, original) + } + }) + + t.Run("missing container fails", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--concurrent=5") + dep := deploymentWithContainer("other", []string{"--concurrent=1"}) + if err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err == nil { + t.Fatal("expected error for missing container") + } + }) + + t.Run("empty containers list fails", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--concurrent=5") + dep := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "test"}} + if err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar); err == nil { + t.Fatal("expected error for empty containers list") + } + }) + + t.Run("bitwarden args applied onto empty base", func(t *testing.T) { + t.Setenv(OperandBitwardenSDKServerArgsEnvVar, "--port=9999") + dep := deploymentWithContainer(OperandBitwardenContainer, nil) + if err := applyOperandArgsFromEnv(dep, OperandBitwardenContainer, OperandBitwardenSDKServerArgsEnvVar); err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := []string{"--port=9999"} + if !reflect.DeepEqual(dep.Spec.Template.Spec.Containers[0].Args, want) { + t.Errorf("Args = %#v, want %#v", dep.Spec.Template.Spec.Containers[0].Args, want) + } + }) +} + +func TestGetDeploymentObjectOperandArgsFromEnv(t *testing.T) { + t.Setenv(externalsecretsImageEnvVarName, commontest.TestExternalSecretsImageName) + t.Setenv(bitwardenImageEnvVarName, commontest.TestBitwardenImageName) + + esc := commontest.TestExternalSecretsConfig() + resourceMetadata := testResourceMetadata(esc) + r := testReconciler(t) + + t.Run("controller overrides concurrent", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--concurrent=5") + dep, err := r.getDeploymentObject(controllerDeploymentAssetName, esc, resourceMetadata) + if err != nil { + t.Fatalf("getDeploymentObject() unexpected error: %v", err) + } + args := containerArgsByName(dep, OperandCoreControllerContainer) + if !slices.Contains(args, "--concurrent=5") { + t.Errorf("expected --concurrent=5 in args, got %#v", args) + } + if slices.Contains(args, "--concurrent=1") { + t.Errorf("default --concurrent=1 should have been overridden, got %#v", args) + } + }) + + t.Run("webhook preserves positional token", func(t *testing.T) { + t.Setenv(OperandWebhookArgsEnvVar, "--loglevel=debug") + dep, err := r.getDeploymentObject(webhookDeploymentAssetName, esc, resourceMetadata) + if err != nil { + t.Fatalf("getDeploymentObject() unexpected error: %v", err) + } + args := containerArgsByName(dep, OperandWebhookContainer) + if len(args) == 0 || args[0] != "webhook" { + t.Errorf("expected leading webhook token, got %#v", args) + } + if !slices.Contains(args, "--loglevel=debug") { + t.Errorf("expected --loglevel=debug in args, got %#v", args) + } + }) + + t.Run("cert controller preserves positional token", func(t *testing.T) { + t.Setenv(OperandCertControllerArgsEnvVar, "--crd-requeue-interval=10m") + dep, err := r.getDeploymentObject(certControllerDeploymentAssetName, esc, resourceMetadata) + if err != nil { + t.Fatalf("getDeploymentObject() unexpected error: %v", err) + } + args := containerArgsByName(dep, OperandCertControllerContainer) + if len(args) == 0 || args[0] != "certcontroller" { + t.Errorf("expected leading certcontroller token, got %#v", args) + } + if !slices.Contains(args, "--crd-requeue-interval=10m") { + t.Errorf("expected overridden interval in args, got %#v", args) + } + }) + + t.Run("bitwarden applies args", func(t *testing.T) { + escWithBW := esc.DeepCopy() + escWithBW.Spec.Plugins.BitwardenSecretManagerProvider = &v1alpha1.BitwardenSecretManagerProvider{ + Mode: v1alpha1.Enabled, + SecretRef: &v1alpha1.SecretReference{ + Name: "bitwarden-certs", + }, + } + t.Setenv(OperandBitwardenSDKServerArgsEnvVar, "--enable-debug=true") + dep, err := r.getDeploymentObject(bitwardenDeploymentAssetName, escWithBW, resourceMetadata) + if err != nil { + t.Fatalf("getDeploymentObject() unexpected error: %v", err) + } + args := containerArgsByName(dep, OperandBitwardenContainer) + if !reflect.DeepEqual(args, []string{"--enable-debug=true"}) { + t.Errorf("Args = %#v, want [--enable-debug=true]", args) + } + }) + + t.Run("invalid env fails", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "bad-arg") + _, err := r.getDeploymentObject(controllerDeploymentAssetName, esc, resourceMetadata) + if err == nil { + t.Fatal("expected error for invalid operand args env") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + wantSubstrings := []string{ + OperandExternalSecretsArgsEnvVar, + "invalid custom arg override", + `argument "bad-arg" must start with --`, + } + for _, sub := range wantSubstrings { + if !strings.Contains(err.Error(), sub) { + t.Fatalf("error = %v, want substring %q", err, sub) + } + } + }) + + t.Run("webhook positional env fails", func(t *testing.T) { + t.Setenv(OperandWebhookArgsEnvVar, "webhook,--port=10251") + _, err := r.getDeploymentObject(webhookDeploymentAssetName, esc, resourceMetadata) + if err == nil { + t.Fatal("expected error for positional webhook env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + }) + + t.Run("cert controller single dash env fails", func(t *testing.T) { + t.Setenv(OperandCertControllerArgsEnvVar, "-crd-requeue-interval=10m") + _, err := r.getDeploymentObject(certControllerDeploymentAssetName, esc, resourceMetadata) + if err == nil { + t.Fatal("expected error for single-dash cert-controller env value") + } + if !common.IsUserConfigurationError(err) { + t.Fatalf("error = %v, want UserConfigurationError", err) + } + }) +} + +func containerArgsByName(dep *appsv1.Deployment, name string) []string { + for i := range dep.Spec.Template.Spec.Containers { + if dep.Spec.Template.Spec.Containers[i].Name == name { + return dep.Spec.Template.Spec.Containers[i].Args + } + } + return nil +} diff --git a/test/e2e/README.md b/test/e2e/README.md index 0524987fa..c42df58bc 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -28,6 +28,7 @@ make test-e2e E2E_GINKGO_LABEL_FILTER="" | Value | Test area | |-------|-----------| | `OverrideEnv` | Custom env vars on operand deployments | +| `OverrideOperandArgs` | Operator `OPERAND_*_ARGS` env overrides for operand Deployments | | `RevisionHistoryLimit` | Deployment revision history limits | | `UnsafeAllowGenericTargets` | ExternalSecretsManager feature gate propagation | | `CustomAnnotations` | Annotation apply/remove and managed-annotation restoration | @@ -93,6 +94,7 @@ If a prerequisite is missing, the affected spec **fails** with a message pointin | `Feature:Upgrade` | Post-upgrade network policy migration check | | `Feature:NetworkPolicy` | Static and custom network policy naming | | `Feature:OverrideEnv` | Component override env vars | +| `Feature:OverrideOperandArgs` | Operator `OPERAND_*_ARGS` env overrides for operand Deployments | | `Feature:RevisionHistoryLimit` | Revision history limit defaults and overrides | | `Feature:UnsafeAllowGenericTargets` | UnsafeAllowGenericTargets feature propagation | | `Feature:CustomAnnotations` | Annotation lifecycle tests | @@ -143,6 +145,12 @@ File: `e2e_test.go` | `NetworkPolicy` + `Upgrade` | Post-upgrade skip-np-cleanup-check annotation (also tagged `Feature:Upgrade`) | | `Proxy` | Proxy Egress Network Policy | +File: `operand_args_test.go` + +| Feature | Describe | +|---------|----------| +| `OverrideOperandArgs` | Operand Args Env Overrides | + File: `trusted_ca_bundle_test.go` | Feature | Describe | diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index c0de57ef3..8b07633fe 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -38,6 +38,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorv1alpha1 "github.com/openshift/external-secrets-operator/api/v1alpha1" "github.com/openshift/external-secrets-operator/test/utils" @@ -78,6 +79,7 @@ var _ = BeforeSuite(func() { scheme := runtime.NewScheme() utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) + utilruntime.Must(olmv1alpha1.AddToScheme(scheme)) suiteRuntimeClient, err = client.New(cfg, client.Options{Scheme: scheme}) Expect(err).NotTo(HaveOccurred(), "failed to create runtime client") }) diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index 6117ca406..b3cc50409 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -22,15 +22,20 @@ import ( "context" "fmt" "slices" + "strings" "testing" "time" . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" operatorv1alpha1 "github.com/openshift/external-secrets-operator/api/v1alpha1" @@ -38,6 +43,16 @@ import ( "github.com/openshift/external-secrets-operator/test/utils" ) +const ( + operatorDeploymentName = common.ExternalSecretsOperatorCommonName + "-controller-manager" + operatorManagerContainerName = "manager" + // operatorCSVNamePrefix matches ClusterServiceVersion names like + // openshift-external-secrets-operator.v1.2.0. + operatorCSVNamePrefix = "openshift-external-secrets-operator." + // operatorPackageName is the OLM package / Subscription.spec.name value. + operatorPackageName = "openshift-external-secrets-operator" +) + // ensureExternalSecretsConfigReady creates the cluster ExternalSecretsConfig CR when missing // and waits until Ready=True. Shared by suite Describes that may run before e2e_test BeforeAll. func ensureExternalSecretsConfigReady(ctx context.Context) error { @@ -229,3 +244,297 @@ func deploymentContainerHasArg(deployment *appsv1.Deployment, containerName, arg } return slices.Contains(args, arg), true } + +// setOperatorManagerEnv sets or updates env vars on the operator manager container. +// Prefer updating Subscription.spec.config.env (OLM-supported) when a matching CSV +// and Subscription exist; otherwise update the Deployment directly. +// Works for any manager env (OPERAND_*_ARGS, OPERATOR_LOG_LEVEL, METRICS_*, etc.). +// OLM rolls a new manager pod after Subscription updates; the startup reconcile reads +// process env and applies operand args. This helper waits until that Ready pod has the +// desired env before returning. +func setOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, envVars map[string]string) error { + if len(envVars) == 0 { + return nil + } + updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, c, envVars, nil) + if err != nil { + return err + } + if !updatedViaSub { + if err := updateOperatorDeploymentEnv(ctx, clientset, envVars, nil); err != nil { + return err + } + } + waitForOperatorManagerEnv(ctx, clientset, envVars, nil) + return nil +} + +// unsetOperatorManagerEnv removes env vars from the operator manager container. +func unsetOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, keys []string) error { + if len(keys) == 0 { + return nil + } + updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, c, nil, keys) + if err != nil { + return err + } + if !updatedViaSub { + if err := updateOperatorDeploymentEnv(ctx, clientset, nil, keys); err != nil { + return err + } + } + waitForOperatorManagerEnv(ctx, clientset, nil, keys) + return nil +} + +// updateSubscriptionEnv merges env into Subscription.spec.config.env using the CSV to +// locate the Subscription namespace. Returns false when no OLM Subscription is found. +func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, set map[string]string, unset []string) (bool, error) { + csv, err := findOperatorCSV(ctx, clientset, c) + if err != nil { + return false, err + } + if csv == nil { + return false, nil + } + + subNamespace := csv.Annotations[olmv1alpha1.OperatorGroupNamespaceAnnotationKey] + if subNamespace == "" { + subNamespace = csv.Namespace + } + if subNamespace == "" { + return false, fmt.Errorf("CSV %s has empty namespace and no %s annotation", csv.Name, olmv1alpha1.OperatorGroupNamespaceAnnotationKey) + } + + sub, err := findOperatorSubscription(ctx, c, subNamespace) + if err != nil { + return false, err + } + if sub == nil { + return false, nil + } + + err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + current := &olmv1alpha1.Subscription{} + if err := c.Get(ctx, client.ObjectKey{Namespace: subNamespace, Name: sub.Name}, current); err != nil { + return fmt.Errorf("get Subscription %s/%s: %w", subNamespace, sub.Name, err) + } + + var existing []corev1.EnvVar + if current.Spec.Config != nil { + existing = current.Spec.Config.Env + } + merged := mergeEnvVars(existing, set, unset) + if current.Spec.Config == nil { + if len(merged) == 0 { + return nil + } + current.Spec.Config = &olmv1alpha1.SubscriptionConfig{} + } + current.Spec.Config.Env = merged + if isEmptySubscriptionConfig(current.Spec.Config) { + current.Spec.Config = nil + } + + return c.Update(ctx, current) + }) + if err != nil { + return false, err + } + return true, nil +} + +// findOperatorCSV returns the installed openshift-external-secrets-operator CSV, or nil +// when the operator is not managed by OLM. +func findOperatorCSV(ctx context.Context, clientset kubernetes.Interface, c client.Client) (*olmv1alpha1.ClusterServiceVersion, error) { + var list olmv1alpha1.ClusterServiceVersionList + if err := c.List(ctx, &list, client.InNamespace(operatorNamespace)); err != nil { + // NotFound / NoMatch: OLM CRDs missing or no CSVs — fall through to Deployment path. + if !k8serrors.IsNotFound(err) && !meta.IsNoMatchError(err) { + return nil, fmt.Errorf("list CSVs in %s: %w", operatorNamespace, err) + } + } + for i := range list.Items { + if strings.HasPrefix(list.Items[i].Name, operatorCSVNamePrefix) { + return list.Items[i].DeepCopy(), nil + } + } + + // Fallback: resolve CSV from the operator Deployment ownerReference. + dep, err := clientset.AppsV1().Deployments(operatorNamespace).Get(ctx, operatorDeploymentName, metav1.GetOptions{}) + if err != nil { + if k8serrors.IsNotFound(err) { + return nil, nil + } + return nil, fmt.Errorf("get operator deployment: %w", err) + } + for _, ref := range dep.OwnerReferences { + if ref.Kind != "ClusterServiceVersion" || ref.Name == "" { + continue + } + csv := &olmv1alpha1.ClusterServiceVersion{} + if err := c.Get(ctx, client.ObjectKey{Namespace: operatorNamespace, Name: ref.Name}, csv); err != nil { + if meta.IsNoMatchError(err) { + return nil, nil + } + if k8serrors.IsNotFound(err) { + continue + } + return nil, fmt.Errorf("get CSV %s/%s: %w", operatorNamespace, ref.Name, err) + } + return csv, nil + } + return nil, nil +} + +// findOperatorSubscription returns the Subscription for the operator package in ns. +func findOperatorSubscription(ctx context.Context, c client.Client, ns string) (*olmv1alpha1.Subscription, error) { + var list olmv1alpha1.SubscriptionList + if err := c.List(ctx, &list, client.InNamespace(ns)); err != nil { + return nil, fmt.Errorf("list Subscriptions in %s: %w", ns, err) + } + for i := range list.Items { + item := &list.Items[i] + if item.Spec.Package == operatorPackageName || strings.HasPrefix(item.Name, operatorPackageName) { + return item.DeepCopy(), nil + } + } + return nil, nil +} + +func isEmptySubscriptionConfig(c *olmv1alpha1.SubscriptionConfig) bool { + if c == nil { + return true + } + return c.Selector == nil && + len(c.NodeSelector) == 0 && + len(c.Tolerations) == 0 && + c.Resources == nil && + len(c.EnvFrom) == 0 && + len(c.Env) == 0 && + len(c.Volumes) == 0 && + len(c.VolumeMounts) == 0 && + c.Affinity == nil && + len(c.Annotations) == 0 +} + +func updateOperatorDeploymentEnv(ctx context.Context, clientset kubernetes.Interface, set map[string]string, unset []string) error { + return retry.RetryOnConflict(retry.DefaultRetry, func() error { + dep, err := clientset.AppsV1().Deployments(operatorNamespace).Get(ctx, operatorDeploymentName, metav1.GetOptions{}) + if err != nil { + return err + } + idx := managerContainerIndex(dep.Spec.Template.Spec.Containers) + if idx < 0 { + return fmt.Errorf("manager container not found in operator deployment") + } + dep.Spec.Template.Spec.Containers[idx].Env = mergeEnvVars(dep.Spec.Template.Spec.Containers[idx].Env, set, unset) + _, err = clientset.AppsV1().Deployments(operatorNamespace).Update(ctx, dep, metav1.UpdateOptions{}) + return err + }) +} + +func managerContainerIndex(containers []corev1.Container) int { + for i, c := range containers { + if c.Name == operatorManagerContainerName { + return i + } + } + return -1 +} + +func mergeEnvVars(existing []corev1.EnvVar, set map[string]string, unset []string) []corev1.EnvVar { + remove := make(map[string]struct{}, len(unset)) + for _, k := range unset { + remove[k] = struct{}{} + } + out := make([]corev1.EnvVar, 0, len(existing)+len(set)) + seen := make(map[string]bool, len(existing)) + for _, env := range existing { + if _, drop := remove[env.Name]; drop { + continue + } + if val, ok := set[env.Name]; ok { + env.Value = val + env.ValueFrom = nil + } + out = append(out, env) + seen[env.Name] = true + } + // Sort newly appended names so repeated merges produce a stable Env order + // (map iteration order is nondeterministic and can trigger an extra OLM rollout). + toAdd := make([]string, 0, len(set)) + for name := range set { + if !seen[name] { + toAdd = append(toAdd, name) + } + } + slices.Sort(toAdd) + for _, name := range toAdd { + out = append(out, corev1.EnvVar{Name: name, Value: set[name]}) + } + return out +} + +func waitForOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, want map[string]string, unset []string) { + Eventually(func(g Gomega) { + dep, err := clientset.AppsV1().Deployments(operatorNamespace).Get(ctx, operatorDeploymentName, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + idx := managerContainerIndex(dep.Spec.Template.Spec.Containers) + g.Expect(idx).To(BeNumerically(">=", 0), "manager container should exist") + assertEnvMap(g, envSliceToMap(dep.Spec.Template.Spec.Containers[idx].Env), want, unset, "operator Deployment") + + // Deployment env can update before the rolled pod is the Ready one; os.Getenv in the + // manager only sees the running pod's env, so wait for that too. + pods, err := clientset.CoreV1().Pods(operatorNamespace).List(ctx, metav1.ListOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + var readyPod *corev1.Pod + for i := range pods.Items { + pod := &pods.Items[i] + if pod.DeletionTimestamp != nil || !strings.HasPrefix(pod.Name, operatorPodPrefix) { + continue + } + if pod.Status.Phase == corev1.PodRunning && isOperatorPodReady(pod) { + readyPod = pod + break + } + } + g.Expect(readyPod).NotTo(BeNil(), "expected a Ready non-terminating operator manager pod") + cidx := managerContainerIndex(readyPod.Spec.Containers) + g.Expect(cidx).To(BeNumerically(">=", 0), "manager container should exist on Ready pod %s", readyPod.Name) + assertEnvMap(g, envSliceToMap(readyPod.Spec.Containers[cidx].Env), want, unset, "operator pod "+readyPod.Name) + }, 3*time.Minute, 5*time.Second).Should(Succeed()) +} + +func envSliceToMap(env []corev1.EnvVar) map[string]string { + out := make(map[string]string, len(env)) + for _, e := range env { + out[e.Name] = e.Value + } + return out +} + +func assertEnvMap(g Gomega, envMap map[string]string, want map[string]string, unset []string, where string) { + for name, val := range want { + g.Expect(envMap).To(HaveKeyWithValue(name, val), "%s should have env %s=%s", where, name, val) + } + for _, name := range unset { + g.Expect(envMap).NotTo(HaveKey(name), "%s should not have env %s", where, name) + } +} + +func isOperatorPodReady(pod *corev1.Pod) bool { + ready, containersReady := false, false + for _, cond := range pod.Status.Conditions { + if cond.Status != corev1.ConditionTrue { + continue + } + switch cond.Type { + case corev1.PodReady: + ready = true + case corev1.ContainersReady: + containersReady = true + } + } + return ready && containersReady +} diff --git a/test/e2e/operand_args_test.go b/test/e2e/operand_args_test.go new file mode 100644 index 000000000..0f13268ac --- /dev/null +++ b/test/e2e/operand_args_test.go @@ -0,0 +1,285 @@ +//go:build e2e +// +build e2e + +/* +Copyright 2025. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package e2e + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + operatorv1alpha1 "github.com/openshift/external-secrets-operator/api/v1alpha1" + "github.com/openshift/external-secrets-operator/pkg/controller/common" + externalsecrets "github.com/openshift/external-secrets-operator/pkg/controller/external_secrets" + "github.com/openshift/external-secrets-operator/test/utils" +) + +var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic", "Feature:OverrideOperandArgs"), func() { + ctx := context.Background() + + const ( + controllerArg = "--concurrent=2" + webhookArg = "--check-interval=10m0s" + certControllerArg = "--crd-requeue-interval=10m" + bitwardenArg = "--key-file=/certs/key.pem" + ) + + var ( + clientset *kubernetes.Clientset + dynamicClient *dynamic.DynamicClient + runtimeClient client.Client + + // originalBitwardenProvider is captured before BeforeAll enables the plugin so + // AfterAll can restore cluster-scoped ExternalSecretsConfig for later suites. + originalBitwardenProvider *operatorv1alpha1.BitwardenSecretManagerProvider + + operandArgsEnv = map[string]string{ + externalsecrets.OperandExternalSecretsArgsEnvVar: controllerArg, + externalsecrets.OperandWebhookArgsEnvVar: webhookArg, + externalsecrets.OperandCertControllerArgsEnvVar: certControllerArg, + externalsecrets.OperandBitwardenSDKServerArgsEnvVar: bitwardenArg, + } + operandArgsEnvKeys = []string{ + externalsecrets.OperandExternalSecretsArgsEnvVar, + externalsecrets.OperandWebhookArgsEnvVar, + externalsecrets.OperandCertControllerArgsEnvVar, + externalsecrets.OperandBitwardenSDKServerArgsEnvVar, + } + ) + + waitForOperandArg := func(deploymentName, containerName, arg string, present bool) { + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, deploymentName, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred(), "should get %s deployment", deploymentName) + hasArg, found := deploymentContainerHasArg(deployment, containerName, arg) + g.Expect(found).To(BeTrue(), "%s container should exist in %s", containerName, deploymentName) + if present { + g.Expect(hasArg).To(BeTrue(), "%s/%s should include %q", deploymentName, containerName, arg) + } else { + g.Expect(hasArg).To(BeFalse(), "%s/%s should not include %q", deploymentName, containerName, arg) + } + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + } + + BeforeAll(func() { + clientset = suiteClientset + dynamicClient = suiteDynamicClient + runtimeClient = suiteRuntimeClient + Expect(clientset).NotTo(BeNil()) + Expect(dynamicClient).NotTo(BeNil()) + Expect(runtimeClient).NotTo(BeNil()) + + By("Ensuring ExternalSecretsConfig is Ready") + Expect(ensureExternalSecretsConfigReady(ctx)).To(Succeed()) + + esc := &operatorv1alpha1.ExternalSecretsConfig{} + Expect(runtimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc)).To(Succeed()) + if esc.Spec.Plugins.BitwardenSecretManagerProvider != nil { + originalBitwardenProvider = esc.Spec.Plugins.BitwardenSecretManagerProvider.DeepCopy() + } + + By("Provisioning bitwarden-sdk-server so its Deployment can be verified") + Expect(ensureBitwardenOperandReady(ctx, nil)).To(Succeed()) + + By("Setting OPERAND_*_ARGS on the operator manager") + Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnv)).To(Succeed()) + + By("Waiting for operator pod to be ready after env update") + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + }) + + AfterAll(func() { + By("Clearing OPERAND_*_ARGS from the operator manager") + Expect(unsetOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnvKeys)).To(Succeed()) + + By("Waiting for operator pod to be ready after env cleanup") + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + + By("Reverting ExternalSecretsConfig Bitwarden plugin to pre-suite state") + Expect(retry.RetryOnConflict(retry.DefaultRetry, func() error { + esc := &operatorv1alpha1.ExternalSecretsConfig{} + if err := runtimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc); err != nil { + return err + } + esc.Spec.Plugins.BitwardenSecretManagerProvider = originalBitwardenProvider + return runtimeClient.Update(ctx, esc) + })).To(Succeed()) + Expect(utils.WaitForExternalSecretsConfigReady(ctx, dynamicClient, common.ExternalSecretsConfigObjectName, 3*time.Minute)).To(Succeed()) + + esc := &operatorv1alpha1.ExternalSecretsConfig{} + Expect(runtimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc)).To(Succeed()) + By("Waiting for operand pods to be ready after args cleanup") + Expect(utils.VerifyOperandPodsReady(ctx, clientset, operandNamespace, esc)).To(Succeed()) + }) + + It("should override args on the core controller Deployment", func() { + By("Verifying controller args override and default concurrent flag is replaced") + waitForOperandArg(externalsecrets.OperandCoreControllerDeployment, externalsecrets.OperandCoreControllerContainer, controllerArg, true) + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, externalsecrets.OperandCoreControllerDeployment, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + hasDefault, found := deploymentContainerHasArg(deployment, externalsecrets.OperandCoreControllerContainer, "--concurrent=1") + g.Expect(found).To(BeTrue()) + g.Expect(hasDefault).To(BeFalse(), "default --concurrent=1 should be overridden") + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + }) + + It("should override args on the webhook Deployment and keep the positional token", func() { + waitForOperandArg(externalsecrets.OperandWebhookDeployment, externalsecrets.OperandWebhookContainer, webhookArg, true) + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, externalsecrets.OperandWebhookDeployment, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + args, found := getDeploymentContainerArgs(deployment, externalsecrets.OperandWebhookContainer) + g.Expect(found).To(BeTrue()) + g.Expect(args).NotTo(BeEmpty()) + g.Expect(args[0]).To(Equal("webhook"), "webhook positional token should be preserved") + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + }) + + It("should override args on the cert-controller Deployment when present", func() { + esc := &operatorv1alpha1.ExternalSecretsConfig{} + Expect(runtimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc)).To(Succeed()) + if !utils.IsCertControllerExpected(esc) { + Skip("cert-controller Deployment is not expected with current ExternalSecretsConfig (cert-manager enabled)") + } + + waitForOperandArg(externalsecrets.OperandCertControllerDeployment, externalsecrets.OperandCertControllerContainer, certControllerArg, true) + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, externalsecrets.OperandCertControllerDeployment, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + args, found := getDeploymentContainerArgs(deployment, externalsecrets.OperandCertControllerContainer) + g.Expect(found).To(BeTrue()) + g.Expect(args).NotTo(BeEmpty()) + g.Expect(args[0]).To(Equal("certcontroller"), "certcontroller positional token should be preserved") + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + }) + + It("should apply args on the bitwarden-sdk-server Deployment", func() { + waitForOperandArg(externalsecrets.OperandBitwardenSDKServerDeployment, externalsecrets.OperandBitwardenContainer, bitwardenArg, true) + }) + + It("should mark ExternalSecretsConfig Degraded for invalid OPERAND_*_ARGS", func() { + By("Setting an invalid controller args override") + Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, map[string]string{ + externalsecrets.OperandExternalSecretsArgsEnvVar: "not-a-flag", + })).To(Succeed()) + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + + By("Waiting for ExternalSecretsConfig to become Degraded with a user-configuration message") + Eventually(func(g Gomega) { + g.Expect(isExternalSecretsConfigDegraded(ctx)).To(BeTrue(), + "ExternalSecretsConfig should be Degraded for invalid OPERAND_*_ARGS") + msg := externalSecretsConfigDegradedMessage(ctx) + g.Expect(msg).To(ContainSubstring("invalid custom arg override")) + g.Expect(msg).To(ContainSubstring(`argument "not-a-flag" must start with --`)) + g.Expect(msg).To(ContainSubstring(externalsecrets.OperandExternalSecretsArgsEnvVar)) + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + + By("Verifying the invalid token was not applied to the controller Deployment") + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, externalsecrets.OperandCoreControllerDeployment, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + hasArg, found := deploymentContainerHasArg(deployment, externalsecrets.OperandCoreControllerContainer, "not-a-flag") + g.Expect(found).To(BeTrue()) + g.Expect(hasArg).To(BeFalse(), "invalid arg must not be present on controller container") + }, time.Minute, 5*time.Second).Should(Succeed()) + }) + + It("should mark ExternalSecretsConfig Degraded for positional OPERAND_WEBHOOK_ARGS", func() { + By("Restoring a valid controller override so webhook invalidation is the only failure") + Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, map[string]string{ + externalsecrets.OperandExternalSecretsArgsEnvVar: controllerArg, + externalsecrets.OperandWebhookArgsEnvVar: "webhook,--port=10251", + })).To(Succeed()) + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + + By("Waiting for ExternalSecretsConfig to become Degraded") + Eventually(func(g Gomega) { + g.Expect(isExternalSecretsConfigDegraded(ctx)).To(BeTrue(), + "ExternalSecretsConfig should be Degraded for positional webhook args") + msg := externalSecretsConfigDegradedMessage(ctx) + g.Expect(msg).To(ContainSubstring("invalid custom arg override")) + g.Expect(msg).To(ContainSubstring(externalsecrets.OperandWebhookArgsEnvVar)) + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + }) + + It("should recover from Degraded when invalid OPERAND_*_ARGS are corrected", func() { + By("Ensuring ExternalSecretsConfig is currently Degraded from prior invalid args") + Eventually(func(g Gomega) { + g.Expect(isExternalSecretsConfigDegraded(ctx)).To(BeTrue()) + }, time.Minute, 5*time.Second).Should(Succeed()) + + By("Correcting OPERAND_*_ARGS back to valid overrides") + Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnv)).To(Succeed()) + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + + By("Waiting for ExternalSecretsConfig to become Ready again") + Expect(utils.WaitForExternalSecretsConfigReady(ctx, dynamicClient, common.ExternalSecretsConfigObjectName, 3*time.Minute)).To(Succeed()) + + By("Verifying valid overrides are applied after recovery") + waitForOperandArg(externalsecrets.OperandCoreControllerDeployment, externalsecrets.OperandCoreControllerContainer, controllerArg, true) + waitForOperandArg(externalsecrets.OperandWebhookDeployment, externalsecrets.OperandWebhookContainer, webhookArg, true) + }) + + It("should restore default operand args when OPERAND_*_ARGS are cleared", func() { + By("Clearing OPERAND_*_ARGS to verify restoration") + Expect(unsetOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnvKeys)).To(Succeed()) + Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) + + waitForOperandArg(externalsecrets.OperandCoreControllerDeployment, externalsecrets.OperandCoreControllerContainer, controllerArg, false) + Eventually(func(g Gomega) { + deployment, err := clientset.AppsV1().Deployments(operandNamespace).Get(ctx, externalsecrets.OperandCoreControllerDeployment, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred()) + hasDefault, found := deploymentContainerHasArg(deployment, externalsecrets.OperandCoreControllerContainer, "--concurrent=1") + g.Expect(found).To(BeTrue()) + g.Expect(hasDefault).To(BeTrue(), "default --concurrent=1 should be restored") + }, 3*time.Minute, 5*time.Second).Should(Succeed()) + + waitForOperandArg(externalsecrets.OperandWebhookDeployment, externalsecrets.OperandWebhookContainer, webhookArg, false) + waitForOperandArg(externalsecrets.OperandBitwardenSDKServerDeployment, externalsecrets.OperandBitwardenContainer, bitwardenArg, false) + + esc := &operatorv1alpha1.ExternalSecretsConfig{} + Expect(runtimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc)).To(Succeed()) + if utils.IsCertControllerExpected(esc) { + waitForOperandArg(externalsecrets.OperandCertControllerDeployment, externalsecrets.OperandCertControllerContainer, certControllerArg, false) + } + }) +}) + +// externalSecretsConfigDegradedMessage returns the Degraded condition message, or "". +func externalSecretsConfigDegradedMessage(ctx context.Context) string { + esc := &operatorv1alpha1.ExternalSecretsConfig{} + if err := suiteRuntimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc); err != nil { + return "" + } + for _, cond := range esc.Status.Conditions { + if cond.Type == operatorv1alpha1.Degraded && cond.Status == metav1.ConditionTrue { + return cond.Message + } + } + return "" +} diff --git a/test/e2e/trusted_ca_bundle_test.go b/test/e2e/trusted_ca_bundle_test.go index cc5817c66..92bbbef09 100644 --- a/test/e2e/trusted_ca_bundle_test.go +++ b/test/e2e/trusted_ca_bundle_test.go @@ -418,20 +418,12 @@ func setTrustedCABundle(ctx context.Context, cmName, key string) { } func isExternalSecretsConfigDegraded(ctx context.Context) bool { - u, err := suiteDynamicClient.Resource(operatorv1alpha1.ExternalSecretsConfigGVR).Get(ctx, common.ExternalSecretsConfigObjectName, metav1.GetOptions{}) - if err != nil { - return false - } - conds, found, _ := unstructured.NestedSlice(u.Object, "status", "conditions") - if !found { + esc := &operatorv1alpha1.ExternalSecretsConfig{} + if err := suiteRuntimeClient.Get(ctx, client.ObjectKey{Name: common.ExternalSecretsConfigObjectName}, esc); err != nil { return false } - for _, c := range conds { - cond, ok := c.(map[string]interface{}) - if !ok { - continue - } - if cond["type"] == "Degraded" && cond["status"] == "True" { + for _, cond := range esc.Status.Conditions { + if cond.Type == operatorv1alpha1.Degraded && cond.Status == metav1.ConditionTrue { return true } } From c6b3fd9552cb1a6f37941d0ae025207850b5bbf7 Mon Sep 17 00:00:00 2001 From: Bharath B Date: Sat, 8 Aug 2026 13:40:41 +0530 Subject: [PATCH 2/3] ESO-566: Use dynamic client for e2e OLM helpers instead of operator-framework/api Signed-off-by: Bharath B --- pkg/controller/external_secrets/constants.go | 4 - .../external_secrets/deployments.go | 4 - test/e2e/e2e_suite_test.go | 2 - test/e2e/helpers_test.go | 158 ++++++++++++------ test/e2e/operand_args_test.go | 12 +- 5 files changed, 111 insertions(+), 69 deletions(-) diff --git a/pkg/controller/external_secrets/constants.go b/pkg/controller/external_secrets/constants.go index b82fa01dc..97bdefe71 100644 --- a/pkg/controller/external_secrets/constants.go +++ b/pkg/controller/external_secrets/constants.go @@ -112,10 +112,6 @@ const ( // containing the image version of the bitwarden-sdk-server as value. bitwardenImageVersionEnvVarName = "BITWARDEN_SDK_SERVER_IMAGE_VERSION" - // TODO: Remove in v1.4.0. Backported to 1.1/1.2 as a temporary escape hatch; - // v1.3.0 adds ExternalSecretsConfig advancedOverrides for per-component Deployment - // overrides and is the migration window before these env vars are removed. - // // OperandExternalSecretsArgsEnvVar is the operator env var for core controller container args overrides. OperandExternalSecretsArgsEnvVar = "OPERAND_EXTERNAL_SECRETS_ARGS" // OperandWebhookArgsEnvVar is the operator env var for webhook container args overrides. diff --git a/pkg/controller/external_secrets/deployments.go b/pkg/controller/external_secrets/deployments.go index be04f07ed..6e8c08147 100644 --- a/pkg/controller/external_secrets/deployments.go +++ b/pkg/controller/external_secrets/deployments.go @@ -873,10 +873,6 @@ func mergeContainerArgs(base []string, overrides []string) []string { // applyOperandArgsFromEnv reads envVarName and merges its comma-separated --key=value // flags into the named container's Args. Unset or empty env is a no-op. -// -// TODO: Remove in v1.4.0. Backported to 1.1/1.2 as a temporary escape hatch; -// v1.3.0 adds ExternalSecretsConfig advancedOverrides for per-component Deployment -// overrides and is the migration window before this env-based path is removed. func applyOperandArgsFromEnv(deployment *appsv1.Deployment, containerName, envVarName string) error { raw := strings.TrimSpace(os.Getenv(envVarName)) if raw == "" { diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 8b07633fe..c0de57ef3 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -38,7 +38,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" operatorv1alpha1 "github.com/openshift/external-secrets-operator/api/v1alpha1" "github.com/openshift/external-secrets-operator/test/utils" @@ -79,7 +78,6 @@ var _ = BeforeSuite(func() { scheme := runtime.NewScheme() utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) - utilruntime.Must(olmv1alpha1.AddToScheme(scheme)) suiteRuntimeClient, err = client.New(cfg, client.Options{Scheme: scheme}) Expect(err).NotTo(HaveOccurred(), "failed to create runtime client") }) diff --git a/test/e2e/helpers_test.go b/test/e2e/helpers_test.go index b3cc50409..9b4ac7581 100644 --- a/test/e2e/helpers_test.go +++ b/test/e2e/helpers_test.go @@ -27,13 +27,15 @@ import ( "time" . "github.com/onsi/gomega" - olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" @@ -51,6 +53,21 @@ const ( operatorCSVNamePrefix = "openshift-external-secrets-operator." // operatorPackageName is the OLM package / Subscription.spec.name value. operatorPackageName = "openshift-external-secrets-operator" + // olmOperatorNamespaceAnnotation is set on CSVs by OLM. + olmOperatorNamespaceAnnotation = "olm.operatorNamespace" +) + +var ( + csvGVR = schema.GroupVersionResource{ + Group: "operators.coreos.com", + Version: "v1alpha1", + Resource: "clusterserviceversions", + } + subscriptionGVR = schema.GroupVersionResource{ + Group: "operators.coreos.com", + Version: "v1alpha1", + Resource: "subscriptions", + } ) // ensureExternalSecretsConfigReady creates the cluster ExternalSecretsConfig CR when missing @@ -252,11 +269,14 @@ func deploymentContainerHasArg(deployment *appsv1.Deployment, containerName, arg // OLM rolls a new manager pod after Subscription updates; the startup reconcile reads // process env and applies operand args. This helper waits until that Ready pod has the // desired env before returning. -func setOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, envVars map[string]string) error { +// +// Uses the dynamic client for OLM types so release branches do not need +// github.com/operator-framework/api vendored solely for e2e helpers. +func setOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, dynamicClient dynamic.Interface, envVars map[string]string) error { if len(envVars) == 0 { return nil } - updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, c, envVars, nil) + updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, dynamicClient, envVars, nil) if err != nil { return err } @@ -270,11 +290,11 @@ func setOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, } // unsetOperatorManagerEnv removes env vars from the operator manager container. -func unsetOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, keys []string) error { +func unsetOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface, dynamicClient dynamic.Interface, keys []string) error { if len(keys) == 0 { return nil } - updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, c, nil, keys) + updatedViaSub, err := updateSubscriptionEnv(ctx, clientset, dynamicClient, nil, keys) if err != nil { return err } @@ -289,8 +309,8 @@ func unsetOperatorManagerEnv(ctx context.Context, clientset kubernetes.Interface // updateSubscriptionEnv merges env into Subscription.spec.config.env using the CSV to // locate the Subscription namespace. Returns false when no OLM Subscription is found. -func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, c client.Client, set map[string]string, unset []string) (bool, error) { - csv, err := findOperatorCSV(ctx, clientset, c) +func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, dynamicClient dynamic.Interface, set map[string]string, unset []string) (bool, error) { + csv, err := findOperatorCSV(ctx, clientset, dynamicClient) if err != nil { return false, err } @@ -298,15 +318,15 @@ func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, return false, nil } - subNamespace := csv.Annotations[olmv1alpha1.OperatorGroupNamespaceAnnotationKey] + subNamespace := csv.GetAnnotations()[olmOperatorNamespaceAnnotation] if subNamespace == "" { - subNamespace = csv.Namespace + subNamespace = csv.GetNamespace() } if subNamespace == "" { - return false, fmt.Errorf("CSV %s has empty namespace and no %s annotation", csv.Name, olmv1alpha1.OperatorGroupNamespaceAnnotationKey) + return false, fmt.Errorf("CSV %s has empty namespace and no %s annotation", csv.GetName(), olmOperatorNamespaceAnnotation) } - sub, err := findOperatorSubscription(ctx, c, subNamespace) + sub, err := findOperatorSubscription(ctx, dynamicClient, subNamespace) if err != nil { return false, err } @@ -315,28 +335,30 @@ func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, } err = retry.RetryOnConflict(retry.DefaultRetry, func() error { - current := &olmv1alpha1.Subscription{} - if err := c.Get(ctx, client.ObjectKey{Namespace: subNamespace, Name: sub.Name}, current); err != nil { - return fmt.Errorf("get Subscription %s/%s: %w", subNamespace, sub.Name, err) + current, err := dynamicClient.Resource(subscriptionGVR).Namespace(subNamespace).Get(ctx, sub.GetName(), metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("get Subscription %s/%s: %w", subNamespace, sub.GetName(), err) } - var existing []corev1.EnvVar - if current.Spec.Config != nil { - existing = current.Spec.Config.Env + config, _, _ := unstructured.NestedMap(current.Object, "spec", "config") + if config == nil { + config = map[string]interface{}{} } - merged := mergeEnvVars(existing, set, unset) - if current.Spec.Config == nil { - if len(merged) == 0 { - return nil - } - current.Spec.Config = &olmv1alpha1.SubscriptionConfig{} + rawEnv, _, _ := unstructured.NestedSlice(config, "env") + merged := mergeUnstructuredEnv(rawEnv, set, unset) + if len(merged) == 0 { + delete(config, "env") + } else { + config["env"] = merged } - current.Spec.Config.Env = merged - if isEmptySubscriptionConfig(current.Spec.Config) { - current.Spec.Config = nil + if len(config) == 0 { + unstructured.RemoveNestedField(current.Object, "spec", "config") + } else if err := unstructured.SetNestedMap(current.Object, config, "spec", "config"); err != nil { + return err } - return c.Update(ctx, current) + _, err = dynamicClient.Resource(subscriptionGVR).Namespace(subNamespace).Update(ctx, current, metav1.UpdateOptions{}) + return err }) if err != nil { return false, err @@ -346,17 +368,19 @@ func updateSubscriptionEnv(ctx context.Context, clientset kubernetes.Interface, // findOperatorCSV returns the installed openshift-external-secrets-operator CSV, or nil // when the operator is not managed by OLM. -func findOperatorCSV(ctx context.Context, clientset kubernetes.Interface, c client.Client) (*olmv1alpha1.ClusterServiceVersion, error) { - var list olmv1alpha1.ClusterServiceVersionList - if err := c.List(ctx, &list, client.InNamespace(operatorNamespace)); err != nil { +func findOperatorCSV(ctx context.Context, clientset kubernetes.Interface, dynamicClient dynamic.Interface) (*unstructured.Unstructured, error) { + list, err := dynamicClient.Resource(csvGVR).Namespace(operatorNamespace).List(ctx, metav1.ListOptions{}) + if err != nil { // NotFound / NoMatch: OLM CRDs missing or no CSVs — fall through to Deployment path. if !k8serrors.IsNotFound(err) && !meta.IsNoMatchError(err) { return nil, fmt.Errorf("list CSVs in %s: %w", operatorNamespace, err) } } - for i := range list.Items { - if strings.HasPrefix(list.Items[i].Name, operatorCSVNamePrefix) { - return list.Items[i].DeepCopy(), nil + if list != nil { + for i := range list.Items { + if strings.HasPrefix(list.Items[i].GetName(), operatorCSVNamePrefix) { + return list.Items[i].DeepCopy(), nil + } } } @@ -372,8 +396,8 @@ func findOperatorCSV(ctx context.Context, clientset kubernetes.Interface, c clie if ref.Kind != "ClusterServiceVersion" || ref.Name == "" { continue } - csv := &olmv1alpha1.ClusterServiceVersion{} - if err := c.Get(ctx, client.ObjectKey{Namespace: operatorNamespace, Name: ref.Name}, csv); err != nil { + csv, err := dynamicClient.Resource(csvGVR).Namespace(operatorNamespace).Get(ctx, ref.Name, metav1.GetOptions{}) + if err != nil { if meta.IsNoMatchError(err) { return nil, nil } @@ -388,34 +412,62 @@ func findOperatorCSV(ctx context.Context, clientset kubernetes.Interface, c clie } // findOperatorSubscription returns the Subscription for the operator package in ns. -func findOperatorSubscription(ctx context.Context, c client.Client, ns string) (*olmv1alpha1.Subscription, error) { - var list olmv1alpha1.SubscriptionList - if err := c.List(ctx, &list, client.InNamespace(ns)); err != nil { +func findOperatorSubscription(ctx context.Context, dynamicClient dynamic.Interface, ns string) (*unstructured.Unstructured, error) { + list, err := dynamicClient.Resource(subscriptionGVR).Namespace(ns).List(ctx, metav1.ListOptions{}) + if err != nil { + if meta.IsNoMatchError(err) || k8serrors.IsNotFound(err) { + return nil, nil + } return nil, fmt.Errorf("list Subscriptions in %s: %w", ns, err) } for i := range list.Items { item := &list.Items[i] - if item.Spec.Package == operatorPackageName || strings.HasPrefix(item.Name, operatorPackageName) { + pkg, _, _ := unstructured.NestedString(item.Object, "spec", "name") + if pkg == operatorPackageName || strings.HasPrefix(item.GetName(), operatorPackageName) { return item.DeepCopy(), nil } } return nil, nil } -func isEmptySubscriptionConfig(c *olmv1alpha1.SubscriptionConfig) bool { - if c == nil { - return true - } - return c.Selector == nil && - len(c.NodeSelector) == 0 && - len(c.Tolerations) == 0 && - c.Resources == nil && - len(c.EnvFrom) == 0 && - len(c.Env) == 0 && - len(c.Volumes) == 0 && - len(c.VolumeMounts) == 0 && - c.Affinity == nil && - len(c.Annotations) == 0 +func mergeUnstructuredEnv(raw []interface{}, set map[string]string, unset []string) []interface{} { + remove := make(map[string]struct{}, len(unset)) + for _, k := range unset { + remove[k] = struct{}{} + } + seen := make(map[string]bool) + out := make([]interface{}, 0, len(raw)+len(set)) + for _, item := range raw { + m, ok := item.(map[string]interface{}) + if !ok { + continue + } + name, _, _ := unstructured.NestedString(m, "name") + if name == "" { + continue + } + if _, drop := remove[name]; drop { + continue + } + if val, ok := set[name]; ok { + m["value"] = val + delete(m, "valueFrom") + } + out = append(out, m) + seen[name] = true + } + toAdd := make([]string, 0, len(set)) + for name := range set { + if seen[name] { + continue + } + toAdd = append(toAdd, name) + } + slices.Sort(toAdd) + for _, name := range toAdd { + out = append(out, map[string]interface{}{"name": name, "value": set[name]}) + } + return out } func updateOperatorDeploymentEnv(ctx context.Context, clientset kubernetes.Interface, set map[string]string, unset []string) error { diff --git a/test/e2e/operand_args_test.go b/test/e2e/operand_args_test.go index 0f13268ac..451e78eb4 100644 --- a/test/e2e/operand_args_test.go +++ b/test/e2e/operand_args_test.go @@ -106,7 +106,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" Expect(ensureBitwardenOperandReady(ctx, nil)).To(Succeed()) By("Setting OPERAND_*_ARGS on the operator manager") - Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnv)).To(Succeed()) + Expect(setOperatorManagerEnv(ctx, clientset, dynamicClient, operandArgsEnv)).To(Succeed()) By("Waiting for operator pod to be ready after env update") Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) @@ -114,7 +114,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" AfterAll(func() { By("Clearing OPERAND_*_ARGS from the operator manager") - Expect(unsetOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnvKeys)).To(Succeed()) + Expect(unsetOperatorManagerEnv(ctx, clientset, dynamicClient, operandArgsEnvKeys)).To(Succeed()) By("Waiting for operator pod to be ready after env cleanup") Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) @@ -184,7 +184,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" It("should mark ExternalSecretsConfig Degraded for invalid OPERAND_*_ARGS", func() { By("Setting an invalid controller args override") - Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, map[string]string{ + Expect(setOperatorManagerEnv(ctx, clientset, dynamicClient, map[string]string{ externalsecrets.OperandExternalSecretsArgsEnvVar: "not-a-flag", })).To(Succeed()) Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) @@ -211,7 +211,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" It("should mark ExternalSecretsConfig Degraded for positional OPERAND_WEBHOOK_ARGS", func() { By("Restoring a valid controller override so webhook invalidation is the only failure") - Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, map[string]string{ + Expect(setOperatorManagerEnv(ctx, clientset, dynamicClient, map[string]string{ externalsecrets.OperandExternalSecretsArgsEnvVar: controllerArg, externalsecrets.OperandWebhookArgsEnvVar: "webhook,--port=10251", })).To(Succeed()) @@ -234,7 +234,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" }, time.Minute, 5*time.Second).Should(Succeed()) By("Correcting OPERAND_*_ARGS back to valid overrides") - Expect(setOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnv)).To(Succeed()) + Expect(setOperatorManagerEnv(ctx, clientset, dynamicClient, operandArgsEnv)).To(Succeed()) Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) By("Waiting for ExternalSecretsConfig to become Ready again") @@ -247,7 +247,7 @@ var _ = Describe("Operand Args Env Overrides", Ordered, Label("Platform:Generic" It("should restore default operand args when OPERAND_*_ARGS are cleared", func() { By("Clearing OPERAND_*_ARGS to verify restoration") - Expect(unsetOperatorManagerEnv(ctx, clientset, runtimeClient, operandArgsEnvKeys)).To(Succeed()) + Expect(unsetOperatorManagerEnv(ctx, clientset, dynamicClient, operandArgsEnvKeys)).To(Succeed()) Expect(utils.VerifyPodsReadyByPrefix(ctx, clientset, operatorNamespace, []string{operatorPodPrefix})).To(Succeed()) waitForOperandArg(externalsecrets.OperandCoreControllerDeployment, externalsecrets.OperandCoreControllerContainer, controllerArg, false) From bcf950a454d5e106f6e397b803fdeff0033cccba Mon Sep 17 00:00:00 2001 From: Bharath B Date: Sat, 8 Aug 2026 18:46:34 +0530 Subject: [PATCH 3/3] Bump golang.org/x/text to v0.39.0 to address GO-2026-5970 Signed-off-by: Bharath B --- cmd/external-secrets-operator/go.mod | 11 +- cmd/external-secrets-operator/go.sum | 28 +- go.mod | 11 +- go.sum | 28 +- test/go.mod | 14 +- test/go.sum | 28 +- tools/go.mod | 16 +- tools/go.sum | 36 +- vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 73 +- vendor/golang.org/x/crypto/scrypt/scrypt.go | 3 + vendor/golang.org/x/mod/modfile/read.go | 8 +- vendor/golang.org/x/mod/modfile/rule.go | 65 +- vendor/golang.org/x/net/html/entity.go | 5 +- vendor/golang.org/x/net/html/escape.go | 140 +- vendor/golang.org/x/net/html/foreign.go | 2 +- vendor/golang.org/x/net/html/iter.go | 2 - vendor/golang.org/x/net/html/node.go | 1 + .../golang.org/x/net/html/nodetype_string.go | 31 + vendor/golang.org/x/net/html/parse.go | 287 +- vendor/golang.org/x/net/html/render.go | 35 +- vendor/golang.org/x/net/html/token.go | 52 +- vendor/golang.org/x/net/http2/README.md | 19 + .../x/net/http2/client_conn_pool.go | 14 +- .../x/net/http2/client_priority_go126.go | 20 + .../x/net/http2/client_priority_go127.go | 13 + vendor/golang.org/x/net/http2/clientconn.go | 57 + vendor/golang.org/x/net/http2/config.go | 2 + vendor/golang.org/x/net/http2/frame.go | 188 +- vendor/golang.org/x/net/http2/http2.go | 20 +- vendor/golang.org/x/net/http2/server.go | 298 +- .../golang.org/x/net/http2/server_common.go | 221 + vendor/golang.org/x/net/http2/server_wrap.go | 217 + vendor/golang.org/x/net/http2/transport.go | 477 +- .../x/net/http2/transport_common.go | 447 + .../golang.org/x/net/http2/transport_wrap.go | 392 + vendor/golang.org/x/net/http2/writesched.go | 44 +- .../x/net/http2/writesched_common.go | 90 + .../net/http2/writesched_priority_rfc7540.go | 48 +- .../net/http2/writesched_priority_rfc9218.go | 2 + .../x/net/http2/writesched_random.go | 4 + .../x/net/http2/writesched_roundrobin.go | 2 + vendor/golang.org/x/net/idna/go118.go | 13 - .../x/net/idna/{idna10.0.0.go => idna.go} | 181 +- vendor/golang.org/x/net/idna/idna9.0.0.go | 717 -- vendor/golang.org/x/net/idna/pre_go118.go | 11 - vendor/golang.org/x/net/idna/punycode.go | 5 +- vendor/golang.org/x/net/idna/tables10.0.0.go | 4559 ---------- vendor/golang.org/x/net/idna/tables11.0.0.go | 4653 ---------- vendor/golang.org/x/net/idna/tables12.0.0.go | 4733 ---------- vendor/golang.org/x/net/idna/tables13.0.0.go | 4959 ----------- vendor/golang.org/x/net/idna/tables15.0.0.go | 2 +- vendor/golang.org/x/net/idna/tables17.0.0.go | 5302 ++++++++++++ vendor/golang.org/x/net/idna/tables9.0.0.go | 4486 ---------- vendor/golang.org/x/net/idna/trie12.0.0.go | 30 - vendor/golang.org/x/net/idna/trie13.0.0.go | 30 - .../x/net/internal/httpcommon/request.go | 8 + .../x/net/internal/httpsfv/httpsfv.go | 665 ++ vendor/golang.org/x/sync/errgroup/errgroup.go | 2 +- .../golang.org/x/sync/semaphore/semaphore.go | 10 +- .../x/sync/singleflight/singleflight.go | 22 +- .../golang.org/x/sys/plan9/syscall_plan9.go | 8 +- .../golang.org/x/sys/unix/affinity_linux.go | 128 +- vendor/golang.org/x/sys/unix/ioctl_signed.go | 11 +- .../golang.org/x/sys/unix/ioctl_unsigned.go | 11 +- vendor/golang.org/x/sys/unix/mkall.sh | 2 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 3 + vendor/golang.org/x/sys/unix/readv_unix.go | 103 + .../golang.org/x/sys/unix/syscall_darwin.go | 89 - vendor/golang.org/x/sys/unix/syscall_linux.go | 114 +- .../x/sys/unix/syscall_linux_arm.go | 3 + .../x/sys/unix/syscall_linux_arm64.go | 3 + .../x/sys/unix/syscall_linux_loong64.go | 3 + .../x/sys/unix/syscall_linux_riscv64.go | 3 + .../golang.org/x/sys/unix/syscall_openbsd.go | 4 + .../golang.org/x/sys/unix/syscall_solaris.go | 8 - vendor/golang.org/x/sys/unix/syscall_unix.go | 10 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 61 +- .../x/sys/unix/zerrors_linux_386.go | 7 +- .../x/sys/unix/zerrors_linux_amd64.go | 7 +- .../x/sys/unix/zerrors_linux_arm.go | 7 +- .../x/sys/unix/zerrors_linux_arm64.go | 7 +- .../x/sys/unix/zerrors_linux_loong64.go | 7 +- .../x/sys/unix/zerrors_linux_mips.go | 7 +- .../x/sys/unix/zerrors_linux_mips64.go | 7 +- .../x/sys/unix/zerrors_linux_mips64le.go | 7 +- .../x/sys/unix/zerrors_linux_mipsle.go | 7 +- .../x/sys/unix/zerrors_linux_ppc.go | 7 +- .../x/sys/unix/zerrors_linux_ppc64.go | 7 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 7 +- .../x/sys/unix/zerrors_linux_riscv64.go | 1114 +-- .../x/sys/unix/zerrors_linux_s390x.go | 7 +- .../x/sys/unix/zerrors_linux_sparc64.go | 7 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 12 +- .../x/sys/unix/zsyscall_openbsd_386.go | 84 + .../x/sys/unix/zsyscall_openbsd_386.s | 20 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 84 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 20 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 84 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 20 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 84 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 24 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 84 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 20 + .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 5 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_loong64.go | 5 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 5 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 352 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 12 + .../x/sys/unix/ztypes_linux_amd64.go | 12 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 12 + .../x/sys/unix/ztypes_linux_arm64.go | 12 + .../x/sys/unix/ztypes_linux_loong64.go | 12 + .../x/sys/unix/ztypes_linux_mips.go | 12 + .../x/sys/unix/ztypes_linux_mips64.go | 12 + .../x/sys/unix/ztypes_linux_mips64le.go | 12 + .../x/sys/unix/ztypes_linux_mipsle.go | 12 + .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 12 + .../x/sys/unix/ztypes_linux_ppc64.go | 12 + .../x/sys/unix/ztypes_linux_ppc64le.go | 12 + .../x/sys/unix/ztypes_linux_riscv64.go | 12 + .../x/sys/unix/ztypes_linux_s390x.go | 12 + .../x/sys/unix/ztypes_linux_sparc64.go | 12 + vendor/golang.org/x/sys/windows/aliases.go | 1 + .../golang.org/x/sys/windows/dll_windows.go | 37 +- .../golang.org/x/sys/windows/registry/key.go | 15 +- .../x/sys/windows/security_windows.go | 6 +- .../x/sys/windows/syscall_windows.go | 31 +- .../golang.org/x/sys/windows/types_windows.go | 118 +- .../x/sys/windows/zsyscall_windows.go | 78 + .../internal/crashmonitor/monitor.go | 85 +- vendor/golang.org/x/text/cases/context.go | 2 +- vendor/golang.org/x/text/cases/map.go | 4 +- .../golang.org/x/text/cases/tables10.0.0.go | 2255 ----- .../golang.org/x/text/cases/tables11.0.0.go | 2316 ----- .../golang.org/x/text/cases/tables12.0.0.go | 2359 ----- .../golang.org/x/text/cases/tables15.0.0.go | 2 +- .../{tables13.0.0.go => tables17.0.0.go} | 1473 ++-- vendor/golang.org/x/text/cases/tables9.0.0.go | 2215 ----- .../x/text/message/catalog/catalog.go | 2 +- .../golang.org/x/text/message/catalog/dict.go | 6 +- .../golang.org/x/text/message/catalog/go19.go | 15 - .../x/text/message/catalog/gopre19.go | 23 - .../x/text/secure/bidirule/bidirule.go | 4 + .../x/text/secure/bidirule/bidirule10.0.0.go | 11 - .../x/text/secure/bidirule/bidirule9.0.0.go | 14 - .../x/text/unicode/bidi/tables10.0.0.go | 1815 ---- .../x/text/unicode/bidi/tables11.0.0.go | 1887 ---- .../x/text/unicode/bidi/tables12.0.0.go | 1923 ---- .../x/text/unicode/bidi/tables13.0.0.go | 1955 ----- .../x/text/unicode/bidi/tables15.0.0.go | 2 +- .../x/text/unicode/bidi/tables17.0.0.go | 2135 +++++ .../x/text/unicode/bidi/tables9.0.0.go | 1781 ---- .../x/text/unicode/norm/forminfo.go | 35 +- vendor/golang.org/x/text/unicode/norm/iter.go | 8 +- .../x/text/unicode/norm/normalize.go | 20 +- .../x/text/unicode/norm/tables10.0.0.go | 7657 ---------------- .../x/text/unicode/norm/tables11.0.0.go | 7693 ---------------- .../x/text/unicode/norm/tables12.0.0.go | 7710 ----------------- .../x/text/unicode/norm/tables15.0.0.go | 2820 +++--- .../norm/{tables13.0.0.go => tables17.0.0.go} | 6716 +++++++------- .../x/text/unicode/norm/tables9.0.0.go | 7637 ---------------- .../golang.org/x/text/width/tables10.0.0.go | 1328 --- .../golang.org/x/text/width/tables11.0.0.go | 1340 --- .../golang.org/x/text/width/tables12.0.0.go | 1360 --- .../golang.org/x/text/width/tables15.0.0.go | 2 +- .../{tables13.0.0.go => tables17.0.0.go} | 533 +- vendor/golang.org/x/text/width/tables9.0.0.go | 1296 --- .../x/tools/go/analysis/analysis.go | 19 +- .../go/analysis/passes/composite/composite.go | 142 +- .../go/analysis/passes/directive/directive.go | 10 +- .../go/analysis/passes/errorsas/errorsas.go | 11 +- .../passes/fieldalignment/fieldalignment.go | 2 +- .../passes/httpresponse/httpresponse.go | 7 +- .../analysis/passes/lostcancel/lostcancel.go | 3 +- .../analysis/passes/modernize/atomictypes.go | 251 + .../tools/go/analysis/passes/modernize/doc.go | 104 +- .../go/analysis/passes/modernize/embedlit.go | 450 + .../analysis/passes/modernize/errorsastype.go | 154 +- .../analysis/passes/modernize/fmtappendf.go | 90 +- .../go/analysis/passes/modernize/maps.go | 10 +- .../go/analysis/passes/modernize/minmax.go | 102 +- .../go/analysis/passes/modernize/modernize.go | 80 +- .../go/analysis/passes/modernize/newexpr.go | 9 +- .../go/analysis/passes/modernize/plusbuild.go | 10 +- .../go/analysis/passes/modernize/rangeint.go | 106 +- .../go/analysis/passes/modernize/reflect.go | 79 +- .../passes/modernize/slicesbackward.go | 270 + .../passes/modernize/slicescontains.go | 34 +- .../analysis/passes/modernize/stditerators.go | 32 +- .../passes/modernize/stringsbuilder.go | 78 +- .../analysis/passes/modernize/stringscut.go | 373 +- .../passes/modernize/stringscutprefix.go | 61 +- .../analysis/passes/modernize/unsafefuncs.go | 16 +- .../{waitgroup.go => waitgroupgo.go} | 13 +- .../x/tools/go/analysis/passes/printf/doc.go | 10 + .../tools/go/analysis/passes/printf/printf.go | 37 +- .../go/analysis/passes/structtag/structtag.go | 2 +- vendor/golang.org/x/tools/go/ast/edge/edge.go | 24 +- .../x/tools/go/ast/inspector/cursor.go | 34 +- .../x/tools/go/ast/inspector/inspector.go | 4 +- .../x/tools/go/ast/inspector/iter.go | 36 +- .../x/tools/go/buildutil/allpackages.go | 12 +- .../golang.org/x/tools/go/callgraph/util.go | 1 + .../go/callgraph/vta/internal/trie/scope.go | 4 +- .../x/tools/go/callgraph/vta/propagation.go | 4 +- .../x/tools/go/callgraph/vta/vta.go | 3 + .../golang.org/x/tools/go/packages/golist.go | 50 +- .../x/tools/go/packages/packages.go | 49 +- vendor/golang.org/x/tools/go/ssa/builder.go | 166 +- vendor/golang.org/x/tools/go/ssa/create.go | 33 +- vendor/golang.org/x/tools/go/ssa/emit.go | 2 +- .../golang.org/x/tools/go/ssa/instantiate.go | 57 +- vendor/golang.org/x/tools/go/ssa/methods.go | 23 +- vendor/golang.org/x/tools/go/ssa/sanity.go | 53 +- vendor/golang.org/x/tools/go/ssa/ssa.go | 109 +- .../x/tools/go/ssa/ssautil/visit.go | 13 +- vendor/golang.org/x/tools/go/ssa/subst.go | 33 +- vendor/golang.org/x/tools/go/ssa/wrappers.go | 42 +- .../x/tools/go/types/objectpath/objectpath.go | 575 +- .../x/tools/internal/aliases/aliases.go | 30 +- .../x/tools/internal/aliases/aliases_go122.go | 80 - .../internal/analysis/analyzerutil/version.go | 8 +- .../x/tools/internal/astutil/comment.go | 51 +- .../x/tools/internal/astutil/cursor.go | 38 + .../x/tools/internal/astutil/purge.go | 43 +- .../x/tools/internal/astutil/stringlit.go | 56 +- .../x/tools/internal/astutil/util.go | 130 +- .../x/tools/internal/event/core/event.go | 23 +- .../x/tools/internal/event/keys/keys.go | 439 +- .../x/tools/internal/event/label/label.go | 11 +- .../x/tools/internal/gcimporter/iexport.go | 14 +- .../x/tools/internal/gcimporter/iimport.go | 30 +- .../gcimporter/{ureader_yes.go => ureader.go} | 138 +- .../x/tools/internal/gocommand/version.go | 8 +- .../x/tools/internal/goplsexport/export.go | 17 - .../x/tools/internal/imports/fix.go | 7 +- .../x/tools/internal/imports/imports.go | 4 + .../x/tools/internal/imports/mod.go | 6 +- .../tools/internal/imports/source_modindex.go | 100 - .../x/tools/internal/modindex/directories.go | 131 - .../x/tools/internal/modindex/index.go | 292 - .../x/tools/internal/modindex/lookup.go | 184 - .../x/tools/internal/modindex/modindex.go | 119 - .../x/tools/internal/modindex/symbols.go | 244 - .../x/tools/internal/moreiters/iters.go | 8 + .../x/tools/internal/pkgbits/version.go | 17 + .../x/tools/internal/refactor/delete.go | 12 +- .../x/tools/internal/refactor/imports.go | 33 +- .../x/tools/internal/refactor/refactor.go | 7 +- .../x/tools/internal/stdlib/deps.go | 654 +- .../x/tools/internal/stdlib/manifest.go | 287 +- .../x/tools/internal/typeparams/coretype.go | 8 +- .../x/tools/internal/typeparams/free.go | 4 +- .../x/tools/internal/typesinternal/element.go | 8 +- .../typesinternal/typeindex/typeindex.go | 25 +- .../x/tools/internal/typesinternal/types.go | 79 +- .../tools/internal/typesinternal/zerovalue.go | 16 +- .../x/tools/internal/versions/features.go | 1 + .../x/tools/refactor/satisfy/find.go | 183 +- vendor/modules.txt | 39 +- 276 files changed, 23457 insertions(+), 89698 deletions(-) create mode 100644 vendor/golang.org/x/net/html/nodetype_string.go create mode 100644 vendor/golang.org/x/net/http2/README.md create mode 100644 vendor/golang.org/x/net/http2/client_priority_go126.go create mode 100644 vendor/golang.org/x/net/http2/client_priority_go127.go create mode 100644 vendor/golang.org/x/net/http2/clientconn.go create mode 100644 vendor/golang.org/x/net/http2/server_common.go create mode 100644 vendor/golang.org/x/net/http2/server_wrap.go create mode 100644 vendor/golang.org/x/net/http2/transport_common.go create mode 100644 vendor/golang.org/x/net/http2/transport_wrap.go create mode 100644 vendor/golang.org/x/net/http2/writesched_common.go delete mode 100644 vendor/golang.org/x/net/idna/go118.go rename vendor/golang.org/x/net/idna/{idna10.0.0.go => idna.go} (81%) delete mode 100644 vendor/golang.org/x/net/idna/idna9.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/pre_go118.go delete mode 100644 vendor/golang.org/x/net/idna/tables10.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/tables11.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/tables12.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/tables13.0.0.go create mode 100644 vendor/golang.org/x/net/idna/tables17.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/tables9.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/trie12.0.0.go delete mode 100644 vendor/golang.org/x/net/idna/trie13.0.0.go create mode 100644 vendor/golang.org/x/net/internal/httpsfv/httpsfv.go create mode 100644 vendor/golang.org/x/sys/unix/readv_unix.go delete mode 100644 vendor/golang.org/x/text/cases/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/cases/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/cases/tables12.0.0.go rename vendor/golang.org/x/text/cases/{tables13.0.0.go => tables17.0.0.go} (60%) delete mode 100644 vendor/golang.org/x/text/cases/tables9.0.0.go delete mode 100644 vendor/golang.org/x/text/message/catalog/go19.go delete mode 100644 vendor/golang.org/x/text/message/catalog/gopre19.go delete mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go delete mode 100644 vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go create mode 100644 vendor/golang.org/x/text/unicode/bidi/tables17.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables12.0.0.go rename vendor/golang.org/x/text/unicode/norm/{tables13.0.0.go => tables17.0.0.go} (53%) delete mode 100644 vendor/golang.org/x/text/unicode/norm/tables9.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables10.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables11.0.0.go delete mode 100644 vendor/golang.org/x/text/width/tables12.0.0.go rename vendor/golang.org/x/text/width/{tables13.0.0.go => tables17.0.0.go} (74%) delete mode 100644 vendor/golang.org/x/text/width/tables9.0.0.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/atomictypes.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/embedlit.go create mode 100644 vendor/golang.org/x/tools/go/analysis/passes/modernize/slicesbackward.go rename vendor/golang.org/x/tools/go/analysis/passes/modernize/{waitgroup.go => waitgroupgo.go} (93%) delete mode 100644 vendor/golang.org/x/tools/internal/aliases/aliases_go122.go create mode 100644 vendor/golang.org/x/tools/internal/astutil/cursor.go rename vendor/golang.org/x/tools/internal/gcimporter/{ureader_yes.go => ureader.go} (84%) delete mode 100644 vendor/golang.org/x/tools/internal/goplsexport/export.go delete mode 100644 vendor/golang.org/x/tools/internal/imports/source_modindex.go delete mode 100644 vendor/golang.org/x/tools/internal/modindex/directories.go delete mode 100644 vendor/golang.org/x/tools/internal/modindex/index.go delete mode 100644 vendor/golang.org/x/tools/internal/modindex/lookup.go delete mode 100644 vendor/golang.org/x/tools/internal/modindex/modindex.go delete mode 100644 vendor/golang.org/x/tools/internal/modindex/symbols.go diff --git a/cmd/external-secrets-operator/go.mod b/cmd/external-secrets-operator/go.mod index 2cb2e2104..bcdc2d6bd 100644 --- a/cmd/external-secrets-operator/go.mod +++ b/cmd/external-secrets-operator/go.mod @@ -81,13 +81,12 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/net v0.49.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect diff --git a/cmd/external-secrets-operator/go.sum b/cmd/external-secrets-operator/go.sum index 6c641f910..259af05a4 100644 --- a/cmd/external-secrets-operator/go.sum +++ b/cmd/external-secrets-operator/go.sum @@ -189,24 +189,24 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= diff --git a/go.mod b/go.mod index 846e9c57f..b06e92aa2 100644 --- a/go.mod +++ b/go.mod @@ -66,14 +66,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.49.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.41.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/go.sum b/go.sum index 96f9478c0..fadd67b73 100644 --- a/go.sum +++ b/go.sum @@ -140,24 +140,24 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= diff --git a/test/go.mod b/test/go.mod index 1c3f90f47..06565ebe8 100644 --- a/test/go.mod +++ b/test/go.mod @@ -76,15 +76,15 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/net v0.49.0 // indirect + golang.org/x/mod v0.37.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/term v0.44.0 // indirect + golang.org/x/text v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.41.0 // indirect + golang.org/x/tools v0.47.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/test/go.sum b/test/go.sum index 0830d1ba7..6163896bc 100644 --- a/test/go.sum +++ b/test/go.sum @@ -203,22 +203,22 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -228,21 +228,21 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= diff --git a/tools/go.mod b/tools/go.mod index 4697cea85..328450bf0 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -259,17 +259,17 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.53.0 // indirect golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546 // indirect - golang.org/x/mod v0.32.0 // indirect - golang.org/x/net v0.49.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/mod v0.37.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 // indirect + golang.org/x/text v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.41.0 // indirect + golang.org/x/tools v0.47.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/grpc v1.79.3 // indirect diff --git a/tools/go.sum b/tools/go.sum index aa048c217..785b43c64 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -636,8 +636,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -653,8 +653,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -668,8 +668,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -681,8 +681,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -703,18 +703,18 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= -golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 h1:nwGZBCt+FnXUrGsj5vjzAsEmkcaFvd82BbOjECiFYZc= +golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57/go.mod h1:3AWMyWHS+caVoiEXpiq6+tzKA40J4vQT3MYr80ZtQpc= 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= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -723,8 +723,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -739,8 +739,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go index 28cd99c7f..b33212203 100644 --- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -2,24 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC -2898 / PKCS #5 v2.0. - -A key derivation function is useful when encrypting data based on a password -or any other not-fully-random data. It uses a pseudorandom function to derive -a secure encryption key based on the password. - -While v2.0 of the standard defines only one pseudorandom function to use, -HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved -Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To -choose, you can pass the `New` functions from the different SHA packages to -pbkdf2.Key. -*/ +// Package pbkdf2 implements the key derivation function PBKDF2 as defined in +// RFC 8018 (PKCS #5 v2.1). +// +// This package is a wrapper for the PBKDF2 implementation in the +// [crypto/pbkdf2] package. It is [frozen] and is not accepting new features. +// +// [frozen]: https://go.dev/wiki/Frozen package pbkdf2 import ( - "crypto/hmac" + "crypto/pbkdf2" "hash" ) @@ -27,51 +20,11 @@ import ( // []byte of length keylen that can be used as cryptographic key. The key is // derived based on the method described as PBKDF2 with the HMAC variant using // the supplied hash function. -// -// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you -// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by -// doing: -// -// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) -// -// Remember to get a good random salt. At least 8 bytes is recommended by the -// RFC. -// -// Using a higher iteration count will increase the cost of an exhaustive -// search but will also make derivation proportionally slower. func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { - prf := hmac.New(h, password) - hashLen := prf.Size() - numBlocks := (keyLen + hashLen - 1) / hashLen - - var buf [4]byte - dk := make([]byte, 0, numBlocks*hashLen) - U := make([]byte, hashLen) - for block := 1; block <= numBlocks; block++ { - // N.B.: || means concatenation, ^ means XOR - // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter - // U_1 = PRF(password, salt || uint(i)) - prf.Reset() - prf.Write(salt) - buf[0] = byte(block >> 24) - buf[1] = byte(block >> 16) - buf[2] = byte(block >> 8) - buf[3] = byte(block) - prf.Write(buf[:4]) - dk = prf.Sum(dk) - T := dk[len(dk)-hashLen:] - copy(U, T) - - // U_n = PRF(password, U_(n-1)) - for n := 2; n <= iter; n++ { - prf.Reset() - prf.Write(U) - U = U[:0] - U = prf.Sum(U) - for x := range U { - T[x] ^= U[x] - } - } + out, err := pbkdf2.Key(h, string(password), salt, iter, keyLen) + if err != nil { + // FIPS 140 enforcement, or an invalid key length. + panic(err) } - return dk[:keyLen] + return out } diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go index 76fa40fb2..b422b7d7f 100644 --- a/vendor/golang.org/x/crypto/scrypt/scrypt.go +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -196,6 +196,9 @@ func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) { if N <= 1 || N&(N-1) != 0 { return nil, errors.New("scrypt: N must be > 1 and a power of 2") } + if r <= 0 || p <= 0 { + return nil, errors.New("scrypt: parameters must be > 0") + } if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r { return nil, errors.New("scrypt: parameters are too large") } diff --git a/vendor/golang.org/x/mod/modfile/read.go b/vendor/golang.org/x/mod/modfile/read.go index 504a2f1df..5b528c718 100644 --- a/vendor/golang.org/x/mod/modfile/read.go +++ b/vendor/golang.org/x/mod/modfile/read.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "os" + "slices" "strconv" "strings" "unicode" @@ -105,8 +106,7 @@ func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line { if hint == nil { // If no hint given, add to the last statement of the given type. Loop: - for i := len(x.Stmt) - 1; i >= 0; i-- { - stmt := x.Stmt[i] + for _, stmt := range slices.Backward(x.Stmt) { switch stmt := stmt.(type) { case *Line: if stmt.Token != nil && stmt.Token[0] == tokens[0] { @@ -718,9 +718,7 @@ func (in *input) assignComments() { } // Assign suffix comments to syntax immediately before. - for i := len(in.post) - 1; i >= 0; i-- { - x := in.post[i] - + for _, x := range slices.Backward(in.post) { start, end := x.Span() if debug { fmt.Fprintf(os.Stderr, "post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte) diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go index c5b8305de..9ab203b56 100644 --- a/vendor/golang.org/x/mod/modfile/rule.go +++ b/vendor/golang.org/x/mod/modfile/rule.go @@ -327,6 +327,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parse } var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))?([a-z]+[0-9]+)?$`) + var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`) // Toolchains must be named beginning with `go1`, @@ -1272,6 +1273,17 @@ func (f *File) SetRequire(req []*Require) { // SetRequireSeparateIndirect will split it into a direct-only and indirect-only // block. This aids in the transition to separate blocks. func (f *File) SetRequireSeparateIndirect(req []*Require) { + f.setRequireSeparateIndirect(req, false) +} + +// SetRequireAtMostTwo is like SetRequireSeparateIndirect but it aggressively +// consolidates all requirements into at most two blocks (one direct, one indirect). +// It ignores existing blocks and comments when deciding where to place requirements. +func (f *File) SetRequireAtMostTwo(req []*Require) { + f.setRequireSeparateIndirect(req, true) +} + +func (f *File) setRequireSeparateIndirect(req []*Require, simplify bool) { // hasComments returns whether a line or block has comments // other than "indirect". hasComments := func(c Comments) bool { @@ -1304,6 +1316,17 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { } // Examine existing require lines and blocks. + need := make(map[string]*Require) + for _, r := range req { + need[r.Mod.Path] = r + } + lineIndirect := make(map[*Line]bool) + for _, r := range f.Require { + if n := need[r.Mod.Path]; n != nil { + lineIndirect[r.Syntax] = n.Indirect + } + } + var ( // We may insert new requirements into the last uncommented // direct-only and indirect-only blocks. We may also move requirements @@ -1321,7 +1344,9 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { // Track the block each requirement belongs to (if any) so we can // move them later. - lineToBlock = make(map[*Line]*LineBlock) + lineToBlock = make(map[*Line]*LineBlock) + directBlockComments []Comment + indirectBlockComments []Comment ) for i, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { @@ -1364,6 +1389,24 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { if allIndirect { lastIndirectIndex = i } + if simplify { + anyDirect := false + for _, line := range stmt.Line { + if ind, ok := lineIndirect[line]; ok && !ind { + anyDirect = true + break + } + } + target := &directBlockComments + if !anyDirect && len(stmt.Line) > 0 { + target = &indirectBlockComments + } + if len(*target) > 0 && len(stmt.Comments.Before) > 0 { + *target = append(*target, Comment{Token: "//"}) + } + *target = append(*target, stmt.Comments.Before...) + stmt.Comments.Before = nil + } } } @@ -1422,6 +1465,15 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { lastIndirectBlock = ensureBlock(lastIndirectIndex) } + if simplify { + if len(directBlockComments) > 0 { + lastDirectBlock.Comments.Before = append(lastDirectBlock.Comments.Before, directBlockComments...) + } + if len(indirectBlockComments) > 0 { + lastIndirectBlock.Comments.Before = append(lastIndirectBlock.Comments.Before, indirectBlockComments...) + } + } + // Delete requirements we don't want anymore. // Update versions and indirect comments on requirements we want to keep. // If a requirement is in last{Direct,Indirect}Block with the wrong @@ -1430,10 +1482,6 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { // correct block. // // Some blocks may be empty after this. Cleanup will remove them. - need := make(map[string]*Require) - for _, r := range req { - need[r.Mod.Path] = r - } have := make(map[string]*Require) for _, r := range f.Require { path := r.Mod.Path @@ -1446,10 +1494,10 @@ func (f *File) SetRequireSeparateIndirect(req []*Require) { r.setVersion(need[path].Mod.Version) r.setIndirect(need[path].Indirect) if need[path].Indirect && - (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) { + (simplify || oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastDirectBlock) { moveReq(r, lastIndirectBlock) } else if !need[path].Indirect && - (oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) { + (simplify || oneFlatUncommentedBlock || lineToBlock[r.Syntax] == lastIndirectBlock) { moveReq(r, lastDirectBlock) } } @@ -1736,8 +1784,7 @@ func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace, to // Remove duplicate replacements. // Later replacements take priority over earlier ones. haveReplace := make(map[module.Version]bool) - for i := len(*replace) - 1; i >= 0; i-- { - x := (*replace)[i] + for _, x := range slices.Backward(*replace) { if haveReplace[x.Old] { kill[x.Syntax] = true continue diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go index b628880a0..4e8d5d55f 100644 --- a/vendor/golang.org/x/net/html/entity.go +++ b/vendor/golang.org/x/net/html/entity.go @@ -2156,9 +2156,8 @@ var entity = map[string]rune{ // HTML entities that are two unicode codepoints. var entity2 = map[string][2]rune{ - // TODO(nigeltao): Handle replacements that are wider than their names. - // "nLt;": {'\u226A', '\u20D2'}, - // "nGt;": {'\u226B', '\u20D2'}, + "nLt;": {'\u226A', '\u20D2'}, + "nGt;": {'\u226B', '\u20D2'}, "NotEqualTilde;": {'\u2242', '\u0338'}, "NotGreaterFullEqual;": {'\u2267', '\u0338'}, "NotGreaterGreater;": {'\u226B', '\u0338'}, diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go index 12f227370..df3edc5b1 100644 --- a/vendor/golang.org/x/net/html/escape.go +++ b/vendor/golang.org/x/net/html/escape.go @@ -6,6 +6,7 @@ package html import ( "bytes" + "slices" "strings" "unicode/utf8" ) @@ -50,25 +51,24 @@ var replacementTable = [...]rune{ // 0x0D->'\u000D' is a no-op. } -// unescapeEntity reads an entity like "<" from b[src:] and writes the -// corresponding "<" to b[dst:], returning the incremented dst and src cursors. -// Precondition: b[src] == '&' && dst <= src. -// attribute should be true if parsing an attribute value. -func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { +// unescapeEntity attempts to consume a character reference from s[src:], +// returning the rune, potential second rune, and number of bytes consumed +// (which indicates the length of the character reference). It is assumed that +// the first byte of s is '&'. attribute should be true if parsing an attribute +// value. +func unescapeEntity(s []byte, attribute bool) (rune, rune, int) { // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference // i starts at 1 because we already know that s[0] == '&'. - i, s := 1, b[src:] + i := 1 if len(s) <= 1 { - b[dst] = b[src] - return dst + 1, src + 1 + return '&', 0, 1 } if s[i] == '#' { - if len(s) <= 3 { // We need to have at least "&#.". - b[dst] = b[src] - return dst + 1, src + 1 + if len(s) <= 2 { // We need to have at least "&#". + return '&', 0, 1 } i++ c := s[i] @@ -78,34 +78,43 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { i++ } + i0 := i x := '\x00' for i < len(s) { c = s[i] - i++ + var d rune + var mult rune if hex { + mult = 16 if '0' <= c && c <= '9' { - x = 16*x + rune(c) - '0' - continue + d = rune(c) - '0' } else if 'a' <= c && c <= 'f' { - x = 16*x + rune(c) - 'a' + 10 - continue + d = rune(c) - 'a' + 10 } else if 'A' <= c && c <= 'F' { - x = 16*x + rune(c) - 'A' + 10 - continue + d = rune(c) - 'A' + 10 + } else { + break + } + } else { + mult = 10 + if '0' <= c && c <= '9' { + d = rune(c) - '0' + } else { + break } - } else if '0' <= c && c <= '9' { - x = 10*x + rune(c) - '0' - continue } - if c != ';' { - i-- + if x <= 0x10FFFF { + x = mult*x + d } - break + i++ + } + + if i == i0 { // No characters matched. + return '&', 0, 1 } - if i <= 3 { // No characters matched. - b[dst] = b[src] - return dst + 1, src + 1 + if i < len(s) && s[i] == ';' { + i++ } if 0x80 <= x && x <= 0x9F { @@ -116,7 +125,7 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { x = '\uFFFD' } - return dst + utf8.EncodeRune(b[dst:], x), src + i + return x, 0, i } // Consume the maximum number of characters possible, with the @@ -141,10 +150,9 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { // No-op. } else if x := entity[entityName]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + i + return x, 0, i } else if x := entity2[entityName]; x[0] != 0 { - dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) - return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + return x[0], x[1], i } else if !attribute { maxLen := len(entityName) - 1 if maxLen > longestEntityWithoutSemicolon { @@ -152,35 +160,67 @@ func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { } for j := maxLen; j > 1; j-- { if x := entity[entityName[:j]]; x != 0 { - return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + return x, 0, j + 1 } } } - dst1, src1 = dst+i, src+i - copy(b[dst:dst1], b[src:src1]) - return dst1, src1 + return '&', 0, 1 } -// unescape unescapes b's entities in-place, so that "a<b" becomes "a entityNameLen { + if reusingB { + out = slices.Clone(out) + reusingB = false } - return b[0:dst] + out = slices.Grow(out, replLen) + } + out = utf8.AppendRune(out, r1) + if r2 != 0 { + out = utf8.AppendRune(out, r2) } + + src += entityNameLen } - return b + + return out } // lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc". diff --git a/vendor/golang.org/x/net/html/foreign.go b/vendor/golang.org/x/net/html/foreign.go index e8515d8e8..65d01d1ed 100644 --- a/vendor/golang.org/x/net/html/foreign.go +++ b/vendor/golang.org/x/net/html/foreign.go @@ -23,7 +23,7 @@ func adjustForeignAttributes(aa []Attribute) { } switch a.Key { case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", - "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + "xlink:title", "xlink:type", "xml:lang", "xml:space", "xmlns:xlink": j := strings.Index(a.Key, ":") aa[i].Namespace = a.Key[:j] aa[i].Key = a.Key[j+1:] diff --git a/vendor/golang.org/x/net/html/iter.go b/vendor/golang.org/x/net/html/iter.go index 54be8fd30..349ef73e6 100644 --- a/vendor/golang.org/x/net/html/iter.go +++ b/vendor/golang.org/x/net/html/iter.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build go1.23 - package html import "iter" diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 77741a195..253e4679c 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -11,6 +11,7 @@ import ( // A NodeType is the type of a Node. type NodeType uint32 +//go:generate stringer -type NodeType const ( ErrorNode NodeType = iota TextNode diff --git a/vendor/golang.org/x/net/html/nodetype_string.go b/vendor/golang.org/x/net/html/nodetype_string.go new file mode 100644 index 000000000..8253af491 --- /dev/null +++ b/vendor/golang.org/x/net/html/nodetype_string.go @@ -0,0 +1,31 @@ +// Code generated by "stringer -type NodeType"; DO NOT EDIT. + +package html + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[ErrorNode-0] + _ = x[TextNode-1] + _ = x[DocumentNode-2] + _ = x[ElementNode-3] + _ = x[CommentNode-4] + _ = x[DoctypeNode-5] + _ = x[RawNode-6] + _ = x[scopeMarkerNode-7] +} + +const _NodeType_name = "ErrorNodeTextNodeDocumentNodeElementNodeCommentNodeDoctypeNodeRawNodescopeMarkerNode" + +var _NodeType_index = [...]uint8{0, 9, 17, 29, 40, 51, 62, 69, 84} + +func (i NodeType) String() string { + idx := int(i) - 0 + if i < 0 || idx >= len(_NodeType_index)-1 { + return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _NodeType_name[_NodeType_index[idx]:_NodeType_index[idx+1]] +} diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 88fc0056a..165b6108d 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -5,9 +5,11 @@ package html import ( + "cmp" "errors" "fmt" "io" + "slices" "strings" a "golang.org/x/net/html/atom" @@ -61,7 +63,7 @@ func (p *parser) top() *Node { // Stop tags for use in popUntil. These come from section 12.2.4.2. var ( defaultScopeStopTags = map[string][]a.Atom{ - "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, + "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template, a.Select}, "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, "svg": {a.Desc, a.ForeignObject, a.Title}, } @@ -76,7 +78,6 @@ const ( tableScope tableRowScope tableBodyScope - selectScope ) // popUntil pops the stack of open elements at the highest element whose tag @@ -131,10 +132,6 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { return -1 } - case selectScope: - if tagAtom != a.Optgroup && tagAtom != a.Option { - return -1 - } default: panic(fmt.Sprintf("html: internal error: indexOfElementInScope unknown scope: %d", s)) } @@ -328,6 +325,14 @@ func (p *parser) addText(text string) { }) } +func attrCompare(a, b Attribute) int { + return cmp.Or( + cmp.Compare(a.Namespace, b.Namespace), + cmp.Compare(a.Key, b.Key), + cmp.Compare(a.Val, b.Val), + ) +} + // addElement adds a child element based on the current token. func (p *parser) addElement() { p.addChild(&Node{ @@ -343,6 +348,10 @@ func (p *parser) addFormattingElement() { tagAtom, attr := p.tok.DataAtom, p.tok.Attr p.addElement() + // In order to optimize the search, we need the attributes to be sorted, so we + // can just use slices.Equal. + slices.SortFunc(attr, attrCompare) + // Implement the Noah's Ark clause, but with three per family instead of two. identicalElements := 0 findIdenticalElements: @@ -360,19 +369,7 @@ findIdenticalElements: if n.DataAtom != tagAtom { continue } - if len(n.Attr) != len(attr) { - continue - } - compareAttributes: - for _, t0 := range n.Attr { - for _, t1 := range attr { - if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { - // Found a match for this attribute, continue with the next attribute. - continue compareAttributes - } - } - // If we get here, there is no attribute that matches a. - // Therefore the element is not identical to the new one. + if !slices.Equal(n.Attr, attr) { continue findIdenticalElements } @@ -382,7 +379,11 @@ findIdenticalElements: } } - p.afe = append(p.afe, p.top()) + // Sort the attributes to optimize future identical-element searches. + top := p.top() + slices.SortFunc(top.Attr, attrCompare) + + p.afe = append(p.afe, top) } // Section 12.2.4.3. @@ -454,21 +455,6 @@ func (p *parser) resetInsertionMode() { } switch n.DataAtom { - case a.Select: - if !last { - for ancestor, first := n, p.oe[0]; ancestor != first; { - ancestor = p.oe[p.oe.index(ancestor)-1] - switch ancestor.DataAtom { - case a.Template: - p.im = inSelectIM - return - case a.Table: - p.im = inSelectInTableIM - return - } - } - } - p.im = inSelectIM case a.Td, a.Th: // TODO: remove this divergence from the HTML5 spec. // @@ -996,7 +982,10 @@ func inBodyIM(p *parser) bool { p.popUntil(buttonScope, a.P) p.addElement() case a.Button: - p.popUntil(defaultScope, a.Button) + if p.elementInScope(defaultScope, a.Button) { + p.generateImpliedEndTags() + p.popUntil(defaultScope, a.Button) + } p.reconstructActiveFormattingElements() p.addElement() p.framesetOK = false @@ -1034,7 +1023,18 @@ func inBodyIM(p *parser) bool { p.framesetOK = false p.im = inTableIM return true - case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr: + case a.Area, a.Br, a.Embed, a.Img, a.Keygen, a.Wbr: + p.reconstructActiveFormattingElements() + p.addElement() + p.oe.pop() + p.acknowledgeSelfClosingTag() + p.framesetOK = false + case a.Input: + if p.fragment && p.context.DataAtom == a.Select { + // Ignore the token. + return true + } + p.popUntil(defaultScope, a.Select) p.reconstructActiveFormattingElements() p.addElement() p.oe.pop() @@ -1055,7 +1055,13 @@ func inBodyIM(p *parser) bool { p.oe.pop() p.acknowledgeSelfClosingTag() case a.Hr: - p.popUntil(buttonScope, a.P) + if p.elementInScope(buttonScope, a.P) { + p.generateImpliedEndTags("p") + p.popUntil(defaultScope, a.P) + } + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags() + } p.addElement() p.oe.pop() p.acknowledgeSelfClosingTag() @@ -1089,13 +1095,30 @@ func inBodyIM(p *parser) bool { // Don't let the tokenizer go into raw text mode when scripting is disabled. p.tokenizer.NextIsNotRawText() case a.Select: + if p.fragment && p.context.DataAtom == a.Select { + // Ignore the token. + return true + } else if p.popUntil(defaultScope, a.Select) { + return true + } p.reconstructActiveFormattingElements() p.addElement() p.framesetOK = false - p.im = inSelectIM return true - case a.Optgroup, a.Option: - if p.top().DataAtom == a.Option { + case a.Option: + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags("optgroup") + // If oe has option element in scope, parse error? + } else if p.top().DataAtom == a.Option { + p.oe.pop() + } + p.reconstructActiveFormattingElements() + p.addElement() + case a.Optgroup: + if p.elementInScope(defaultScope, a.Select) { + p.generateImpliedEndTags() + // If oe has option or optgroup element in scope, parse error? + } else if p.top().DataAtom == a.Option { p.oe.pop() } p.reconstructActiveFormattingElements() @@ -1143,7 +1166,12 @@ func inBodyIM(p *parser) bool { return false } return true - case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Summary, a.Ul: + case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Search, a.Section, a.Select, a.Summary, a.Ul: + if !p.elementInScope(defaultScope, p.tok.DataAtom) { + // Ignore the token. + return true + } + p.generateImpliedEndTags() p.popUntil(defaultScope, p.tok.DataAtom) case a.Form: if p.oe.contains(a.Template) { @@ -1372,8 +1400,6 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) { } // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. -// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content -// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) { for i := len(p.oe) - 1; i >= 0; i-- { // Two element nodes have the same tag if they have the same Data (a @@ -1383,7 +1409,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) { // Uncommon (custom) tags get a zero DataAtom. // // The if condition here is equivalent to (p.oe[i].Data == tagName). - if (p.oe[i].DataAtom == tagAtom) && + if p.oe[i].Namespace == "" && (p.oe[i].DataAtom == tagAtom) && ((tagAtom != 0) || (p.oe[i].Data == tagName)) { p.oe = p.oe[:i] break @@ -1484,17 +1510,6 @@ func inTableIM(p *parser) bool { } p.addElement() p.form = p.oe.pop() - case a.Select: - p.reconstructActiveFormattingElements() - switch p.top().DataAtom { - case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: - p.fosterParenting = true - } - p.addElement() - p.fosterParenting = false - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1543,12 +1558,6 @@ func inCaptionIM(p *parser) bool { p.clearActiveFormattingElements() p.im = inTableIM return false - case a.Select: - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1758,12 +1767,6 @@ func inCellIM(p *parser) bool { } // Ignore the token. return true - case a.Select: - p.reconstructActiveFormattingElements() - p.addElement() - p.framesetOK = false - p.im = inSelectInTableIM - return true } case EndTagToken: switch p.tok.DataAtom { @@ -1794,118 +1797,6 @@ func inCellIM(p *parser) bool { return inBodyIM(p) } -// Section 12.2.6.4.16. -func inSelectIM(p *parser) bool { - switch p.tok.Type { - case TextToken: - p.addText(strings.Replace(p.tok.Data, "\x00", "", -1)) - case StartTagToken: - switch p.tok.DataAtom { - case a.Html: - return inBodyIM(p) - case a.Option: - if p.top().DataAtom == a.Option { - p.oe.pop() - } - p.addElement() - case a.Optgroup: - if p.top().DataAtom == a.Option { - p.oe.pop() - } - if p.top().DataAtom == a.Optgroup { - p.oe.pop() - } - p.addElement() - case a.Select: - if !p.popUntil(selectScope, a.Select) { - // Ignore the token. - return true - } - p.resetInsertionMode() - case a.Input, a.Keygen, a.Textarea: - if p.elementInScope(selectScope, a.Select) { - p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) - return false - } - // In order to properly ignore