@@ -202,6 +202,203 @@ func Test_computeClientCacheKey(t *testing.T) {
202202 }
203203}
204204
205+ func Test_computeClientCacheKey_standalone (t * testing.T ) {
206+ t .Parallel ()
207+ tests := []struct {
208+ name string
209+ authObj * secretsv1beta1.VaultAuth
210+ connObj * secretsv1beta1.VaultConnection
211+ providerUID types.UID
212+ wantErr assert.ErrorAssertionFunc
213+ wantPrefix string // expected method prefix in cache key
214+ }{
215+ {
216+ name : "standalone-empty-provideruid-fails" ,
217+ authObj : & secretsv1beta1.VaultAuth {
218+ Spec : secretsv1beta1.VaultAuthSpec {
219+ Method : consts .ProviderMethodAppRole ,
220+ },
221+ },
222+ connObj : & secretsv1beta1.VaultConnection {},
223+ providerUID : "" ,
224+ wantErr : func (t assert.TestingT , err error , i ... interface {}) bool {
225+ return assert .Error (t , err , i ... )
226+ },
227+ },
228+ {
229+ name : "standalone-different-auth-specs-different-keys" ,
230+ authObj : & secretsv1beta1.VaultAuth {
231+ Spec : secretsv1beta1.VaultAuthSpec {
232+ Method : consts .ProviderMethodAppRole ,
233+ AppRole : & secretsv1beta1.VaultAuthConfigAppRole {
234+ RoleID : "role-1" ,
235+ },
236+ },
237+ },
238+ connObj : & secretsv1beta1.VaultConnection {
239+ Spec : secretsv1beta1.VaultConnectionSpec {
240+ Address : "http://vault:8200" ,
241+ },
242+ },
243+ providerUID : providerUID ,
244+ wantErr : assert .NoError ,
245+ wantPrefix : "approle-" ,
246+ },
247+ {
248+ name : "standalone-different-conn-specs-different-keys" ,
249+ authObj : & secretsv1beta1.VaultAuth {
250+ Spec : secretsv1beta1.VaultAuthSpec {
251+ Method : consts .ProviderMethodJWT ,
252+ },
253+ },
254+ connObj : & secretsv1beta1.VaultConnection {
255+ Spec : secretsv1beta1.VaultConnectionSpec {
256+ Address : "http://vault:9200" ,
257+ },
258+ },
259+ providerUID : providerUID ,
260+ wantErr : assert .NoError ,
261+ wantPrefix : "jwt-" ,
262+ },
263+ {
264+ name : "standalone-empty-method-fails" ,
265+ authObj : & secretsv1beta1.VaultAuth {
266+ Spec : secretsv1beta1.VaultAuthSpec {
267+ Method : "" ,
268+ },
269+ },
270+ connObj : & secretsv1beta1.VaultConnection {
271+ ObjectMeta : metav1.ObjectMeta {},
272+ },
273+ providerUID : providerUID ,
274+ wantErr : func (t assert.TestingT , err error , i ... interface {}) bool {
275+ return assert .Error (t , err , i ... )
276+ },
277+ },
278+ }
279+
280+ for _ , tt := range tests {
281+ t .Run (tt .name , func (t * testing.T ) {
282+ got , err := computeClientCacheKey (tt .authObj , tt .connObj , tt .providerUID , true )
283+ if ! tt .wantErr (t , err , fmt .Sprintf ("computeClientCacheKey(%v, %v, %v, true)" ,
284+ tt .authObj , tt .connObj , tt .providerUID )) {
285+ return
286+ }
287+ if tt .wantPrefix != "" {
288+ assert .True (t , strings .HasPrefix (got .String (), tt .wantPrefix ),
289+ "expected key to start with %q, got %q" , tt .wantPrefix , got .String ())
290+ }
291+ })
292+ }
293+ }
294+
295+ // Test that standalone mode produces deterministic, content-based cache keys
296+ func Test_computeClientCacheKey_standalone_deterministic (t * testing.T ) {
297+ t .Parallel ()
298+
299+ authObj := & secretsv1beta1.VaultAuth {
300+ Spec : secretsv1beta1.VaultAuthSpec {
301+ Method : consts .ProviderMethodAppRole ,
302+ AppRole : & secretsv1beta1.VaultAuthConfigAppRole {
303+ RoleID : "test-role" ,
304+ },
305+ },
306+ }
307+ connObj := & secretsv1beta1.VaultConnection {
308+ Spec : secretsv1beta1.VaultConnectionSpec {
309+ Address : "http://vault:8200" ,
310+ },
311+ }
312+
313+ // Call twice with identical inputs
314+ key1 , err1 := computeClientCacheKey (authObj , connObj , providerUID , true )
315+ require .NoError (t , err1 )
316+
317+ key2 , err2 := computeClientCacheKey (authObj , connObj , providerUID , true )
318+ require .NoError (t , err2 )
319+
320+ // Should produce identical cache keys
321+ assert .Equal (t , key1 , key2 , "identical specs should produce identical cache keys" )
322+ }
323+
324+ // Test that standalone and normal mode produce different cache keys
325+ func Test_computeClientCacheKey_standalone_vs_normal (t * testing.T ) {
326+ t .Parallel ()
327+
328+ authObjWithUID := & secretsv1beta1.VaultAuth {
329+ ObjectMeta : metav1.ObjectMeta {
330+ UID : authUID ,
331+ Generation : 1 ,
332+ },
333+ Spec : secretsv1beta1.VaultAuthSpec {
334+ Method : consts .ProviderMethodAppRole ,
335+ AppRole : & secretsv1beta1.VaultAuthConfigAppRole {
336+ RoleID : "test-role" ,
337+ },
338+ },
339+ }
340+ connObjWithUID := & secretsv1beta1.VaultConnection {
341+ ObjectMeta : metav1.ObjectMeta {
342+ UID : connUID ,
343+ Generation : 2 ,
344+ },
345+ Spec : secretsv1beta1.VaultConnectionSpec {
346+ Address : "http://vault:8200" ,
347+ },
348+ }
349+
350+ authObjNoUID := & secretsv1beta1.VaultAuth {
351+ ObjectMeta : metav1.ObjectMeta {
352+ UID : "" ,
353+ Generation : 0 ,
354+ },
355+ Spec : secretsv1beta1.VaultAuthSpec {
356+ Method : consts .ProviderMethodAppRole ,
357+ AppRole : & secretsv1beta1.VaultAuthConfigAppRole {
358+ RoleID : "test-role" ,
359+ },
360+ },
361+ }
362+ connObjNoUID := & secretsv1beta1.VaultConnection {
363+ ObjectMeta : metav1.ObjectMeta {
364+ UID : "" ,
365+ Generation : 0 ,
366+ },
367+ Spec : secretsv1beta1.VaultConnectionSpec {
368+ Address : "http://vault:8200" ,
369+ },
370+ }
371+
372+ // Normal mode with UIDs - should succeed
373+ normalKey , err := computeClientCacheKey (authObjWithUID , connObjWithUID , providerUID , false )
374+ require .NoError (t , err )
375+
376+ // Standalone mode without UIDs - should succeed
377+ standaloneKey , err := computeClientCacheKey (authObjNoUID , connObjNoUID , providerUID , true )
378+ require .NoError (t , err )
379+
380+ // Keys should be different because:
381+ // - Normal mode uses UID + generation
382+ // - Standalone mode uses spec hash + generation=1
383+ assert .NotEqual (t , normalKey , standaloneKey ,
384+ "standalone and normal mode should produce different cache keys even with same specs" )
385+
386+ assert .True (t , strings .HasPrefix (normalKey .String (), "approle-" ))
387+ assert .True (t , strings .HasPrefix (standaloneKey .String (), "approle-" ))
388+
389+ // Normal mode with empty UIDs - should fail (requires UIDs)
390+ _ , err = computeClientCacheKey (authObjNoUID , connObjNoUID , providerUID , false )
391+ require .Error (t , err , "normal mode should fail with empty UIDs" )
392+
393+ // Standalone mode with UIDs - should succeed (UIDs allowed but not required)
394+ standaloneKeyWithUIDs , err := computeClientCacheKey (authObjWithUID , connObjWithUID , providerUID , true )
395+ require .NoError (t , err , "standalone mode should succeed even with UIDs present" )
396+
397+ // Standalone mode with and without UIDs should produce different keys
398+ assert .NotEqual (t , standaloneKey , standaloneKeyWithUIDs ,
399+ "standalone mode should produce different keys with vs without UIDs due to different spec hashes" )
400+ }
401+
205402func TestComputeClientCacheKeyFromClient (t * testing.T ) {
206403 t .Parallel ()
207404 tests := []computeClientCacheKeyTest {
0 commit comments