@@ -390,12 +390,11 @@ def init_git_repo(project_path: Path, quiet: bool = False) -> bool:
390390 os .chdir (original_cwd )
391391
392392
393- def download_template_from_github (ai_assistant : str , download_dir : Path , * , verbose : bool = True , show_progress : bool = True ):
394- """Download the latest template release from GitHub using HTTP requests.
395- Returns (zip_path, metadata_dict)
396- """
393+ def download_template_from_github (ai_assistant : str , download_dir : Path , * , verbose : bool = True , show_progress : bool = True , client : httpx .Client = None ):
397394 repo_owner = "github"
398395 repo_name = "spec-kit"
396+ if client is None :
397+ client = httpx .Client (verify = ssl_context )
399398
400399 if verbose :
401400 console .print ("[cyan]Fetching latest release information...[/cyan]" )
@@ -405,7 +404,7 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, verb
405404 response = client .get (api_url , timeout = 30 , follow_redirects = True )
406405 response .raise_for_status ()
407406 release_data = response .json ()
408- except client .RequestError as e :
407+ except httpx .RequestError as e :
409408 if verbose :
410409 console .print (f"[red]Error fetching release information:[/red] { e } " )
411410 raise typer .Exit (1 )
@@ -445,15 +444,12 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, verb
445444 with client .stream ("GET" , download_url , timeout = 30 , follow_redirects = True ) as response :
446445 response .raise_for_status ()
447446 total_size = int (response .headers .get ('content-length' , 0 ))
448-
449447 with open (zip_path , 'wb' ) as f :
450448 if total_size == 0 :
451- # No content-length header, download without progress
452449 for chunk in response .iter_bytes (chunk_size = 8192 ):
453450 f .write (chunk )
454451 else :
455452 if show_progress :
456- # Show progress bar
457453 with Progress (
458454 SpinnerColumn (),
459455 TextColumn ("[progress.description]{task.description}" ),
@@ -467,11 +463,9 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, verb
467463 downloaded += len (chunk )
468464 progress .update (task , completed = downloaded )
469465 else :
470- # Silent download loop
471466 for chunk in response .iter_bytes (chunk_size = 8192 ):
472467 f .write (chunk )
473-
474- except client .RequestError as e :
468+ except httpx .RequestError as e :
475469 if verbose :
476470 console .print (f"[red]Error downloading template:[/red] { e } " )
477471 if zip_path .exists ():
@@ -488,7 +482,7 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, verb
488482 return zip_path , metadata
489483
490484
491- def download_and_extract_template (project_path : Path , ai_assistant : str , is_current_dir : bool = False , * , verbose : bool = True , tracker : StepTracker | None = None ) -> Path :
485+ def download_and_extract_template (project_path : Path , ai_assistant : str , is_current_dir : bool = False , * , verbose : bool = True , tracker : StepTracker | None = None , client : httpx . Client = None ) -> Path :
492486 """Download the latest release and extract it to create a new project.
493487 Returns project_path. Uses tracker if provided (with keys: fetch, download, extract, cleanup)
494488 """
@@ -502,12 +496,13 @@ def download_and_extract_template(project_path: Path, ai_assistant: str, is_curr
502496 ai_assistant ,
503497 current_dir ,
504498 verbose = verbose and tracker is None ,
505- show_progress = (tracker is None )
499+ show_progress = (tracker is None ),
500+ client = client
506501 )
507502 if tracker :
508503 tracker .complete ("fetch" , f"release { meta ['release' ]} ({ meta ['size' ]:,} bytes)" )
509504 tracker .add ("download" , "Download template" )
510- tracker .complete ("download" , meta ['filename' ]) # already downloaded inside helper
505+ tracker .complete ("download" , meta ['filename' ])
511506 except Exception as e :
512507 if tracker :
513508 tracker .error ("fetch" , str (e ))
@@ -647,6 +642,7 @@ def init(
647642 ignore_agent_tools : bool = typer .Option (False , "--ignore-agent-tools" , help = "Skip checks for AI agent tools like Claude Code" ),
648643 no_git : bool = typer .Option (False , "--no-git" , help = "Skip git repository initialization" ),
649644 here : bool = typer .Option (False , "--here" , help = "Initialize project in the current directory instead of creating a new one" ),
645+ skip_tls : bool = typer .Option (False , "--skip-tls" , help = "Skip SSL/TLS verification (not recommended)" ),
650646):
651647 """
652648 Initialize a new Specify project from the latest template.
@@ -775,7 +771,12 @@ def init(
775771 with Live (tracker .render (), console = console , refresh_per_second = 8 , transient = True ) as live :
776772 tracker .attach_refresh (lambda : live .update (tracker .render ()))
777773 try :
778- download_and_extract_template (project_path , selected_ai , here , verbose = False , tracker = tracker )
774+ # Create a httpx client with verify based on skip_tls
775+ verify = not skip_tls
776+ local_ssl_context = ssl_context if verify else False
777+ local_client = httpx .Client (verify = local_ssl_context )
778+
779+ download_and_extract_template (project_path , selected_ai , here , verbose = False , tracker = tracker , client = local_client )
779780
780781 # Git step
781782 if not no_git :
@@ -839,21 +840,25 @@ def init(
839840 # Removed farewell line per user request
840841
841842
843+ # Add skip_tls option to check
842844@app .command ()
843- def check ():
845+ def check (skip_tls : bool = typer . Option ( False , "--skip-tls" , help = "Skip SSL/TLS verification (not recommended)" ) ):
844846 """Check that all required tools are installed."""
845847 show_banner ()
846848 console .print ("[bold]Checking Specify requirements...[/bold]\n " )
847-
849+
848850 # Check if we have internet connectivity by trying to reach GitHub API
849851 console .print ("[cyan]Checking internet connectivity...[/cyan]" )
852+ verify = not skip_tls
853+ local_ssl_context = ssl_context if verify else False
854+ local_client = httpx .Client (verify = local_ssl_context )
850855 try :
851- response = client .get ("https://api.github.com" , timeout = 5 , follow_redirects = True )
856+ response = local_client .get ("https://api.github.com" , timeout = 5 , follow_redirects = True )
852857 console .print ("[green]✓[/green] Internet connection available" )
853- except client .RequestError :
858+ except httpx .RequestError :
854859 console .print ("[red]✗[/red] No internet connection - required for downloading templates" )
855860 console .print ("[yellow]Please check your internet connection[/yellow]" )
856-
861+
857862 console .print ("\n [cyan]Optional tools:[/cyan]" )
858863 git_ok = check_tool ("git" , "https://git-scm.com/downloads" )
859864
0 commit comments