@@ -232,6 +232,27 @@ func TestConfigHashFromDataIsDeterministicAndSensitive(t *testing.T) {
232232 }
233233}
234234
235+ func TestValkeyConfigArgQuotesSpecialCharacters (t * testing.T ) {
236+ tests := []struct {
237+ name string
238+ value string
239+ want string
240+ }{
241+ {name : "plain" , value : "secret" , want : `"secret"` },
242+ {name : "double quote" , value : `abc"def` , want : `"abc\"def"` },
243+ {name : "space backslash hash" , value : `a b\c#d` , want : `"a b\\c#d"` },
244+ {name : "leading hash" , value : `#comment` , want : `"#comment"` },
245+ {name : "newline" , value : "line\n next" , want : `"line\nnext"` },
246+ }
247+ for _ , tc := range tests {
248+ t .Run (tc .name , func (t * testing.T ) {
249+ if got := valkeyConfigArg (tc .value ); got != tc .want {
250+ t .Errorf ("valkeyConfigArg(%q) = %q, want %q" , tc .value , got , tc .want )
251+ }
252+ })
253+ }
254+ }
255+
235256func TestRenderValkeyConfHasProfileDefaults (t * testing.T ) {
236257 tests := []struct {
237258 name string
@@ -275,14 +296,17 @@ func TestRenderInitScriptSeedsDefaultUserACL(t *testing.T) {
275296
276297 for _ , want := range []string {
277298 "users.acl" ,
278- "requirepass" , // password is read back from runtime.conf
279- "user default on >$PW ~* &* +@all" , // seeded default user carries the password
299+ `printf '%s' "$VALKEY_PASSWORD"` , // hash is computed from the exact Secret value
300+ "user default on #$PW_HASH ~* &* +@all" , // seeded default user carries the password hash
280301 "[ ! -s " + dataMountPath + "/users.acl ]" , // only seed when empty (don't clobber ACL SAVE)
281302 } {
282303 if ! strings .Contains (script , want ) {
283304 t .Errorf ("init script missing %q\n %s" , want , script )
284305 }
285306 }
307+ if strings .Contains (script , "sed -n 's/^requirepass //p'" ) {
308+ t .Errorf ("init script must not parse the escaped config password back out of runtime.conf\n %s" , script )
309+ }
286310 // It must NOT blindly create an empty file in the auth case.
287311 if strings .Contains (script , "touch " + dataMountPath + "/users.acl" ) {
288312 t .Errorf ("init script still touches an empty users.acl (the bug)\n %s" , script )
@@ -303,11 +327,11 @@ func TestRenderInitScriptSeedsSentinelACLUser(t *testing.T) {
303327 vc .Spec .Auth = & cachev1beta1.AuthSpec {Enabled : true }
304328 script := renderInitScript (vc )
305329
306- if ! strings .Contains (script , "user sentinel-user on >$PW &* +@all" ) {
330+ if ! strings .Contains (script , "user sentinel-user on #$PW_HASH &* +@all" ) {
307331 t .Errorf ("Sentinel init script must seed the sentinel ACL user\n %s" , script )
308332 }
309333 // No key glob (~) for the sentinel user — it must not read/write data.
310- if strings .Contains (script , "user sentinel-user on >$PW ~* &* +@all" ) {
334+ if strings .Contains (script , "user sentinel-user on #$PW_HASH ~* &* +@all" ) {
311335 t .Errorf ("sentinel-user must not have key access (~*)\n %s" , script )
312336 }
313337}
@@ -335,6 +359,24 @@ func TestRenderValkeyConfMutualTLS(t *testing.T) {
335359 }
336360}
337361
362+ func TestRenderValkeyConfEscapesPasswordArguments (t * testing.T ) {
363+ vc := minimalCR ()
364+ password := `abc" def\#ghi`
365+ conf := renderValkeyConf (vc , password )
366+ quoted := valkeyConfigArg (password )
367+ for _ , want := range []string {
368+ "requirepass " + quoted ,
369+ "masterauth " + quoted ,
370+ } {
371+ if ! strings .Contains (conf , want ) {
372+ t .Errorf ("missing escaped password directive %q\n %s" , want , conf )
373+ }
374+ }
375+ if strings .Contains (conf , `requirepass abc"` ) {
376+ t .Errorf ("password must not be rendered as an unquoted config argument\n %s" , conf )
377+ }
378+ }
379+
338380func TestInternalEndpoint (t * testing.T ) {
339381 vc := minimalCR ()
340382 vc .Name = "web"
@@ -360,8 +402,8 @@ func TestRenderValkeyConfClusterDirectives(t *testing.T) {
360402 "cluster-config-file " + dataMountPath + "/nodes.conf" ,
361403 "cluster-node-timeout 5000" ,
362404 "cluster-require-full-coverage yes" , // Durable requires it
363- " requirepass secret" ,
364- " masterauth secret" ,
405+ ` requirepass " secret"` ,
406+ ` masterauth " secret"` ,
365407 } {
366408 if ! strings .Contains (conf , want ) {
367409 t .Errorf ("missing %q\n %s" , want , conf )
@@ -464,6 +506,35 @@ func TestBuildExporterAuthSecret(t *testing.T) {
464506 }
465507}
466508
509+ func TestBuildStatefulSetConfigInitGetsAuthPasswordEnv (t * testing.T ) {
510+ passwordSecretRef := func (vc * cachev1beta1.ValkeyCluster ) string {
511+ sts := buildStatefulSet (vc , "h" , false )
512+ for _ , e := range sts .Spec .Template .Spec .InitContainers [0 ].Env {
513+ if e .Name == envValkeyPassword && e .ValueFrom != nil && e .ValueFrom .SecretKeyRef != nil {
514+ return e .ValueFrom .SecretKeyRef .Name
515+ }
516+ }
517+ return ""
518+ }
519+
520+ gen := minimalCR ()
521+ gen .Spec .Auth = & cachev1beta1.AuthSpec {Enabled : true }
522+ if got := passwordSecretRef (gen ); got != "test-auth" {
523+ t .Errorf ("config-init password secret = %q, want generated test-auth" , got )
524+ }
525+
526+ ext := minimalCR ()
527+ ext .Spec .Auth = & cachev1beta1.AuthSpec {Enabled : true , ExistingSecret : "my-auth" }
528+ if got := passwordSecretRef (ext ); got != "my-auth" {
529+ t .Errorf ("config-init password secret = %q, want existingSecret my-auth" , got )
530+ }
531+
532+ disabled := minimalCR ()
533+ if got := passwordSecretRef (disabled ); got != "" {
534+ t .Errorf ("config-init should not get VALKEY_PASSWORD when auth is disabled, got secret %q" , got )
535+ }
536+ }
537+
467538func TestBuildHeadlessServiceHasGossipPortOnlyForCluster (t * testing.T ) {
468539 vc := minimalCR ()
469540 svc := buildHeadlessService (vc )
@@ -630,6 +701,8 @@ func TestSourceCAMergeRendersCombinedBundle(t *testing.T) {
630701 "cat " + tlsMountPath + "/ca.crt " + sourceCAMountPath + "/ca.crt > " + dataMountPath + "/ca-bundle.crt" ,
631702 "replicaof src-primary.dc2.svc.cluster.local 6380" ,
632703 "tls-replication yes" ,
704+ "SOURCE_PASSWORD_ARG=$(printf '%s' \" $SOURCE_PASSWORD\" | valkey_config_arg)" ,
705+ "masterauth ${SOURCE_PASSWORD_ARG}" ,
633706 } {
634707 if ! strings .Contains (script , want ) {
635708 t .Errorf ("init script missing %q\n %s" , want , script )
0 commit comments