@@ -248,3 +248,196 @@ def test_update_whatsnew_toctree(tmp_path: Path) -> None:
248248 # Assert
249249 new_contents = toctree__file .read_text ()
250250 assert " 3.15.rst\n 3.14.rst\n " in new_contents
251+
252+
253+ def test_run_add_to_python_dot_org_quotes_remote_environment (monkeypatch ) -> None :
254+ commands = []
255+
256+ class FakeSFTPClient :
257+ def put (self , source : str , destination : str ) -> None :
258+ pass
259+
260+ def close (self ) -> None :
261+ pass
262+
263+ class FakeSSHClient :
264+ def load_system_host_keys (self ) -> None :
265+ pass
266+
267+ def set_missing_host_key_policy (self , policy ) -> None :
268+ pass
269+
270+ def connect (self , * args , ** kwargs ) -> None :
271+ pass
272+
273+ def get_transport (self ):
274+ return object ()
275+
276+ def exec_command (self , command : str ):
277+ commands .append (command )
278+ return None , io .BytesIO (b"ok" ), io .BytesIO ()
279+
280+ class FakeIssuer :
281+ def __init__ (self , issuer_url : str ) -> None :
282+ self .issuer_url = issuer_url
283+
284+ def identity_token (self ) -> str :
285+ return "token; touch /tmp/pwned"
286+
287+ monkeypatch .setattr (run_release .paramiko , "SSHClient" , FakeSSHClient )
288+ monkeypatch .setattr (
289+ run_release .MySFTPClient ,
290+ "from_transport" ,
291+ staticmethod (lambda transport : FakeSFTPClient ()),
292+ )
293+ monkeypatch .setattr (run_release .sigstore .oidc , "Issuer" , FakeIssuer )
294+
295+ db = {
296+ "auth_info" : "user:key; echo pwned" ,
297+ "release" : Tag ("3.15.0a1" ),
298+ "ssh_key" : None ,
299+ "ssh_user" : "release-manager" ,
300+ }
301+
302+ run_release .run_add_to_python_dot_org (cast (ReleaseShelf , db ))
303+
304+ assert commands == [
305+ "AUTH_INFO='user:key; echo pwned' "
306+ "SIGSTORE_IDENTITY_TOKEN='token; touch /tmp/pwned' "
307+ "python3 add_to_pydotorg.py 3.15.0a1"
308+ ]
309+
310+
311+ def test_upload_files_to_server_quotes_remote_cleanup_path (
312+ monkeypatch , tmp_path : Path
313+ ) -> None :
314+ commands = []
315+
316+ class FakeSFTPClient :
317+ def mkdir (self , path : str ) -> None :
318+ pass
319+
320+ def put_dir (self , source : Path , target : str , progress ) -> None :
321+ pass
322+
323+ def close (self ) -> None :
324+ pass
325+
326+ class FakeSSHClient :
327+ def load_system_host_keys (self ) -> None :
328+ pass
329+
330+ def set_missing_host_key_policy (self , policy ) -> None :
331+ pass
332+
333+ def connect (self , * args , ** kwargs ) -> None :
334+ pass
335+
336+ def get_transport (self ):
337+ return object ()
338+
339+ def exec_command (self , command : str ) -> None :
340+ commands .append (command )
341+
342+ @contextlib .contextmanager
343+ def fake_alive_bar (total : int ):
344+ yield lambda * args , ** kwargs : None
345+
346+ release = Tag ("3.15.0a1" )
347+ artifacts_path = tmp_path / str (release )
348+ (artifacts_path / "downloads" ).mkdir (parents = True )
349+
350+ monkeypatch .setattr (run_release .paramiko , "SSHClient" , FakeSSHClient )
351+ monkeypatch .setattr (
352+ run_release .MySFTPClient ,
353+ "from_transport" ,
354+ staticmethod (lambda transport : FakeSFTPClient ()),
355+ )
356+ monkeypatch .setattr (run_release , "alive_bar" , fake_alive_bar )
357+
358+ db = {
359+ "git_repo" : tmp_path ,
360+ "release" : release ,
361+ "ssh_key" : None ,
362+ "ssh_user" : "release-manager; touch /tmp/pwned #" ,
363+ }
364+
365+ run_release .upload_files_to_server (
366+ cast (ReleaseShelf , db ), run_release .DOWNLOADS_SERVER
367+ )
368+
369+ assert commands == [
370+ "rm -rf '/home/psf-users/release-manager; touch /tmp/pwned #/3.15.0a1'"
371+ ]
372+
373+
374+ def test_release_file_placement_quotes_remote_paths (monkeypatch ) -> None :
375+ commands = []
376+
377+ class FakeChannel :
378+ def exec_command (self , command : str ) -> None :
379+ commands .append (command )
380+
381+ def recv_exit_status (self ) -> int :
382+ return 0
383+
384+ def recv_stderr (self , size : int ) -> bytes :
385+ return b""
386+
387+ class FakeTransport :
388+ def open_session (self ) -> FakeChannel :
389+ return FakeChannel ()
390+
391+ class FakeSSHClient :
392+ def load_system_host_keys (self ) -> None :
393+ pass
394+
395+ def set_missing_host_key_policy (self , policy ) -> None :
396+ pass
397+
398+ def connect (self , * args , ** kwargs ) -> None :
399+ pass
400+
401+ def get_transport (self ) -> FakeTransport :
402+ return FakeTransport ()
403+
404+ monkeypatch .setattr (run_release .paramiko , "SSHClient" , FakeSSHClient )
405+
406+ db = {
407+ "release" : Tag ("3.15.0rc1" ),
408+ "ssh_key" : None ,
409+ "ssh_user" : "release-manager; touch /tmp/pwned #" ,
410+ }
411+
412+ run_release .place_files_in_download_folder (cast (ReleaseShelf , db ))
413+ run_release .unpack_docs_in_the_docs_server (cast (ReleaseShelf , db ))
414+
415+ assert commands == [
416+ "mkdir -p /srv/www.python.org/ftp/python/3.15.0" ,
417+ "cp '/home/psf-users/release-manager; touch /tmp/pwned #/3.15.0rc1'/downloads/* "
418+ "/srv/www.python.org/ftp/python/3.15.0" ,
419+ "find /srv/www.python.org/ftp/python/3.15.0 -maxdepth 0 ! -group downloads "
420+ "-exec chgrp downloads {} +" ,
421+ "find /srv/www.python.org/ftp/python/3.15.0 -maxdepth 0 ! -perm 775 "
422+ "-exec chmod 775 {} +" ,
423+ "find /srv/www.python.org/ftp/python/3.15.0 -type f ! -perm 664 "
424+ "-exec chmod 664 {} +" ,
425+ "mkdir -p /srv/www.python.org/ftp/python/doc/3.15.0rc1" ,
426+ "cp '/home/psf-users/release-manager; touch /tmp/pwned #/3.15.0rc1'/docs/* "
427+ "/srv/www.python.org/ftp/python/doc/3.15.0rc1" ,
428+ "find /srv/www.python.org/ftp/python/doc/3.15.0rc1 -maxdepth 0 ! -group downloads "
429+ "-exec chgrp downloads {} +" ,
430+ "find /srv/www.python.org/ftp/python/doc/3.15.0rc1 -maxdepth 0 ! -perm 775 "
431+ "-exec chmod 775 {} +" ,
432+ "find /srv/www.python.org/ftp/python/doc/3.15.0rc1 -type f ! -perm 664 "
433+ "-exec chmod 664 {} +" ,
434+ "mkdir -p /srv/docs.python.org/release/3.15.0rc1" ,
435+ "unzip '/home/psf-users/release-manager; touch /tmp/pwned #/3.15.0rc1/docs/"
436+ "python-3.15.0rc1-docs-html.zip' -d /srv/docs.python.org/release/3.15.0rc1" ,
437+ "mv //srv/docs.python.org/release/3.15.0rc1/python-3.15.0rc1-docs-html/* "
438+ "/srv/docs.python.org/release/3.15.0rc1" ,
439+ "rm -rf //srv/docs.python.org/release/3.15.0rc1/python-3.15.0rc1-docs-html" ,
440+ "chgrp -R docs /srv/docs.python.org/release/3.15.0rc1" ,
441+ "chmod -R 775 /srv/docs.python.org/release/3.15.0rc1" ,
442+ "find /srv/docs.python.org/release/3.15.0rc1 -type f -exec chmod 664 {} \\ ;" ,
443+ ]
0 commit comments