From 26ba599edea8d88de83c2df067018db79f57ac97 Mon Sep 17 00:00:00 2001 From: Bharath B Date: Tue, 11 Aug 2026 11:28:14 +0530 Subject: [PATCH] ESO-566: Reject arg overrides with an empty flag name Signed-off-by: Bharath B --- .../external_secrets/deployments.go | 7 +++ .../external_secrets/deployments_test.go | 54 ++++++++++++++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/pkg/controller/external_secrets/deployments.go b/pkg/controller/external_secrets/deployments.go index bcd96e6f7..c576b770d 100644 --- a/pkg/controller/external_secrets/deployments.go +++ b/pkg/controller/external_secrets/deployments.go @@ -826,6 +826,13 @@ func parseOperandArgsEnv(raw string) ([]string, error) { } } } + // Reject empty flag names such as "--=value" (argFlagKey is "--"). + if argFlagKey(part) == "--" { + return nil, common.NewIrrecoverableError( + fmt.Errorf("argument %q must include a flag name after --", part), + "invalid custom arg override", + ) + } args = append(args, part) } return args, nil diff --git a/pkg/controller/external_secrets/deployments_test.go b/pkg/controller/external_secrets/deployments_test.go index fc33f7df6..c297b5349 100644 --- a/pkg/controller/external_secrets/deployments_test.go +++ b/pkg/controller/external_secrets/deployments_test.go @@ -1760,10 +1760,11 @@ func TestApplyUserDeploymentConfigsWithOverrideEnv(t *testing.T) { func TestParseOperandArgsEnv(t *testing.T) { tests := []struct { - name string - raw string - want []string - wantErr bool + name string + raw string + want []string + wantErr bool + wantErrSub string // optional; defaults to "must start with --" when wantErr }{ // Empty / whitespace { @@ -1970,6 +1971,24 @@ func TestParseOperandArgsEnv(t *testing.T) { raw: ",--,--", wantErr: true, }, + { + name: "empty flag name rejected", + raw: "--=value", + wantErr: true, + wantErrSub: "must include a flag name after --", + }, + { + name: "empty flag name with empty value rejected", + raw: "--=", + wantErr: true, + wantErrSub: "must include a flag name after --", + }, + { + name: "empty flag name mid-list rejected", + raw: "--concurrent=5,--=value,--loglevel=debug", + wantErr: true, + wantErrSub: "must include a flag name after --", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1984,8 +2003,12 @@ func TestParseOperandArgsEnv(t *testing.T) { 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) + errSub := tt.wantErrSub + if errSub == "" { + errSub = "must start with --" + } + if !strings.Contains(err.Error(), errSub) { + t.Fatalf("parseOperandArgsEnv(%q) error = %v, want cause mentioning %q", tt.raw, err, errSub) } return } @@ -2227,6 +2250,25 @@ func TestApplyOperandArgsFromEnv(t *testing.T) { } }) + t.Run("empty flag name fails without mutating args", func(t *testing.T) { + t.Setenv(OperandExternalSecretsArgsEnvVar, "--=value") + original := []string{"--concurrent=1"} + dep := deploymentWithContainer(OperandCoreControllerContainer, append([]string(nil), original...)) + err := applyOperandArgsFromEnv(dep, OperandCoreControllerContainer, OperandExternalSecretsArgsEnvVar) + if err == nil { + t.Fatal("expected error for empty flag name") + } + if !common.IsIrrecoverableError(err) { + t.Fatalf("error = %v, want IrrecoverableError", err) + } + if !strings.Contains(err.Error(), "must include a flag name after --") { + t.Fatalf("error = %v, want empty flag name message", 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"})