@@ -296,9 +296,10 @@ describe('Deterministic JSON Serialization', () => {
296296
297297 describe ( 'Edge Cases' , ( ) => {
298298 it ( 'should handle empty objects' , ( ) => {
299+ // @ts -expect-error - empty object is valid
299300 const compose : AppCompose = { }
300301 const hash = getComposeHash ( compose )
301-
302+
302303 expect ( hash ) . toHaveLength ( 64 )
303304 expect ( hash ) . toMatch ( / ^ [ a - f 0 - 9 ] { 64 } $ / )
304305 } )
@@ -376,4 +377,215 @@ describe('Deterministic JSON Serialization', () => {
376377 expect ( getComposeHash ( compose1 ) ) . not . toBe ( getComposeHash ( compose2 ) )
377378 } )
378379 } )
380+
381+ describe ( 'New AppCompose Fields' , ( ) => {
382+ it ( 'should handle manifest_version and name fields' , ( ) => {
383+ const compose : AppCompose = {
384+ manifest_version : 1 ,
385+ name : "my-app" ,
386+ runner : "docker-compose" ,
387+ docker_compose_file : "docker-compose.yml"
388+ }
389+
390+ const hash = getComposeHash ( compose )
391+ expect ( hash ) . toBeDefined ( )
392+ expect ( hash ) . toHaveLength ( 64 )
393+ } )
394+
395+ it ( 'should handle docker_config field' , ( ) => {
396+ const compose : AppCompose = {
397+ manifest_version : 1 ,
398+ name : "my-app" ,
399+ runner : "docker-compose" ,
400+ docker_compose_file : "docker-compose.yml" ,
401+ docker_config : {
402+ registry : "docker.io" ,
403+ username : "myuser" ,
404+ token_key : "token123"
405+ }
406+ }
407+
408+ const hash = getComposeHash ( compose )
409+ expect ( hash ) . toBeDefined ( )
410+ expect ( hash ) . toHaveLength ( 64 )
411+ } )
412+
413+ it ( 'should handle boolean flags' , ( ) => {
414+ const compose : AppCompose = {
415+ manifest_version : 1 ,
416+ name : "my-app" ,
417+ runner : "docker-compose" ,
418+ docker_compose_file : "docker-compose.yml" ,
419+ public_logs : true ,
420+ public_sysinfo : false ,
421+ public_tcbinfo : true ,
422+ kms_enabled : true ,
423+ gateway_enabled : false ,
424+ local_key_provider_enabled : true ,
425+ no_instance_id : false ,
426+ secure_time : true
427+ }
428+
429+ const hash = getComposeHash ( compose )
430+ expect ( hash ) . toBeDefined ( )
431+ expect ( hash ) . toHaveLength ( 64 )
432+ } )
433+
434+ it ( 'should handle key_provider and key_provider_id fields' , ( ) => {
435+ const compose : AppCompose = {
436+ manifest_version : 1 ,
437+ name : "my-app" ,
438+ runner : "docker-compose" ,
439+ docker_compose_file : "docker-compose.yml" ,
440+ key_provider : "kms" ,
441+ key_provider_id : "abcd1234"
442+ }
443+
444+ const hash = getComposeHash ( compose )
445+ expect ( hash ) . toBeDefined ( )
446+ expect ( hash ) . toHaveLength ( 64 )
447+ } )
448+
449+ it ( 'should handle allowed_envs array' , ( ) => {
450+ const compose : AppCompose = {
451+ manifest_version : 1 ,
452+ name : "my-app" ,
453+ runner : "docker-compose" ,
454+ docker_compose_file : "docker-compose.yml" ,
455+ allowed_envs : [ "NODE_ENV" , "PORT" , "DATABASE_URL" ]
456+ }
457+
458+ const hash = getComposeHash ( compose )
459+ expect ( hash ) . toBeDefined ( )
460+ expect ( hash ) . toHaveLength ( 64 )
461+ } )
462+
463+ it ( 'should handle features array (deprecated)' , ( ) => {
464+ const compose : AppCompose = {
465+ manifest_version : 1 ,
466+ name : "my-app" ,
467+ runner : "docker-compose" ,
468+ docker_compose_file : "docker-compose.yml" ,
469+ features : [ "feature1" , "feature2" ]
470+ }
471+
472+ const hash = getComposeHash ( compose )
473+ expect ( hash ) . toBeDefined ( )
474+ expect ( hash ) . toHaveLength ( 64 )
475+ } )
476+ } )
477+
478+ describe ( 'Default Values Processing' , ( ) => {
479+ it ( 'should set default values for undefined fields' , ( ) => {
480+ const compose : AppCompose = {
481+ runner : "docker-compose" ,
482+ docker_compose_file : "docker-compose.yml"
483+ }
484+
485+ const hash1 = getComposeHash ( compose )
486+
487+ // Should be the same as explicitly setting defaults (but empty arrays/objects are removed)
488+ const compose2 : AppCompose = {
489+ manifest_version : 1 ,
490+ runner : "docker-compose" ,
491+ docker_compose_file : "docker-compose.yml" ,
492+ public_logs : false ,
493+ public_sysinfo : false ,
494+ public_tcbinfo : true ,
495+ kms_enabled : false ,
496+ gateway_enabled : false ,
497+ local_key_provider_enabled : false ,
498+ no_instance_id : false ,
499+ secure_time : true
500+ // Empty arrays and objects are removed: features, docker_config, key_provider_id, allowed_envs, name
501+ }
502+
503+ expect ( hash1 ) . toBe ( getComposeHash ( compose2 ) )
504+ } )
505+ } )
506+
507+ describe ( 'Gateway/Tproxy Enabled Logic' , ( ) => {
508+ it ( 'should handle tproxy_enabled conversion to gateway_enabled' , ( ) => {
509+ const compose1 : AppCompose = {
510+ runner : "docker-compose" ,
511+ docker_compose_file : "docker-compose.yml" ,
512+ tproxy_enabled : true
513+ }
514+
515+ const compose2 : AppCompose = {
516+ manifest_version : 1 ,
517+ runner : "docker-compose" ,
518+ docker_compose_file : "docker-compose.yml" ,
519+ gateway_enabled : true ,
520+ public_logs : false ,
521+ public_sysinfo : false ,
522+ public_tcbinfo : true ,
523+ kms_enabled : false ,
524+ local_key_provider_enabled : false ,
525+ no_instance_id : false ,
526+ secure_time : true
527+ }
528+
529+ expect ( getComposeHash ( compose1 ) ) . toBe ( getComposeHash ( compose2 ) )
530+ } )
531+
532+ it ( 'should prioritize gateway_enabled over tproxy_enabled' , ( ) => {
533+ const compose1 : AppCompose = {
534+ runner : "docker-compose" ,
535+ docker_compose_file : "docker-compose.yml" ,
536+ gateway_enabled : false ,
537+ tproxy_enabled : true
538+ }
539+
540+ // Should result in gateway_enabled: true because tproxy_enabled is true
541+ const compose2 : AppCompose = {
542+ manifest_version : 1 ,
543+ runner : "docker-compose" ,
544+ docker_compose_file : "docker-compose.yml" ,
545+ gateway_enabled : true ,
546+ public_logs : false ,
547+ public_sysinfo : false ,
548+ public_tcbinfo : true ,
549+ kms_enabled : false ,
550+ local_key_provider_enabled : false ,
551+ no_instance_id : false ,
552+ secure_time : true
553+ }
554+
555+ expect ( getComposeHash ( compose1 ) ) . toBe ( getComposeHash ( compose2 ) )
556+ } )
557+ } )
558+
559+ describe ( 'Backward Compatibility' , ( ) => {
560+ it ( 'should still work with legacy bash_script and pre_launch_script' , ( ) => {
561+ const compose : AppCompose = {
562+ runner : "bash" ,
563+ bash_script : "start.sh" ,
564+ pre_launch_script : "echo 'Starting...'"
565+ }
566+
567+ const hash = getComposeHash ( compose )
568+ expect ( hash ) . toBeDefined ( )
569+ expect ( hash ) . toHaveLength ( 64 )
570+ } )
571+
572+ it ( 'should maintain deterministic behavior across versions' , ( ) => {
573+ // A compose with both old and new fields
574+ const compose : AppCompose = {
575+ runner : "docker-compose" ,
576+ docker_compose_file : "docker-compose.yml" ,
577+ bash_script : "start.sh" , // Should be removed by preprocessing
578+ features : [ "legacy-feature" ] ,
579+ public_logs : true ,
580+ kms_enabled : false ,
581+ gateway_enabled : true ,
582+ allowed_envs : [ "NODE_ENV" ] ,
583+ secure_time : false
584+ }
585+
586+ const hash = getComposeHash ( compose )
587+ expect ( hash ) . toBeDefined ( )
588+ expect ( hash ) . toHaveLength ( 64 )
589+ } )
590+ } )
379591} )
0 commit comments