@@ -3877,6 +3877,49 @@ def fake_install_from_zip(self, zip_path, speckit_version, priority=10):
38773877 assert exc_info .value .exit_code == 1
38783878 assert installed is False
38793879
3880+ def test_preset_add_from_url_rejects_hostless_https_url (self , project_dir ):
3881+ """URL installs reject HTTPS URLs without a hostname before downloading."""
3882+ from typer .testing import CliRunner
3883+ from unittest .mock import patch
3884+ from specify_cli import app
3885+
3886+ runner = CliRunner ()
3887+ with patch .object (Path , "cwd" , return_value = project_dir ), \
3888+ patch ("specify_cli.authentication.http.open_url" ) as open_url :
3889+ result = runner .invoke (app , ["preset" , "add" , "--from" , "https:///preset.zip" ])
3890+
3891+ assert result .exit_code == 1
3892+ assert "URL must use HTTPS" in strip_ansi (result .output )
3893+ open_url .assert_not_called ()
3894+
3895+ def test_preset_add_from_url_redirect_error_describes_disallowed_url (self , project_dir , monkeypatch , capsys ):
3896+ """Redirect rejection message covers hostless HTTPS, not only non-HTTPS URLs."""
3897+ import typer
3898+ from specify_cli .presets ._commands import preset_add
3899+
3900+ class FakeResponse (io .BytesIO ):
3901+ def __enter__ (self ):
3902+ return self
3903+
3904+ def __exit__ (self , exc_type , exc , tb ):
3905+ return False
3906+
3907+ def geturl (self ):
3908+ return "https:///preset.zip"
3909+
3910+ monkeypatch .setattr ("specify_cli._require_specify_project" , lambda : project_dir )
3911+ monkeypatch .setattr ("specify_cli.get_speckit_version" , lambda : "0.6.0" )
3912+ monkeypatch .setattr ("specify_cli.authentication.http.open_url" , lambda url , timeout : FakeResponse (b"zip" ))
3913+ monkeypatch .setattr (PresetManager , "install_from_zip" , lambda * args , ** kwargs : None )
3914+
3915+ with pytest .raises (typer .Exit ) as exc_info :
3916+ preset_add (preset_id = None , from_url = "https://example.com/preset.zip" , dev = None , priority = 10 )
3917+
3918+ assert exc_info .value .exit_code == 1
3919+ output = strip_ansi (capsys .readouterr ().out )
3920+ assert "redirected to a disallowed URL" in output
3921+ assert "must use HTTPS with a hostname" in output
3922+
38803923 def test_preset_add_from_url_streams_download_to_zip (self , project_dir , monkeypatch ):
38813924 """URL installs stream response bytes to disk before installing the ZIP."""
38823925 from specify_cli .presets ._commands import preset_add
0 commit comments