@@ -295,14 +295,22 @@ describe('array handling', () => {
295295 expect ( providers [ 1 ] . name ) . toBe ( 'anthropic' ) ;
296296 } ) ;
297297
298- it ( 'restores secrets inside array entries from current config ' , ( ) => {
298+ it ( 'strips placeholders in array entries on restore (no index-based matching) ' , ( ) => {
299299 const redacted = redactOpenclawConfig ( CONFIG_WITH_ARRAYS ) ;
300300 const merged = restoreRedactedSecrets ( redacted , CONFIG_WITH_ARRAYS ) ;
301301
302- expect ( merged ) . toEqual ( CONFIG_WITH_ARRAYS ) ;
302+ // Array secrets are NOT restored — placeholders are stripped to avoid
303+ // position-dependent mismatches when users reorder entries.
304+ const providers = ( merged . models as Record < string , unknown > ) . providers as Array <
305+ Record < string , unknown >
306+ > ;
307+ expect ( providers [ 0 ] . apiKey ) . toBeUndefined ( ) ;
308+ expect ( providers [ 0 ] . name ) . toBe ( 'openai' ) ;
309+ expect ( providers [ 1 ] . apiKey ) . toBeUndefined ( ) ;
310+ expect ( providers [ 1 ] . name ) . toBe ( 'anthropic' ) ;
303311 } ) ;
304312
305- it ( 'keeps new values in array entries when user changed a secret ' , ( ) => {
313+ it ( 'keeps new values in array entries when user set a non-placeholder value ' , ( ) => {
306314 const redacted = redactOpenclawConfig ( CONFIG_WITH_ARRAYS ) ;
307315 const providers = ( redacted . models as Record < string , unknown > ) . providers as Array <
308316 Record < string , unknown >
@@ -314,10 +322,11 @@ describe('array handling', () => {
314322 Record < string , unknown >
315323 > ;
316324 expect ( mergedProviders [ 0 ] . apiKey ) . toBe ( 'sk-new-key' ) ;
317- expect ( mergedProviders [ 1 ] . apiKey ) . toBe ( 'sk-secret-2' ) ;
325+ // Placeholder in second entry is stripped
326+ expect ( mergedProviders [ 1 ] . apiKey ) . toBeUndefined ( ) ;
318327 } ) ;
319328
320- it ( 'strips unresolvable placeholders in array entries for new subtrees ' , ( ) => {
329+ it ( 'strips placeholders in array entries even when currentConfig has data ' , ( ) => {
321330 const userConfig = {
322331 models : {
323332 providers : [
@@ -335,7 +344,7 @@ describe('array handling', () => {
335344 expect ( providers [ 0 ] . baseUrl ) . toBe ( 'https://example.com' ) ;
336345 } ) ;
337346
338- it ( 'redacts secrets in nested arrays (arrays inside array elements) ' , ( ) => {
347+ it ( 'redacts secrets in nested arrays' , ( ) => {
339348 const config = {
340349 groups : [ { members : [ { apiKey : 'nested-secret' , name : 'bot' } ] } ] ,
341350 } ;
@@ -345,10 +354,6 @@ describe('array handling', () => {
345354
346355 expect ( members [ 0 ] . apiKey ) . toBe ( REDACTED_PLACEHOLDER ) ;
347356 expect ( members [ 0 ] . name ) . toBe ( 'bot' ) ;
348-
349- // round-trip
350- const restored = restoreRedactedSecrets ( redacted , config ) ;
351- expect ( restored ) . toEqual ( config ) ;
352357 } ) ;
353358
354359 it ( 'handles mixed array contents (strings, numbers, objects, nulls)' , ( ) => {
@@ -374,21 +379,25 @@ describe('array handling', () => {
374379 expect ( restored . providers ) . toEqual ( [ ] ) ;
375380 } ) ;
376381
377- it ( 'handles deeply nested objects inside array elements' , ( ) => {
382+ it ( 'strips placeholders in deeply nested objects inside array elements' , ( ) => {
378383 const config = {
379384 list : [ { inner : { deep : { apiKey : 'deep-array-secret' } } } ] ,
380385 } ;
381386 const redacted = redactOpenclawConfig ( config ) ;
382387 const list = redacted . list as Array < Record < string , unknown > > ;
383388 const deep = ( list [ 0 ] . inner as Record < string , unknown > ) . deep as Record < string , unknown > ;
384-
385389 expect ( deep . apiKey ) . toBe ( REDACTED_PLACEHOLDER ) ;
386390
387391 const restored = restoreRedactedSecrets ( redacted , config ) ;
388- expect ( restored ) . toEqual ( config ) ;
392+ const restoredList = restored . list as Array < Record < string , unknown > > ;
393+ const restoredDeep = ( restoredList [ 0 ] . inner as Record < string , unknown > ) . deep as Record <
394+ string ,
395+ unknown
396+ > ;
397+ expect ( restoredDeep . apiKey ) . toBeUndefined ( ) ;
389398 } ) ;
390399
391- it ( 'strips placeholders when user array is longer than current array ' , ( ) => {
400+ it ( 'strips all placeholders regardless of array length mismatch ' , ( ) => {
392401 const userConfig = {
393402 providers : [
394403 { apiKey : REDACTED_PLACEHOLDER , name : 'existing' } ,
@@ -401,8 +410,7 @@ describe('array handling', () => {
401410
402411 const merged = restoreRedactedSecrets ( userConfig , currentConfig ) ;
403412 const providers = merged . providers as Array < Record < string , unknown > > ;
404- expect ( providers [ 0 ] . apiKey ) . toBe ( 'real-key' ) ;
405- // Second element has no match in currentConfig — placeholder stripped
413+ expect ( providers [ 0 ] . apiKey ) . toBeUndefined ( ) ;
406414 expect ( providers [ 1 ] . apiKey ) . toBeUndefined ( ) ;
407415 expect ( providers [ 1 ] . name ) . toBe ( 'new-extra' ) ;
408416 } ) ;
0 commit comments