@@ -193,6 +193,7 @@ def __init__(
193193 api_key : str ,
194194 ssh_user : str ,
195195 sign_gpg : bool ,
196+ ssh_key : str | None = None ,
196197 first_state : Task | None = None ,
197198 ) -> None :
198199 self .tasks = tasks
@@ -215,6 +216,8 @@ def __init__(
215216 self .db ["auth_info" ] = api_key
216217 if not self .db .get ("ssh_user" ):
217218 self .db ["ssh_user" ] = ssh_user
219+ if not self .db .get ("ssh_key" ):
220+ self .db ["ssh_key" ] = ssh_key
218221 if not self .db .get ("sign_gpg" ):
219222 self .db ["sign_gpg" ] = sign_gpg
220223
@@ -227,6 +230,7 @@ def __init__(
227230 print (f"- Normalized release tag: { release_tag .normalized ()} " )
228231 print (f"- Git repo: { self .db ['git_repo' ]} " )
229232 print (f"- SSH username: { self .db ['ssh_user' ]} " )
233+ print (f"- SSH key: { self .db ['ssh_key' ] or 'Default' } " )
230234 print (f"- python.org API key: { self .db ['auth_info' ]} " )
231235 print (f"- Sign with GPG: { self .db ['sign_gpg' ]} " )
232236 print ()
@@ -313,17 +317,17 @@ def check_ssh_connection(db: ReleaseShelf) -> None:
313317 client = paramiko .SSHClient ()
314318 client .load_system_host_keys ()
315319 client .set_missing_host_key_policy (paramiko .WarningPolicy )
316- client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ])
320+ client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
317321 client .exec_command ("pwd" )
318- client .connect (DOCS_SERVER , port = 22 , username = db ["ssh_user" ])
322+ client .connect (DOCS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
319323 client .exec_command ("pwd" )
320324
321325
322326def check_sigstore_client (db : ReleaseShelf ) -> None :
323327 client = paramiko .SSHClient ()
324328 client .load_system_host_keys ()
325329 client .set_missing_host_key_policy (paramiko .WarningPolicy )
326- client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ])
330+ client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
327331 _ , stdout , _ = client .exec_command ("python3 -m sigstore --version" )
328332 sigstore_version = stdout .read (1000 ).decode ()
329333 sigstore_vermatch = re .match ("^sigstore ([0-9.]+)" , sigstore_version )
@@ -398,6 +402,9 @@ def check_cpython_repo_is_clean(db: ReleaseShelf) -> None:
398402
399403def check_magic_number (db : ReleaseShelf ) -> None :
400404 release_tag = db ["release" ]
405+ if release_tag .major == 3 and release_tag .minor <= 13 :
406+ return
407+
401408 if release_tag .is_final or release_tag .is_release_candidate :
402409
403410 def out (msg : str ) -> None :
@@ -623,7 +630,7 @@ def sign_source_artifacts(db: ReleaseShelf) -> None:
623630
624631 subprocess .check_call (
625632 [
626- "python3" ,
633+ sys . executable ,
627634 "-m" ,
628635 "sigstore" ,
629636 "sign" ,
@@ -692,7 +699,7 @@ def upload_files_to_server(db: ReleaseShelf, server: str) -> None:
692699 client = paramiko .SSHClient ()
693700 client .load_system_host_keys ()
694701 client .set_missing_host_key_policy (paramiko .WarningPolicy )
695- client .connect (server , port = 22 , username = db ["ssh_user" ])
702+ client .connect (server , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
696703 transport = client .get_transport ()
697704 assert transport is not None , f"SSH transport to { server } is None"
698705
@@ -737,7 +744,7 @@ def place_files_in_download_folder(db: ReleaseShelf) -> None:
737744 client = paramiko .SSHClient ()
738745 client .load_system_host_keys ()
739746 client .set_missing_host_key_policy (paramiko .WarningPolicy )
740- client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ])
747+ client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
741748 transport = client .get_transport ()
742749 assert transport is not None , f"SSH transport to { DOWNLOADS_SERVER } is None"
743750
@@ -788,7 +795,7 @@ def unpack_docs_in_the_docs_server(db: ReleaseShelf) -> None:
788795 client = paramiko .SSHClient ()
789796 client .load_system_host_keys ()
790797 client .set_missing_host_key_policy (paramiko .WarningPolicy )
791- client .connect (DOCS_SERVER , port = 22 , username = db ["ssh_user" ])
798+ client .connect (DOCS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
792799 transport = client .get_transport ()
793800 assert transport is not None , f"SSH transport to { DOCS_SERVER } is None"
794801
@@ -905,7 +912,7 @@ def wait_until_all_files_are_in_folder(db: ReleaseShelf) -> None:
905912 client = paramiko .SSHClient ()
906913 client .load_system_host_keys ()
907914 client .set_missing_host_key_policy (paramiko .WarningPolicy )
908- client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ])
915+ client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
909916 ftp_client = client .open_sftp ()
910917
911918 destination = f"/srv/www.python.org/ftp/python/{ db ['release' ].normalized ()} "
@@ -943,7 +950,7 @@ def run_add_to_python_dot_org(db: ReleaseShelf) -> None:
943950 client = paramiko .SSHClient ()
944951 client .load_system_host_keys ()
945952 client .set_missing_host_key_policy (paramiko .WarningPolicy )
946- client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ])
953+ client .connect (DOWNLOADS_SERVER , port = 22 , username = db ["ssh_user" ], key_filename = db [ "ssh_key" ] )
947954 transport = client .get_transport ()
948955 assert transport is not None , f"SSH transport to { DOWNLOADS_SERVER } is None"
949956
@@ -1259,6 +1266,13 @@ def _api_key(api_key: str) -> str:
12591266 help = "Username to be used when authenticating via ssh" ,
12601267 type = str ,
12611268 )
1269+ parser .add_argument (
1270+ "--ssh-key" ,
1271+ dest = "ssh_key" ,
1272+ default = None ,
1273+ help = "Path to the SSH key file to use for authentication" ,
1274+ type = str ,
1275+ )
12621276 args = parser .parse_args ()
12631277
12641278 auth_key = args .auth_key or os .getenv ("AUTH_INFO" )
@@ -1353,6 +1367,7 @@ def _api_key(api_key: str) -> str:
13531367 api_key = auth_key ,
13541368 ssh_user = args .ssh_user ,
13551369 sign_gpg = not no_gpg ,
1370+ ssh_key = args .ssh_key ,
13561371 tasks = tasks ,
13571372 )
13581373 automata .run ()
0 commit comments