@@ -115,32 +115,44 @@ def test_execute_attestation
115115 assert_equal Gem ::Net ::HTTP ::Post , @fetcher . last_request . class
116116 content_length = @fetcher . last_request [ "Content-Length" ] . to_i
117117 assert_equal content_length , @fetcher . last_request . body . length
118- assert_equal "multipart" , @fetcher . last_request . main_type , @fetcher . last_request . content_type
119- assert_equal "form-data" , @fetcher . last_request . sub_type
120- assert_include @fetcher . last_request . type_params , "boundary"
121- boundary = @fetcher . last_request . type_params [ "boundary" ]
118+ assert_attestation_multipart Gem . read_binary ( "#{ @path } .sigstore.json" )
119+ end
122120
123- parts = @fetcher . last_request . body . split ( /(?:\r \n |\A )--#{ Regexp . quote ( boundary ) } (?:\r \n |--)/m )
124- refute_empty parts
125- assert_empty parts [ 0 ]
126- parts . shift # remove the first empty part
121+ def test_execute_attestation_auto
122+ @response = "Successfully registered gem: freewill (1.0.0)"
123+ @fetcher . data [ "#{ Gem . host } /api/v1/gems" ] = HTTPResponseFactory . create ( body : @response , code : 200 , msg : "OK" )
127124
128- p1 = parts . shift
129- p2 = parts . shift
130- assert_equal "\r \n " , parts . shift
131- assert_empty parts
125+ attestation_path = "#{ @path } .sigstore.json"
126+ File . write ( attestation_path , "auto-attestation" )
127+ @cmd . options [ :args ] = [ @path ]
132128
133- assert_equal [
134- "Content-Disposition: form-data; name=\" gem\" ; filename=\" #{ @path } \" " ,
135- "Content-Type: application/octet-stream" ,
136- nil ,
137- Gem . read_binary ( @path ) ,
138- ] . join ( "\r \n " ) . b , p1
139- assert_equal [
140- "Content-Disposition: form-data; name=\" attestations\" " ,
141- nil ,
142- "[#{ Gem . read_binary ( "#{ @path } .sigstore.json" ) } ]" ,
143- ] . join ( "\r \n " ) . b , p2
129+ @cmd . stub ( :attest! , attestation_path ) do
130+ @cmd . execute
131+ end
132+
133+ assert_equal Gem ::Net ::HTTP ::Post , @fetcher . last_request . class
134+ content_length = @fetcher . last_request [ "Content-Length" ] . to_i
135+ assert_equal content_length , @fetcher . last_request . body . length
136+ assert_attestation_multipart Gem . read_binary ( attestation_path )
137+ end
138+
139+ def test_execute_attestation_fallback
140+ @response = "Successfully registered gem: freewill (1.0.0)"
141+ @fetcher . data [ "#{ Gem . host } /api/v1/gems" ] = HTTPResponseFactory . create ( body : @response , code : 200 , msg : "OK" )
142+
143+ @cmd . options [ :args ] = [ @path ]
144+
145+ @cmd . stub ( :attest! , proc { raise Gem ::Exception , "boom" } ) do
146+ use_ui @ui do
147+ @cmd . execute
148+ end
149+ end
150+
151+ assert_match "Failed to push with attestation, retrying without attestation." , @ui . error
152+ assert_equal Gem ::Net ::HTTP ::Post , @fetcher . last_request . class
153+ assert_equal Gem . read_binary ( @path ) , @fetcher . last_request . body
154+ assert_equal "application/octet-stream" ,
155+ @fetcher . last_request [ "Content-Type" ]
144156 end
145157
146158 def test_execute_allowed_push_host
@@ -643,6 +655,35 @@ def test_sending_gem_with_no_local_creds
643655
644656 private
645657
658+ def assert_attestation_multipart ( attestation_payload )
659+ assert_equal "multipart" , @fetcher . last_request . main_type , @fetcher . last_request . content_type
660+ assert_equal "form-data" , @fetcher . last_request . sub_type
661+ assert_include @fetcher . last_request . type_params , "boundary"
662+ boundary = @fetcher . last_request . type_params [ "boundary" ]
663+
664+ parts = @fetcher . last_request . body . split ( /(?:\r \n |\A )--#{ Regexp . quote ( boundary ) } (?:\r \n |--)/m )
665+ refute_empty parts
666+ assert_empty parts [ 0 ]
667+ parts . shift # remove the first empty part
668+
669+ p1 = parts . shift
670+ p2 = parts . shift
671+ assert_equal "\r \n " , parts . shift
672+ assert_empty parts
673+
674+ assert_equal [
675+ "Content-Disposition: form-data; name=\" gem\" ; filename=\" #{ @path } \" " ,
676+ "Content-Type: application/octet-stream" ,
677+ nil ,
678+ Gem . read_binary ( @path ) ,
679+ ] . join ( "\r \n " ) . b , p1
680+ assert_equal [
681+ "Content-Disposition: form-data; name=\" attestations\" " ,
682+ nil ,
683+ "[#{ attestation_payload } ]" ,
684+ ] . join ( "\r \n " ) . b , p2
685+ end
686+
646687 def singleton_gem_class
647688 class << Gem ; self ; end
648689 end
0 commit comments