1313# limitations under the License.
1414#
1515
16- import base64
1716import os
1817import subprocess
1918from pathlib import Path
2827class NexusFixture (BaseFixture ):
2928 """Fixture provider that downloads MCAP files from Nexus repository."""
3029
31- NEXUS_CI_USERNAME = os .getenv ('NEXUS_CI_USERNAME' , '' )
32- NEXUS_CI_PASSWORD = os .getenv ('NEXUS_CI_PASSWORD' , '' )
33- NEXUS_SERVER = os .getenv ('NEXUS_SERVER' , '' )
34- NEXUS_REPOSITORY = os .getenv ('NEXUS_REPOSITORY' , 'rosbag-hosted' )
35-
3630 def __init__ (self , path : str ):
3731 self .nexus_path = path
3832
@@ -47,19 +41,17 @@ def download(self, destination_folder: Path) -> Mcap:
4741 Mcap: A Mcap object with paths
4842 to downloaded files
4943 """
50-
51- if self .NEXUS_CI_USERNAME == 'ci' :
52- decoded_password = base64 .b64decode (self .NEXUS_CI_PASSWORD ).decode ().strip ()
53- else :
54- decoded_password = self .NEXUS_CI_PASSWORD
55- _logger_ .info (f'NEXUS_SERVER: { self .NEXUS_SERVER } ' )
56- _logger_ .info (f'NEXUS_REPOSITORY: { self .NEXUS_REPOSITORY } ' )
44+ # Read environment variables at runtime, not at class definition time
45+ username = os .getenv ('NEXUS_USERNAME' , '' )
46+ password = os .getenv ('NEXUS_PASSWORD' , '' )
47+ server = os .getenv ('NEXUS_SERVER' , '' )
48+ repo = os .getenv ('NEXUS_REPOSITORY' , '' )
49+ extra_headers = os .getenv ('NEXUS_EXTRA_HEADERS' , '' )
50+ _logger_ .info (f'NEXUS_SERVER: { server } ' )
51+ _logger_ .info (f'NEXUS_REPOSITORY: { repo } ' )
52+ _logger_ .info (f'NEXUS_USERNAME: { username } ' )
5753 _logger_ .info (f'Downloading { self .nexus_path } to { destination_folder } ' )
5854
59- server = self .NEXUS_SERVER
60- repo = self .NEXUS_REPOSITORY
61- username = self .NEXUS_CI_USERNAME
62-
6355 nexus_filename = self .nexus_path .split ('/' )[- 1 ]
6456
6557 curl_dest = destination_folder / nexus_filename
@@ -68,20 +60,47 @@ def download(self, destination_folder: Path) -> Mcap:
6860 'curl' ,
6961 '-v' ,
7062 '-u' ,
71- f'{ username } :{ decoded_password } ' ,
63+ f'{ username } :{ password } ' ,
7264 '-sL' ,
7365 '-o' ,
7466 str (curl_dest ),
67+ '-w' ,
68+ '%{http_code}' ,
7569 f'{ server } /repository/{ repo } /{ self .nexus_path } ' ,
7670 ]
7771
72+ if extra_headers :
73+ for header in extra_headers .split (';' ):
74+ header = header .strip ()
75+ if header :
76+ curl_command .extend (['-H' , header ])
77+
7878 result = subprocess .run (curl_command , capture_output = True , text = True )
7979
80- if result .returncode == 0 :
81- _logger_ .info (f'Download successful: { curl_dest } ' )
82- return Mcap (path = curl_dest )
83- else :
80+ http_code = result .stdout .strip ()
81+
82+ if result .returncode != 0 :
8483 _logger_ .error (f'Download failed for { self .nexus_path } ' )
85- _logger_ .error (f'STDOUT : { result . stdout } ' )
84+ _logger_ .error (f'HTTP status code : { http_code } ' )
8685 _logger_ .error (f'STDERR: { result .stderr } ' )
8786 raise RuntimeError (f'Failed to download fixture from Nexus: { self .nexus_path } ' )
87+
88+ if not http_code .startswith ('2' ):
89+ _logger_ .error (f'Download failed for { self .nexus_path } ' )
90+ _logger_ .error (f'HTTP status code: { http_code } ' )
91+ _logger_ .error (f'STDERR: { result .stderr } ' )
92+ raise RuntimeError (f'Failed to download fixture from Nexus: { self .nexus_path } (HTTP { http_code } )' )
93+
94+ # Verify the downloaded file is an MCAP by checking magic bytes
95+ mcap_magic = b'\x89 MCAP0\r \n '
96+ with Path .open (curl_dest , 'rb' ) as f :
97+ file_header = f .read (len (mcap_magic ))
98+ if file_header != mcap_magic :
99+ _logger_ .error (f'Downloaded file is not a valid MCAP: { curl_dest } ' )
100+ _logger_ .error (f'Expected magic bytes: { mcap_magic !r} , got: { file_header !r} ' )
101+ raise RuntimeError (
102+ f'Downloaded file is not a valid MCAP (possibly a Cloudflare challenge page): { self .nexus_path } '
103+ )
104+
105+ _logger_ .info (f'Download successful: { curl_dest } (HTTP { http_code } )' )
106+ return Mcap (path = curl_dest )
0 commit comments