@@ -498,18 +498,19 @@ func TestBundle_Pull(t *testing.T) {
498498}
499499
500500func TestBundle_Verify (t * testing.T ) {
501-
502501 tests := []struct {
503- name string
504- bundle Bundle
505- wantErr bool
502+ name string
503+ bundle Bundle
504+ setupFs func (afero.Fs , string )
505+ usePublicKey bool
506+ wantErr bool
507+ wantErrContain string
506508 }{
507509 {
508510 name : "bundle with invalid public key path" ,
509511 bundle : Bundle {
510512 Name : "test" ,
511513 Data : []byte ("test" ),
512- Path : "/test/test.zip" ,
513514 Spec : & APISpec {
514515 APIDefinition : & apidef.APIDefinition {
515516 CustomMiddlewareBundle : "test-mw-bundle" ,
@@ -520,14 +521,14 @@ func TestBundle_Verify(t *testing.T) {
520521 },
521522 Gw : & Gateway {},
522523 },
523- wantErr : true ,
524+ usePublicKey : true ,
525+ wantErr : true ,
524526 },
525527 {
526528 name : "bundle without signature" ,
527529 bundle : Bundle {
528530 Name : "test" ,
529531 Data : []byte ("test" ),
530- Path : "/test/test.zip" ,
531532 Spec : & APISpec {
532533 APIDefinition : & apidef.APIDefinition {
533534 CustomMiddlewareBundle : "test-mw-bundle" ,
@@ -538,20 +539,142 @@ func TestBundle_Verify(t *testing.T) {
538539 },
539540 Gw : & Gateway {},
540541 },
541- wantErr : true ,
542+ usePublicKey : true ,
543+ wantErr : true ,
544+ },
545+ {
546+ name : "valid checksum with empty file list" ,
547+ bundle : Bundle {
548+ Name : "test" ,
549+ Spec : & APISpec {
550+ APIDefinition : & apidef.APIDefinition {
551+ CustomMiddlewareBundle : "test-mw-bundle" ,
552+ },
553+ },
554+ Manifest : apidef.BundleManifest {
555+ Checksum : "d41d8cd98f00b204e9800998ecf8427e" , // MD5 of the empty string
556+ FileList : []string {},
557+ },
558+ Gw : & Gateway {},
559+ },
560+ usePublicKey : false ,
561+ wantErr : false ,
562+ },
563+ {
564+ name : "invalid checksum returns error" ,
565+ bundle : Bundle {
566+ Name : "test" ,
567+ Spec : & APISpec {
568+ APIDefinition : & apidef.APIDefinition {
569+ CustomMiddlewareBundle : "test-mw-bundle" ,
570+ },
571+ },
572+ Manifest : apidef.BundleManifest {
573+ Checksum : "invalidchecksum123" ,
574+ FileList : []string {},
575+ },
576+ Gw : & Gateway {},
577+ },
578+ usePublicKey : false ,
579+ wantErr : true ,
580+ wantErrContain : "Invalid checksum" ,
581+ },
582+ {
583+ name : "file not found in file list" ,
584+ bundle : Bundle {
585+ Name : "test" ,
586+ Spec : & APISpec {
587+ APIDefinition : & apidef.APIDefinition {
588+ CustomMiddlewareBundle : "test-mw-bundle" ,
589+ },
590+ },
591+ Manifest : apidef.BundleManifest {
592+ Checksum : "d41d8cd98f00b204e9800998ecf8427e" ,
593+ FileList : []string {"nonexistent.py" },
594+ },
595+ Gw : & Gateway {},
596+ },
597+ setupFs : func (fs afero.Fs , bundlePath string ) {},
598+ usePublicKey : false ,
599+ wantErr : true ,
600+ },
601+ {
602+ name : "valid checksum with multiple files" ,
603+ bundle : Bundle {
604+ Name : "test" ,
605+ Spec : & APISpec {
606+ APIDefinition : & apidef.APIDefinition {
607+ CustomMiddlewareBundle : "test-mw-bundle" ,
608+ },
609+ },
610+ Manifest : apidef.BundleManifest {
611+ // MD5 of "file1 contentfile2 content"
612+ Checksum : "1510d0e71b31de1c78fd9e823a7c6de9" ,
613+ FileList : []string {"file1.py" , "file2.py" },
614+ },
615+ Gw : & Gateway {},
616+ },
617+ setupFs : func (fs afero.Fs , bundlePath string ) {
618+ assert .NoError (t , afero .WriteFile (fs , filepath .Join (bundlePath , "file1.py" ), []byte ("file1 content" ), 0644 ))
619+ assert .NoError (t , afero .WriteFile (fs , filepath .Join (bundlePath , "file2.py" ), []byte ("file2 content" ), 0644 ))
620+ },
621+ usePublicKey : false ,
622+ wantErr : false ,
623+ },
624+ {
625+ name : "invalid base64 signature returns error" ,
626+ bundle : Bundle {
627+ Name : "test" ,
628+ Spec : & APISpec {
629+ APIDefinition : & apidef.APIDefinition {
630+ CustomMiddlewareBundle : "test-mw-bundle" ,
631+ },
632+ },
633+ Manifest : apidef.BundleManifest {
634+ Checksum : "d41d8cd98f00b204e9800998ecf8427e" ,
635+ FileList : []string {},
636+ Signature : "!!!invalid-base64!!!" ,
637+ },
638+ Gw : & Gateway {},
639+ },
640+ usePublicKey : true ,
641+ wantErr : true ,
542642 },
543643 }
544644 for _ , tt := range tests {
545645 t .Run (tt .name , func (t * testing.T ) {
546646 b := tt .bundle
547647
548648 globalConf := config.Config {}
549- globalConf .PublicKeyPath = "test"
649+ if tt .usePublicKey {
650+ pemfile := createPEMFile (t )
651+ t .Cleanup (func () {
652+ _ = pemfile .Close ()
653+ _ = os .Remove (pemfile .Name ())
654+ })
655+ globalConf .PublicKeyPath = pemfile .Name ()
656+ }
550657 b .Gw .SetConfig (globalConf )
551658
552- if err := b .Verify (afero .NewOsFs ()); (err != nil ) != tt .wantErr {
659+ fs := afero .NewMemMapFs ()
660+ bundlePath := "/test/bundles/test-bundle"
661+ b .Path = bundlePath
662+
663+ if err := fs .MkdirAll (bundlePath , 0755 ); err != nil {
664+ t .Fatalf ("failed to create bundle directory: %v" , err )
665+ }
666+
667+ if tt .setupFs != nil {
668+ tt .setupFs (fs , bundlePath )
669+ }
670+
671+ err := b .Verify (fs )
672+ if (err != nil ) != tt .wantErr {
553673 t .Errorf ("Bundle.Verify() error = %v, wantErr %v" , err , tt .wantErr )
554674 }
675+ if tt .wantErrContain != "" && err != nil {
676+ assert .ErrorContains (t , err , tt .wantErrContain )
677+ }
555678 })
556679 }
557680}
@@ -583,3 +706,84 @@ func createPEMFile(t *testing.T) *os.File {
583706
584707 return tmpfile
585708}
709+
710+ func setupBenchmarkBundle (b * testing.B , fs afero.Fs , bundlePath string , fileSize , numFiles int ) * Bundle {
711+ b .Helper ()
712+
713+ if err := fs .MkdirAll (bundlePath , 0755 ); err != nil {
714+ b .Fatalf ("failed to create bundle directory: %v" , err )
715+ }
716+
717+ fileContent := make ([]byte , fileSize )
718+ for i := range fileContent {
719+ fileContent [i ] = 'A'
720+ }
721+
722+ fileList := make ([]string , numFiles )
723+ md5Hash := md5 .New ()
724+
725+ for i := 0 ; i < numFiles ; i ++ {
726+ fileName := fmt .Sprintf ("file%d.py" , i )
727+ fileList [i ] = fileName
728+ filePath := filepath .Join (bundlePath , fileName )
729+
730+ if err := afero .WriteFile (fs , filePath , fileContent , 0644 ); err != nil {
731+ b .Fatalf ("failed to write file %s: %v" , fileName , err )
732+ }
733+
734+ md5Hash .Write (fileContent )
735+ }
736+
737+ checksum := fmt .Sprintf ("%x" , md5Hash .Sum (nil ))
738+
739+ if numFiles == 0 {
740+ checksum = "d41d8cd98f00b204e9800998ecf8427e"
741+ }
742+
743+ return & Bundle {
744+ Name : "benchmark-bundle" ,
745+ Path : bundlePath ,
746+ Spec : & APISpec {
747+ APIDefinition : & apidef.APIDefinition {
748+ CustomMiddlewareBundle : "benchmark-bundle.zip" ,
749+ },
750+ },
751+ Manifest : apidef.BundleManifest {
752+ Checksum : checksum ,
753+ FileList : fileList ,
754+ },
755+ Gw : & Gateway {},
756+ }
757+ }
758+
759+ func BenchmarkBundle_Verify (b * testing.B ) {
760+ benchmarks := []struct {
761+ name string
762+ fileSize int
763+ numFiles int
764+ }{
765+ {"empty_file_list" , 0 , 0 },
766+ {"single_small_file_1KB" , 1024 , 1 },
767+ {"single_large_file_1MB" , 1024 * 1024 , 1 },
768+ {"multiple_files_10x10KB" , 10 * 1024 , 10 },
769+ }
770+
771+ for _ , bm := range benchmarks {
772+ b .Run (bm .name , func (b * testing.B ) {
773+ // Setup bundle and filesystem
774+ fs := afero .NewMemMapFs ()
775+ bundlePath := "/test/bundles/benchmark-bundle"
776+ bundle := setupBenchmarkBundle (b , fs , bundlePath , bm .fileSize , bm .numFiles )
777+
778+ // Configure GW with no public key (no signature verification)
779+ bundle .Gw .SetConfig (config.Config {})
780+
781+ b .ResetTimer ()
782+ b .ReportAllocs ()
783+
784+ for i := 0 ; i < b .N ; i ++ {
785+ _ = bundle .Verify (fs )
786+ }
787+ })
788+ }
789+ }
0 commit comments